source: TOOLS/MOSAIX/Build_coordinates_mask.py @ 6764

Last change on this file since 6764 was 6190, checked in by omamce, 23 months ago

O.M. : Evolution on MOSAIX

  • Add licensing information
  • Update and beautify README.md
  • Add few model version to known list
  • Property svn:keywords set to Date Author Revision Id SVN_Date
File size: 19.9 KB
Line 
1### ===========================================================================
2###
3### Build coordnates mask
4###
5### ===========================================================================
6# creates file coordinates_mask.nc used by mosaix from NEMO netcdf files
7# coordinates.nc and bathymetry.nc (on the same grid as coordinates.nc)
8##
9##  MOSAIX is under CeCILL_V2 licence. See "Licence_CeCILL_V2-en.txt"
10##  file for an english version of the licence and
11##  "Licence_CeCILL_V2-fr.txt" for a french version.
12##
13##  Permission is hereby granted, free of charge, to any person or
14##  organization obtaining a copy of the software and accompanying
15##  documentation covered by this license (the "Software") to use,
16##  reproduce, display, distribute, execute, and transmit the
17##  Software, and to prepare derivative works of the Software, and to
18##  permit third-parties to whom the Software is furnished to do so,
19##  all subject to the following:
20##
21##  Warning, to install, configure, run, use any of MOSAIX software or
22##  to read the associated documentation you'll need at least one (1)
23##  brain in a reasonably working order. Lack of this implement will
24##  void any warranties (either express or implied).  Authors assumes
25##  no responsability for errors, omissions, data loss, or any other
26##  consequences caused directly or indirectly by the usage of his
27##  software by incorrectly or partially configured
28##
29##
30import numpy  as np
31import xarray as xr
32import nemo
33import datetime, os, platform, argparse
34
35## SVN information
36__Author__   = "$Author$"
37__Date__     = "$Date$"
38__Revision__ = "$Revision$"
39__Id__       = "$Id$"
40__HeadURL__  = "$HeadURL: $"
41###
42
43### ===== Handling command line parameters ==================================================
44# Creating a parser
45parser = argparse.ArgumentParser (
46    description = """Read coordinates and bathymetry to build masks, grid bounds and areas for MOSAIX""",
47    epilog='-------- End of the help message --------',
48    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
49
50# Adding arguments
51parser.add_argument ('--model'   , help='oce model name', type=str, default='eORCA1.2', choices=('paleORCA', 'ORCA2.3', 'ORCA2.4', 'eORCA1.2', 'eORCA025', 'eORCA025.1') )
52parser.add_argument ('--bathy'   , help='bathymetry file name', type=str, default='bathy_meter.nc' )
53parser.add_argument ('--coord'   , help='coordinates file name', type=str, default='coordinates.nc' )
54parser.add_argument ('--fout'    , help='output file name (given as an input to MOSAIX)', type=str, default='coordinates_mask.nc' )
55parser.add_argument ('--ocePerio', help='periodicity of ocean grid, if not given is imposed according to --model', type=int, default=0, choices=range(1, 7) )
56parser.add_argument ('--nemo4Ubug',help='reproduce NEMO lbc_lnk bug for U grid and periodicity 4', type=bool, default=False, choices=(True, False) )
57parser.add_argument ('--straits' , help='modify grid metrics for selected strait points (depends on model name)', type=bool, default=False, choices=(True, False) )
58parser.add_argument ('--coordPerio', help='impose periodicity of coordinates and areas through lbc', type=bool, default=False, choices=(True, False) )
59parser.add_argument ('--maskbathy', help='use the same formula as in NEMO to compute mask_T from the bathymetry file. Does not always give the same result as NEMO ???', type=bool, default=False, choices=(True, False) )
60
61# Parse command line
62myargs = parser.parse_args()
63
64# ocean model name
65model = myargs.model
66
67# bathymetry input file
68n_bathy = myargs.bathy
69# coordinates input file
70n_coord = myargs.coord
71# coordinates and mask output file
72n_out = myargs.fout
73
74# reproduce periodicity lbclnk bug for U and nperio = 4
75nemoUbug = myargs.nemo4Ubug
76# change metrics (and bathymetry) for straits
77straits = myargs.straits
78# periodicity imposed on coordinates, metrics and areas
79coordperio = myargs.coordPerio
80# function used to compute mask_T from bathymetry
81maskbathynemo = myargs.maskbathy
82
83# type of grid periodicity
84nperio = myargs.ocePerio
85
86# check of periodicity with type of grid
87if model in ('eORCA1.2', 'paleORCA', 'ORCA025', 'eORCA025', 'eORCA025.1') :
88    if nperio != 0 :
89        if nperio != 6 :
90            print(f'Warning ! model = {model} and ocePerio = {nperio} instead of 6 !')
91    else :
92        nperio = 6
93
94if model in ('ORCA2.3', 'ORCA2.4') :
95    if nperio != 0 :
96        if nperio != 4 :
97            print(f'Attention ! model = {model} and ocePerio = {nperio} instead of 4 !')
98    else :
99        nperio = 4
100
101print(f' model = {model}\n ocePerio = {nperio}\n bathy = {n_bathy}\n coord = {n_coord}\n fout  = {n_out}')
102print(f' Switchs : nemo4Ubug = {nemoUbug}, straits = {straits}, coordPerio = {coordperio}, maskbathy = {maskbathynemo}')
103
104##
105#!!! bathymetry and coordinates files
106##
107
108# open input files while removing the time dimension
109f_coord = xr.open_dataset (n_coord, decode_times=False).squeeze()
110f_bathy = xr.open_dataset (n_bathy, decode_times=False).squeeze()
111
112# Suppress time if necessary
113try    :
114    del f_coord['time']
115    print ('time successfully removed')
116except :
117    pass
118    print ('failed to suppress time')
119
120# rename latitude, longitude and grid variables in bathymetry
121Bathymetry = f_bathy['Bathymetry'].copy()
122
123nav_lon_grid_T = f_bathy['nav_lon'].data
124nav_lat_grid_T = f_bathy['nav_lat'].data
125Bathymetry = xr.DataArray (Bathymetry, coords = { "nav_lat_grid_T": (["y", "x"], nav_lat_grid_T),
126                                                  "nav_lon_grid_T": (["y", "x"], nav_lon_grid_T) } )
127   
128Bathymetry = Bathymetry.rename ({'y':'y_grid_T', 'x':'x_grid_T'})
129
130# modify Bathymetry in straits for select grids (might change computed mask_T)
131if straits :
132    # Open straits for usual grids
133    if model == 'ORCA2.3' :
134        # orca_r2: Gibraltar strait open
135        Bathymetry[101,139] = 284.
136        # orca_r2: Bab el Mandeb strait open
137        Bathymetry[87,159] = 137.
138
139# impose periodicity of bathymetry
140Bathymetry = nemo.lbc (Bathymetry, nperio=nperio, cd_type='T')
141# suppress ocean points at southernmost position only if nperio in {3, 4, 5, 6}
142if nperio in (3, 4, 5, 6) :
143    Bathymetry[0,:] = 0.0
144
145##
146#!!! Create masks from bathymetry
147##
148
149# Creation of mask_T following choosed option maskbathy
150if maskbathynemo :
151    # Use same formula as domzgr.
152    mask_T = xr.where (Bathymetry - 1. + 0.1 >= 0.0, 1, 0).astype (dtype='f4')
153else :
154    mask_T = xr.where (Bathymetry > 0.0, 1, 0).astype (dtype='f4')
155
156# Creation of U, V, W, F masks from mask_T
157mask_U = mask_T * mask_T.shift (x_grid_T=-1)
158mask_V = mask_T * mask_T.shift (y_grid_T=-1)
159mask_F = mask_T * mask_T.shift (y_grid_T=-1) * mask_T.shift (x_grid_T=-1) * mask_T.shift (y_grid_T=-1, x_grid_T=-1)
160mask_W = mask_T
161
162# loop on TUVFW to modify coordinates and attributes of mask_[TUVFW] and maskutil_[TUVFW]
163for cd_type in ['T', 'U', 'V', 'F', 'W'] :
164    MaskName = 'mask_'     + cd_type
165    UtilName = 'maskutil_' + cd_type
166    # impose periodicity of chosen grid model on masks
167    locals()[MaskName] = nemo.lbc (locals()[MaskName], nperio=nperio, cd_type=cd_type, nemo_4U_bug=nemoUbug).astype (dtype='f4')
168    # rename masks coordinates
169    if cd_type != 'T' :
170        locals()[MaskName] = locals()[MaskName].rename \
171                    ( {'y_grid_T'      :       'y_grid_'+cd_type, 'x_grid_T'      :       'x_grid_'+cd_type,
172                       'nav_lat_grid_T': 'nav_lat_grid_'+cd_type, 'nav_lon_grid_T': 'nav_lon_grid_'+cd_type} )
173
174    # create masks without duplicate points : maskutil_[TUVWF]
175    locals()[UtilName] = nemo.lbc_mask (locals()[MaskName].copy(), nperio=nperio, cd_type=cd_type)
176 
177    #set name attribute of mask dataset
178    locals()[MaskName].name = MaskName
179    locals()[UtilName].name = UtilName
180
181    # remove _FillVallue from mskutil
182    locals()[MaskName].encoding['_FillValue'] = None
183    locals()[UtilName].encoding['_FillValue'] = None
184
185    # add masks attributes
186    locals()[MaskName].attrs['cell_measures'] = 'area: area_grid_'+cd_type
187    locals()[UtilName].attrs['cell_measures'] = 'area: area_grid_'+cd_type
188
189##
190#!!! create grid coordinates from NEMO coordinates.nc file
191##
192
193angle = { 'lon' : 'glam', 'lat' : 'gphi' }
194gridv = { 'T' : 't', 'U' : 'u', 'V' : 'v', 'F' : 'f', 'W' : 't' }
195for cd_type in ['T', 'U', 'V', 'F', 'W'] :
196    for dir_type in ['lon', 'lat'] :
197        coord_name = 'nav_' + dir_type + '_grid_' + cd_type
198        dir_name = angle[dir_type]+gridv[cd_type]
199# impose or not periodicity on coordinates read from file
200        if coordperio :
201            locals()[coord_name] = nemo.lbc (f_coord[dir_name].copy(), nperio=nperio, cd_type=cd_type, nemo_4U_bug=nemoUbug)
202        else :
203            locals()[coord_name] = f_coord[dir_name].copy()
204
205        locals()[coord_name] = locals()[coord_name].rename( {'y':'y_grid_'+cd_type, 'x':'x_grid_'+cd_type} )
206
207# remove _FillValue and missing_value
208        locals()[coord_name].encoding['_FillValue'] = None
209        locals()[coord_name].encoding['missing_value'] = None
210
211# define name attribute
212        locals()[coord_name].name = coord_name
213
214# add coordinates attributes
215        locals()[coord_name].attrs['bounds'] ='bounds_' + dir_type + '_grid_' + cd_type
216
217    locals()['nav_lon_grid_'+cd_type].attrs['standard_name'] = 'longitude'
218    locals()['nav_lon_grid_'+cd_type].attrs['long_name']     = 'Longitude'
219    locals()['nav_lon_grid_'+cd_type].attrs['units']         = 'degrees_east'
220    locals()['nav_lat_grid_'+cd_type].attrs['standard_name'] = 'latitude'
221    locals()['nav_lat_grid_'+cd_type].attrs['long_name']     = 'Latitude'
222    locals()['nav_lat_grid_'+cd_type].attrs['units']         = 'degrees_north'
223
224##
225#!!! compute areas of cells at coordinate points
226##
227
228# create areas variables for grid cells from NEMO coordinates.nc file
229# create new variables e1 e2 to keep f_coord the same
230for cd_type in ['t', 'u', 'v', 'f'] :
231    for axis in ['1', '2'] :
232        coordName = 'e' + axis + cd_type
233        locals()[coordName]=f_coord[coordName].copy()
234        # remove zero values from areas
235        # need to be define for the extended grid south of -80S
236        # some point are undefined but you need to have e1 and e2 .NE. 0
237        locals()[coordName]=xr.where(locals()[coordName] == 0.0, 1.0e2, locals()[coordName])
238
239# Correct areas for straits
240if straits :
241    # ORCA R2 configuration
242    if model == 'ORCA2.3' :
243        # Gibraltar     : e2u reduced to 20 km
244        e2u[101,138:140] = 20.e3
245        # Bab el Mandeb : e2u reduced to 30 km
246        #                e1v reduced to 18 km
247        e1v[87,159] = 18.e3
248        e2u[87,159] = 30.e3
249        # Danish Straits: e2u reduced to 10 km
250        e2u[115,144:146] = 10.e3
251    # ORCA R1 configuration
252    if model == 'eORCA1.2' :
253        # Gibraltar : e2u reduced to 20 km
254        e2u[240,281:283] = 20.e3
255        # Bhosporus : e2u reduced to 10 km
256        e2u[247,313:315] =  10.e3
257        # Lombok : e1v reduced to 13 km
258        e1v[163:165,43] =  13.e3
259        # Sumba : e1v reduced to 8 km
260        e1v[163:165,47] =  8.e3
261        # Ombai : e1v reduced to 13 km
262        e1v[163:165,52] = 13.e3
263        # Timor Passage : e1v reduced to 20 km
264        #e1v[163:165,55] = 20.e3
265        # W Halmahera : e1v reduced to 30 km
266        e1v[180:182,54] = 30.e3
267        # E Halmahera : e1v reduced to 50 km
268        e1v[180:182,57] = 50.e3
269    # ORCA R05 configuration
270    if model == 'ORCA.05' :
271        # Reduced e2u at the Gibraltar Strait
272        e2u[326,562:564] =  20.e3
273        # Reduced e2u at the Bosphore Strait
274        e2u[342,626:628] =  10.e3
275        # Reduced e2u at the Sumba Strait
276        e2u[231,92:94] =  40.e3
277        # Reduced e2u at the Ombai Strait
278        e2u[231,102] =  15.e3
279        # Reduced e2u at the Palk Strait
280        e2u[269,14] =  10.e3
281        # Reduced e1v at the Lombok Strait
282        e1v[231:233,86] =  10.e3
283        # Reduced e1v at the Bab el Mandeb
284        e1v[275,661] =  25.e3
285
286# compute cells areas
287
288for cd_type in ['T', 'U', 'V', 'F', 'W'] :
289    areaName = 'area_grid_' + cd_type
290    if coordperio :
291        locals()[areaName] = nemo.lbc (locals()['e1'+gridv[cd_type]]*locals()['e2'+gridv[cd_type]],
292                                                           nperio=nperio, cd_type=cd_type, nemo_4U_bug=nemoUbug)
293    else :
294        locals()[areaName] = locals()['e1'+gridv[cd_type]]*locals()['e2'+gridv[cd_type]]
295
296    # rename indices
297    locals()[areaName] = locals()[areaName].rename ({'y':'y_grid_'+cd_type, 'x':'x_grid_'+cd_type})
298
299    # add attributes
300    locals()[areaName].name = areaName
301    locals()[areaName].attrs['standard_name'] = 'cell_area'
302    locals()[areaName].attrs['units']         = 'm2'
303
304    # remove fill values
305    locals()[areaName].encoding['_FillValue'] = None
306
307##
308#!!! compute grid bounds !!!
309##
310
311#---------------------------------------------------------------
312# function to generate grid bounds from NEMO coordinates.nc file
313def set_bounds (cdgrd) :
314    '''
315    Constructs lon/lat bounds
316    Bounds are numerated counter clockwise, from bottom left
317    See NEMO file OPA_SRC/IOM/iom.F90, ROUTINE set_grid_bounds, for more details
318    '''
319    # Define offset of coordinate representing bottom-left corner
320    if cdgrd in ['T', 'W'] : 
321        icnr = -1 ; jcnr = -1
322        corner_lon = f_coord['glamf'].copy() ; corner_lat = f_coord['gphif'].copy()
323        center_lon = f_coord['glamt'].copy() ; center_lat = f_coord['gphit'].copy()
324    if cdgrd == 'U'        : 
325        icnr =  0 ; jcnr = -1
326        corner_lon = f_coord['glamv'].copy() ; corner_lat = f_coord['gphiv'].copy()
327        center_lon = f_coord['glamu'].copy() ; center_lat = f_coord['gphiu'].copy()
328    if cdgrd == 'V'        : 
329        icnr = -1 ; jcnr =  0
330        corner_lon = f_coord['glamu'].copy() ; corner_lat = f_coord['gphiu'].copy()
331        center_lon = f_coord['glamv'].copy() ; center_lat = f_coord['gphiv'].copy()
332    if cdgrd == 'F'        : 
333        icnr = -1 ; jcnr = -1
334        corner_lon = f_coord['glamt'].copy() ; corner_lat = f_coord['gphit'].copy()
335        center_lon = f_coord['glamf'].copy() ; center_lat = f_coord['gphif'].copy()
336     
337    jpj, jpi = corner_lon.shape ;
338    nvertex = 4
339    dims = ['y_grid_' + cdgrd, 'x_grid_' + cdgrd, 'nvertex_grid_' + cdgrd]
340   
341    bounds_lon = xr.DataArray (np.zeros ((jpj, jpi, nvertex)), dims=dims)
342    bounds_lat = xr.DataArray (np.zeros ((jpj, jpi, nvertex)), dims=dims)
343   
344    idx = [(jcnr,icnr), (jcnr,icnr+1), (jcnr+1,icnr+1), (jcnr+1,icnr)]
345   
346    # Compute cell vertices that can be defined,
347    # and complete with periodicity
348    for nn in range (nvertex) :
349        tmp = np.roll (corner_lon, shift=tuple(-1*np.array(idx[nn])), axis=(-2,-1))
350        bounds_lon[1:jpj,1:jpi,nn] = tmp[1:jpj,1:jpi]
351        tmp = np.roll (corner_lat, shift=tuple(-1*np.array(idx[nn])), axis=(-2,-1))
352        bounds_lat[1:jpj,1:jpi,nn] = tmp[1:jpj,1:jpi]
353        bounds_lon[:,:,nn] = nemo.lbc (bounds_lon[:,:,nn], nperio=nperio, cd_type=cdgrd, nemo_4U_bug=nemoUbug)
354        bounds_lat[:,:,nn] = nemo.lbc (bounds_lat[:,:,nn], nperio=nperio, cd_type=cdgrd, nemo_4U_bug=nemoUbug)
355   
356    # Zero-size cells at closed boundaries if cell points provided,
357    # otherwise they are closed cells with unrealistic bounds
358    if not (nperio == 1 or nperio == 4 or nperio == 6) :
359        for nn in range (nvertex) : 
360            bounds_lon[:,0,nn]   = center_lon[:,0]   # (West or jpni = 1), closed E-W
361            bounds_lat[:,0,nn]   = center_lat[:,0]
362            bounds_lon[:,jpi,nn] = center_lon[:,jpi] # (East or jpni = 1), closed E-W
363            bounds_lat[:,jpi,nn] = center_lat[:,jpi]
364    if nperio != 2 :
365        for nn in range (nvertex) :
366            bounds_lon[0,:,nn] = center_lon[0,:] # (South or jpnj = 1), not symmetric
367            bounds_lat[0,:,nn] = center_lat[0,:]
368    if nperio < 3 :
369        for nn in range (nvertex) :
370            bounds_lon[jpj,:,nn] = center_lon[jpj,:] # (North or jpnj = 1), no north fold
371            bounds_lat[jpj,:,nn] = center_lat[jpj,:]
372   
373    # Rotate cells at the north fold
374    if nperio >= 3 :
375        # Working array for location of northfold
376        z_fld = nemo.lbc (np.ones ((jpj, jpi)), nperio=nperio, cd_type=cdgrd, psgn=-1., nemo_4U_bug=nemoUbug)
377        z_fld = np.repeat((z_fld == -1.0)[...,np.newaxis],4,axis=2)
378        # circular shift of 2 indices in bounds third index
379        bounds_lon_tmp = np.roll (bounds_lon, shift=-2, axis=2)
380        bounds_lat_tmp = np.roll (bounds_lat, shift=-2, axis=2)
381        bounds_lon[:,:,:]  = np.where (z_fld, bounds_lon_tmp[:,:,:] , bounds_lon[:,:,:] )
382        bounds_lat[:,:,:]  = np.where (z_fld, bounds_lat_tmp[:,:,:] , bounds_lat[:,:,:] )
383   
384    # Invert cells at the symmetric equator
385    if nperio == 2 :
386        bounds_lon_tmp = np.roll (bounds_lon, shift=-2, axis=2)
387        bounds_lat_tmp = np.roll (bounds_lat, shift=-2, axis=2)
388        bounds_lon[0,:,:] = bounds_lon[0,:,:]
389        bounds_lat[0,:,:] = bounds_lat[0,:,:]
390   
391    #bounds_lon.attrs['coordinates'] = 'nav_lat_grid_' + cdgrd + ' nav_lon_grid_' + cdgrd
392    #bounds_lat.attrs['coordinates'] = 'nav_lat_grid_' + cdgrd + ' nav_lon_grid_' + cdgrd
393    bounds_lon.attrs['units']       = 'degrees_east'
394    bounds_lat.attrs['units']       = 'degrees_north'
395    bounds_lon.name = 'bounds_lon_grid_' + cdgrd
396    bounds_lat.name = 'bounds_lat_grid_' + cdgrd
397    # remove _FillValue
398    bounds_lon.encoding['_FillValue'] = None
399    bounds_lat.encoding['_FillValue'] = None
400
401    return bounds_lon, bounds_lat
402#------------------------------------------------------------
403
404bounds_lon_grid_T, bounds_lat_grid_T = set_bounds ('T')
405bounds_lon_grid_U, bounds_lat_grid_U = set_bounds ('U')
406bounds_lon_grid_V, bounds_lat_grid_V = set_bounds ('V')
407bounds_lon_grid_W, bounds_lat_grid_W = set_bounds ('W')
408bounds_lon_grid_F, bounds_lat_grid_F = set_bounds ('F')
409
410# build xarray dataset to be saved
411ds = xr.Dataset ({
412    'mask_T'      : mask_T     ,
413    'mask_U'      : mask_U     ,
414    'mask_V'      : mask_V     ,
415    'mask_W'      : mask_W     ,
416    'mask_F'      : mask_F     ,
417    'area_grid_T' : area_grid_T,
418    'area_grid_U' : area_grid_U,
419    'area_grid_V' : area_grid_V,
420    'area_grid_W' : area_grid_W,
421    'area_grid_F' : area_grid_F,
422    'maskutil_T'  : maskutil_T ,
423    'maskutil_U'  : maskutil_U ,
424    'maskutil_V'  : maskutil_V ,
425    'maskutil_W'  : maskutil_W ,
426    'maskutil_F'  : maskutil_F ,
427    'bounds_lon_grid_T': bounds_lon_grid_T,
428    'bounds_lat_grid_T': bounds_lat_grid_T,
429    'bounds_lon_grid_U': bounds_lon_grid_U,
430    'bounds_lat_grid_U': bounds_lat_grid_U,
431    'bounds_lon_grid_V': bounds_lon_grid_V,
432    'bounds_lat_grid_V': bounds_lat_grid_V,
433    'bounds_lon_grid_W': bounds_lon_grid_W,
434    'bounds_lat_grid_W': bounds_lat_grid_W,
435    'bounds_lon_grid_F': bounds_lon_grid_F,
436    'bounds_lat_grid_F': bounds_lat_grid_F,
437})
438
439#replace nav_lon nav_lat with variables obtained from NEMO coordinates.nc file
440#by construction nav_lon nav_lat come from the bathymetry
441for cd_type in ['T', 'U', 'V', 'F', 'W'] :
442    for dir_type in ['lon', 'lat'] :
443        coord_name = 'nav_' + dir_type + '_grid_' + cd_type
444        ds.coords[coord_name]=locals()[coord_name]
445
446ds.attrs['name']         = 'coordinates_mask'
447ds.attrs['description']  = 'coordinates and mask for MOSAIX'
448ds.attrs['title']        = 'coordinates_mask'
449ds.attrs['source']       = 'IPSL Earth system model'
450ds.attrs['group']        = 'ICMC IPSL Climate Modelling Center'
451ds.attrs['Institution']  = 'IPSL https.//www.ipsl.fr'
452ds.attrs['Model']        = model
453ds.attrs['timeStamp']    = '{:%Y-%b-%d %H:%M:%S}'.format (datetime.datetime.now ())
454ds.attrs['history']      = 'Build from ' + n_coord + ' and ' + n_bathy
455ds.attrs['directory']    = os.getcwd     ()
456try:
457    ds.attrs['user']         = os.getlogin   ()
458except:
459    ds.attrs['user']         = 'NoUser'
460ds.attrs['HOSTNAME']     = platform.node ()
461ds.attrs['Python']       = 'Python version: ' +  platform.python_version ()
462ds.attrs['xarray']       = 'xarray version: ' +  xr.__version__
463ds.attrs['OS']           = platform.system  ()
464ds.attrs['release']      = platform.release ()
465ds.attrs['hardware']     = platform.machine ()
466
467ds.attrs['SVN_Author']   = "$Author$"
468ds.attrs['SVN_Date']     = "$Date$"
469ds.attrs['SVN_Revision'] = "$Revision$"
470ds.attrs['SVN_Id']       = "$Id$"
471ds.attrs['SVN_HeadURL']  = "$HeadURL: http://forge.ipsl.jussieu.fr/igcmg/svn/TOOLS/MOSAIX/Build_coordinates_mask.py $"
472
473# save to output file
474ds.to_netcdf (n_out)
Note: See TracBrowser for help on using the repository browser.