source: TOOLS/MOSAIX/cotes_etal.py @ 4147

Last change on this file since 4147 was 4147, checked in by omamce, 5 years ago

O.M. : add cote_etal.py to compute run-off weights (for LMDZ only)

File size: 15.1 KB
Line 
1# -*- Mode: python -*-
2import netCDF4
3import numpy as np
4import nemo
5from scipy import ndimage
6import sys, os, platform, argparse, textwrap, time
7
8zero = np.dtype('float64').type(0.0)
9zone = np.dtype('float64').type(1.0)
10epsfrac = np.dtype('float64').type(1.0E-10)
11pi  = np.pi
12rad = pi/np.dtype('float64').type(180.0)
13ra = np.dtype('float64').type(6400000.0) # Earth radius
14
15def geodist (plon1, plat1, plon2, plat2) :
16      """Distance between two points (on sphere)"""
17      zs = np.sin (rad*plat1) * np.sin (rad*plat2) +  np.cos (rad*plat1) * np.cos (rad*plat2) * np.cos(rad*(plon2-plon1))
18      zs = np.maximum (-zone, np.minimum (zone, zs))
19      geodist =  np.arccos (zs)
20      return geodist
21
22###
23###   A partir d'un fichier de poids, complete avec les rivieres et
24###   les poids pour le run off
25###   On met a zero les poids sur les points non cotiers, et on renormalise
26###
27
28   
29### Lecture de la ligne de comande
30# SVN information
31__Author__   = "$Author: omamce $"
32__Date__     = "$Date: 2018-10-25 17:59:40 +0200 (Thu, 25 Oct 2018) $"
33__Revision__ = "$Revision: 4097 $"
34__Id__       = "$Id: CalvingWeights.py 4097 2018-10-25 15:59:40Z omamce $"
35__HeadURL__  = "$HeadURL: http://forge.ipsl.jussieu.fr/igcmg/svn/TOOLS/MOSAIX/CalvingWeights.py $"
36__SVN_Date__ = "$SVN_Date: $"
37
38###
39
40### ===== Handling command line parameters ==================================================
41# Creating a parser
42parser = argparse.ArgumentParser (
43    description = """Compute calving weights""",
44    epilog='-------- This is the end of the help message --------')
45
46# Adding arguments
47parser.add_argument ('--oce'   , help='oce model name', type=str, default='eORCA1.2', choices=['ORCA2.3', 'eORCA1.2', 'eORCA025'] )
48parser.add_argument ('--atm'   , help='atm model name (LMD*)', type=str, default='LMD9695'    )
49parser.add_argument ('--atmCoastWidth', help='width of the coastal band in atmosphere (in grid points)', default=1 )
50parser.add_argument ('--oceCoastWidth', help='width of the coastal band in ocean (in grid points)', default=1 )
51parser.add_argument ('--grids', help='grids file name', default='grids.nc' )
52parser.add_argument ('--areas', help='masks file name', default='areas.nc' )
53parser.add_argument ('--masks', help='areas file name', default='masks.nc' )
54parser.add_argument ('--o2a'  , help='o2a file name', default='o2a.nc' )
55parser.add_argument ('--output', help='output rmp file name', default='rmp_tlmd_to_torc_runoff.nc' )
56
57
58# Parse command line
59myargs = parser.parse_args()
60
61#
62grids = myargs.grids
63areas = myargs.areas
64masks = myargs.masks
65o2a   = myargs.o2a
66
67# Model Names
68atm_Name = myargs.atm
69oce_Name = myargs.oce
70# Largeur de la bande cotiere cote atm
71atmCoastWidth = myargs.atmCoastWidth
72# Largeur de la bande cotiere cote oce
73oceCoastWidth = myargs.oceCoastWidth
74
75
76### Read coordinates of all models
77###
78
79diaFile    = netCDF4.Dataset ( o2a   )
80gridFile   = netCDF4.Dataset ( grids )
81areaFile   = netCDF4.Dataset ( areas )
82maskFile   = netCDF4.Dataset ( masks )
83
84o2aFrac             = diaFile ['field01_dst'][:].filled()
85o2aFrac = np.where ( np.abs(o2aFrac) < 1E10, o2aFrac, 0.0)
86
87atm_grid_center_lat = gridFile['tlmd.lat'][:].filled()
88atm_grid_center_lon = gridFile['tlmd.lon'][:].filled()
89atm_grid_corner_lat = gridFile['tlmd.cla'][:].filled()
90atm_grid_corner_lon = gridFile['tlmd.clo'][:].filled()
91
92atm_grid_area       = areaFile['tlmd.srf'][:].filled()
93atm_grid_imask      = 1-maskFile['tlmd.msk'][:].squeeze().filled()
94atm_grid_dims       = atm_grid_area.shape
95(atm_nvertex, atm_jpj, atm_jpi) = atm_grid_corner_lat.shape
96if atm_jpi == 1 : atm_perio = 0 # Icosahedre
97else            : atm_perio = 1 #
98atm_grid_pmask = nemo.lbc_mask (atm_grid_imask, 'T', atm_perio)
99atm_address = np.reshape ( np.arange(atm_jpj*atm_jpi), (atm_jpj, atm_jpi) )
100atm_grid_size = atm_jpj*atm_jpi
101
102oce_grid_center_lat = gridFile['torc.lat'][:].filled()
103oce_grid_center_lon = gridFile['torc.lon'][:].filled()
104oce_grid_corner_lat = gridFile['torc.cla'][:].filled()
105oce_grid_corner_lon = gridFile['torc.clo'][:].filled()
106oce_grid_area       = areaFile['torc.srf'][:].filled()
107oce_grid_imask      = 1-maskFile['torc.msk'][:].filled()
108oce_grid_dims       = oce_grid_area.shape
109(oce_nvertex, oce_jpj, oce_jpi) = oce_grid_corner_lat.shape ; jpon=oce_jpj*oce_jpj
110if oce_jpi ==  182 : oce_perio = 4 # ORCA 2
111if oce_jpi ==  362 : oce_perio = 6 # ORCA 1
112if oce_jpi == 1442 : oce_perio = 6 # ORCA 025
113oce_grid_pmask = nemo.lbc_mask (oce_grid_imask, 'T', oce_perio)
114oce_address = np.reshape ( np.arange(oce_jpj*oce_jpi), (oce_jpj, oce_jpi) )
115oce_grid_size = oce_jpj*oce_jpi
116
117print ('Calculs points terre/oce/cote sur grille atmosphere' )
118
119# Fill closed sea with image processing library
120oce_grid_imask = nemo.lbc_mask ( 1-ndimage.binary_fill_holes (1-nemo.lbc(oce_grid_imask, nperio=oce_perio, cd_type='T')), nperio=oce_perio, cd_type='T' )
121
122print ("Determination d'une bande cotiere ocean")
123
124oceLand  = np.where (oce_grid_imask[:] < 0.5, True, False)
125oceOcean = np.where (oce_grid_imask[:] > 0.5, True, False)
126
127oceCoast = np.where (ndimage.uniform_filter(oceOcean.astype(float), size=1+2*oceCoastWidth)<1.0,True,False) & oceOcean
128oceCoast = nemo.lbc_mask (oceCoast, oce_perio, 'T')
129
130print ('Nombre de point oceLand  : ' + str(oceLand.sum()) )
131print ('Nombre de point oceOcean : ' + str(oceOcean.sum()) )
132print ('Nombre de point oceCoast : ' + str(oceCoast.sum()) )
133
134# Faire une liste de ces points
135oceCoast_grid_center_lon = oce_grid_center_lon[oceCoast]
136oceCoast_grid_center_lat = oce_grid_center_lat[oceCoast]
137oceCoast_grid_area       = oce_grid_area      [oceCoast]
138oceCoast_grid_imask      = oce_grid_imask     [oceCoast]
139oceCoast_grid_pmask      = oce_grid_pmask     [oceCoast]
140oceCoast_address         = oce_address        [oceCoast]
141
142
143print ("Determination d'une bande cotiere atmosphere " )
144atmLand  = np.where (o2aFrac[:] < epsfrac, True, False)
145atmFrac  = np.where (o2aFrac[:] < epsfrac, True, False) & np.where (o2aFrac[:] < (zone-epsfrac), True, False)
146atmOcean = np.where (o2aFrac[:] < (zone-epsfrac), True, False)
147
148atmCoast = np.where (ndimage.uniform_filter(atmLand.astype(float), size=1+2*atmCoastWidth)<1.0,True,False) & atmLand
149atmCoast = nemo.lbc_mask (atmCoast, 1, 'T')
150
151print ('Nombre de point atmLand  : ' + str(atmLand.sum()) )
152print ('Nombre de point atmOcean : ' + str(atmOcean.sum()) )
153print ('Nombre de point atmCoast : ' + str(atmCoast.sum()) )
154
155# Faire une liste de ces points
156atmCoast_grid_center_lon = atm_grid_center_lon[atmCoast]
157atmCoast_grid_center_lat = atm_grid_center_lat[atmCoast]
158atmCoast_grid_area       = atm_grid_area      [atmCoast]
159atmCoast_grid_imask      = atm_grid_imask     [atmCoast]
160atmCoast_grid_pmask      = atm_grid_pmask     [atmCoast]
161atmCoast_address         = atm_address        [atmCoast]
162
163remap_matrix = np.empty ( shape=(0), dtype=np.float64 )
164atm_address  = np.empty ( shape=(0), dtype=np.int32   )
165oce_address  = np.empty ( shape=(0), dtype=np.int32   )
166
167for ja in np.arange(len(atmCoast_grid_pmask)) :
168    z_dist = geodist ( atmCoast_grid_center_lon[ja], atmCoast_grid_center_lat[ja], oceCoast_grid_center_lon, oceCoast_grid_center_lat)
169    z_mask = np.where ( z_dist*ra < 600000.0, True, False)
170    num_links = z_mask.sum()
171    if num_links == 0 : continue
172    z_area = oceCoast_grid_area[z_mask].sum()
173    poids = 1.0 / z_area
174    print ( num_links, z_mask.sum(), z_area )
175    #
176    matrix_local     = np.ones ((num_links),dtype=np.float64) * poids
177    # address on source grid : all links points to the same LMDZ point.
178    atm_address_local = np.ones(num_links, dtype=np.int32 ) * atmCoast_address[ja]
179    # address on destination grid
180    oce_address_local = oceCoast_address[z_mask]
181    # Append to global tabs
182    remap_matrix = np.append ( remap_matrix, matrix_local      )
183    atm_address  = np.append ( atm_address , atm_address_local )
184    oce_address  = np.append ( oce_address , oce_address_local )
185       
186
187print ('fini')
188
189num_links = remap_matrix.shape[0]
190
191# Output file
192runoff = myargs.output
193f_runoff = netCDF4.Dataset ( runoff, 'w', format='NETCDF3_64BIT' )
194
195print ('Output file: ' + runoff )
196
197f_runoff.Conventions     = "CF-1.6"
198f_runoff.source          = "IPSL Earth system model"
199f_runoff.group           = "ICMC IPSL Climate Modelling Center"
200f_runoff.Institution     = "IPSL https.//www.ipsl.fr"
201f_runoff.Ocean           = oce_Name + " https://www.nemo-ocean.eu"
202f_runoff.Atmosphere      = atm_Name + " http://lmdz.lmd.jussieu.fr"
203f_runoff.associatedFiles = grids + " " + areas + " " + masks
204f_runoff.directory       = os.getcwd ()
205f_runoff.description     = "Generated with ???"
206f_runoff.title           = runoff
207f_runoff.Program         = "Generated by " + sys.argv[0] + " with flags " + str(sys.argv[1:])
208f_runoff.timeStamp       = time.asctime()
209f_runoff.uuid            = areaFile.uuid
210f_runoff.HOSTNAME        = platform.node()
211#f_runoff.LOGNAME         = os.getlogin()
212f_runoff.Python          = "Python version " +  platform.python_version()
213f_runoff.OS              = platform.system()
214f_runoff.release         = platform.release()
215f_runoff.hardware        = platform.machine()
216f_runoff.Comment         = "Preliminary attempt - Do not trust !"
217f_runoff.conventions     = "SCRIP"
218f_runoff.source_grid     = "curvilinear"
219f_runoff.dest_grid       = "curvilinear"
220f_runoff.Model           = "IPSL CM6"
221f_runoff.SVN_Author      = "$Author:  $"
222f_runoff.SVN_Date        = "$Date:  $"
223f_runoff.SVN_Revision    = "$Revision:  $"
224f_runoff.SVN_Id          = "$Id:  $"
225f_runoff.SVN_HeadURL     = "$HeadURL:  $"
226
227num_links        = f_runoff.createDimension ('num_links'       , num_links )
228num_wgts         = f_runoff.createDimension ('num_wgts'        ,         1 )
229
230atm_grid_size    = f_runoff.createDimension ('src_grid_size'   , atm_grid_size )
231atm_grid_corners = f_runoff.createDimension ('src_grid_corners', atm_grid_corner_lon.shape[0]  )
232atm_grid_rank    = f_runoff.createDimension ('src_grid_rank'   ,        2  )
233
234oce_grid_size    = f_runoff.createDimension ('dst_grid_size'   , oce_grid_size )
235oce_grid_corners = f_runoff.createDimension ('dst_grid_corners', oce_grid_corner_lon.shape[0] )
236oce_grid_rank    = f_runoff.createDimension ('dst_grid_rank'   ,        2  )
237
238v_remap_matrix = f_runoff.createVariable ( 'remap_matrix', 'f8', ('num_links', 'num_wgts') )
239
240v_atm_address  = f_runoff.createVariable ( 'src_address' , 'i4', ('num_links',) )
241v_oce_address  = f_runoff.createVariable ( 'dst_address' , 'i4', ('num_links',) )
242
243v_remap_matrix[:] = remap_matrix
244v_atm_address [:] = atm_address
245v_oce_address [:] = oce_address
246
247v_atm_grid_dims       = f_runoff.createVariable ( 'src_grid_dims'      , 'i4', ('src_grid_rank',) )
248v_atm_grid_center_lon = f_runoff.createVariable ( 'src_grid_center_lon', 'i4', ('src_grid_size',) )
249v_atm_grid_center_lat = f_runoff.createVariable ( 'src_grid_center_lat', 'i4', ('src_grid_size',) )
250v_atm_grid_center_lon.units='degrees_east'  ; v_atm_grid_center_lon.long_name='Longitude' ; v_atm_grid_center_lon.long_name='longitude' ; v_atm_grid_center_lon.bounds="src_grid_corner_lon"
251v_atm_grid_center_lat.units='degrees_north' ; v_atm_grid_center_lat.long_name='Latitude'  ; v_atm_grid_center_lat.long_name='latitude ' ; v_atm_grid_center_lat.bounds="src_grid_corner_lat"
252v_atm_grid_corner_lon = f_runoff.createVariable ( 'src_grid_corner_lon', 'f8', ('src_grid_size', 'src_grid_corners')  )
253v_atm_grid_corner_lat = f_runoff.createVariable ( 'src_grid_corner_lat', 'f8', ('src_grid_size', 'src_grid_corners')  )
254v_atm_grid_corner_lon.units="degrees_east"
255v_atm_grid_corner_lat.units="degrees_north"
256v_atm_grid_area       = f_runoff.createVariable ( 'src_grid_area'      , 'f8', ('src_grid_size',)  )
257v_atm_grid_area.long_name="Grid area" ; v_atm_grid_area.standard_name="cell_area" ; v_atm_grid_area.units="m2"
258v_atm_grid_imask      = f_runoff.createVariable ( 'src_grid_imask'     , 'f8', ('src_grid_size',)  )
259v_atm_grid_imask.long_name="Land-sea mask" ; v_atm_grid_imask.units="Land:1, Ocean:0"
260
261v_atm_grid_dims      [:] = atm_grid_dims
262v_atm_grid_center_lon[:] = atm_grid_center_lon[:].ravel()
263v_atm_grid_center_lat[:] = atm_grid_center_lat[:].ravel()
264v_atm_grid_corner_lon[:] = atm_grid_corner_lon.reshape( (atm_jpi*atm_jpj, atm_grid_corners.__len__()) )
265v_atm_grid_corner_lat[:] = atm_grid_corner_lat.reshape( (atm_jpi*atm_jpj, atm_grid_corners.__len__()) )
266v_atm_grid_area      [:] = atm_grid_area[:].ravel()
267v_atm_grid_imask     [:] = atm_grid_imask[:].ravel()
268
269# --
270
271v_oce_grid_dims       = f_runoff.createVariable ( 'dst_grid_dims'      , 'i4', ('dst_grid_rank',) )
272v_oce_grid_center_lon = f_runoff.createVariable ( 'dst_grid_center_lon', 'i4', ('dst_grid_size',) )
273v_oce_grid_center_lat = f_runoff.createVariable ( 'dst_grid_center_lat', 'i4', ('dst_grid_size',) )
274v_oce_grid_center_lon.units='degrees_east'  ; v_oce_grid_center_lon.long_name='Longitude' ; v_oce_grid_center_lon.long_name='longitude' ; v_oce_grid_center_lon.bounds="dst_grid_corner_lon"
275v_oce_grid_center_lat.units='degrees_north' ; v_oce_grid_center_lat.long_name='Latitude'  ; v_oce_grid_center_lat.long_name='latitude'  ; v_oce_grid_center_lat.bounds="dst_grid_corner_lat"
276v_oce_grid_corner_lon = f_runoff.createVariable ( 'oce_grid_corner_lon', 'f8', ('dst_grid_size', 'dst_grid_corners')  )
277v_oce_grid_corner_lat = f_runoff.createVariable ( 'dst_grid_corner_lat', 'f8', ('dst_grid_size', 'dst_grid_corners')  )
278v_oce_grid_corner_lon.units="degrees_east"
279v_oce_grid_corner_lat.units="degrees_north"
280v_oce_grid_area       = f_runoff.createVariable ( 'dst_grid_area'      , 'f8', ('dst_grid_size',)  )
281v_oce_grid_area.long_name="Grid area" ; v_oce_grid_area.standard_name="cell_area" ; v_oce_grid_area.units="m2"
282v_oce_grid_imask      = f_runoff.createVariable ( 'dst_grid_imask'     , 'f8', ('dst_grid_size',)  )
283v_oce_grid_imask.long_name="Land-sea mask" ; v_oce_grid_imask.units="Land:1, Ocean:0"
284
285v_oce_grid_dims      [:] = oce_grid_dims
286v_oce_grid_center_lon[:] = oce_grid_center_lon[:].ravel()
287v_oce_grid_center_lat[:] = oce_grid_center_lat[:].ravel()
288v_oce_grid_corner_lon[:] = oce_grid_corner_lon.reshape( (oce_jpi*oce_jpj, oce_grid_corners.__len__()) )
289v_oce_grid_corner_lat[:] = oce_grid_corner_lon.reshape( (oce_jpi*oce_jpj, oce_grid_corners.__len__()) )
290v_oce_grid_area      [:] = oce_grid_area[:].ravel()
291v_oce_grid_imask     [:] = oce_grid_imask[:].ravel()
292
293# For diags
294v_atm_lon_addressed = f_runoff.createVariable ( 'src_lon_addressed', 'f8', ('num_links',) )
295v_atm_lat_addressed = f_runoff.createVariable ( 'src_lat_addressed', 'f8', ('num_links',) )
296v_oce_lon_addressed = f_runoff.createVariable ( 'dst_lon_addressed', 'f8', ('num_links',) )
297v_oce_lat_addressed = f_runoff.createVariable ( 'dst_lat_addressed', 'f8', ('num_links',) )
298
299v_atm_lon_addressed.long_name="Longitude" ; v_atm_lon_addressed.standard_name="longitude" ; v_atm_lon_addressed.units="degrees_east"
300v_atm_lat_addressed.long_name="Latitude"  ; v_atm_lat_addressed.standard_name="latitude"  ; v_atm_lat_addressed.units="degrees_east"
301v_atm_lon_addressed [:] = atm_grid_center_lon.ravel()[atm_address].ravel()
302v_atm_lat_addressed [:] = atm_grid_center_lat.ravel()[atm_address].ravel()
303
304v_oce_lon_addressed.long_name="Longitude" ; v_oce_lon_addressed.standard_name="longitude" ; v_oce_lon_addressed.units="degrees_east"
305v_oce_lat_addressed.long_name="Latitude"  ; v_oce_lat_addressed.standard_name="latitude"  ; v_oce_lat_addressed.units="degrees_east"
306v_oce_lon_addressed [:] = oce_grid_center_lon.ravel()[oce_address].ravel()
307v_oce_lat_addressed [:] = oce_grid_center_lat.ravel()[oce_address].ravel()
308
309f_runoff.close ()
Note: See TracBrowser for help on using the repository browser.