1 | import cdms,MV |
---|
2 | import Numeric |
---|
3 | import csml |
---|
4 | import sys |
---|
5 | |
---|
6 | class NCwriter(object): |
---|
7 | #This provides a simplified wrapper to CDMS to write a CF compliant NetCDF |
---|
8 | def __init__(self, fileName): |
---|
9 | #initiates a new NetCDF file |
---|
10 | self.nc=cdms.open(fileName,'w') |
---|
11 | |
---|
12 | def setGlobalAttributes(self, **kwargs): |
---|
13 | #sets global attributes |
---|
14 | pass |
---|
15 | |
---|
16 | def addAxis(self,axisName, data,isLon=None,isLat=None,isTime=None,**kwargs): |
---|
17 | #first ensure tuple does not contains a list |
---|
18 | if type(data[0]) is list: |
---|
19 | newdata=tuple(data[0]) |
---|
20 | data=newdata |
---|
21 | |
---|
22 | # Now create the axis |
---|
23 | dataarray=MV.array(data) |
---|
24 | ax=cdms.createAxis(dataarray) |
---|
25 | ax.id = axisName |
---|
26 | if not hasattr(self,'axes'): |
---|
27 | self.axes=[] |
---|
28 | if isLon is not None: |
---|
29 | ax.designateLongitude() |
---|
30 | elif isLat is not None: |
---|
31 | ax.designateLatitude() |
---|
32 | elif isTime is not None: |
---|
33 | ax.designateTime() |
---|
34 | for key in kwargs: |
---|
35 | setattr(ax, key,kwargs[key]) |
---|
36 | self.axes.append(ax) |
---|
37 | |
---|
38 | |
---|
39 | def getAxis(self, axID): |
---|
40 | for axis in self.axes: |
---|
41 | if axis.id == axID: |
---|
42 | return axis |
---|
43 | |
---|
44 | |
---|
45 | |
---|
46 | def addTimeVariable(self,timeval): |
---|
47 | dataarray=MV.array(timeval) |
---|
48 | #dataarray.id='time' |
---|
49 | #dataarray.name ='time' |
---|
50 | ax=self.getAxis('time') |
---|
51 | dataarray.setAxis(0,ax) |
---|
52 | self.nc.write(dataarray) |
---|
53 | |
---|
54 | |
---|
55 | def addVariable(self,data, variableName,axesList, fillvalue, **kwargs): |
---|
56 | #creates a new variable containing data with named attributes from **kwargs |
---|
57 | |
---|
58 | dataarray=MV.array(data) |
---|
59 | dataarray.id=variableName |
---|
60 | dataarray.name=variableName |
---|
61 | for key in kwargs: |
---|
62 | setattr(dataarray, key,kwargs[key]) |
---|
63 | axisCount=0 |
---|
64 | |
---|
65 | #depending on whether time is modelled in the underlying data as a dimension or not the shapes may not match |
---|
66 | if len(dataarray.shape) < len(axesList): |
---|
67 | #take time out and create a separate variable |
---|
68 | newaxesList=[] |
---|
69 | for a in axesList: |
---|
70 | if a != 'time': |
---|
71 | newaxesList.append(a) |
---|
72 | axesList=newaxesList |
---|
73 | if hasattr(self, 'axes'): |
---|
74 | for axis in axesList: |
---|
75 | for ax in self.axes: |
---|
76 | if ax.id == axis: |
---|
77 | dataarray.setAxis(axisCount,ax) |
---|
78 | axisCount = axisCount +1 |
---|
79 | setattr(dataarray, 'missing_value' ,fillvalue) |
---|
80 | self.nc.write(dataarray) |
---|
81 | |
---|
82 | def genWriteVar(self,varid, ordinates, times, caltype, axisorder, unitlist, fulldata, fillvalue, **kwargs): |
---|
83 | #**kwargs may contain additional axes not contained in a GridCoordinatesTable - e.g latitude, longitude may be stored in other attribute not in the rectified grid. |
---|
84 | axesdone=[] |
---|
85 | floatTimes=[] |
---|
86 | #determine base units for times: |
---|
87 | tOne=csml.csmllibs.csmltime.getCDtime(times[0]) |
---|
88 | tbase=csml.csmllibs.csmltime.getBaseUnits(tOne) |
---|
89 | for time in times: |
---|
90 | time=csml.csmllibs.csmltime.getCDtime(time).torel(tbase) |
---|
91 | floatTimes.append(time.value) |
---|
92 | self.addAxis('time',floatTimes,isTime=1,units=tbase,calendar=caltype) |
---|
93 | |
---|
94 | axesdone.append('time') |
---|
95 | if ordinates is not None: |
---|
96 | for ord in enumerate(ordinates): |
---|
97 | vals=[] |
---|
98 | lon,lat=None,None |
---|
99 | if ord[1].coordAxisLabel.CONTENT=='time': |
---|
100 | continue |
---|
101 | else: |
---|
102 | for val in ord[1].coordAxisValues.coordinateList.CONTENT.split(): |
---|
103 | if val != ' ': |
---|
104 | vals.append(eval(val)) |
---|
105 | if ord[1].coordAxisLabel.CONTENT=='longitude': |
---|
106 | lon=1 |
---|
107 | name='longitude' |
---|
108 | elif ord[1].coordAxisLabel.CONTENT=='latitude': |
---|
109 | lat=1 |
---|
110 | name='latitude' |
---|
111 | else: |
---|
112 | name=ord[1].coordAxisLabel.CONTENT |
---|
113 | for ax in enumerate(axisorder): |
---|
114 | if ax[1]==name: |
---|
115 | position=ax[0] |
---|
116 | axesdone.append(name) |
---|
117 | self.addAxis(name,vals,isLon=lon,isLat=lat,units=unitlist[position])#to do, units attribute for CF compliance |
---|
118 | |
---|
119 | if kwargs is not None: |
---|
120 | for kw in kwargs: |
---|
121 | lon,lat=None,None |
---|
122 | if kw=='longitude': |
---|
123 | lon=1 |
---|
124 | elif kw == 'latitude': |
---|
125 | lat=1 |
---|
126 | name = kw |
---|
127 | for ax in enumerate(axisorder): |
---|
128 | if ax[1]==name: |
---|
129 | position=ax[0] |
---|
130 | vals=(kwargs[kw],) |
---|
131 | self.addAxis(name,vals,isLon=lon,isLat=lat,units=unitlist[position]) |
---|
132 | axesdone.append(name) |
---|
133 | self.addVariable(fulldata,varid, axisorder, fillvalue, units=unitlist[-1] ) #to do, units attribute for CF compliance |
---|
134 | |
---|
135 | for ax in self.axes: |
---|
136 | if ax.id =='time': |
---|
137 | if self.nc.variables.has_key('time') is False: |
---|
138 | self.addTimeVariable(floatTimes) |
---|
139 | |
---|
140 | |
---|
141 | def closeFinishedFile(self): |
---|
142 | #returns finished (hopefully) NetCDF file |
---|
143 | self.nc.close() |
---|