From e4c832e5f4ffe37b64f2e20555be50252aab161d Mon Sep 17 00:00:00 2001
From: Anthony <anthony.schrapffer@polytechnique.fr>
Date: Thu, 27 Feb 2020 18:25:32 +0100
Subject: [PATCH] Truncate class for monoproc alternative

---
 Truncate.py | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 288 insertions(+)
 create mode 100755 Truncate.py

diff --git a/Truncate.py b/Truncate.py
new file mode 100755
index 0000000..6115dd5
--- /dev/null
+++ b/Truncate.py
@@ -0,0 +1,288 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+"""
+Created on Sat Feb 22 10:19:21 2020
+
+@author: anthony
+"""
+
+from netCDF4 import Dataset as NetCDFFile
+import numpy as np
+import numpy.ma as ma
+import time
+import sys
+import os
+from inspect import currentframe, getframeinfo
+
+localdir=os.path.dirname(getframeinfo(currentframe()).filename)
+sys.path.append(localdir+'/F90subroutines')
+
+import routing_interface
+
+######################
+
+class truncation:
+    """
+    Indices in Fortran index : need to adapt when using numpy
+    """
+    def __init__(self, dfile, nbasmax):
+        self.nc  = NetCDFFile(dfile, "r")
+        
+        self.nbasmax = nbasmax
+        self.num_largest = 10
+        self.FillValue=np.nan
+        self.IntFillValue=999999
+        #
+        self.proc_num = self.nc.variables["proc_num"][:]
+        self.nbpt_proc = self.nc.variables["nbpt_proc"][:]
+        #
+        self.nbpt = self.nc.variables["nbpt_glo"][:]
+        self.nbpt_num = int(np.max(self.nbpt))
+        self.nj, self.ni = self.nbpt.shape
+        #
+        self.il_ji = [[k[0][0], k[1][0]] for k in [np.where(self.nbpt == i) for i in range(1,self.nbpt_num+1)]] 
+        #
+        # Get i,j variables
+        self.contfrac_e = self.nc.variables["contfrac"][:]
+        self.area_e = self.nc.variables["area"][:]
+        self.basin_count_e = self.nc.variables["basin_count"][:]
+        self.basin_notrun_e = self.nc.variables["basin_notrun"][:]
+        self.basin_area_e = self.nc.variables["basin_area"][:]
+        self.basin_cg_lon_e = self.nc.variables["CG_lon"][:]
+        self.basin_cg_lat_e = self.nc.variables["CG_lat"][:]
+        self.basin_topoind_e = self.nc.variables["basin_topoind"][:]
+        self.fetch_basin_e = self.nc.variables["fetch_basin"][:]
+        self.basin_id_e = self.nc.variables["basin_id"][:]
+        self.basin_outcoor_lon_e = self.nc.variables["outcoor_lon"][:]
+        self.basin_outcoor_lat_e = self.nc.variables["outcoor_lat"][:]
+        self.basin_type_e = self.nc.variables["basin_type"][:]
+        self.basin_flowdir_e = self.nc.variables["basin_flowdir"][:]
+        self.outflow_grid_e = self.nc.variables["HTUoutgrid"][:] # name
+        self.outflow_basin_e = self.nc.variables["HTUoutbasin"][:] # name
+        self.inflow_grid_e = self.nc.variables["HTUingrid"][:] # name
+        self.inflow_basin_e = self.nc.variables["HTUinbas"][:] # name
+        self.inflow_number_e = self.nc.variables["HTUinnum"][:]
+        #
+        # Conversion
+        #
+        self.gridarea = self.convert_toland(self.area_e).astype(np.int32)
+        self.contfrac = self.convert_toland(self.contfrac_e).astype(np.int32)
+        self.basin_count = self.convert_toland(self.basin_count_e).astype(np.int32)
+        self.basin_notrun = self.convert_toland(self.basin_notrun_e).astype(np.int32)
+        self.basin_area = self.convert_toland(self.basin_area_e).astype(np.float32)
+        self.basin_cg_lon = self.convert_toland(self.basin_cg_lon_e).astype(np.float32)
+        self.basin_cg_lat = self.convert_toland(self.basin_cg_lat_e).astype(np.float32)
+        self.basin_cg = np.zeros((self.basin_cg_lon.shape[0], self.basin_cg_lon.shape[1], 2), order = 'F').astype(np.float32)
+        self.basin_cg[:,:,0] = self.basin_cg_lat
+        self.basin_cg[:,:,1] = self.basin_cg_lon
+        
+        self.basin_topoind = self.convert_toland(self.basin_topoind_e).astype(np.float32)
+        self.fetch_basin = self.convert_toland(self.fetch_basin_e).astype(np.float32)
+        self.basin_id = self.convert_toland(self.basin_id_e).astype(np.int32)
+        self.basin_outcoor_lon = self.convert_toland(self.basin_outcoor_lon_e)
+        self.basin_outcoor_lat = self.convert_toland(self.basin_outcoor_lat_e)
+        self.basin_outcoor = np.zeros((self.basin_outcoor_lon.shape[0], self.basin_outcoor_lon.shape[1], 2), order = 'F').astype(np.float32)
+        self.basin_outcoor[:,:,0] = self.basin_outcoor_lat
+        self.basin_outcoor[:,:,1] = self.basin_outcoor_lon
+        
+        self.basin_type = self.convert_toland(self.basin_type_e).astype(np.float32)
+        self.basin_flowdir = self.convert_toland(self.basin_flowdir_e).astype(np.int32)
+        self.outflow_grid = self.convert_toland(self.outflow_grid_e).astype(np.int32)
+        self.outflow_basin = self.convert_toland(self.outflow_basin_e).astype(np.int32)
+        
+        self.inflow_grid = self.convert_toland(self.inflow_grid_e).astype(np.int32)
+        self.inflow_basin = self.convert_toland(self.inflow_basin_e).astype(np.int32)
+        self.inflow_number = self.convert_toland(self.inflow_number_e).astype(np.int32)
+        
+        
+    def convert_toland(self, array):
+        if array.ndim == 2:
+            dim = (self.nbpt_num)
+        if array.ndim == 3:
+            dim = (self.nbpt_num, array.shape[0])
+        if array.ndim == 4:
+            dim = (self.nbpt_num, array.shape[1], array.shape[1]) # (inflow, htu, lat, lon) -> nbpt, htu, inflow
+            
+        # Ne pas mettre à 0, mettre à IntFillValue
+        out = np.zeros(dim, order = 'F')
+         
+        for il in range(self.nbpt_num):
+            j,i = self.il_ji[il]
+            if array.ndim == 2:
+                out[il] = array[j,i]
+            if array.ndim == 3:
+                out[il,:] = array[:,j,i]
+            if array.ndim == 4:
+                out[il,:,:array.shape[0]] = np.swapaxes(array[:,:,j,i],0,1)
+        return out
+
+    ###############
+
+    def convert_toij(self, array):
+        if array.ndim == 1:
+            dim = (self.nj,self.ni)
+        if array.ndim == 2:
+            dim = (array.shape[1], self.nj, self.ni)
+        if array.ndim == 3:
+            dim = (array.shape[2], array.shape[1], self.nj, self.ni) # (grid, htu, inflow) -> inflow, htu, lat, lon
+            
+        # Ne pas mettre à 0, mettre à IntFillValue
+        dtype = array.dtype
+        out = np.zeros(dim, order = 'F', dtype = dtype)
+        if dtype == np.int32:
+            out[:] = self.IntFillValue
+        elif dtype == np.float32:
+            out[:] = self.FillValue
+         
+        for il in range(self.nbpt_num):
+            j,i = self.il_ji[il]
+            if array.ndim == 1:
+                out[j,i] = array[il]
+            if array.ndim == 2:
+                out[:,j,i] = array[il,:]
+            if array.ndim == 3:
+                out[:,:,j,i] = np.swapaxes(array[il,:,:], 0, 1) # (inflow, htu, lat, lon)
+        return out
+
+    ###############
+    
+    def truncate(self):
+        nwbas = self.basin_topoind.shape[1]
+        nbxmax_in = self.inflow_grid.shape[1]
+        inf = np.copy(self.inflow_number)
+        self.routing_area, self.routing_cg, self.topo_resid, self.route_nbbasin, 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(nbpt = self.nbpt_num, nbxmax_in = nbxmax_in, nbasmax = self.nbasmax, nwbas = nwbas, num_largest = self.num_largest, gridarea = self.gridarea, cfrac = self.contfrac, basin_count = self.basin_count, \
+                                                               basin_notrun = self.basin_notrun, basin_area = self.basin_area, basin_cg = self.basin_cg, \
+                                                               basin_topoind = self.basin_topoind, fetch_basin = self.fetch_bis, basin_id = self.basin_id, \
+                                                               basin_coor = self.basin_outcoor, basin_type = self.basin_type, basin_flowdir = self.basin_flowdir, \
+                                                               outflow_grid = self.outflow_grid, outflow_basin = self.outflow_basin, \
+                                                               inflow_number = self.inflow_number, inflow_grid = self.inflow_grid, inflow_basin = self.inflow_basin)
+
+        # Adjust inflows -> add this part in fortran
+        for il in range(self.nbpt_num):
+            for ib in range(self.nbasmax):
+                self.inflow_grid[il,ib,self.inflow_number[il,ib]:] = self.IntFillValue
+                self.inflow_basin[il,ib,self.inflow_number[il,ib]:] = self.IntFillValue
+
+        self.inflow_grid[il,self.nbasmax:,:] = self.IntFillValue
+        self.inflow_basin[il,self.nbasmax:,:] = self.IntFillValue        
+        self.inflow_number[il,self.nbasmax:] = self.IntFillValue
+                
+
+    def finalrivclass(self, largest_rivarea):
+
+        A = np.where((self.route_tobasin > self.nbasmax) & (self.routing_fetch > largest_rivarea))
+        A = [[A[0][l], A[1][l]] for l in range(len(A[0]))]
+        num_largest = len(A)
+        for il, ib in A:
+            self.route_tobasin[il,ib] = self.nbasmax +3
+        
+        print('NUMBER OF RIVERS :', len(A))
+
+
+    def get_downstream(self, L, ig, ib):
+        """
+        Useful to add / remove fetch
+        """
+        L.append([ig,ib])
+        if self.outflow_grid[ig-1,ib-1]>0:
+            self.get_downstream(L, int(self.outflow_grid[ig-1, ib-1]), int(self.outflow_basin[ig-1, ib-1]))
+        else:
+            L.append(int(self.outflow_grid[ig-1, ib-1]))#,int(self.outbasin[ib-1,j,i])])                                
+                                    
+    def get_fetch(self):
+    
+        L_area = []
+        for ig, J in enumerate(self.il_ji):
+            j,i = J
+            L_area.append([self.basin_area[ig,k] for k in range(self.basin_count[ig])])
+        
+        L_fetch_calc = []
+        for ig, J in enumerate(self.il_ji):
+            j,i = J
+            L_fetch_calc.append([0 for k in range(self.basin_count[ig])])
+
+        for ig in range(1, len(self.basin_count)+1): # plus propre nbpt_num
+            for ib in range(1, self.basin_count[ig-1]+1):
+                fe = L_area[ig-1][ib-1]
+                L = []
+                self.get_downstream(L, ig, ib)
+                for igf,ibf in L[:-1]:
+                    L_fetch_calc[igf-1][ibf-1] += fe
+                
+        self.fetch_bis = np.zeros(self.fetch_basin.shape, order = 'F').astype(np.float32)
+        for ig in range(1, len(self.basin_count)+1):# plus propre nbpt_num
+            self.fetch_bis[ig-1,:self.basin_count[ig-1]] = np.array(L_fetch_calc[ig-1])
+ 
+        return
+
+    ####################################################
+    #
+    # Generation of the NetCDF output
+    # 
+
+    def addcoordinates(self, outnf) :
+        #
+        for varn in ["longitude", "latitude", "lon_bnd", "land", "area", "proc_num", "nbpt_proc", "nbpt_glo"]: 
+            ovar = self.nc.variables[varn]
+            nvar = outnf.createVariable(varn, ovar.dtype, ovar.dimensions)
+            nvar[:] = ovar[:]
+            for attrn in ovar.ncattrs():
+                attrv = ovar.getncattr(attrn)
+                nvar.setncattr(attrn,attrv)
+            outnf.sync()
+        return
+    
+    def add_variable(self, outnf, data, NCFillValue, name, vtyp, dim, title, unit, type_data):
+        dtype = data.dtype
+        data_ij = self.convert_toij(data)
+        data_ij = data_ij.astype(vtyp)
+
+        if dtype == np.int32:
+            data_ij[data_ij >= self.IntFillValue] = NCFillValue
+        elif dtype == np.float32:
+            data_ij[np.isnan(data_ij)] = NCFillValue
+
+        ncvar = outnf.createVariable(name, vtyp, dim, fill_value=NCFillValue)
+        ncvar.title = title
+        ncvar.units = unit
+        ncvar[:] = data_ij[:]
+
+    def dumpnetcdf(self, filename) :
+        #
+        NCFillValue=1.0e20
+        insize = 100
+        vtyp=np.float64
+        cornerind=[0,2,4,6]
+        nbcorners = len(cornerind)
+        #
+        outnf=NetCDFFile(filename, 'w', format='NETCDF4_CLASSIC')
+        # Dimensions
+        outnf.createDimension('x', self.ni)
+        outnf.createDimension('y', self.nj)
+        outnf.createDimension('in', insize)
+        outnf.createDimension('land', self.nbpt_num)
+        outnf.createDimension('htu', self.nbasmax)
+        outnf.createDimension('bnd', nbcorners)
+
+        self.add_variable(outnf, self.route_togrid, NCFillValue, "routetogrid", vtyp, ('htu','y','x'), "Grid into which the basin flows", "-", "int")
+        self.add_variable(outnf, self.route_tobasin, NCFillValue, "routetobasin", vtyp, ('htu','y','x'), "Basin in to which the water goes", "-", "int")
+        self.add_variable(outnf, self.global_basinid, NCFillValue, "basinid", vtyp, ('htu','y','x'), "ID of basin", "-", "int")
+        self.add_variable(outnf, self.route_nbintobas, NCFillValue, "routenbintobas", vtyp, ('y','x'), "Number of basin into current one", "-", "int")
+        self.add_variable(outnf, self.origin_nbintobas, NCFillValue, "originnbintobas", vtyp, ('y','x'), "Number of sub-grid basin into current one before truncation", "-", "int")
+        self.add_variable(outnf, self.route_outlet[:,:,0], NCFillValue, "outletlat", vtyp, ('htu','y','x'), "Latitude of Outlet","degrees north", "float")
+        self.add_variable(outnf, self.route_outlet[:,:,1], NCFillValue, "outletlon", vtyp, ('htu','y','x'), "Longitude of outlet","degrees east", "float")
+        self.add_variable(outnf, self.route_type[:,:], NCFillValue, "outlettype", vtyp, ('htu','y','x'), "Type of outlet","code", "int")
+        self.add_variable(outnf, self.topo_resid[:,:], NCFillValue, "topoindex", vtyp, ('htu','y','x'), "Topographic index of the retention time","m", "float")
+        self.add_variable(outnf, self.routing_cg[:,:,1], NCFillValue, "CG_lon", vtyp, ('htu','y','x'), "Longitude of centre of gravity of HTU","degrees east", "float")    
+        self.add_variable(outnf, self.routing_cg[:,:,0], NCFillValue, "CG_lat", vtyp, ('htu','y','x'), "Latitude of centre of gravity of HTU","degrees east", "float")
+        self.add_variable(outnf, self.routing_fetch, NCFillValue, "fetch", vtyp, ('htu','y','x'), "Fetch contributing to each HTU","m^2", "float")
+
+        self.add_variable(outnf, self.inflow_number[:,:self.nbasmax], NCFillValue, "inflow_number", vtyp, ('htu','y','x'), "Fetch contributing to each HTU","m^2", "int")
+        self.add_variable(outnf, self.inflow_grid[:,:self.nbasmax,:100], NCFillValue, "inflow_grid", vtyp, ('in', 'htu','y','x'), "Grid of HTUs flowing into the basin","-", "int")
+        self.add_variable(outnf, self.inflow_basin[:,:self.nbasmax,:100], NCFillValue, "inflow_basin", vtyp, ('in', 'htu','y','x'), "Basin of HTUs flowing into the basin","-", "int")
+        # Revoir inflows
+
+        outnf.close()
+        return
-- 
GitLab