From 49d70d0b67c9444cb5314f03427e239fbc4e5288 Mon Sep 17 00:00:00 2001 From: Anthony <anthony.schrapffer@polytechnique.fr> Date: Mon, 4 May 2020 15:36:15 +0200 Subject: [PATCH] Tools to check the output and correct eventual fetch and inflows errors --- Diags/HTUs_test_and_corr.pbs | 14 ++ Diags/Makefile | 15 ++ Diags/Routing_Test_and_Correction.py | 207 +++++++++++++++++++++ Diags/hydrosuper.f90 | 259 +++++++++++++++++++++++++++ 4 files changed, 495 insertions(+) create mode 100644 Diags/HTUs_test_and_corr.pbs create mode 100644 Diags/Makefile create mode 100644 Diags/Routing_Test_and_Correction.py create mode 100644 Diags/hydrosuper.f90 diff --git a/Diags/HTUs_test_and_corr.pbs b/Diags/HTUs_test_and_corr.pbs new file mode 100644 index 0000000..81a352f --- /dev/null +++ b/Diags/HTUs_test_and_corr.pbs @@ -0,0 +1,14 @@ +#!/bin/bash +# +#PBS -N HTUs_test +# +#PBS -j oe +#PBS -l nodes=1:ppn=1 +#PBS -l walltime=1:00:00 +#PBS -l mem=40gb +#PBS -l vmem=40gb +# +cd ${PBS_O_WORKDIR} +# +python3 Routing_Test_and_Correction.py +# diff --git a/Diags/Makefile b/Diags/Makefile new file mode 100644 index 0000000..0f90e28 --- /dev/null +++ b/Diags/Makefile @@ -0,0 +1,15 @@ +# +FC = gfortran +FFLAG = -fPIC +FDBG = -g -fbounds-check +# +FPY = f2py3 +PDBG = --debug +# +all : hydrosuper.so + +clean : + rm -f compilation.log *.o *.so *.mod hydrosuper.so *~ + +hydrosuper.so : hydrosuper.f90 + $(FPY) -c hydrosuper.f90 $(PDBG) --fcompiler=gfortran -m hydrosuper > compilation.log diff --git a/Diags/Routing_Test_and_Correction.py b/Diags/Routing_Test_and_Correction.py new file mode 100644 index 0000000..298d925 --- /dev/null +++ b/Diags/Routing_Test_and_Correction.py @@ -0,0 +1,207 @@ +# +# +import sys +sys.path.append("/home/anthony/Documents/LOCAL/RoutingPP/ROUTING_Analysis_tools/Programs") +import numpy as np +from netCDF4 import Dataset as NetCDFFile +from hydrosuper import check_fetch_order, check_inflows_in_outflow, check_outflow_in_inflows, test_outflow, compute_fetch, compute_inflows +# +############################ +# +# Direction of the netCDF graph file obtained from RoutingPP +input_file = "" + +# Direction to save the corrected netCDF graph file +output_file = "" +# +############################ +# +def searchInlist(listname, nameFind): + """ Function to search a value within a list + listname = list + nameFind = value to find + >>> searInlist(['1', '2', '3', '5'], '5') + True + """ + for x in listname: + if x == nameFind: + return True + return False +# +class routing_test: + def __init__(self, dire): + self.nc = NetCDFFile(dire, "r") + self.nbpt_glo = self.nc.variables["nbpt_glo"][:] + + self.num_pt = int(np.nanmax(self.nbpt_glo)) + self.conv_land_ji = [[np.where(self.nbpt_glo == i)[0][0], np.where(self.nbpt_glo == i)[1][0]] for i in range(1, self.num_pt+1)] + + self.basin_count_land = self.var1d("routenbintobas") + self.max_bas_count = int(np.max(self.basin_count_land)) + + self.HTUoutgrid_land = self.var2d("routetogrid") + self.HTUoutbasin_land = self.var2d("routetobasin") + self.basin_area_land = self.var2d('basin_area') + self.fetch_land = self.var2d("fetch") + self.HTUinnum = self.var2d("route_innum") + self.max_innum = int(np.max(self.HTUinnum)) + + self.HTUingrid = self.var3d("route_ingrid") + self.HTUinbas = self.var3d("route_inbasin") + + def var1d(self, varn): + var = self.nc.variables[varn][:] + output = np.array([var[j,i] for j,i in self.conv_land_ji]) + return output + + def var2d(self, varn): + var = self.nc.variables[varn][:] + output = np.array([var[:self.max_bas_count,j,i] for j,i in self.conv_land_ji]) + return output + + def var3d(self, varn): + var = self.nc.variables[varn][:] + output = np.zeros((self.num_pt,self.max_bas_count, self.max_innum)) + for l, ji in enumerate(self.conv_land_ji): + j,i = ji + output[l,:,:] = np.transpose(var[:self.max_innum,:self.max_bas_count,j,i]) + return output + + ################## + + def check_fetch_order(self): + check_fetch_order(nbpt = self.num_pt, nbbas = self.max_bas_count, fetch = self.fetch_land, \ + outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, basin_count = self.basin_count_land) + + def check_inflows_in_outflow(self): + check_inflows_in_outflow(nbpt = self.num_pt, nbbas = self.max_bas_count, outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, \ + basin_count = self.basin_count_land, ingrid = self.HTUingrid, inbas = self.HTUinbas, innum = self.HTUinnum) + + def check_outflow_in_inflows(self): + check_outflow_in_inflows(nbpt = self.num_pt, nbbas = self.max_bas_count, outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, \ + basin_count = self.basin_count_land, ingrid = self.HTUingrid, inbas = self.HTUinbas, innum = self.HTUinnum) + + def test_outflow(self): + test_outflow(nbpt = self.num_pt, nbbas = self.max_bas_count, outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, \ + basin_count = self.basin_count_land) + + def compute_fetch(self): + self.fetch_new = compute_fetch(nbpt = self.num_pt, nbbas = self.max_bas_count, outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, \ + basin_count = self.basin_count_land, basin_area = self.basin_area_land) + + + def compute_inflows(self): + self.ingrid_new, self.inbas_new, self.innum_new = compute_inflows(nbpt = self.num_pt, nbbas = self.max_bas_count, nbin = self.max_innum,outgrid = self.HTUoutgrid_land, outbas = self.HTUoutbasin_land, \ + basin_count = self.basin_count_land) + + def full_test(self): + self.check_fetch_order() + self.check_inflows_in_outflow() + self.check_outflow_in_inflows() + self.test_outflow() + + #### + def get_var_corr(self, X): + if X.ndim == 2: + A = np.zeros(self.nc.variables["fetch"][:].shape) + for k,ji in enumerate(self.conv_land_ji): + j,i = ji + A[:self.max_bas_count,j,i] = X[k,:] + + if X.ndim == 3: + A = np.zeros(self.nc.variables["route_ingrid"][:].shape) + for k,ji in enumerate(self.conv_land_ji): + j,i = ji + A[:self.max_innum, :self.max_bas_count,j,i] = np.transpose(X[k,:,:]) + + return A + + def map_var(self): + self.D_corr = {} + rr.compute_fetch() + rr.compute_inflows() + + self.D_corr["fetch"] = self.get_var_corr(self.fetch_new) + self.D_corr["route_innum"] = self.get_var_corr(self.innum_new) + self.D_corr["route_ingrid"] = self.get_var_corr(self.ingrid_new) + self.D_corr["route_inbasin"] = self.get_var_corr(self.inbas_new) + + + def netcdf_corr(self, ofile): + self.map_var() + + with NetCDFFile(ofile, 'w') as onew: + # Dimensions + for dimn in self.nc.dimensions: + if not searchInlist(onew.dimensions,dimn): + odim = self.nc.dimensions[dimn] + if odim.isunlimited(): + onew.createDimension(dimn, None) + else: + onew.createDimension(dimn, len(odim)) + # Variables + for varn in self.nc.variables: + print(varn + " ....") + if not searchInlist(onew.variables,varn): + ovar = self.nc.variables[varn] + newvar = onew.createVariable(varn, ovar.dtype, ovar.dimensions) + for attrn in ovar.ncattrs(): + attrv = ovar.getncattr(attrn) + newvar.setncattr(attrn,attrv) + + if np.prod(ovar.shape) > 300*300*100: + for it in range(0,ovar.shape[0], 5): + print(" ", iit, ',', eit) + iit = it + eit = it + 5 + if varn in list(self.D_corr.keys()): + newvar[iit:eit,] = self.D_corr[varn][iit:eit,] + else: + newvar[iit:eit,] = ovar[iit:eit,] + if eit != ovar.shape[0]: + print(" ", iit, ',', eit) + iit = eit + eit = ovar.shape[0] + if varn in list(self.D_corr.keys()): + newvar[iit:eit,] = self.D_corr[varn][iit:eit,] + else: + newvar[iit:eit,] = ovar[iit:eit,] + else: + if varn in list(self.D_corr.keys()): + newvar[:] = self.D_corr[varn][:] + else: + newvar[:] = ovar[:] + + onew.sync() + + # global attributes + for attrn in self.nc.ncattrs(): + attrv = self.nc.getncattr(attrn) + onew.setncattr(attrn,attrv) + onew.sync() + + +################## +# +# Class test +if __name__ == "__main__": + """ + Run the program + """ + if input_file == "": + "Error: please inform an input file ! " + else: + if output_file == "": + output_file = input_file.replace(".nc", "_corr.nc") + filename = input_file.split("/")[-1] + print("-- {0} --".format(filename)) + print("Testing the input file") + rr = routing_test(input_file) + rr.full_test() + + print("Generation of the corrected file") + rr.netcdf_corr(output_file) + print("Testing the corrected file") + rr2 = routing_test(output_file) + rr2.full_test() + diff --git a/Diags/hydrosuper.f90 b/Diags/hydrosuper.f90 new file mode 100644 index 0000000..79453d7 --- /dev/null +++ b/Diags/hydrosuper.f90 @@ -0,0 +1,259 @@ +SUBROUTINE check_fetch_order(nbpt, nbbas, fetch, outgrid, outbas, basin_count) + + IMPLICIT NONE + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas + REAL,DIMENSION(nbpt, nbbas), INTENT(in) :: fetch + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx + REAL :: f1, f2 + + + WRITE(*,*) " *** Checking fetch order errors *** " + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + IF (outbas(ig,ib) .LE. 35) THEN + f1 = fetch(ig,ib) + f2 = fetch(outgrid(ig,ib), outbas(ig,ib)) + IF (f1 .GT. f2) THEN + WRITE(*,*) "*ERROR*", ig, ib, f1, f2 + WRITE(*,*) "outflows : ", outgrid(ig,ib), outbas(ig,ib) + END IF + END IF + END DO + END DO + +END SUBROUTINE check_fetch_order + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +SUBROUTINE check_inflows_in_outflow(nbpt, nbbas, nbin, outgrid, outbas, basin_count, ingrid, inbas, innum) + + IMPLICIT NONE + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas, nbin + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas, innum + INTEGER, DIMENSION(nbpt, nbbas, nbin), INTENT(in) :: ingrid, inbas + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx, og, ob, test + INTEGER :: iin, iinmx, ii, limiin + + + WRITE(*,*) " *** Checking upstream HTUs is in the inflows *** " + + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + og = outgrid(ig,ib) + ob = outbas(ig,ib) + IF ( ob .LE. 35) THEN + iinmx = innum(og,ob) + test = 0 + ! Look through the inflows + DO iin=1,iinmx + IF (test .EQ. 0) THEN + IF ((ingrid(og,ob,iin) .EQ. ig) .AND. (inbas(og,ob,iin) .EQ. ib)) test = 1 + IF (ingrid(og,ob,iin) .EQ. 0) THEN + test = -1 + limiin = iin-1 + END IF + END IF + ENDDO + ! Error : not present + IF (test .EQ. 0) THEN + WRITE(*,*) "Error at", ig, ib + WRITE(*,*) "Outflow:", og, ob, "with", iinmx, "inflows" + DO ii=1,iinmx + WRITE(*,*) ii, ingrid(og,ob,ii), inbas(og,ob,ii) + END DO + END IF + ! Error, less inflows than innum (and not present) + IF (test .EQ. -1) WRITE(*,*) "innum does not correspond (iin, iinmax)", limiin, iinmx + END IF + + END DO + END DO + +END SUBROUTINE check_inflows_in_outflow + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! + +SUBROUTINE check_outflow_in_inflows(nbpt, nbbas, nbin, outgrid, outbas, basin_count, ingrid, inbas, innum) + + IMPLICIT NONE + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas, nbin + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas, innum + INTEGER, DIMENSION(nbpt, nbbas, nbin), INTENT(in) :: ingrid, inbas + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx, test, ing, inb + INTEGER :: iinmx, ii + + + WRITE(*,*) " *** Checking if the inflows corresponds to the upstream outflows *** " + + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + iinmx = innum(ig,ib) + IF ( iinmx .GT. 0) THEN + test = 0 + DO ii=1,iinmx + ing = ingrid(ig,ib,ii) + inb = inbas(ig,ib,ii) + IF ((outgrid(ing,inb) .NE. ig) .OR. (outbas(ing,inb) .NE. ib)) THEN + WRITE(*,*) "Error at", ig, ib + WRITE(*,*) "outflow->", outgrid(ing,inb), outbas(ing,inb) + END IF + ENDDO + END IF + END DO + END DO + +END SUBROUTINE check_outflow_in_inflows + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! + +SUBROUTINE test_outflow(nbpt, nbbas, outgrid, outbas, basin_count) + + IMPLICIT NONE + ! Changes to do : + ! Optimize by keeping in memory the points already checked + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx, og, ob, ind + INTEGER :: it + + WRITE(*,*) " *** Checking all HTUs goes to ocean *** " + + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + ind = 0 + og = outgrid(ig,ib) + ob = outbas(ig,ib) + DO WHILE (ob .LE. 35) + it = outgrid(og,ob) + ob = outbas(og,ob) + og = it + ind = ind+1 + IF (ind .GE. 5000) THEN + og = 0 + WRITE(*,*) "ERROR", ig, ib + END IF + END DO + END DO + END DO + + +END SUBROUTINE test_outflow + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +! + + +SUBROUTINE compute_fetch(nbpt, nbbas, outgrid, outbas, basin_count, basin_area, fetch_new) + + IMPLICIT NONE + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas + REAL, DIMENSION(nbpt, nbbas), INTENT(in) :: basin_area + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + !! OUTPUT VARIABLES + REAL, DIMENSION(nbpt,nbbas), INTENT(out) :: fetch_new + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx, og, ob, ind + INTEGER :: it + REAL :: area + + WRITE(*,*) " *** Computing the fetch *** " + + fetch_new(:,:) = 0 + + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + ind = 0 + area = basin_area(ig,ib) + fetch_new(ig,ib) = fetch_new(ig,ib) + area + + og = outgrid(ig,ib) + ob = outbas(ig,ib) + DO WHILE (ob .LE. 35) + fetch_new(og,ob) = fetch_new(og,ob) + area + it = outgrid(og,ob) + ob = outbas(og,ob) + og = it + END DO + END DO + END DO + + +END SUBROUTINE compute_fetch + + + +SUBROUTINE compute_inflows(nbpt, nbbas, nbin, outgrid, outbas, basin_count, ingrid_new, inbas_new, innum_new) + + IMPLICIT NONE + + !! INPUT VARIABLES + INTEGER, INTENT(in) :: nbpt, nbbas, nbin + INTEGER, DIMENSION(nbpt, nbbas), INTENT(in) :: outgrid, outbas + INTEGER, DIMENSION(nbpt), INTENT(in) :: basin_count + + INTEGER, DIMENSION(nbpt, nbbas), INTENT(OUT) :: innum_new + INTEGER, DIMENSION(nbpt, nbbas, nbin), INTENT(OUT) :: ingrid_new, inbas_new + + !! LOCAL VARIABLES + INTEGER :: ig, ib, ibmx, og, ob + INTEGER :: iin + + innum_new(:,:) = 0 + ingrid_new(:,:,:) = 0 + inbas_new(:,:,:) = 0 + + WRITE(*,*) " *** Computing the inflows *** " + + DO ig=1,nbpt + ibmx = basin_count(ig) + DO ib=1,ibmx + og = outgrid(ig,ib) + ob = outbas(ig,ib) + IF ( ob .LE. 35) THEN + innum_new(og,ob) = innum_new(og,ob) +1 + iin = innum_new(og,ob) + ingrid_new(og,ob,iin) = ig + inbas_new(og,ob,iin) = ib + END IF + END DO + END DO + +END SUBROUTINE compute_inflows + + + + -- GitLab