source: TOOLS/CMIP6_FORCING/AER_TROP_EMISSIONS/REGRID/netcdfwrite.pro @ 3391

Last change on this file since 3391 was 3391, checked in by oboucher, 4 years ago

Current version of regrid scripts for creating aerosol emissions files for CMIP6

File size: 8.2 KB
Line 
1; 1.11 01/10/07
2;
3; Takes an IDL structure and writes to NetCDF much as netcdf_read
4; but from the opposite direction.
5;
6; Dimension variables are identified as the first vector in the structure
7; of a certain length, and linked to all following vectors and multi-D
8; arrays with dimensions the same size.
9;
10; The approach is simple and powerful but with one big flaw - arrays
11; with non-unique dimension sizes (e.g. fltarr[36,36,5] rather than
12; fltarr[36,37,5]) cannot be written unless:
13;
14;   a) A quick and dirty solution that breaks the NetCDF dimension
15;      links: the DIM_ALL keyword is used.
16;
17;   b) A tedious but exact solution: the dimensions are explicilty
18;      specified with the DIMENSIONS keyword.
19;
20; It will be possible to actually define which are dimensions etc...
21; ...in a later version... perhaps by defining "d_latitude" or "d_pressure"
22; as indicating a dimension? Or if this is not flexible enough
23; just write your own netcdf file following the Chapter 6 of the IDL
24; Scientific Data Formats manual
25;
26; Parameters
27; ----------
28;
29; I:    file     string containing filename and path to be written
30; I:    field    IDL structure to be written to file, arranged as
31;                in the example below
32;
33; Keywords
34; --------
35;
36; CLOBBER - overwrite any existing file (otherwise, we fail with error
37;       status if there's an exisitng file there)
38;
39; DIM_ALL - treat all vectors as dimensions. This is needed in order to
40;       write arrays non-unique dimension sizes, e.g. fltarr[36,36,5]
41;
42; DIMENSIONS - specify the exact dimensions and links. See below for
43;      an example.
44;
45; ATTRIBUTES - pass in a structure containing the attributes for each
46;      dimension and variable, in the order they are found in the data
47;      structure we are writing to file. The structure should contain a
48;      strarr for each attribute. The attribute name when written to
49;      file will be the variable name in the struture, in lowercase.
50;
51; Example
52; -------
53;
54; To add "units" and "long_name" attributes to each variable
55; for a partial compatability with the NetCDF standard, e.g. when
56; writing the 3D array/structure ozone:
57;
58;      ozone = {lon:fltarr(96),lat:fltarr(73),pressure:fltarr(50),$
59;         ozone:fltarr(96,73,50)}
60;
61;      attributes = {units:strarr(4),long_name:strarr(4)}
62;      attributes.units = ['degrees_east','degrees_north','Pa','kg kg-1']
63;      attributes.long_name = ['Longitude','Latitude','Pressure',$
64;         'Ozone']
65;
66;      netcdfwrite, 'filename', ozone, attributes=attributes
67;
68; On the unix command line "ncdump -h filename" produces:
69;
70;      netcdf filename {
71;      dimensions:
72;         LON = 96 ;
73;         LAT = 73 ;
74;         PRESSURE = 50 ;
75;      variables:
76;         float LON(LON) ;
77;                 LON:units = "degrees_east" ;
78;                 LON:long_name = "Longitude" ;
79;         float LAT(LAT) ;
80;                 LAT:units = "degrees_north" ;
81;                 LAT:long_name = "Latitude" ;
82;         float PRESSURE(PRESSURE) ;
83;                 PRESSURE:units = "Pa" ;
84;                 PRESSURE:long_name = "Pressure" ;
85;         float OZONE(PRESSURE, LAT, LON) ;
86;                 OZONE:units = "kg kg-1" ;
87;                 OZONE:long_name = "Ozone" ;
88;      }
89;
90; Note that NCDUMP reverses the order of the dimensions in multi-
91; dimensional arrays compared to IDL.
92;
93; To explicitly specify the dimensions and linkages (not needed in most
94; cases including this example: it's only needed if the rule of matching
95; dimensions by length breaks down because there are two dimensions of the
96; same length):
97;
98;      dimensions = {isdim:intarr(4), links:intarr(5,4)}
99;      dimensions.isdim =  [1,1,1,0]  ; (1=dimension, 0=variable)
100;      dimensions.links = [[-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1],$
101;          [-1,-1,-1,-1,-1],[0,1,2,-1,-1]]
102;
103;      netcdfwrite, 'filename', ozone, attributes=attributes, $
104;        dimensions=dimensions
105;
106;
107;
108; AJG 22/5/2003
109;
110
111; ------------------------------------------------------------------
112;
113; Add a non-string variable to the NetCDF file
114;
115; INPUTS
116;
117; var_type            - IDL type code - see IDL help for SIZE function
118; ncid, name, dim_ids - parameters passed to ncdf_vardef (see IDL help here too)
119;
120; RETURNS
121;
122; NetCDF variable ID
123;
124function add_var, var_type, ncid, name, dim_ids
125
126case var_type of
127  ; byte
128  1: var_id = ncdf_vardef(ncid, name, dim_ids, /BYTE)
129
130  ; int
131  2: var_id = ncdf_vardef(ncid, name, dim_ids, /SHORT)
132
133  ; long
134  3: var_id = ncdf_vardef(ncid, name, dim_ids, /LONG)
135
136  ; float
137  4: var_id = ncdf_vardef(ncid, name, dim_ids, /FLOAT)
138
139  ; double
140  5: var_id = ncdf_vardef(ncid, name, dim_ids, /DOUBLE)
141
142  ; catch all (will probably catch us out some-day...)
143  else: var_id = ncdf_vardef(ncid, name, dim_ids, /FLOAT)
144endcase
145
146return, var_id
147
148end
149
150; ------------------------------------------------------------------
151;
152; Main function
153;
154
155pro  netcdfwrite, file, field, clobber=clobber, dim_all=dim_all, $
156        attributes=attributes, dimensions=dimensions
157
158   on_error, 2 ; on error, return to caller (could be improved
159               ; at a later date to catch IO errors and close the
160               ; file correctly).
161
162   if ~keyword_set(clobber) then clobber = 0
163
164   tag_names = tag_names(field)
165   nTags = N_TAGS(field)
166
167   if keyword_set(attributes) then begin
168     ; Attributes are being supplied. Check they match the
169     ; data structure also supplied.
170     att_names = tag_names(attributes)
171     nAtts = n_tags(attributes)
172     nInAtt = lonarr(nAtts)
173     for i=0,nAtts-1 do nInAtt[i] = n_elements(attributes.(i))
174     if ~array_equal(nInAtt,replicate(nTags,nAtts)) then message, $
175       'Each attribute must have a member for each data structure element'
176   endif
177 
178   ncid = ncdf_create(file, clobber = clobber)   
179
180   ; Run through all data "tags" to identify "dimensions" and
181   ; "variables". For this to work, the data structure must always
182   ; have dimensions before normal variables 
183   struct_dims, field, dimension_sizes, is_string_max, var_type, $
184     nDimensions, dim_num, iDimLink, dim_all=dim_all, dimensions=dimensions
185
186   dim_ids = intarr(nTags)
187   var_ids = intarr(nTags)
188   string_id = 0 ; a unique ID for any hidden string dimensions
189
190   ; initialise file, defining the dimensions and variables
191   ncdf_control, ncid, /fill
192   for iTag=0, nTags-1 do begin
193   
194      if dim_num[iTag] eq 0 then begin
195     
196         ; Each dimension will have an associated variable
197         ; containing the values at each point
198         dim_ids[iTag] = ncdf_dimdef(ncid, tag_names[iTag], $
199            dimension_sizes[iTag])
200
201         var_ids[iTag] = add_var(var_type[iTag], ncid, tag_names[iTag], $
202           dim_ids[iTag])
203           
204      endif else begin     
205         if is_string_max[iTag] eq 0 then begin
206
207           var_ids[iTag] = add_var(var_type[iTag], ncid, tag_names[iTag], $
208             dim_ids[reform(iDimlink[iTag,0:dim_num[iTag]-1])])
209           
210         endif else begin
211         
212            ; Deal with the string array special case
213
214            ; * Note that a string variable will gain an extra, hidden
215            ; dimension when we write it to file because of NetCDF
216            ; limitations.
217           
218            ; Create a new dimension for the array of characters which forms
219            ; a string, with its length being that of the longest string
220            ; in the original array of strings. Don't bother defining
221            ; a variable for the dimension.
222            string_id = string_id+1
223            string_dim = ncdf_dimdef(ncid, $
224               'STRING'+string(format='(i0)', string_id), $
225               is_string_max[iTag])
226
227            ; Combine the "IDL" dimensions with the extra hidden
228            ; string dimension (which must be the first, "fastest varying")
229            string_dim_ids = $
230               [string_dim, dim_ids[reform(iDimlink[iTag,0:dim_num[iTag]-1])]]           
231            var_ids[iTag] = ncdf_vardef(ncid, tag_names[iTag], $
232               string_dim_ids, /CHAR)   
233                     
234         endelse
235      endelse
236     
237      ; Write any associated atributes
238      if keyword_set(attributes) then begin
239        for iAtt = 0, nAtts-1 do begin
240          ncdf_attput, ncid, var_ids[iTag], strlowcase(att_names[iAtt]), $
241            attributes.(iAtt)[iTag]
242        endfor
243      endif
244
245   endfor
246   ncdf_control, ncid, /endef
247
248   ; write the data
249   for iTag=0, nTags-1 do begin
250   
251      ncdf_varput, ncid, var_ids[iTag], field.(iTag)
252     
253   endfor
254
255   ; close the file
256   ncdf_close, ncid
257   
258end
Note: See TracBrowser for help on using the repository browser.