001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2015 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029package edu.wisc.ssec.mcidasv.data.hydra; 030 031import java.io.File; 032import java.io.IOException; 033import java.util.ArrayList; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.List; 038import java.util.Map; 039import java.util.Set; 040import java.util.StringTokenizer; 041 042import ucar.nc2.Attribute; 043import ucar.nc2.NetcdfFile; 044 045/** 046 * Utility class to support Joint Polar Satellite System (JPSS) functionality. 047 * Documentation referenced is from Suomi NPP Common Data Format Control Book. 048 * See: 049 * http://jointmission.gsfc.nasa.gov/science/documents.html 050 * 051 * @author tommyj 052 * 053 */ 054 055public abstract class JPSSUtilities { 056 057 public static final String JPSS_FIELD_SEPARATOR = "_"; 058 059 // This regular expression matches a Suomi NPP Data Product as defined by the 060 // spec in CDFCB-X Volume 1, Page 21 061 public static final String SUOMI_NPP_REGEX = 062 // Product Id, Multiple (ex: VSSTO-GATMO-VSLTO) 063 "(\\w\\w\\w\\w\\w-)*" + 064 // Product Id, Single (ex: VSSTO) 065 "\\w\\w\\w\\w\\w" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 066 // Spacecraft Id (ex: npp) 067 "\\w\\w\\w" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 068 // Data Start Date (ex: dYYYYMMDD) 069 "d20[0-3]\\d[0-1]\\d[0-3]\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 070 // Data Start Time (ex: tHHMMSSS) 071 "t[0-2]\\d[0-5]\\d[0-6]\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 072 // Data Stop Time (ex: eHHMMSSS) 073 "e[0-2]\\d[0-5]\\d[0-6]\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 074 // Orbit Number (ex: b00015) 075 "b\\d\\d\\d\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 076 // Creation Date (ex: cYYYYMMDDHHMMSSSSSSSS) 077 "c20[0-3]\\d[0-1]\\d[0-3]\\d[0-2]\\d[0-5]\\d[0-6]\\d\\d\\d\\d\\d\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 078 // Origin (ex: navo) 079 "\\w\\w\\w\\w" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 080 // Domain (ex: ops) 081 "\\w\\w\\w" + 082 // HDF5 suffix 083 ".h5"; 084 085 public static float[] ATMSChannelCenterFrequencies = { 086 23.8f, 087 31.4f, 088 50.3f, 089 51.76f, 090 52.8f, 091 53.596f, 092 54.40f, 093 54.94f, 094 55.50f, 095 57.29032f, 096 57.29033f, 097 57.29034f, 098 57.29035f, 099 57.29036f, 100 57.29037f, 101 88.20f, 102 165.5f, 103 183.3101f, 104 183.3102f, 105 183.3103f, 106 183.3104f, 107 183.3105f 108 }; 109 110 // the list of valid geolocation product ids 111 public static String[] geoProductIDs = { 112 "GATMO", 113 "GCRSO", 114 "GAERO", 115 "GCLDO", 116 "GDNBO", 117 "GNCCO", 118 "GIGTO", 119 "GIMGO", 120 "GITCO", 121 "GMGTO", 122 "GMODO", 123 "GMTCO", 124 "GNHFO", 125 "GOTCO", 126 "GOSCO", 127 "GONPO", 128 "GONCO", 129 "GCRIO", 130 "GATRO", 131 "IVMIM", 132 "VMUGE" 133 }; 134 135 // This regular expression matches a Suomi NPP geolocation granule, see 136 // spec in CDFCB-X Volume 1, Page 21 137 public static final String SUOMI_GEO_REGEX = 138 // Geo Id, Single (ex: GMODO) 139 // NOTE: This MUST match the list of product ids in static array above! 140 "(GATMO|GCRSO|GAERO|GCLDO|GDNBO|GNCCO|GIGTO|GIMGO|GITCO|" + 141 "GMGTO|GMODO|GMTCO|GNHFO|GOTCO|GOSCO|GONPO|GONCO|GCRIO|GATRO|IVMIM|VMUGE)" + 142 JPSSUtilities.JPSS_FIELD_SEPARATOR + 143 // Spacecraft Id (ex: npp) 144 "\\w\\w\\w" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 145 // Data Start Date (ex: dYYYYMMDD) 146 "d20[0-3]\\d[0-1]\\d[0-3]\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 147 // Data Start Time (ex: tHHMMSSS) 148 "t[0-2]\\d[0-5]\\d[0-6]\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 149 // Data Stop Time (ex: eHHMMSSS) 150 "e[0-2]\\d[0-5]\\d[0-6]\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 151 // Orbit Number (ex: b00015) 152 "b\\d\\d\\d\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 153 // Creation Date (ex: cYYYYMMDDHHMMSSSSSSSS) 154 "c20[0-3]\\d[0-1]\\d[0-3]\\d[0-2]\\d[0-5]\\d[0-6]\\d\\d\\d\\d\\d\\d\\d" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 155 // Origin (ex: navo) 156 "\\w\\w\\w\\w" + JPSSUtilities.JPSS_FIELD_SEPARATOR + 157 // Domain (ex: ops) 158 "\\w\\w\\w" + 159 // HDF5 suffix 160 ".h5"; 161 162 /** 163 * Determine if the set if filenames constitutes contiguous SNPP granules of the 164 * same geographic coverage. 165 * 166 * @return True if passes checks 167 */ 168 169 public static boolean isValidSet(List fileList) { 170 171 // map with filename from start date through orbit will be used for comparisons 172 Map metadataMap = new HashMap<String, List<String>>(); 173 174 // Pass 1, populate the list of products selected, and empty maps 175 for (Object o : fileList) { 176 String filename = (String) o; 177 // start at last path separator to clip off absolute paths 178 int lastSeparator = filename.lastIndexOf(File.separatorChar); 179 // products go to first underscore, see regex above for more detail 180 int firstUnderscore = filename.indexOf("_", lastSeparator + 1); 181 String prodStr = filename.substring(lastSeparator + 1, firstUnderscore); 182 if (! metadataMap.containsKey(prodStr)) { 183 List<String> l = new ArrayList<String>(); 184 metadataMap.put(prodStr, l); 185 } 186 } 187 188 // Pass 2, build up the lists of meta data strings and full filenames 189 for (Object o : fileList) { 190 String filename = (String) o; 191 // start at last path separator to clip off absolute paths 192 int lastSeparator = filename.lastIndexOf(File.separatorChar); 193 // products go to first underscore, see regex above for more detail 194 int firstUnderscore = filename.indexOf("_", lastSeparator + 1); 195 // this is the key for the maps 196 String prodStr = filename.substring(lastSeparator + 1, firstUnderscore); 197 // this is the value for the meta data map - start time through orbit 198 String metaStr = filename.substring(firstUnderscore + 1, firstUnderscore + 39); 199 // get the appropriate list, add the new value 200 List l = (List) metadataMap.get(prodStr); 201 l.add(metaStr); 202 metadataMap.put(prodStr, l); 203 } 204 205 // loop over metadata map, every list much match the one for ALL other products 206 Set s = metadataMap.keySet(); 207 Iterator iterator = s.iterator(); 208 List prvList = null; 209 while (iterator.hasNext()) { 210 String key = (String) iterator.next(); 211 List l = (List) metadataMap.get(key); 212 for (int i = 0; i < l.size(); i++) { 213 if (prvList != null) { 214 if (! l.equals(prvList)) return false; 215 } 216 } 217 prvList = l; 218 } 219 220 return true; 221 } 222 223 /** 224 * Determine if a set if filenames which constitutes contiguous SNPP granules of 225 * various products all share the same geolocation data type. 226 * 227 * @return True if passes checks 228 */ 229 230 public static boolean hasCommonGeo(List fileList, File directory) { 231 Set<String> s = new HashSet<String>(); 232 boolean isCombinedProduct = false; 233 234 // loop through all filenames provided 235 for (Object o : fileList) { 236 isCombinedProduct = false; 237 String filename = (String) o; 238 239 // check the case where GEO is embedded in the data granules 240 int lastSeparator = filename.lastIndexOf(File.separatorChar); 241 int firstUnderscore = filename.indexOf("_", lastSeparator + 1); 242 String prodStr = filename.substring(lastSeparator + 1, firstUnderscore); 243 StringTokenizer st = new StringTokenizer(prodStr, "-"); 244 while (st.hasMoreTokens()) { 245 String singleProd = st.nextToken(); 246 for (int i = 0; i < JPSSUtilities.geoProductIDs.length; i++) { 247 if (singleProd.equals(JPSSUtilities.geoProductIDs[i])) { 248 s.add(singleProd); 249 isCombinedProduct = true; 250 break; 251 } 252 } 253 } 254 // GEO not embedded in file, need to see which GEO file is referenced in 255 // the global attribute 256 if (! isCombinedProduct) { 257 try { 258 String fileFullPath = directory.getAbsolutePath() + File.separator + filename; 259 NetcdfFile ncfile = NetcdfFile.open(fileFullPath); 260 Attribute a = ncfile.findGlobalAttribute("N_GEO_Ref"); 261 if (a != null) { 262 String geoFromAttr = a.getStringValue().substring(0, 5); 263 s.add(geoFromAttr); 264 } 265 ncfile.close(); 266 } catch (IOException ioe) { 267 ioe.printStackTrace(); 268 } 269 } 270 } 271 272 // if the products chosen utilize multiple GEO types, fail the selection 273 if (s.size() > 1) return false; 274 return true; 275 } 276 277}