001 /** 002 * 003 */ 004 package org.wdssii.ncingest; 005 006 import java.io.File; 007 import java.io.IOException; 008 import java.util.Calendar; 009 import java.util.Date; 010 import java.util.GregorianCalendar; 011 012 import org.apache.commons.logging.Log; 013 import org.apache.commons.logging.LogFactory; 014 import org.wdssii.core.DataEncoder; 015 import org.wdssii.core.Ingestor; 016 import org.wdssii.core.LatLonGrid; 017 import org.wdssii.core.Location; 018 019 import ucar.ma2.Array; 020 import ucar.ma2.Index; 021 import ucar.nc2.NetcdfFile; 022 import ucar.nc2.Variable; 023 024 /** 025 * A general-purpose ingestor for netcdf files. Reads netcdf files and writes 026 * out WDSS-II format files and notification records. 027 * 028 * @author lakshman 029 * 030 */ 031 public class NetcdfIngest extends Ingestor { 032 private static Log log = LogFactory.getLog(NetcdfIngest.class); 033 034 private String typeNameGlobalAttribute = ""; 035 private String defaultTypeName = ""; 036 private String cornerLatGlobalAttribute = ""; 037 private double defaultCornerLat = 35; 038 private String cornerLonGlobalAttribute = ""; 039 private double defaultCornerLon = -97; 040 private String heightGlobalAttribute = ""; 041 private double defaultHeight = 0; 042 private String timeGlobalAttribute = ""; 043 private String julianDateVariable = ""; 044 private String timeOfDayVariable = ""; 045 private String variableGlobalAttribute = ""; 046 private String defaultVariableName = "data"; 047 private String latSpacingGlobalAttribute = ""; 048 private double defaultLatSpacing = 0.01; 049 private String lonSpacingGlobalAttribute = ""; 050 private double defaultLonSpacing = 0.01; 051 private boolean cornerIsNorthwest = true; // otherwise, southwest 052 private String subTypeGlobalAttribute = ""; 053 private String defaultSubType = ""; 054 private String defaultUnit = "dimensionless"; 055 056 public String getTypeNameGlobalAttribute() { 057 return typeNameGlobalAttribute; 058 } 059 060 public void setTypeNameGlobalAttribute(String typeNameGlobalAttribute) { 061 this.typeNameGlobalAttribute = typeNameGlobalAttribute; 062 } 063 064 public String getDefaultTypeName() { 065 return defaultTypeName; 066 } 067 068 public void setDefaultTypeName(String defaultTypeName) { 069 this.defaultTypeName = defaultTypeName; 070 } 071 072 public String getCornerLatGlobalAttribute() { 073 return cornerLatGlobalAttribute; 074 } 075 076 public void setCornerLatGlobalAttribute(String cornerLatGlobalAttribute) { 077 this.cornerLatGlobalAttribute = cornerLatGlobalAttribute; 078 } 079 080 public double getDefaultCornerLat() { 081 return defaultCornerLat; 082 } 083 084 public void setDefaultCornerLat(double defaultCornerLat) { 085 this.defaultCornerLat = defaultCornerLat; 086 } 087 088 public String getCornerLonGlobalAttribute() { 089 return cornerLonGlobalAttribute; 090 } 091 092 public void setCornerLonGlobalAttribute(String cornerLonGlobalAttribute) { 093 this.cornerLonGlobalAttribute = cornerLonGlobalAttribute; 094 } 095 096 public double getDefaultCornerLon() { 097 return defaultCornerLon; 098 } 099 100 public void setDefaultCornerLon(double defaultCornerLon) { 101 this.defaultCornerLon = defaultCornerLon; 102 } 103 104 public String getHeightGlobalAttribute() { 105 return heightGlobalAttribute; 106 } 107 108 public void setHeightGlobalAttribute(String heightGlobalAttribute) { 109 this.heightGlobalAttribute = heightGlobalAttribute; 110 } 111 112 public double getDefaultHeight() { 113 return defaultHeight; 114 } 115 116 public void setDefaultHeight(double defaultHeight) { 117 this.defaultHeight = defaultHeight; 118 } 119 120 public String getTimeGlobalAttribute() { 121 return timeGlobalAttribute; 122 } 123 124 public void setTimeGlobalAttribute(String timeGlobalAttribute) { 125 this.timeGlobalAttribute = timeGlobalAttribute; 126 } 127 128 public String getVariableGlobalAttribute() { 129 return variableGlobalAttribute; 130 } 131 132 public void setVariableGlobalAttribute(String variableGlobalAttribute) { 133 this.variableGlobalAttribute = variableGlobalAttribute; 134 } 135 136 public String getDefaultVariableName() { 137 return defaultVariableName; 138 } 139 140 public void setDefaultVariableName(String defaultVariableName) { 141 this.defaultVariableName = defaultVariableName; 142 } 143 144 public String getLatSpacingGlobalAttribute() { 145 return latSpacingGlobalAttribute; 146 } 147 148 public void setLatSpacingGlobalAttribute(String latSpacingGlobalAttribute) { 149 this.latSpacingGlobalAttribute = latSpacingGlobalAttribute; 150 } 151 152 public double getDefaultLatSpacing() { 153 return defaultLatSpacing; 154 } 155 156 public void setDefaultLatSpacing(double defaultLatSpacing) { 157 this.defaultLatSpacing = defaultLatSpacing; 158 } 159 160 public String getLonSpacingGlobalAttribute() { 161 return lonSpacingGlobalAttribute; 162 } 163 164 public void setLonSpacingGlobalAttribute(String lonSpacingGlobalAttribute) { 165 this.lonSpacingGlobalAttribute = lonSpacingGlobalAttribute; 166 } 167 168 public double getDefaultLonSpacing() { 169 return defaultLonSpacing; 170 } 171 172 public void setDefaultLonSpacing(double defaultLonSpacing) { 173 this.defaultLonSpacing = defaultLonSpacing; 174 } 175 176 public boolean isCornerIsNorthwest() { 177 return cornerIsNorthwest; 178 } 179 180 public void setCornerIsNorthwest(boolean cornerIsNorthwest) { 181 this.cornerIsNorthwest = cornerIsNorthwest; 182 } 183 184 public String getSubTypeGlobalAttribute() { 185 return subTypeGlobalAttribute; 186 } 187 188 public void setSubTypeGlobalAttribute(String subTypeGlobalAttribute) { 189 this.subTypeGlobalAttribute = subTypeGlobalAttribute; 190 } 191 192 public String getDefaultSubType() { 193 return defaultSubType; 194 } 195 196 public void setDefaultSubType(String defaultSubType) { 197 this.defaultSubType = defaultSubType; 198 } 199 200 public String getJulianDateVariable() { 201 return julianDateVariable; 202 } 203 204 public void setJulianDateVariable(String julianDateVariable) { 205 this.julianDateVariable = julianDateVariable; 206 } 207 208 public String getTimeOfDayVariable() { 209 return timeOfDayVariable; 210 } 211 212 public void setTimeOfDayVariable(String timeOfDayVariable) { 213 this.timeOfDayVariable = timeOfDayVariable; 214 } 215 216 public String getDefaultUnit() { 217 return defaultUnit; 218 } 219 220 public void setDefaultUnit(String defaultUnit) { 221 this.defaultUnit = defaultUnit; 222 } 223 224 private String getValue(NetcdfFile ncfile, String what, String attrName, 225 String value) { 226 if (attrName.length() != 0) { 227 return ncfile.findGlobalAttribute(attrName).getStringValue(); 228 } else if (value.length() != 0) { 229 return value; 230 } else { 231 throw new IllegalStateException("Need to specify " + what); 232 } 233 } 234 235 private long getValue(NetcdfFile ncfile, String what, String attrName) { 236 if (attrName.length() != 0) { 237 return ncfile.findGlobalAttribute(attrName).getNumericValue() 238 .longValue(); 239 } else { 240 throw new IllegalStateException("Need to specify " + what); 241 } 242 } 243 244 private double getValue(NetcdfFile ncfile, String what, String attrName, 245 double value) { 246 if (attrName.length() != 0) { 247 return ncfile.findGlobalAttribute(attrName).getNumericValue() 248 .doubleValue(); 249 } else { 250 return value; 251 } 252 } 253 254 private float[][] readData2D(NetcdfFile ncfile) throws IOException { 255 String variableName = getValue(ncfile, "VariableName", 256 variableGlobalAttribute, defaultVariableName); 257 Variable data = ncfile.findVariable(variableName); 258 int numDims = data.getDimensions().size(); 259 if (numDims < 2) { 260 throw new IllegalArgumentException(data.getName() 261 + " should have at least 2 dimensions"); 262 } 263 Array gate_values = data.read(); 264 int num_radials = data.getDimension(numDims - 2).getLength(); 265 int num_gates = data.getDimension(numDims - 1).getLength(); 266 float[][] values = new float[num_radials][num_gates]; 267 Index gate_index = gate_values.getIndex(); 268 int[] index = new int[numDims]; 269 for (int i = 0; i < num_radials; ++i) { 270 for (int j = 0; j < num_gates; ++j) { 271 index[index.length - 2] = i; 272 index[index.length - 1] = j; 273 gate_index.set(index); 274 values[i][j] = gate_values.getFloat(gate_index); 275 } 276 } 277 return values; 278 } 279 280 @Override 281 protected void doIngest(File path) { 282 NetcdfFile ncfile = null; 283 284 try { 285 log.info("Opening " + path + " for reading"); 286 ncfile = NetcdfFile.open(path.getAbsolutePath()); 287 288 // expected global variables 289 String typeName = getValue(ncfile, "typeName", 290 typeNameGlobalAttribute, defaultTypeName); 291 // String dataType = "LatLonGrid"; 292 293 // location 294 double lat = getValue(ncfile, "Latitude", cornerLatGlobalAttribute, 295 defaultCornerLat); 296 double lon = getValue(ncfile, "Longitude", 297 cornerLonGlobalAttribute, defaultCornerLon); 298 double ht = getValue(ncfile, "Height", heightGlobalAttribute, 299 defaultHeight); 300 301 // time 302 Date dt; 303 if (timeGlobalAttribute.length() != 0) { 304 long tm = getValue(ncfile, "TimeUTC", timeGlobalAttribute); 305 long tm_long = 1000 * tm; 306 dt = new Date(tm_long); 307 } else if (julianDateVariable.length() != 0 308 && timeOfDayVariable.length() != 0) { 309 int julianDate = ncfile.findVariable(julianDateVariable) 310 .readScalarInt(); 311 int timeOfDay = ncfile.findVariable(timeOfDayVariable) 312 .readScalarInt(); 313 Calendar c = GregorianCalendar.getInstance(); 314 c.set(julianDate / 1000 + 1900, 0, julianDate % 1000, 0, 0, 315 timeOfDay); 316 dt = c.getTime(); 317 } else { 318 throw new IllegalStateException( 319 "Need to provide either the timeGlobalAttribute or the julianDateVariable/timeOfDayVariable"); 320 } 321 // spacing 322 double deltaLat = Math.abs(getValue(ncfile, "LatSpacing", 323 latSpacingGlobalAttribute, defaultLatSpacing)); 324 double deltaLon = Math.abs(getValue(ncfile, "LonSpacing", 325 lonSpacingGlobalAttribute, defaultLonSpacing)); 326 327 // values 328 float[][] values = readData2D(ncfile); 329 int numLat = values.length; 330 // int numLon = values[0].length; 331 332 // northwest corner; flip rows if necessary 333 Location nwcorner; 334 if (cornerIsNorthwest) { 335 nwcorner = new Location(lat, lon, ht / 1000); 336 // no need to flip 337 } else { 338 nwcorner = new Location(lat + (numLat + 1) * deltaLat, lon, 339 ht / 1000); 340 float[][] tmp = new float[numLat][]; 341 for (int i = 0; i < numLat; ++i) { 342 tmp[i] = values[numLat - i]; 343 } 344 values = tmp; 345 } 346 347 // unit 348 String unit = getValue(ncfile, "Unit", "", defaultUnit); 349 350 // create latlongrid, write and notify 351 LatLonGrid llgrid = new LatLonGrid(nwcorner, dt, typeName, 352 (float) deltaLat, (float) deltaLon, values); 353 llgrid.setAttribute("Unit", unit); 354 355 String subtype = null; 356 try { 357 subtype = getValue(ncfile, "SubType", subTypeGlobalAttribute, 358 defaultSubType); 359 } catch (Exception e) { 360 // ok if not there 361 } 362 DataEncoder.writeDataAndNotify(llgrid, super.getOutputDir(), 363 subtype); 364 365 } catch (Exception e) { 366 log.warn(e); 367 } finally { 368 try { 369 if (ncfile != null) 370 ncfile.close(); 371 } catch (Exception e) { 372 } 373 } 374 } 375 376 public static void main(String[] args) { 377 final NetcdfIngest alg = new NetcdfIngest(); 378 alg.setupAndExecute(args); 379 } 380 381 }