[3403] | 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 | ; |
---|
| 124 | function add_var, var_type, ncid, name, dim_ids |
---|
| 125 | |
---|
| 126 | case 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) |
---|
| 144 | endcase |
---|
| 145 | |
---|
| 146 | return, var_id |
---|
| 147 | |
---|
| 148 | end |
---|
| 149 | |
---|
| 150 | ; ------------------------------------------------------------------ |
---|
| 151 | ; |
---|
| 152 | ; Main function |
---|
| 153 | ; |
---|
| 154 | |
---|
| 155 | pro 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 | |
---|
| 258 | end |
---|