#!/usr/bin/env python """ generated source for module 1 """ import java.io.File import java.io.IOException import java.util.LinkedList import java.util.List import joptsimple.OptionParser import joptsimple.OptionSet import joptsimple.OptionSpec import org.joda.time.DateTime import org.joda.time.DateTimeZone import org.joda.time.format.DateTimeFormatterBuilder import ucar.ma2.Array import ucar.ma2.DataType import ucar.ma2.IndexIterator import ucar.nc2.Attribute import ucar.nc2.Dimension import ucar.nc2.NetcdfFile import ucar.nc2.Variable # # * This class serializes a netcdf file to JSON. The netcdf file needs to have # * the following dimensions: # *
    # *
  1. time
  2. # *
  3. lat - latitude
  4. # *
  5. lon - longitude
  6. # *
# * and one more more 3 dimensional variables with the time, lat, and lon # * dimensions in that order. # * # * # class NetCdfSerializer(object): """ generated source for class NetCdfSerializer """ # # * The first time variable in the netcdf file. # timeVariable = None # # * The time range from the # timeRangeString = None # # * The latitude variable in the netcdf file. # latitudeVariable = None # # * The longitude variable in the netcdf file. # longitudeVariable = None # # * The data variables in the netcdf file. # dataVariables = LinkedList() # # * Data day variable, if it exists. # dataDayVariable = None # # * Data month variable, if it exists. # dataMonthVariable = None # # * The number of spaces for each indent level. # NUM_SPACES = 2 # # * The netcdf file we are converting. # file_ = None # # * The temporal resolution of the paired data. # temporalResolution = None # # * @throws Exception # * # @classmethod def main(cls, args): """ generated source for method main """ parser = OptionParser() fileSpec = parser.accepts("file").withRequiredArg().ofType(File.__class__) sigDigitsSpec = parser.accepts("significantDigits").withRequiredArg().ofType(Integer.__class__) options = parser.parse(args) if not options.has(fileSpec) or not options.has(sigDigitsSpec): raise Exception("Usage: java NetCdfSerializer --file file --significantDigits number") file_ = options.valueOf(fileSpec) significantDigits = options.valueOf(sigDigitsSpec) print convert(file_, significantDigits) @classmethod def convert(cls, netCdfFile, significantDigits): """ generated source for method convert """ obj = None if not netCdfFile.exists(): raise Exception(String.format("File does not exist: %s", netCdfFile.getCanonicalPath())) try: obj = NetCdfSerializer(netCdfFile) return obj.convertNotStatic(significantDigits) finally: try: obj.closeFile() except Exception as e: pass def __init__(self, netCdfFile): """ generated source for method __init__ """ self.file_ = NetcdfFile.open(netCdfFile.__str__()) variables = self.file_.getVariables() for var in variables: if name == "lat": self.latitudeVariable = var elif name == "lon": self.longitudeVariable = var elif name == "dataday": self.dataDayVariable = var elif name == "datamonth": self.dataMonthVariable = var else: for att in attributes: if att.getShortName() == "plot_hint_axis_title": self.dataVariables.add(var) if len(self.dataVariables) != 2: raise Exception("Expected to find 2 plot hint variables, actually found " + len(self.dataVariables) + ".") self.timeVariable = getTimeDimensionVariable(self.dataVariables.get(0), variables) globalAttributes = self.file_.getGlobalAttributes() for attribute in globalAttributes: if attribute.getShortName() == "temporal_resolution" or attribute.getShortName() == "input_temporal_resolution": self.temporalResolution = attribute.getStringValue() if self.temporalResolution == None: self.temporalResolution = "hourly" setTimeRangeString() def getTimeDimensionVariable(self, dataVariable, variables): """ generated source for method getTimeDimensionVariable """ dimensions = dataVariable.getDimensions() for dimension in dimensions: for variable in variables: if variable.getShortName() == name: if standardName != None and standardName == "time": return variable return None def getStandardName(self, variable): """ generated source for method getStandardName """ attributes = variable.getAttributes() for attribute in attributes: if attribute.getShortName() == "standard_name": return attribute.getStringValue() return None def convertNotStatic(self, significantDigits): """ generated source for method convertNotStatic """ buf = StringBuffer(String.format("{\n")) addTime(buf, significantDigits) buf.append(String.format(",\n")) if self.latitudeVariable != None: addGeoDimension(buf, significantDigits, self.latitudeVariable) buf.append(String.format(",\n")) if self.longitudeVariable != None: addGeoDimension(buf, significantDigits, self.longitudeVariable) buf.append(String.format(",\n")) addDataVariables(buf, significantDigits, self.dataVariables) buf.append(String.format("\n}\n")) return buf.__str__() def addTime(self, buf, significantDigits): """ generated source for method addTime """ buf.append(String.format(getIndentStr(self.NUM_SPACES) + "\"time\": {\n")) buf.append(String.format(getIndentStr(2 * self.NUM_SPACES) + "\"data\": \n")) timeStrings = None if self.timeVariable == None: timeStrings = [None]*1 timeStrings[0] = self.timeRangeString else: if self.dataDayVariable != None: timeStrings = getFormattedDataDay() elif self.dataMonthVariable != None: timeStrings = getFormattedDataMonth() else: timeStrings = getFormattedTime() buf.append(getIndentStr(3 * self.NUM_SPACES) + "[") i = 0 while len(timeStrings): buf.append(String.format(" \"%s\"", timeStrings[i])) if i != (len(timeStrings)): buf.append(",") i += 1 buf.append("]\n" + getIndentStr(self.NUM_SPACES) + "}") def getFormattedDataDay(self): """ generated source for method getFormattedDataDay """ timeArray = self.dataDayVariable.read() shape = timeArray.getShape() timeStrings = [None]*shape[0] i = 0 while i < shape[0]: time = time.plusDays(day - 1) timeStrings[i] = convertTime(time, "daily") i += 1 return timeStrings def getFormattedDataMonth(self): """ generated source for method getFormattedDataMonth """ timeArray = self.dataMonthVariable.read() shape = timeArray.getShape() timeStrings = [None]*shape[0] i = 0 while i < shape[0]: time = time.plusMonths(month - 1) timeStrings[i] = convertTime(time, "monthly") i += 1 return timeStrings def getFormattedTime(self): """ generated source for method getFormattedTime """ timeArray = self.timeVariable.read() units = self.timeVariable.findAttribute("units").getStringValue() shape = timeArray.getShape() baseDate = getBaseDateTime(units) timeStrings = [None]*shape[0] i = 0 while i < shape[0]: if units.startsWith("seconds since"): if self.timeVariable.getDataType()==SHORT: value = timeArray.getShort(i) elif self.timeVariable.getDataType()==INT: value = timeArray.getInt(i) elif self.timeVariable.getDataType()==LONG: value = int(timeArray.getLong(i)) elif self.timeVariable.getDataType()==FLOAT: value = Math.round(timeArray.getFloat(i)) elif self.timeVariable.getDataType()==DOUBLE: value = int(Math.round(timeArray.getDouble(i))) else: raise Exception(String.format("Unable to understand time data type %s", self.timeVariable.getDataType().__str__())) time = baseDate.plusSeconds(value) else: raise Exception(String.format("Unable to understand time units '%s'", units)) timeStrings[i] = convertTime(time, self.temporalResolution) i += 1 return timeStrings @classmethod def getBaseDateTime(cls, units): """ generated source for method getBaseDateTime """ beginIndex = 19 - len(units) dateString = units.substring(beginIndex) return getDateTime(dateString) @classmethod def getDateTime(cls, dateString): """ generated source for method getDateTime """ year = Integer.parseInt(dateString.substring(0, 4)) month = Integer.parseInt(dateString.substring(5, 7)) day = Integer.parseInt(dateString.substring(8, 10)) hour = Integer.parseInt(dateString.substring(11, 13)) minute = Integer.parseInt(dateString.substring(14, 16)) second = Integer.parseInt(dateString.substring(17, 19)) return DateTime(year, month, day, hour, minute, second, DateTimeZone.UTC) def setTimeRangeString(self): """ generated source for method setTimeRangeString """ attributes = self.file_.getGlobalAttributes() startTimeString = None endTimeString = None for att in attributes: if att.getShortName()=="matched_start_time": startTimeString = att.getStringValue() elif att.getShortName()=="matched_end_time": endTimeString = att.getStringValue() if startTimeString == None: raise Exception("Unable to find matched_start_time") elif endTimeString == None: raise Exception("Unable to find matched_end_time") formattedStartTime = convertTime(self.getDateTime(startTimeString), self.temporalResolution) formattedEndTime = convertTime(self.getDateTime(endTimeString), self.temporalResolution) if formattedStartTime == formattedEndTime: self.timeRangeString = formattedStartTime else: self.timeRangeString = formattedStartTime + " - " + formattedEndTime @classmethod def convertTime(cls, time, temporalResolution): """ generated source for method convertTime """ time = time.toDateTime(DateTimeZone.UTC) builder = DateTimeFormatterBuilder() if temporalResolution==("monthly"): builder.appendYear(4, 4) builder.appendLiteral('-') builder.appendMonthOfYear(2) elif temporalResolution==("daily"): builder.appendYear(4, 4) builder.appendLiteral('-') builder.appendMonthOfYear(2) builder.appendLiteral('-') builder.appendDayOfMonth(2) elif temporalResolution==("hourly"): pass elif temporalResolution==("3-hourly"): builder.appendYear(4, 4) builder.appendLiteral('-') builder.appendMonthOfYear(2) builder.appendLiteral('-') builder.appendDayOfMonth(2) builder.appendLiteral(' ') builder.appendHourOfDay(2) builder.appendLiteral('Z') elif temporalResolution==("half-hourly"): builder.appendYear(4, 4) builder.appendLiteral('-') builder.appendMonthOfYear(2) builder.appendLiteral('-') builder.appendDayOfMonth(2) builder.appendLiteral(' ') builder.appendHourOfDay(2) builder.appendLiteral(':') builder.appendMinuteOfHour(2) builder.appendLiteral('Z') else: raise Exception("Unrecognized temporal resolution '" + temporalResolution + "'") return time.toString(builder.toFormatter()) @classmethod def addDataVariables(cls, buf, significantDigits, dataVariables): """ generated source for method addDataVariables """ i = 0 for var in dataVariables: if att != None: addOffset = att.getNumericValue().doubleValue() att = var.findAttribute("scale_factor") if att != None: scaleFactor = att.getNumericValue().doubleValue() buf.append(String.format(getIndentStr(cls.NUM_SPACES) + "\"" + name + "\": {\n")) if units != None: unitsStr = units.getStringValue() buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"units\": \"%s\",\n", unitsStr)) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"quantity_type\": \"%s\",\n", quantity_type.getStringValue())) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"long_name\": \"%s\",\n", long_name.getStringValue())) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"product_short_name\": \"%s\",\n", product_short_name.getStringValue())) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"product_version\": \"%s\",\n", product_version.getStringValue())) if fillValue != None: fill = fill * scaleFactor + addOffset buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"_FillValue\": [%s],\n", printValue(fill, significantDigits))) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"plot_hint_axis_title\": \"%s\",\n", plot_hint_axis_title.getStringValue())) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"data\": \n")) if len(shape): writeArray(buf, array, significantDigits, 3 * cls.NUM_SPACES, var.getDataType(), scaleFactor, addOffset) elif len(shape): buf.append(getIndentStr(3 * cls.NUM_SPACES) + "[ " + String.format("\n")) writeArray(buf, array, significantDigits, 4 * cls.NUM_SPACES, var.getDataType(), scaleFactor, addOffset) buf.append(String.format("\n") + getIndentStr(3 * cls.NUM_SPACES) + "]") else: raise Exception("Expected data fields to be two or three dimensional variables") buf.append("\n" + getIndentStr(cls.NUM_SPACES) + "}") i += 1 if i != len(dataVariables): buf.append(String.format(",\n")) @classmethod def addGeoDimension(cls, buf, significantDigits, var): """ generated source for method addGeoDimension """ name = var.getShortName() buf.append(String.format(getIndentStr(cls.NUM_SPACES) + "\"" + name + "\": {\n")) units = var.findAttribute("units") buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"units\": \"%s\",\n", units.getStringValue())) buf.append(String.format(getIndentStr(2 * cls.NUM_SPACES) + "\"data\": \n")) array = var.read() writeArray(buf, array, significantDigits, 3 * cls.NUM_SPACES, var.getDataType(), 1, 0) buf.append("\n" + getIndentStr(cls.NUM_SPACES) + "}") @classmethod def getIndentStr(cls, length): """ generated source for method getIndentStr """ buf = StringBuffer() i = 0 while i < length: buf.append(' ') i += 1 return buf.__str__() @classmethod def writeArray(cls, buf, arr, significantDigits, indent, dataType, scaleFactor, addOffset): """ generated source for method writeArray """ shape = arr.getShape() if len(shape): buf.append(cls.getIndentStr(indent) + "[ ") while it.hasNext(): value = value * scaleFactor + addOffset buf.append(printValue(value, significantDigits)) i += 1 if i != shape[0]: buf.append(", ") buf.append(" ]") else: buf.append(String.format(cls.getIndentStr(indent) + "[\n")) while i < shape[0]: cls.writeArray(buf, arr.slice_(0, i), significantDigits, indent + cls.NUM_SPACES, dataType, scaleFactor, addOffset) if i != (shape[0] - 1): buf.append(String.format(",\n")) else: buf.append(String.format("\n")) i += 1 buf.append(cls.getIndentStr(indent) + "]") @classmethod def printValue(cls, value, significantDigits): """ generated source for method printValue """ if Double.isNaN(value) or Double.isInfinite(value): return "null" else: return String.format(doubleFormatStr, value) def closeFile(self): """ generated source for method closeFile """ self.file_.close()