# # import numpy as np import os import pickle from netCDF4 import Dataset import RPPtools as RPP from mpi4py import MPI # import sys sys.path.append(os.getcwd()+'/F90subroutines') if MPI.COMM_WORLD.Get_rank() == 0 : err=os.system("cd F90subroutines; make all") if err != 0 : print("Compilation error in the FORTRAN interface") sys.exit() else : print("Not compiling on other cores") MPI.COMM_WORLD.Barrier() # import routing_interface # import configparser config=configparser.ConfigParser({'Documentation':'false', 'nbxmax':'63'}) config.read("run.def") gendoc=config.get("OverAll", "Documentation") nbxmax=config.getint("OverAll", "nbxmax") # undef_int = 999999999.9 # # Print the documentation for the FORTRAN interface # if gendoc.lower() == "true" : docwrapper = open('DocumentationInterface', 'w') docwrapper.write(routing_interface.initatmgrid.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.gethydrogrid.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.findbasins.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.globalize.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.linkup.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.fetch.__doc__) docwrapper.write("====================================================================\n") docwrapper.write(routing_interface.truncate.__doc__) docwrapper.close # # Functions to access the interfaces # # # initatmgrid : Initialises the grid.f90 module and passes the description of the atmospheric grid. # def initatmgrid(rank, nbcore, nbpt, modelgrid) : print("INITATMGRID corners", np.array(modelgrid.polyll).shape) print("INITATMGRID area", np.array(modelgrid.area).shape) print("INITATMGRID neighbours", np.array(modelgrid.neighbours).shape) routing_interface.initatmgrid(rank, nbcore, modelgrid.polyll, modelgrid.coordll, modelgrid.area, modelgrid.contfrac, modelgrid.neighbours) return # # # def closeinterface(comm) : comm.Barrier() routing_interface.closeinterface() return # # # class HydroOverlap : # def __init__(self, nbpt, nbvmax, sub_pts, sub_index_in, sub_area_in, sub_lon_in, sub_lat_in, modelgrid, hydrodata) : # # Reshape stuff so that it fits into arrays # sub_index = np.zeros((nbpt,nbvmax,2), dtype=np.int8, order='F') sub_area = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') sub_lon = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') sub_lat = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') for ib in range(nbpt) : sub_area[ib,0:sub_pts[ib]] = sub_area_in[ib][:] sub_lon[ib,0:sub_pts[ib]] = sub_lon_in[ib][:] sub_lat[ib,0:sub_pts[ib]] = sub_lat_in[ib][:] for ip in range(sub_pts[ib]) : sub_index[ib,ip,:] = [sub_index_in[ib][0][ip],sub_index_in[ib][1][ip]] # trip_tmp = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') basins_tmp = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') topoind_tmp = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') fac_tmp = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') hierarchy_tmp = np.zeros((nbpt,nbvmax), dtype=np.float32, order='F') # trip_tmp[:,:] = np.nan basins_tmp[:,:] = np.nan for ib in range(nbpt) : trip_tmp[ib,0:sub_pts[ib]] = np.asarray(hydrodata.trip[ib][:]) basins_tmp[ib,0:sub_pts[ib]] = np.asarray(hydrodata.basins[ib][:]) topoind_tmp[ib,0:sub_pts[ib]] = np.asarray(hydrodata.topoind[ib][:]) fac_tmp[ib,0:sub_pts[ib]] = np.asarray(hydrodata.fac[ib][:]) hierarchy_tmp[ib,0:sub_pts[ib]] = np.asarray(hydrodata.disto[ib][:]) # trip_tmp[np.isnan(trip_tmp)] = undef_int basins_tmp[np.isnan(trip_tmp)] = undef_int # # Go to the call of the FORTRAN interface # print("GETHYDROGRID : nbpt = ", nbpt, nbvmax) print("GETHYDROGRID : nbvmax = ", nbvmax) print("GETHYDROGRID : nbxmax = ", nbxmax) self.nbi, self.nbj, self.area_bx, self.trip_bx, self.basin_bx, self.topoind_bx, self.fac_bx, self.hierarchy_bx, \ self.lon_bx, self.lat_bx, self.lshead_bx, self.nwbas = \ routing_interface.gethydrogrid(nbxmax, sub_pts, sub_index, sub_area, \ hydrodata.basinsmax, hydrodata.topoindmin, sub_lon, sub_lat, trip_tmp, basins_tmp, topoind_tmp, fac_tmp, hierarchy_tmp) # # Plot some diagnostics for the hydrology grid within the atmospheric meshes. # # Clean-up these arrays so that they are easy to use in Python. self.lon_bx[self.lon_bx > 360.]=np.nan self.lat_bx[self.lat_bx > 90.]=np.nan # return # # # class HydroSuper : def __init__(self, nbvmax, hydrodata, hydrooverlap) : # # Call findbasins # nb_basin, basin_inbxid, basin_outlet, basin_outtp, self.basin_sz, basin_bxout, basin_bbout, self.basin_pts, basin_lshead, coast_pts = \ routing_interface.findbasins(nbvmax, hydrooverlap.nbi, hydrooverlap.nbj, hydrooverlap.trip_bx, \ hydrooverlap.basin_bx, hydrooverlap.fac_bx, hydrooverlap.hierarchy_bx, \ hydrooverlap.topoind_bx, hydrooverlap.lshead_bx, \ hydrooverlap.lon_bx, hydrooverlap.lat_bx) # # Call Globalize # lon_bx_tmp = hydrooverlap.lon_bx lon_bx_tmp[np.isnan(lon_bx_tmp)] = undef_int lat_bx_tmp = hydrooverlap.lat_bx lat_bx_tmp[np.isnan(lat_bx_tmp)] = undef_int self.basin_count, self.basin_notrun, self.basin_area, self.basin_cg, self.basin_hierarchy, self.basin_fac, self.basin_topoind, \ self.basin_id, self.basin_outcoor, self.basin_type, self.basin_flowdir, \ self.basin_lshead, self.outflow_grid, self.outflow_basin, self.nbcoastal, self.coastal_basin = \ routing_interface.globalize(hydrooverlap.area_bx, lon_bx_tmp, lat_bx_tmp, hydrooverlap.trip_bx, \ hydrooverlap.hierarchy_bx, hydrooverlap.fac_bx, hydrooverlap.topoind_bx, hydrodata.topoindmin, \ nb_basin, basin_inbxid, basin_outlet, basin_outtp, self.basin_sz, self.basin_pts, basin_bxout, \ basin_bbout, basin_lshead, coast_pts, hydrooverlap.nwbas) return # def linkup(self, hydrodata) : # # Call the linkup routine in routing_reg. # print("Invented basins =", hydrodata.basinsmax) self.inflow_number,self.inflow_grid,self.inflow_basin = routing_interface.linkup(nbxmax, self.basin_count, self.basin_area, self.basin_id, \ self.basin_flowdir, self.basin_lshead, self.basin_hierarchy, \ self.basin_fac, self.outflow_grid, self.outflow_basin, \ self.nbcoastal, self.coastal_basin, float(hydrodata.basinsmax)) return # def fetch(self, part, modelgrid) : # largest_pos = -50 # fetch_basin = np.zeros(self.basin_area.shape, dtype=np.float32, order='F') # self.basin_area = routing_interface.areanorm(self.basin_count, self.basin_area) partial_sum = np.zeros(self.basin_area.shape, dtype=np.float32, order='F') # for i in range(part.size) : fetch_basin[:,:] = 0.0 outflow_uparea = routing_interface.fetch(self.basin_count, self.basin_area, self.basin_id, self.basin_hierarchy, \ self.basin_fac, self.outflow_grid, self.outflow_basin, partial_sum, fetch_basin) partial_sum = np.copy(fetch_basin) part.landsendtohalo(partial_sum, order='F') partial_sum = part.zerocore(partial_sum, order='F') # yy=modelgrid.landscatter(np.sum(fetch_basin, axis=1)/np.sum(self.basin_area, axis=1)) self.fetch_basin = np.copy(fetch_basin) # # Find area the largest basins need at least to have. # xtmp = np.hstack(part.comm.allgather(outflow_uparea[np.where(outflow_uparea > 0.0)])) sorted_outareas = np.sort(np.array(xtmp)) largest_rivarea = sorted_outareas[largest_pos] # # # yy=modelgrid.landscatter(np.sum(self.fetch_basin, axis=1)/np.sum(self.basin_area, axis=1)) print("Rank :"+str(part.rank)+" OUT of fetch =+=+=+=+=+=+=+=+=+= \n"+str(yy)+"\n =+=+=+=+=+=+=+=+=+=") self.num_largest = routing_interface.rivclassification(self.basin_count, self.outflow_grid, self.outflow_basin, \ self.fetch_basin, largest_rivarea) return # # # class HydroGraph : def __init__(self, nbasmax, hydrosuper, part, modelgrid) : self.nbasmax = nbasmax self.routing_area, self.routing_cg, self.topo_resid, self.route_togrid, self.route_tobasin, self.route_nbintobas, self.global_basinid, \ self.route_outlet, self.route_type, self.origin_nbintobas, self.routing_fetch = \ routing_interface.truncate(nbasmax, hydrosuper.num_largest, hydrosuper.basin_count, hydrosuper.basin_notrun, \ hydrosuper.basin_area, hydrosuper.basin_cg, \ hydrosuper.basin_topoind, hydrosuper.fetch_basin, hydrosuper.basin_id, \ hydrosuper.basin_outcoor, hydrosuper.basin_type, hydrosuper.basin_flowdir, \ hydrosuper.outflow_grid, hydrosuper.outflow_basin, \ hydrosuper.inflow_number,hydrosuper.inflow_grid,hydrosuper.inflow_basin) yy=modelgrid.landscatter(np.sum(self.routing_fetch, axis=1)/np.sum(self.routing_area, axis=1)) print ("Rank :"+str(part.rank)+" OUT of truncate =+=+=+=+=+=+=+=+=+= \n"+str(yy)+"\n =+=+=+=+=+=+=+=+=+=") return # def dumpnetcdf(self, filename, globalgrid, procgrid, part) : # NCFillValue=1.0e20 vtyp=np.float64 cornerind=[0,2,4,6] nbcorners = len(cornerind) # if part.rank == 0 : outnf=Dataset(filename, 'w', format='NETCDF4_CLASSIC') # Dimensions outnf.createDimension('x', globalgrid.ni) outnf.createDimension('y', globalgrid.nj) outnf.createDimension('land', len(procgrid.area)) outnf.createDimension('htu', self.nbasmax) outnf.createDimension('bnd', nbcorners) # # Coordinates # # Longitude longitude = part.gather(procgrid.lon_full) if part.rank == 0 : lon=outnf.createVariable("lon", vtyp, ('y','x'), fill_value=NCFillValue) lon.units="grid box centre degrees east" lon.title="Longitude" lon.axis="X" lon[:,:] = longitude[:,:] # # Latitude latitude = part.gather(procgrid.lat_full) if part.rank == 0 : lat=outnf.createVariable("lat", vtyp, ('y','x'), fill_value=NCFillValue) lat.units="grid box centre degrees north" lat.standard_name="grid latitude" lat.title="Latitude" lat.axis="Y" lat[:] = latitude[:,:] # # Bounds of grid box # llonpoly=np.zeros((nbcorners,procgrid.nbland)) llatpoly=np.zeros((nbcorners,procgrid.nbland)) for i in range(procgrid.nbland) : llonpoly[:,i] = [procgrid.polyll[i][ic][0] for ic in cornerind] llatpoly[:,i] = [procgrid.polyll[i][ic][1] for ic in cornerind] lon_bnd = procgrid.landscatter(llonpoly) lat_bnd = procgrid.landscatter(llatpoly) if part.rank == 0 : lonbnd=outnf.createVariable("lon_bnd", vtyp, ('bnd','y','x'), fill_value=NCFillValue) lonbnd.units="grid box corners degrees east" lonbnd.title="Longitude of Corners" latbnd=outnf.createVariable("lat_bnd", vtyp, ('bnd','y','x'), fill_value=NCFillValue) latbnd.units="grid box corners degrees north" latbnd.title="Latitude of Corners" else : lonbnd= np.zeros((1,1,1)) latbnd= np.zeros((1,1,1)) lonbnd[:,:,:] = part.gather(lon_bnd[:,:,:]) latbnd[:,:,:] = part.gather(lat_bnd[:,:,:]) # # Land sea mask # if part.rank == 0 : land=outnf.createVariable("land", vtyp, ('y','x'), fill_value=NCFillValue) land.units="Land Sea mask" land.standard_name="landsea mask" land.title="Land" land[:,:] = globalgrid.land[:,:] # Area areas = procgrid.landscatter(np.array(procgrid.area, dtype=np.float64)) areas[np.isnan(areas)] = NCFillValue if part.rank == 0 : area=outnf.createVariable("area", vtyp, ('y','x'), fill_value=NCFillValue) area.units="m^2" area.standard_name="grid area" area.title="Area" else : area = np.zeros((1,1)) area[:,:] = part.gather(areas[:,:]) # # Variables # Once gathered on root_proc we transform them into float64. Careful, Integer variables do not have NaN ! # rarea = procgrid.landscatter(self.routing_area[:,:], order='F') rarea = rarea.astype(vtyp, copy=False) rarea[np.isnan(rarea)] = NCFillValue if part.rank == 0 : routingarea = outnf.createVariable("routingarea", vtyp, ('htu','y','x'), fill_value=NCFillValue) routingarea.title = "Surface of basin" routingarea.units = "m^2" else : routingarea = np.zeros((1,1,1)) routingarea[:,:,:] = part.gather(rarea) # # The field route_togrid is with indices on the local grid. That needs to be converted to the global grid. # itarget=-1 for il in range(procgrid.nbland) : lo = procgrid.lon_full[procgrid.indP[il][0],procgrid.indP[il][1]] la = procgrid.lat_full[procgrid.indP[il][0],procgrid.indP[il][1]] d=np.sqrt((lo-3.13)**2+(la-39.70)**2) if d < 0.05 : itarget = il if itarget >+ 0 : print(part.rank, itarget, " Before route_togrid = ", self.route_togrid[itarget,:]) grgrid = part.l2glandindex(self.route_togrid[:,:]) if itarget >+ 0 : print(part.rank, itarget, " After route_togrid = ", self.route_togrid[itarget,:]) rgrid = procgrid.landscatter(grgrid, order='F') rgrid = rgrid.astype(vtyp, copy=False) rgrid[rgrid >= RPP.IntFillValue] = NCFillValue if part.rank == 0 : routetogrid = outnf.createVariable("routetogrid", vtyp, ('htu','y','x'), fill_value=NCFillValue) routetogrid.title = "Grid into which the basin flows" routetogrid.units = "-" else : routetogrid = np.zeros((1,1,1)) routetogrid[:,:,:] = part.gather(rgrid) # rtobasin = procgrid.landscatter(self.route_tobasin[:,:], order='F') rtobasin = rtobasin.astype(vtyp, copy=False) rtobasin[rtobasin >= RPP.IntFillValue] = NCFillValue if part.rank == 0 : routetobasin = outnf.createVariable("routetobasin", vtyp, ('htu','y','x'), fill_value=NCFillValue) routetobasin.title = "Basin in to which the water goes" routetobasin.units = "-" else : routetobasin = np.zeros((1,1,1)) routetobasin[:,:,:] = part.gather(rtobasin) # rid = procgrid.landscatter(self.global_basinid[:,:], order='F') rid = rid.astype(vtyp, copy=False) rid[rid >= RPP.IntFillValue] = NCFillValue if part.rank == 0 : basinid = outnf.createVariable("basinid", vtyp, ('htu','y','x'), fill_value=NCFillValue) basinid.title = "ID of basin" basinid.units = "-" else : basinid = np.zeros((1,1,1)) basinid[:,:,:] = part.gather(rid) # rintobas = procgrid.landscatter(self.route_nbintobas[:]) rintobas = rintobas.astype(vtyp, copy=False) rintobas[rintobas >= RPP.IntFillValue] = NCFillValue if part.rank == 0 : routenbintobas = outnf.createVariable("routenbintobas", vtyp, ('y','x'), fill_value=NCFillValue) routenbintobas.title = "Number of basin into current one" routenbintobas.units = "-" else : routenbintobas = np.zeros((1,1)) routenbintobas[:,:] = part.gather(rintobas) # onbintobas = procgrid.landscatter(self.origin_nbintobas[:]) onbintobas = onbintobas.astype(vtyp, copy=False) onbintobas[onbintobas >= RPP.IntFillValue] = NCFillValue if part.rank == 0 : originnbintobas = outnf.createVariable("originnbintobas", vtyp, ('y','x'), fill_value=NCFillValue) originnbintobas.title = "Number of sub-grid basin into current one before truncation" originnbintobas.units = "-" else : originnbintobas = np.zeros((1,1)) originnbintobas[:,:] = part.gather(onbintobas) # olat = procgrid.landscatter(self.route_outlet[:,:,0], order='F') olat = olat.astype(vtyp, copy=False) olat[np.isnan(olat)] = NCFillValue if part.rank == 0 : outletlat = outnf.createVariable("outletlat", vtyp, ('htu','y','x'), fill_value=NCFillValue) outletlat.title = "Latitude of Outlet" outletlat.title = "degrees north" else : outletlat = np.zeros((1,1,1)) outletlat[:,:,:] = part.gather(olat) # olon = procgrid.landscatter(self.route_outlet[:,:,1], order='F') olon = olon.astype(vtyp, copy=False) olon[np.isnan(olon)] = NCFillValue if part.rank == 0 : outletlon = outnf.createVariable("outletlon", vtyp, ('htu','y','x'), fill_value=NCFillValue) outletlon.title = "Longitude of outlet" outletlon.units = "degrees east" else : outletlon = np.zeros((1,1,1)) outletlon[:,:,:] = part.gather(olon) # otype = procgrid.landscatter(self.route_type[:,:], order='F') otype = otype.astype(vtyp, copy=False) otype[np.isnan(otype)] = NCFillValue if part.rank == 0 : outlettype = outnf.createVariable("outlettype", vtyp, ('htu','y','x'), fill_value=NCFillValue) outlettype.title = "Type of outlet" outlettype.units = "code" else : outlettype = np.zeros((1,1,1)) outlettype[:,:,:] = part.gather(otype) # tind = procgrid.landscatter(self.topo_resid[:,:], order='F') tind = tind.astype(vtyp, copy=False) tind[np.isnan(tind)] = NCFillValue if part.rank == 0 : topoindex = outnf.createVariable("topoindex", vtyp, ('htu','y','x'), fill_value=NCFillValue) topoindex.title = "Topographic index of the retention time" topoindex.units = "m" else : topoindex = np.zeros((1,1,1)) topoindex[:,:,:] = part.gather(tind) # # Save centre of gravity of HTU # cg = procgrid.landscatter(self.routing_cg[:,:,:], order='F') cg = cg.astype(vtyp, copy=False) cg[np.isnan(cg)] = NCFillValue if part.rank == 0 : CG_lon = outnf.createVariable("CG_lon", vtyp, ('htu','y','x'), fill_value=NCFillValue) CG_lon.title = "Longitude of centre of gravity of HTU" CG_lon.units = "degrees east" CG_lat = outnf.createVariable("CG_lat", vtyp, ('htu','y','x'), fill_value=NCFillValue) CG_lat.title = "Latitude of centre of gravity of HTU" CG_lat.units = "degrees north" else : CG_lon = np.zeros((1,1,1)) CG_lat = np.zeros((1,1,1)) CG_lon[:,:,:] = part.gather(cg[1,:,:,:]) CG_lat[:,:,:] = part.gather(cg[0,:,:,:]) # # Save the fetch of each basin # fe = procgrid.landscatter(self.routing_fetch[:,:], order='F') fe = fe.astype(vtyp, copy=False) fe[np.isnan(fe)] = NCFillValue if part.rank == 0 : fetch = outnf.createVariable("fetch", vtyp, ('htu','y','x'), fill_value=NCFillValue) fetch.title = "Fetch contributing to each HTU" fetch.units = "m^2" else : fetch = np.zeros((1,1,1)) fetch[:,:,:] = part.gather(fe) # if part.rank == 0 : outnf.close() # return