# -*- Mode: python -*- #!/usr/bin/env python3 ### =========================================================================== ### ### Compute runoff weights. ### For LMDZ only. Not suitable for DYNAMICO ### ### =========================================================================== ## ## Warning, to install, configure, run, use any of Olivier Marti's ## software or to read the associated documentation you'll need at least ## one (1) brain in a reasonably working order. Lack of this implement ## will void any warranties (either express or implied). ## O. Marti assumes no responsability for errors, omissions, ## data loss, or any other consequences caused directly or indirectly by ## the usage of his software by incorrectly or partially configured ## personal. ## # SVN information __Author__ = "$Author$" __Date__ = "$Date$" __Revision__ = "$Revision$" __Id__ = "$Id$" __HeadURL__ = "$HeadURL$" __SVN_Date__ = "$SVN_Date: $" ## ## Modules import numpy as np, xarray as xr import nemo from scipy import ndimage import sys, os, platform, argparse, textwrap, time ## Useful constants zero = np.dtype('float64').type(0.0) zone = np.dtype('float64').type(1.0) epsfrac = np.dtype('float64').type(1.0E-10) pi = np.pi rad = pi/np.dtype('float64').type(180.0) # Conversion from degrees to radian ra = np.dtype('float64').type(6371229.0) # Earth radius ## Functions def geodist (plon1, plat1, plon2, plat2) : """Distance between two points (on sphere)""" zs = np.sin (rad*plat1) * np.sin (rad*plat2) + np.cos (rad*plat1) * np.cos (rad*plat2) * np.cos(rad*(plon2-plon1)) zs = np.maximum (-zone, np.minimum (zone, zs)) geodist = np.arccos (zs) return geodist ### ===== Reading command line parameters ================================================== # Creating a parser parser = argparse.ArgumentParser ( description = """Compute calving weights""", epilog='-------- End of the help message --------') # Adding arguments parser.add_argument ('--oce' , help='oce model name', type=str, default='eORCA1.2', choices=['ORCA2.3', 'eORCA1.2', 'eORCA1.4', 'eORCA1.4.2', 'eORCA025', 'eORCA025.1', 'eORCA025.4'] ) parser.add_argument ('--atm' , help='atm model name', type=str, default='LMD9695' ) parser.add_argument ('--atmCoastWidth', help='width of the coastal band in atmosphere (in grid points)', type=int, default=1 ) parser.add_argument ('--oceCoastWidth', help='width of the coastal band in ocean (in grid points)' , type=int, default=2 ) parser.add_argument ('--atmQuantity' , help='Quantity if atm provides quantities (m/s), Surfacic if atm provided flux (m/s/m2)' , type=str, default='Quantity', choices=['Quantity', 'Surfacic'] ) parser.add_argument ('--oceQuantity' , help='Quantity if oce requires quantities (ks/s), Surfacic if oce requires flux (m/s/m2)', type=str, default='Surfacic', choices=['Quantity', 'Surfacic'] ) parser.add_argument ('--searchRadius' , help='max distance to connect a land point to an ocean point (in km)', type=float, default=600.0 ) parser.add_argument ('--grids' , help='grids file name', default='grids.nc' ) parser.add_argument ('--areas' , help='masks file name', default='areas.nc' ) parser.add_argument ('--masks' , help='areas file name', default='masks.nc' ) parser.add_argument ('--o2a' , help='o2a file name' , default='o2a.nc' ) parser.add_argument ('--output', help='output rmp file name', default='rmp_tlmd_to_torc_runoff.nc' ) parser.add_argument ('--fmt' , help='NetCDF file format, using nco syntax', default='netcdf4', choices=['classic', 'netcdf3', '64bit', '64bit_data', '64bit_data', 'netcdf4', 'netcdf4_classsic'] ) parser.add_argument ('--ocePerio' , help='periodicity of ocean grid', type=float, default=0, choices=nemo.nperio_valid_range) # Parse command line myargs = parser.parse_args() # grids = myargs.grids areas = myargs.areas masks = myargs.masks o2a = myargs.o2a # Model Names atm_Name = myargs.atm oce_Name = myargs.oce # Width of the coastal band (land points) in the atmopshere atmCoastWidth = myargs.atmCoastWidth # Width of the coastal band (ocean points) in the ocean oceCoastWidth = myargs.oceCoastWidth searchRadius = myargs.searchRadius * 1000.0 # From km to meters # Netcdf format if myargs.fmt == 'classic' : FmtNetcdf = 'CLASSIC' if myargs.fmt == 'netcdf3' : FmtNetcdf = 'CLASSIC' if myargs.fmt == '64bit' : FmtNetcdf = 'NETCDF3_64BIT_OFFSET' if myargs.fmt == '64bit_data' : FmtNetcdf = 'NETCDF3_64BIT_DATA' if myargs.fmt == '64bit_offset' : FmtNetcdf = 'NETCDF3_64BIT_OFFSET' if myargs.fmt == 'netcdf4' : FmtNetcdf = 'NETCDF4' if myargs.fmt == 'netcdf4_classic' : FmtNetcdf = 'NETCDF4_CLASSIC' # if atm_Name.find('LMD') >= 0 : atm_n = 'lmd' ; atmDomainType = 'rectilinear' if atm_Name.find('ICO') >= 0 : atm_n = 'ico' ; atmDomainType = 'unstructured' print ('atmQuantity : ' + str (myargs.atmQuantity) ) print ('oceQuantity : ' + str (myargs.oceQuantity) ) # Ocean grid periodicity oce_perio = myargs.ocePerio ### Read coordinates of all models ### diaFile = xr.open_dataset ( o2a ) gridFile = xr.open_dataset ( grids ) areaFile = xr.open_dataset ( areas ) maskFile = xr.open_dataset ( masks ) o2aFrac = diaFile ['OceFrac'].squeeze() o2aFrac = np.where ( np.abs(o2aFrac) < 1E10, o2aFrac, 0.0) (atm_nvertex, atm_jpj, atm_jpi) = gridFile['t'+atm_n+'.clo'][:].shape atm_grid_size = atm_jpj*atm_jpi atm_grid_rank = len(gridFile['t'+atm_n+'.lat'][:].shape) atm_grid_center_lat = gridFile['t'+atm_n+'.lat'].squeeze() atm_grid_center_lon = gridFile['t'+atm_n+'.lon'].squeeze() atm_grid_corner_lat = gridFile['t'+atm_n+'.cla'].squeeze() atm_grid_corner_lon = gridFile['t'+atm_n+'.clo'].squeeze() atm_grid_area = areaFile['t'+atm_n+'.srf'].squeeze() atm_grid_imask = 1-maskFile['t'+atm_n+'.msk'][:].squeeze() atm_grid_dims = gridFile['t'+atm_n+'.lat'][:].shape if atmDomainType == 'unstructured' : atm_grid_center_lat = atm_grid_center_lat.rename ({'ycell':'cell'}) atm_grid_center_lon = atm_grid_center_lon.rename ({'ycell':'cell'}) atm_grid_corner_lat = atm_grid_corner_lat.rename ({'ycell':'cell'}) atm_grid_corner_lon = atm_grid_corner_lon.rename ({'ycell':'cell'}) atm_grid_area = atm_grid_area.rename ({'ycell':'cell'}) atm_grid_imask = atm_grid_imask.rename ({'ycell':'cell'}) if atmDomainType == 'rectilinear' : atm_grid_center_lat = atm_grid_center_lat.stack (cell=['y', 'x']) atm_grid_center_lon = atm_grid_center_lon.stack (cell=['y', 'x']) atm_grid_corner_lat = atm_grid_corner_lat.stack (cell=['y', 'x']).rename({'nvertex_lmd':'nvertex'}) atm_grid_corner_lon = atm_grid_corner_lon.stack (cell=['y', 'x']).rename({'nvertex_lmd':'nvertex'}) atm_grid_area = atm_grid_area.stack (cell=['y', 'x']) atm_grid_imask = atm_grid_imask.stack (cell=['y', 'x']) atm_perio = 0 atm_grid_pmask = atm_grid_imask atm_address = np.arange(atm_jpj*atm_jpi) (oce_nvertex, oce_jpj, oce_jpi) = gridFile['torc.cla'][:].shape ; jpon=oce_jpj*oce_jpj oce_grid_size = oce_jpj*oce_jpi oce_grid_rank = len(gridFile['torc.lat'][:].shape) oce_grid_center_lat = gridFile['torc.lat'].stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_center_lon = gridFile['torc.lon'].stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_corner_lat = gridFile['torc.cla'].squeeze().stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_corner_lon = gridFile['torc.clo'].squeeze().stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_area = areaFile['torc.srf'].stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_imask = 1-maskFile['torc.msk'].stack(oce_grid_size=['y_grid_T', 'x_grid_T']) oce_grid_dims = gridFile['torc.lat'][:].shape if oce_perio == 0 : if oce_jpi == 182 : oce_perio = 4 # ORCA 2 if oce_jpi == 362 : oce_perio = 6 # ORCA 1 if oce_jpi == 1442 : oce_perio = 6 # ORCA 025 print ("Oce NPERIO parameter : {:}".format(oce_perio)) oce_grid_pmask = nemo.lbc_mask (np.reshape(oce_grid_imask.values, (oce_jpj,oce_jpi)), nperio=oce_perio, cd_type='T', sval=0).ravel() oce_address = np.arange(oce_jpj*oce_jpi) print ("Fill closed sea with image processing library") oce_grid_imask2D = np.reshape(oce_grid_pmask,(oce_jpj,oce_jpi)) oce_grid_imask2D = nemo.lbc_mask ( 1-ndimage.binary_fill_holes (1-nemo.lbc(oce_grid_imask2D, nperio=oce_perio, cd_type='T')), nperio=oce_perio, cd_type='T', sval=0 ) oce_grid_imask = oce_grid_imask2D.ravel() ## print ("Computes an ocean coastal band") oceLand2D = np.reshape ( np.where (oce_grid_pmask < 0.5, True, False), (oce_jpj, oce_jpi) ) oceOcean2D = np.reshape ( np.where (oce_grid_pmask > 0.5, True, False), (oce_jpj, oce_jpi) ) NNocean = 1+2*oceCoastWidth oceOceanFiltered2D = ndimage.uniform_filter(oceOcean2D.astype(float), size=NNocean) oceCoast2D = np.where (oceOceanFiltered2D<(1.0-0.5/(NNocean**2)),True,False) & oceOcean2D oceCoast2D = nemo.lbc_mask (np.reshape(oceCoast2D,(oce_jpj,oce_jpi)), nperio=oce_perio, cd_type='T').ravel() oceOceanFiltered = oceOceanFiltered2D.ravel() oceLand = oceLand2D.ravel () oceOcean = oceOcean2D.ravel() oceCoast = oceCoast2D.ravel() print ('Number of points in oceLand : {:8d}'.format (oceLand.sum()) ) print ('Number of points in oceOcean : {:8d}'.format (oceOcean.sum()) ) print ('Number of points in oceCoast : {:8d}'.format (oceCoast.sum()) ) # Arrays with coastal points only oceCoast_grid_center_lon = oce_grid_center_lon[oceCoast] oceCoast_grid_center_lat = oce_grid_center_lat[oceCoast] oceCoast_grid_area = oce_grid_area [oceCoast] oceCoast_grid_imask = oce_grid_imask [oceCoast] oceCoast_grid_pmask = oce_grid_pmask [oceCoast] oceCoast_address = oce_address [oceCoast] print ("Computes an atmosphere coastal band " ) atmLand = np.where (o2aFrac[:] < epsfrac , True, False) atmLandFrac = np.where (o2aFrac[:] < zone-epsfrac , True, False) atmFrac = np.where (o2aFrac[:] > epsfrac , True, False) & np.where (o2aFrac[:] < (zone-epsfrac), True, False) atmOcean = np.where (o2aFrac[:] < (zone-epsfrac), True, False) atmOceanFrac = np.where (o2aFrac[:] > epsfrac , True, False) ## For LMDZ only !! if atmDomainType == 'rectilinear' : print ("Extend coastal band " ) NNatm = 1+2*atmCoastWidth atmLand2D = np.reshape ( atmLand, ( atm_jpj, atm_jpi) ) atmLandFiltered2D = ndimage.uniform_filter(atmLand2D.astype(float), size=NNatm) atmCoast2D = np.where (atmLandFiltered2D<(1.0-0.5/(NNatm**2)),True,False) & atmLandFrac atmLandFiltered = atmLandFiltered2D.ravel() atmCoast = atmCoast2D.ravel() print ('Number of points in atmLand : {:8d}'.format (atmLand.sum()) ) print ('Number of points in atmOcean : {:8d}'.format (atmOcean.sum()) ) print ('Number of points in atmCoast : {:8d}'.format (atmCoast.sum()) ) else : atmCoast = atmFrac # Arrays with coastal points only atmCoast_grid_center_lon = atm_grid_center_lon[atmCoast] atmCoast_grid_center_lat = atm_grid_center_lat[atmCoast] atmCoast_grid_area = atm_grid_area [atmCoast] atmCoast_grid_imask = atm_grid_imask [atmCoast] atmCoast_grid_pmask = atm_grid_pmask [atmCoast] atmCoast_address = atm_address [atmCoast] # Initialisations before the loop remap_matrix = np.empty ( shape=(0), dtype=np.float64 ) atm_address = np.empty ( shape=(0), dtype=np.int32 ) oce_address = np.empty ( shape=(0), dtype=np.int32 ) ## Loop on atmosphere coastal points if searchRadius > 0. : print ("Loop on atmosphere coastal points") for ja in np.arange(len(atmCoast_grid_pmask)) : z_dist = geodist ( atmCoast_grid_center_lon[ja], atmCoast_grid_center_lat[ja], oceCoast_grid_center_lon, oceCoast_grid_center_lat) z_mask = np.where (z_dist*ra < searchRadius, True, False) num_links = int(z_mask.sum()) if num_links == 0 : continue z_area = oceCoast_grid_area[z_mask].sum().values poids = np.ones ((num_links),dtype=np.float64) / z_area if myargs.atmQuantity == 'Surfacic' : poids = poids * atm_grid_area[ja] if myargs.oceQuantity == 'Quantity' : poids = poids * oceCoast_grid_area[z_mask] if ja % (len(atmCoast_grid_pmask)//50) == 0 : # Control print print ( 'ja:{:8d}, num_links:{:8d}, z_area:{:8.4e}, atm area:{:8.4e}, weights sum:{:8.4e} ' .format(ja, num_links, z_area, atm_grid_area[ja].values, poids.sum() ) ) # matrix_local = poids atm_address_local = np.ones(num_links, dtype=np.int32 ) * atmCoast_address[ja] # Address on destination grid oce_address_local = oceCoast_address[z_mask] # Append to global arrays remap_matrix = np.append ( remap_matrix, matrix_local ) atm_address = np.append ( atm_address , atm_address_local ) oce_address = np.append ( oce_address , oce_address_local ) print ('End of loop') num_links = remap_matrix.shape[0] print ("Write output file") runoff = myargs.output print ('Output file: ' + runoff ) remap_matrix = xr.DataArray ( np.reshape(remap_matrix, (num_links, 1)), dims = ['num_links', 'num_wgts'] ) # OASIS uses Fortran style indexing, starting at one src_address = xr.DataArray ( atm_address.astype(np.int32)+1, dims = ['num_links'], attrs={"convention": "Fortran style addressing, starting at 1"}) dst_address = xr.DataArray ( oce_address.astype(np.int32)+1, dims = ['num_links'], attrs={"convention": "Fortran style addressing, starting at 1"}) src_grid_dims = xr.DataArray (np.array(atm_grid_dims, dtype=np.int32), dims = ['src_grid_rank',] ) src_grid_center_lon = xr.DataArray (atm_grid_center_lon.values , dims = ['src_grid_size',] ) src_grid_center_lat = xr.DataArray (atm_grid_center_lat.values , dims = ['src_grid_size',] ) src_grid_center_lon.attrs['units']='degrees_east' ; src_grid_center_lon.attrs['long_name']='Longitude' src_grid_center_lon.attrs['long_name']='longitude' ; src_grid_center_lon.attrs['bounds']="src_grid_corner_lon" src_grid_center_lat.attrs['units']='degrees_north' ; src_grid_center_lat.attrs['long_name']='Latitude' src_grid_center_lat.attrs['long_name']='latitude ' ; src_grid_center_lat.attrs['bounds']="src_grid_corner_lat" src_grid_corner_lon = xr.DataArray (atm_grid_corner_lon.values.transpose(), dims = [ 'src_grid_size', 'src_grid_corners'] ) src_grid_corner_lat = xr.DataArray (atm_grid_corner_lat.values.transpose(), dims = [ 'src_grid_size', 'src_grid_corners'] ) src_grid_corner_lon.attrs['units']="degrees_east" src_grid_corner_lat.attrs['units']="degrees_north" src_grid_area = xr.DataArray (atm_grid_area.values, dims = ['src_grid_size',] ) src_grid_area.attrs['long_name']="Grid area" ; src_grid_area.attrs['standard_name']="cell_area" ; src_grid_area.attrs['units']="m2" src_grid_imask = xr.DataArray (atm_grid_imask.values, dims = ['src_grid_size',] ) src_grid_imask.attrs['long_name']="Land-sea mask" ; src_grid_imask.attrs['units']="Land:1, Ocean:0" src_grid_pmask = xr.DataArray (atm_grid_pmask.values, dims = ['src_grid_size',] ) src_grid_pmask.attrs['long_name']="Land-sea mask (periodicity removed)" ; src_grid_pmask.attrs['units']="Land:1, Ocean:0" # -- dst_grid_dims = xr.DataArray (np.array(oce_grid_dims, dtype=np.int32), dims = ['dst_grid_rank',] ) dst_grid_center_lon = xr.DataArray (oce_grid_center_lon.values, dims = ['dst_grid_size',] ) dst_grid_center_lat = xr.DataArray (oce_grid_center_lat.values, dims = ['dst_grid_size',] ) dst_grid_center_lon.attrs['units']='degrees_east' ; dst_grid_center_lon.attrs['long_name']='Longitude' dst_grid_center_lon.attrs['long_name']='longitude' ; dst_grid_center_lon.attrs['bounds']="dst_grid_corner_lon" dst_grid_center_lat.attrs['units']='degrees_north' ; dst_grid_center_lat.attrs['long_name']='Latitude' dst_grid_center_lat.attrs['long_name']='latitude ' ; dst_grid_center_lat.attrs['bounds']="dst_grid_corner_lat" dst_grid_corner_lon = xr.DataArray (np.transpose(oce_grid_corner_lon.values), dims = [ 'dst_grid_size', 'dst_grid_corners'] ) dst_grid_corner_lat = xr.DataArray (np.transpose(oce_grid_corner_lat.values), dims = [ 'dst_grid_size', 'dst_grid_corners'] ) dst_grid_corner_lon.attrs['units']="degrees_east" dst_grid_corner_lat.attrs['units']="degrees_north" dst_grid_area = xr.DataArray (oce_grid_area.values, dims = ['dst_grid_size',] ) dst_grid_area.attrs['long_name']="Grid area" ; dst_grid_area.attrs['standard_name']="cell_area" ; dst_grid_area.attrs['units']="m2" dst_grid_imask = xr.DataArray (oce_grid_imask.astype(np.int32), dims = ['dst_grid_size',] ) dst_grid_imask.attrs['long_name']="Land-sea mask" ; dst_grid_imask.attrs['units']="Land:1, Ocean:0" dst_grid_pmask = xr.DataArray (oce_grid_pmask, dims = ['dst_grid_size',] ) dst_grid_pmask.attrs['long_name']="Land-sea mask (periodicity removed)" ; dst_grid_pmask.attrs['units']="Land:1, Ocean:0" src_lon_addressed = xr.DataArray (atm_grid_center_lon.values[atm_address] , dims = ['num_links'] ) src_lat_addressed = xr.DataArray (atm_grid_center_lat.values[atm_address] , dims = ['num_links'] ) src_area_addressed = xr.DataArray (atm_grid_area .values[atm_address] , dims = ['num_links'] ) src_imask_addressed = xr.DataArray (1-atm_grid_imask .values[atm_address].astype(np.int32) , dims = ['num_links'] ) src_pmask_addressed = xr.DataArray (1-atm_grid_pmask .values[atm_address].astype(np.int32) , dims = ['num_links'] ) dst_lon_addressed = xr.DataArray (oce_grid_center_lon.values[atm_address], dims = ['num_links'] ) dst_lat_addressed = xr.DataArray (oce_grid_center_lat.values[oce_address], dims = ['num_links'] ) dst_area_addressed = xr.DataArray (oce_grid_area.values[oce_address].astype(np.int32) , dims = ['num_links'] ) dst_imask_addressed = xr.DataArray (1-oce_grid_imask[oce_address].astype(np.int32) , dims = ['num_links'] ) dst_pmask_addressed = xr.DataArray (1-oce_grid_pmask[oce_address].astype(np.int32) , dims = ['num_links'] ) src_lon_addressed.attrs['long_name']="Longitude" ; src_lon_addressed.attrs['standard_name']="longitude" ; src_lon_addressed.attrs['units']="degrees_east" src_lat_addressed.attrs['long_name']="Latitude" ; src_lat_addressed.attrs['standard_name']="latitude" ; src_lat_addressed.attrs['units']="degrees_north" dst_lon_addressed.attrs['long_name']="Longitude" ; dst_lon_addressed.attrs['standard_name']="longitude" ; dst_lon_addressed.attrs['units']="degrees_east" dst_lat_addressed.attrs['long_name']="Latitude" ; dst_lat_addressed.attrs['standard_name']="latitude" ; dst_lat_addressed.attrs['units']="degrees_north" if atmDomainType == 'rectilinear' : atmLand = xr.DataArray ( atmLand.ravel() , dims = ['src_grid_size',] ) atmLandFiltered = xr.DataArray ( atmLandFrac.ravel() , dims = ['src_grid_size',] ) atmLandFrac = xr.DataArray ( atmFrac.ravel() , dims = ['src_grid_size',] ) atmFrac = xr.DataArray ( atmFrac.ravel() , dims = ['src_grid_size',] ) atmOcean = xr.DataArray ( atmOcean.ravel() , dims = ['src_grid_size',] ) atmOceanFrac = xr.DataArray ( atmOceanFrac.ravel(), dims = ['src_grid_size',] ) atmCoast = xr.DataArray (atmCoast.astype(np.int32) , dims = ['src_grid_size',]) oceLand = xr.DataArray (oceLand.astype(np.int32) , dims = ['dst_grid_size',]) oceOcean = xr.DataArray (oceOcean.astype(np.int32) , dims = ['dst_grid_size',]) oceOceanFiltered = xr.DataArray (oceOceanFiltered.astype(np.float32), dims = ['dst_grid_size',]) oceCoast = xr.DataArray (oceCoast.astype(np.int32) , dims = ['dst_grid_size',]) f_runoff = xr.Dataset ( { 'remap_matrix' : remap_matrix, 'src_address' : src_address, 'dst_address' : dst_address, 'src_grid_dims' : src_grid_dims, 'src_grid_center_lon' : src_grid_center_lon, 'src_grid_center_lat' : src_grid_center_lat, 'src_grid_corner_lon' : src_grid_corner_lon, 'src_grid_corner_lat' : src_grid_corner_lat, 'src_grid_area' : src_grid_area, 'src_grid_area' : src_grid_area, 'src_grid_pmask' : src_grid_pmask, 'dst_grid_dims' : dst_grid_dims, 'dst_grid_center_lon' : dst_grid_center_lon, 'st_grid_center_lat' : dst_grid_center_lat, 'dst_grid_corner_lon' : dst_grid_corner_lon, 'dst_grid_corner_lat' : dst_grid_corner_lat, 'dst_grid_area' : dst_grid_area, 'dst_grid_imask' : dst_grid_imask, 'dst_grid_pmask' : dst_grid_pmask, 'src_lon_addressed' : src_lon_addressed, 'src_lat_addressed' : src_lat_addressed, 'src_area_addressed' : src_area_addressed, 'dst_lon_addressed' : dst_lon_addressed, 'dst_lat_addressed' : dst_lat_addressed, 'dst_area_addressed' : dst_area_addressed, 'dst_imask_addressed' : dst_imask_addressed, 'dst_pmask_addressed' : dst_pmask_addressed, 'atmCoast' : atmCoast, 'oceLand' : oceLand, 'oceOcean' : oceOcean, 'oceOceanFiltered' : oceOceanFiltered, 'oceCoast' : oceCoast } ) f_runoff.attrs['Conventions'] = "CF-1.6" f_runoff.attrs['source'] = "IPSL Earth system model" f_runoff.attrs['group'] = "ICMC IPSL Climate Modelling Center" f_runoff.attrs['Institution'] = "IPSL https.//www.ipsl.fr" f_runoff.attrs['Ocean'] = oce_Name + " https://www.nemo-ocean.eu" f_runoff.attrs['Atmosphere'] = atm_Name + " http://lmdz.lmd.jussieu.fr" f_runoff.attrs['associatedFiles'] = grids + " " + areas + " " + masks f_runoff.attrs['description'] = "Generated with RunoffWeights.py" f_runoff.attrs['title'] = runoff f_runoff.attrs['Program'] = "Generated by " + sys.argv[0] + " with flags " + ' '.join (sys.argv[1:]) f_runoff.attrs['atmCoastWidth'] = "{:d} grid points".format(atmCoastWidth) f_runoff.attrs['oceCoastWidth'] = "{:d} grid points".format(oceCoastWidth) f_runoff.attrs['searchRadius'] = "{:.0f} km".format(searchRadius/1000.) f_runoff.attrs['atmQuantity'] = myargs.atmQuantity f_runoff.attrs['oceQuantity'] = myargs.oceQuantity f_runoff.attrs['gridsFile'] = grids f_runoff.attrs['areasFile'] = areas f_runoff.attrs['masksFile'] = masks f_runoff.attrs['o2aFile'] = o2a f_runoff.attrs['timeStamp'] = time.asctime () try : f_calving.attrs['directory'] = os.getcwd () except : pass try : f_runoff.attrs['HOSTNAME'] = platform.node () except : pass try : f_runoff.attrs['LOGNAME'] = os.getlogin () except : pass try : f_runoff.attrs['Python'] = "Python version " + platform.python_version () except : pass try : f_runoff.attrs['OS'] = platform.system () except : pass try : f_runoff.attrs['release'] = platform.release () except : pass try : f_runoff.attrs['hardware'] = platform.machine () except : pass f_runoff.attrs['conventions'] = "SCRIP" f_runoff.attrs['source_grid'] = "curvilinear" f_runoff.attrs['dest_grid'] = "curvilinear" f_runoff.attrs['Model'] = "IPSL CM6" f_runoff.attrs['SVN_Author'] = "$Author$" f_runoff.attrs['SVN_Date'] = "$Date$" f_runoff.attrs['SVN_Revision'] = "$Revision$" f_runoff.attrs['SVN_Id'] = "$Id$" f_runoff.attrs['SVN_HeadURL'] = "$HeadURL$" f_runoff.to_netcdf ( runoff, mode='w', format=FmtNetcdf ) f_runoff.close () ## print ('That''s all folks !') ## ======================================================================================