#!/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:
# *
# * - time
# * - lat - latitude
# * - lon - longitude
# *
# * 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()