wolfhece 2.2.38__py3-none-any.whl → 2.2.39__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. wolfhece/Coordinates_operations.py +5 -0
  2. wolfhece/GraphNotebook.py +72 -1
  3. wolfhece/GraphProfile.py +1 -1
  4. wolfhece/MulticriteriAnalysis.py +1579 -0
  5. wolfhece/PandasGrid.py +62 -1
  6. wolfhece/PyCrosssections.py +194 -43
  7. wolfhece/PyDraw.py +891 -73
  8. wolfhece/PyGui.py +913 -72
  9. wolfhece/PyGuiHydrology.py +528 -74
  10. wolfhece/PyPalette.py +26 -4
  11. wolfhece/PyParams.py +33 -0
  12. wolfhece/PyPictures.py +2 -2
  13. wolfhece/PyVertex.py +25 -0
  14. wolfhece/PyVertexvectors.py +94 -28
  15. wolfhece/PyWMS.py +52 -36
  16. wolfhece/acceptability/acceptability.py +15 -8
  17. wolfhece/acceptability/acceptability_gui.py +507 -360
  18. wolfhece/acceptability/func.py +80 -183
  19. wolfhece/apps/version.py +1 -1
  20. wolfhece/compare_series.py +480 -0
  21. wolfhece/drawing_obj.py +12 -1
  22. wolfhece/hydrology/Catchment.py +228 -162
  23. wolfhece/hydrology/Internal_variables.py +43 -2
  24. wolfhece/hydrology/Models_characteristics.py +69 -67
  25. wolfhece/hydrology/Optimisation.py +893 -182
  26. wolfhece/hydrology/PyWatershed.py +267 -165
  27. wolfhece/hydrology/SubBasin.py +185 -140
  28. wolfhece/hydrology/cst_exchanges.py +76 -1
  29. wolfhece/hydrology/forcedexchanges.py +413 -49
  30. wolfhece/hydrology/read.py +65 -5
  31. wolfhece/hydrometry/kiwis.py +14 -7
  32. wolfhece/insyde_be/INBE_func.py +746 -0
  33. wolfhece/insyde_be/INBE_gui.py +1776 -0
  34. wolfhece/insyde_be/__init__.py +3 -0
  35. wolfhece/interpolating_raster.py +366 -0
  36. wolfhece/irm_alaro.py +1457 -0
  37. wolfhece/irm_qdf.py +889 -57
  38. wolfhece/lifewatch.py +6 -3
  39. wolfhece/picc.py +124 -8
  40. wolfhece/pyLandUseFlanders.py +146 -0
  41. wolfhece/pydownloader.py +2 -1
  42. wolfhece/pywalous.py +225 -31
  43. wolfhece/toolshydrology_dll.py +149 -0
  44. wolfhece/wolf_array.py +63 -25
  45. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/METADATA +3 -1
  46. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/RECORD +49 -40
  47. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/WHEEL +0 -0
  48. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/entry_points.txt +0 -0
  49. {wolfhece-2.2.38.dist-info → wolfhece-2.2.39.dist-info}/top_level.txt +0 -0
@@ -25,6 +25,7 @@ from ..wolf_array import *
25
25
  from ..PyCrosssections import crosssections as CrossSections
26
26
  from ..GraphNotebook import PlotNotebook
27
27
  from .read import *
28
+ from ..PyParams import Wolf_Param
28
29
 
29
30
  LISTDEM=['dem_before_corr','dem_after_corr','dem_10m','dem_20m','crosssection']
30
31
  #LISTDEM=['dem_after_corr']
@@ -607,17 +608,21 @@ class RiverSystem:
607
608
 
608
609
  #recherche de l'index max --> à l'exutoire
609
610
  self.maxlevels = self.parent.outlet.reachlevel
610
- self.maxstrahler=0
611
- self.reaches['indexed']={}
612
- for i in range(1,self.maxlevels+1):
613
- self.reaches['indexed'][i]=[]
614
611
 
615
- #création de listes pour chaque niveau
616
- for curreach in self.reaches['reaches']:
617
- curdict=self.reaches['reaches'][curreach]
618
- listreach=curdict['baselist']
619
- curlevel=listreach[0].reachlevel
620
- self.reaches['indexed'][curlevel].append(curreach)
612
+ if self.maxlevels == 0:
613
+ logging.warning(_("No reaches found in the watershed. Please check the model configuration and the outlet's position."))
614
+ else:
615
+ self.maxstrahler=0
616
+ self.reaches['indexed']={}
617
+ for i in range(1,self.maxlevels+1):
618
+ self.reaches['indexed'][i]=[]
619
+
620
+ #création de listes pour chaque niveau
621
+ for curreach in self.reaches['reaches']:
622
+ curdict=self.reaches['reaches'][curreach]
623
+ listreach=curdict['baselist']
624
+ curlevel=listreach[0].reachlevel
625
+ self.reaches['indexed'][curlevel].append(curreach)
621
626
 
622
627
  #création de listes pour chaque amont
623
628
  # on parcourt toutes les mailles depuis chaque amont et on ajoute les index de biefs qui sont différents
@@ -632,57 +637,58 @@ class RiverSystem:
632
637
  curdict['fromuptodown'].append(curnode.reach)
633
638
  curnode=curnode.down
634
639
 
635
- #création de l'indice de Strahler
636
- self.reaches['strahler']={}
637
- #on commence par ajouter les biefs de 1er niveau qui sont à coup sûr d'indice 1
638
- self.reaches['strahler'][1]=self.reaches['indexed'][1]
639
- for curreach in self.reaches['strahler'][1]:
640
- self.set_strahler_in_nodes(curreach,1)
641
-
642
- #on parcourt les différents niveaux
643
- for i in range(2,self.maxlevels+1):
644
- listlevel=self.reaches['indexed'][i]
645
- for curreach in listlevel:
646
- curup:Node_Watershed
647
- curup=self.reaches['reaches'][curreach]['upstream']
648
- upidx=list(x.strahler for x in curup.upriver)
649
- sameidx=upidx[0]==upidx[-1]
650
- maxidx=max(upidx)
651
-
652
- curidx=maxidx
653
- if sameidx:
654
- curidx+=1
655
- if not curidx in self.reaches['strahler'].keys():
656
- #création de la liste du niveau supérieur
657
- self.reaches['strahler'][curidx]=[]
658
- self.maxstrahler=curidx
659
-
660
- self.reaches['strahler'][curidx].append(curreach)
661
- self.set_strahler_in_nodes(curreach,curidx)
662
-
663
-
664
- myarray=WolfArray(mold=self.parent.subs_array)
665
- myarray.reset()
666
- curnode:Node_Watershed
667
- for curreach in self.reaches['reaches']:
668
- curdict=self.reaches['reaches'][curreach]
669
- listreach=curdict['baselist']
670
- for curnode in listreach:
671
- i=curnode.i
672
- j=curnode.j
673
- myarray.array[i,j]=curnode.strahler
674
- myarray.filename = self.parent.dir+'\\Characteristic_maps\\Drainage_basin.strahler'
675
- myarray.write_all()
676
- myarray.reset()
677
- for curreach in self.reaches['reaches']:
678
- curdict=self.reaches['reaches'][curreach]
679
- listreach=curdict['baselist']
680
- for curnode in listreach:
681
- i=curnode.i
682
- j=curnode.j
683
- myarray.array[i,j]=curnode.reachlevel
684
- myarray.filename = self.parent.dir+'\\Characteristic_maps\\Drainage_basin.reachlevel'
685
- myarray.write_all()
640
+ if self.maxlevels > 0:
641
+ #création de l'indice de Strahler
642
+ self.reaches['strahler']={}
643
+ #on commence par ajouter les biefs de 1er niveau qui sont à coup sûr d'indice 1
644
+ self.reaches['strahler'][1]=self.reaches['indexed'][1]
645
+ for curreach in self.reaches['strahler'][1]:
646
+ self.set_strahler_in_nodes(curreach,1)
647
+
648
+ #on parcourt les différents niveaux
649
+ for i in range(2,self.maxlevels+1):
650
+ listlevel=self.reaches['indexed'][i]
651
+ for curreach in listlevel:
652
+ curup:Node_Watershed
653
+ curup=self.reaches['reaches'][curreach]['upstream']
654
+ upidx=list(x.strahler for x in curup.upriver)
655
+ sameidx=upidx[0]==upidx[-1]
656
+ maxidx=max(upidx)
657
+
658
+ curidx=maxidx
659
+ if sameidx:
660
+ curidx+=1
661
+ if not curidx in self.reaches['strahler'].keys():
662
+ #création de la liste du niveau supérieur
663
+ self.reaches['strahler'][curidx]=[]
664
+ self.maxstrahler=curidx
665
+
666
+ self.reaches['strahler'][curidx].append(curreach)
667
+ self.set_strahler_in_nodes(curreach,curidx)
668
+
669
+
670
+ myarray=WolfArray(mold=self.parent.subs_array)
671
+ myarray.reset()
672
+ curnode:Node_Watershed
673
+ for curreach in self.reaches['reaches']:
674
+ curdict=self.reaches['reaches'][curreach]
675
+ listreach=curdict['baselist']
676
+ for curnode in listreach:
677
+ i=curnode.i
678
+ j=curnode.j
679
+ myarray.array[i,j]=curnode.strahler
680
+ myarray.filename = self.parent.directory+'\\Characteristic_maps\\Drainage_basin.strahler'
681
+ myarray.write_all()
682
+ myarray.reset()
683
+ for curreach in self.reaches['reaches']:
684
+ curdict=self.reaches['reaches'][curreach]
685
+ listreach=curdict['baselist']
686
+ for curnode in listreach:
687
+ i=curnode.i
688
+ j=curnode.j
689
+ myarray.array[i,j]=curnode.reachlevel
690
+ myarray.filename = self.parent.directory+'\\Characteristic_maps\\Drainage_basin.reachlevel'
691
+ myarray.write_all()
686
692
 
687
693
  def set_strahler_in_nodes(self, whichreach:int, strahler:int):
688
694
  """
@@ -862,7 +868,7 @@ class RiverSystem:
862
868
  """
863
869
  #Uniquement les pentes rivières
864
870
  for curlist in LISTDEM:
865
- slopes= WolfArray(self.parent.dir+'\\Characteristic_maps\\Drainage_basin.slope')
871
+ slopes= WolfArray(self.parent.directory+'\\Characteristic_maps\\Drainage_basin.slope')
866
872
  slopes.reset()
867
873
  for curreach in self.reaches['reaches']:
868
874
  curdict=self.reaches['reaches'][curreach]
@@ -872,7 +878,7 @@ class RiverSystem:
872
878
  ijval = np.asarray([[curnode.i, curnode.j, curnode.slopecorr[curlist]['value']] for curnode in listreach])
873
879
  slopes.array[np.int32(ijval[:,0]),np.int32(ijval[:,1])]=ijval[:,2]
874
880
 
875
- slopes.filename = self.parent.dir+'\\Characteristic_maps\\Drainage_basin.slope_corr_riv_'+curlist
881
+ slopes.filename = self.parent.directory+'\\Characteristic_maps\\Drainage_basin.slope_corr_riv_'+curlist
876
882
  slopes.write_all()
877
883
 
878
884
  def slope_correctionmin(self):
@@ -1224,7 +1230,7 @@ class RunoffSystem:
1224
1230
  def write_slopes(self):
1225
1231
  #Uniquement les pentes runoff
1226
1232
  for curlist in LISTDEM:
1227
- slopes= WolfArray(self.parent.dir+'\\Characteristic_maps\\Drainage_basin.slope')
1233
+ slopes= WolfArray(self.parent.directory+'\\Characteristic_maps\\Drainage_basin.slope')
1228
1234
  slopes.reset()
1229
1235
  curnode:Node_Watershed
1230
1236
  for curnode in self.nodes:
@@ -1232,7 +1238,7 @@ class RunoffSystem:
1232
1238
  j=curnode.j
1233
1239
  slopes.array[i,j]=curnode.slopecorr[curlist]['value']
1234
1240
 
1235
- slopes.filename = self.parent.dir+'\\Characteristic_maps\\Drainage_basin.slope_corr_run_'+curlist
1241
+ slopes.filename = self.parent.directory+'\\Characteristic_maps\\Drainage_basin.slope_corr_run_'+curlist
1236
1242
  slopes.write_all()
1237
1243
 
1238
1244
  def slope_correctionmin(self):
@@ -1638,12 +1644,13 @@ class SubWatershed:
1638
1644
 
1639
1645
  # rivers are sorted by dem value, so the first one is the outlet
1640
1646
  return self.get_list_nodes_river(reach)[0]
1647
+
1641
1648
  class Watershed:
1642
1649
  """Classe bassin versant"""
1643
1650
 
1644
1651
  header:header_wolf # header_wolf of "Drainage_basin.sub" wolf_array
1645
1652
 
1646
- dir: str # Répertoire de modélisation
1653
+ directory: str # Répertoire de modélisation
1647
1654
 
1648
1655
  outlet:Node_Watershed # exutoire
1649
1656
 
@@ -1669,7 +1676,7 @@ class Watershed:
1669
1676
  to_update_times:bool # switch to detect if the time matrix should be updated
1670
1677
 
1671
1678
  def __init__(self,
1672
- dir:str,
1679
+ directory:str,
1673
1680
  thzmin:float=None,
1674
1681
  thslopemin:float=None,
1675
1682
  thzmax:float=None,
@@ -1682,19 +1689,37 @@ class Watershed:
1682
1689
  dir_mnt_subpixels:str=None,
1683
1690
  *args, **kwargs):
1684
1691
 
1692
+ self.rivers = []
1693
+ self.runoff = []
1694
+ self.nodes = []
1695
+ self.subcatchments = []
1696
+ self.statisticss = {}
1697
+ self.header = None
1698
+ self.couplednodesij = []
1699
+ self.couplednodesxy = []
1700
+ self.couplednodes = []
1701
+
1685
1702
  self.virtualcatchments = []
1686
1703
 
1687
1704
  logging.info(_('Read files...'))
1688
1705
 
1689
- self.dir=os.path.normpath(dir)
1690
- self.dir_mnt_subpixels = dir_mnt_subpixels if dir_mnt_subpixels is not None else self.dir
1706
+ self.directory = os.path.normpath(directory)
1707
+ self.dir_mnt_subpixels = dir_mnt_subpixels if dir_mnt_subpixels is not None else self.directory
1691
1708
 
1692
- self.subs_array = WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.sub')
1709
+ self.subs_array = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.sub')
1693
1710
 
1694
- self.header = self.subs_array.get_header()
1711
+ self.header = header_wolf.read_header((self.directory+'\\Characteristic_maps\\Drainage_basin.b'))
1695
1712
 
1696
- #FIXME
1697
- isOk, fe_file = check_path(os.path.join(self.dir, "Coupled_pairs.txt"), prefix=self.dir)
1713
+ if self.subs_array.nbx == 0 or self.subs_array.nby == 0:
1714
+ logging.error(_('The Watershed sub file is empty or not valid.'))
1715
+ return
1716
+
1717
+ # Use params to get the directory and filename of forced exchanges
1718
+ _mainparams = Wolf_Param(filename = os.path.join(self.directory, "Main_model.param"), init_GUI= False, toShow= False)
1719
+ dir_fe = _mainparams[('Forced Exchanges', 'Directory')]
1720
+ fn_fe = _mainparams[('Forced Exchanges', 'Filename')]
1721
+
1722
+ isOk, fe_file = check_path(os.path.join(self.directory, dir_fe, fn_fe), prefix=self.directory)
1698
1723
  self.couplednodesxy=[]
1699
1724
  self.couplednodesij=[]
1700
1725
 
@@ -1703,15 +1728,19 @@ class Watershed:
1703
1728
  lines = f.read().splitlines()
1704
1729
  f.close()
1705
1730
 
1706
- if lines[0]=='COORDINATES':
1707
- for xy in enumerate(lines[1:]):
1708
- xy_split = xy[1].split('\t')
1709
- if len(xy_split)==4:
1710
- xup,yup,xdown,ydown=xy_split
1711
- else:
1712
- xup,yup,xdown,ydown=xy_split[:4]
1713
- self.couplednodesxy.append([float(xup),float(yup),float(xdown),float(ydown)])
1714
- self.couplednodesij.append([self.subs_array.get_ij_from_xy(float(xup),float(yup)),self.subs_array.get_ij_from_xy(float(xdown),float(ydown))])
1731
+ if len(lines) > 1:
1732
+
1733
+ if lines[0]=='COORDINATES':
1734
+ for xy in enumerate(lines[1:]):
1735
+ xy_split = xy[1].split('\t')
1736
+ if len(xy_split)==4:
1737
+ xup,yup,xdown,ydown=xy_split
1738
+ else:
1739
+ xup,yup,xdown,ydown=xy_split[:4]
1740
+ self.couplednodesxy.append([float(xup),float(yup),float(xdown),float(ydown)])
1741
+ self.couplednodesij.append([self.subs_array.get_ij_from_xy(float(xup),float(yup)),self.subs_array.get_ij_from_xy(float(xdown),float(ydown))])
1742
+ else:
1743
+ logging.warning(_('Unknown format in Coupled_pairs.txt'))
1715
1744
 
1716
1745
  logging.info(_('Initialization of nodes...'))
1717
1746
  self.nodesindex = np.zeros([self.subs_array.nbx,self.subs_array.nby], dtype=int)
@@ -1753,6 +1782,13 @@ class Watershed:
1753
1782
 
1754
1783
  @property
1755
1784
  def nb_subs(self):
1785
+ """ Nombre de sous-bassins """
1786
+
1787
+ if self.subs_array is None:
1788
+ return 0
1789
+ if self.subs_array.array is None:
1790
+ return 0
1791
+
1756
1792
  return int(ma.max(self.subs_array.array))
1757
1793
 
1758
1794
  @property
@@ -1891,6 +1927,24 @@ class Watershed:
1891
1927
  vect.find_minmax()
1892
1928
  return vect
1893
1929
 
1930
+ def get_vector_from_xy_to_outlet(self,
1931
+ x:float,
1932
+ y:float) -> vector:
1933
+
1934
+ down_to_outlet = self.get_node_from_xy(x, y)
1935
+
1936
+ if down_to_outlet is None:
1937
+ logging.error(_('No node found at coordinates ({}, {})').format(x, y))
1938
+ return None
1939
+
1940
+ vec_to_outlet = vector(name='Vector from ({}, {}) to outlet'.format(down_to_outlet.i, down_to_outlet.j))
1941
+
1942
+ while down_to_outlet is not None:
1943
+ vec_to_outlet.add_vertex(wolfvertex(down_to_outlet.x, down_to_outlet.y, down_to_outlet.dem['dem_after_corr']))
1944
+ down_to_outlet = down_to_outlet.down
1945
+
1946
+ return vec_to_outlet
1947
+
1894
1948
  def get_subwatershed(self, idx_sorted_or_name:int | str) -> SubWatershed:
1895
1949
  """
1896
1950
  Récupération d'un sous-bassin sur base de l'index trié
@@ -1920,7 +1974,7 @@ class Watershed:
1920
1974
 
1921
1975
  return None
1922
1976
 
1923
- def get_node_from_ij(self, i:int,j:int):
1977
+ def get_node_from_ij(self, i:int,j:int) -> Node_Watershed:
1924
1978
  """
1925
1979
  Récupération d'un objet Node_Watershed sur base des indices (i,j)
1926
1980
  """
@@ -1935,7 +1989,7 @@ class Watershed:
1935
1989
 
1936
1990
  return self.nodes[idx]
1937
1991
 
1938
- def get_node_from_xy(self, x:float, y:float):
1992
+ def get_node_from_xy(self, x:float, y:float) -> Node_Watershed:
1939
1993
  """
1940
1994
  Récupération d'un objet Node_Watershed sur base des coordonnées (x,y)
1941
1995
  """
@@ -1947,9 +2001,9 @@ class Watershed:
1947
2001
  Ecriture sur disque
1948
2002
  """
1949
2003
  for curlist in LISTDEM:
1950
- curpath=self.dir+'\\Characteristic_maps\\corrslopes\\'+curlist
2004
+ curpath=self.directory+'\\Characteristic_maps\\corrslopes\\'+curlist
1951
2005
  os.makedirs(curpath,exist_ok=True)
1952
- slopes= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.slope')
2006
+ slopes= WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.slope')
1953
2007
 
1954
2008
  ijval = np.asarray([[curnode.i, curnode.j, curnode.slopecorr[curlist]['value']] for curnode in self.nodes])
1955
2009
  slopes.array[np.int32(ijval[:,0]),np.int32(ijval[:,1])]=ijval[:,2]
@@ -1962,9 +2016,9 @@ class Watershed:
1962
2016
  Ecriture sur disque
1963
2017
  """
1964
2018
  for curlist in LISTDEM:
1965
- curpath=self.dir+'\\Characteristic_maps\\corrdem\\'+curlist
2019
+ curpath=self.directory+'\\Characteristic_maps\\corrdem\\'+curlist
1966
2020
  os.makedirs(curpath,exist_ok=True)
1967
- dem= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basincorr.b')
2021
+ dem= WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basincorr.b')
1968
2022
 
1969
2023
  ijval = np.asarray([[curnode.i, curnode.j, curnode.demcorr[curlist]['value']] for curnode in self.nodes])
1970
2024
  dem.array[np.int32(ijval[:,0]),np.int32(ijval[:,1])]=ijval[:,2]
@@ -2012,10 +2066,10 @@ class Watershed:
2012
2066
 
2013
2067
  self.nodes=[Node_Watershed() for i in range(self.subs_array.nbnotnull)]
2014
2068
 
2015
- dem_before_corr= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.b')
2016
- dem_after_corr= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basincorr.b')
2069
+ dem_before_corr= WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.b')
2070
+ dem_after_corr= WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basincorr.b')
2017
2071
  #Tests of the existance of the delta dem
2018
- isOk,demdeltaFile = check_path(os.path.join(self.dir,'Characteristic_maps\\Drainage_basindiff.b'))
2072
+ isOk,demdeltaFile = check_path(os.path.join(self.directory,'Characteristic_maps\\Drainage_basindiff.b'))
2019
2073
  if isOk<0:
2020
2074
  logging.error("The ...dif.b file is not present! Please check the reason or launch again the hydrological preprocessing! A Null diff matrix will then be considered for the next steps.")
2021
2075
  demdelta = WolfArray(mold=dem_after_corr)
@@ -2023,76 +2077,102 @@ class Watershed:
2023
2077
  else:
2024
2078
  demdelta = WolfArray(demdeltaFile)
2025
2079
  #
2026
- slopes= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.slope',masknull=False)
2027
- reaches= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.reachs')
2028
- cnv= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.cnv')
2029
- times= WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.time')
2080
+ if (Path(self.directory) / 'Characteristic_maps' /'Drainage_basin.slope').exists():
2081
+ # If the slope file exists, read it
2082
+ slopes = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.slope', masknull=False)
2083
+ else:
2084
+ slopes = None
2085
+ logging.error(_('The slope file is not present! Please check the reason or launch again the hydrological preprocessing! A Null slope matrix will then be considered for the next steps.'))
2086
+
2087
+ if (Path(self.directory) / 'Characteristic_maps' /'Drainage_basin.reachs').exists():
2088
+ # If the reaches file exists, read it
2089
+ reaches = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.reachs')
2090
+ else:
2091
+ reaches = None
2092
+ logging.error(_('The reaches file is not present! Please check the reason or launch again the hydrological preprocessing! A Null reaches matrix will then be considered for the next steps.'))
2093
+
2094
+ if (Path(self.directory) / 'Characteristic_maps' /'Drainage_basin.cnv').exists():
2095
+ # If the cnv file exists, read it
2096
+ cnv = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.cnv')
2097
+ else:
2098
+ cnv = None
2099
+ logging.error(_('The cnv file is not present! Please check the reason or launch again the hydrological preprocessing! A Null cnv matrix will then be considered for the next steps.'))
2030
2100
 
2101
+ if (Path(self.directory) / 'Characteristic_maps' /'Drainage_basin.time').exists():
2102
+ # If the time file exists, read it
2103
+ times = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.time')
2104
+ else:
2105
+ times = None
2106
+ logging.error(_('The time file is not present! Please check the reason or launch again the hydrological preprocessing! A Null time matrix will then be considered for the next steps.'))
2031
2107
 
2032
2108
  dem_after_corr.array.mask = self.subs_array.array.mask
2033
2109
 
2034
- nb=0
2035
- for index,i_sub in tqdm(np.ndenumerate(self.subs_array.array), 'Numbering'):
2036
- if(i_sub>0):
2037
- i=int(index[0])
2038
- j=int(index[1])
2039
- self.nodesindex[i,j]=nb
2040
- nb+=1
2110
+ # Efficiently fill nodesindex using numpy where and flat indexing
2111
+ indices = np.argwhere(self.subs_array.array > 0)
2112
+ position = np.arange(len(indices))
2113
+ self.nodesindex[indices[:, 0], indices[:, 1]] = position
2041
2114
 
2042
- curnode:Node_Watershed
2043
- nb=0
2044
- for index, i_sub in tqdm(np.ndenumerate(self.subs_array.array), 'Initialization'):
2045
- if(i_sub>0):
2046
- i=int(index[0])
2047
- j=int(index[1])
2048
- x, y = self.header.get_xy_from_ij(i,j)
2049
- curnode =self.nodes[self.nodesindex[i,j]]
2050
-
2051
- curnode.i = i
2052
- curnode.j = j
2053
-
2054
- curnode.x = x
2055
- curnode.y = y
2056
-
2057
- curnode.crosssections = None
2058
- curnode.down = None
2059
-
2060
- curnode.index=nb
2061
- curnode.dem={}
2062
- curnode.dem['dem_before_corr']=dem_before_corr.array[i,j]
2063
- curnode.dem['dem_after_corr']=dem_after_corr.array[i,j]
2064
- curnode.dem['crosssection']=99999.
2065
- curnode.demdelta=demdelta.array[i,j]
2066
- curnode.slope=slopes.array[i,j]
2067
-
2068
- curnode.slopecorr={}
2069
- for curlist in LISTDEM:
2070
- curnode.slopecorr[curlist]={}
2071
- curnode.slopecorr[curlist]['parts']=[]
2072
- curnode.slopecorr[curlist]['value']=curnode.slope
2073
-
2074
- curnode.demcorr={}
2075
- for curlist in LISTDEM:
2076
- curnode.demcorr[curlist]={}
2077
- curnode.demcorr[curlist]['parts']=[]
2078
- curnode.demcorr[curlist]['value']=curnode.dem['dem_after_corr']
2079
-
2080
- curnode.sub=int(i_sub)
2081
- curnode.time=times.array[i,j]
2082
- curnode.uparea=cnv.array[i,j]
2115
+ def init_node(i, j):
2116
+ """ Initialisation d'un noeud
2117
+ """
2118
+ curnode:Node_Watershed
2119
+ x, y = self.header.get_xy_from_ij(i,j)
2120
+ curnode =self.nodes[self.nodesindex[i,j]]
2121
+
2122
+ curnode.i = i
2123
+ curnode.j = j
2124
+
2125
+ curnode.x = x
2126
+ curnode.y = y
2127
+
2128
+ curnode.crosssections = None
2129
+ curnode.down = None
2130
+
2131
+ curnode.index=self.nodesindex[i,j]
2132
+ curnode.dem={}
2133
+ curnode.dem['dem_before_corr']=dem_before_corr.array[i,j]
2134
+ curnode.dem['dem_after_corr']=dem_after_corr.array[i,j]
2135
+ curnode.dem['crosssection']=99999.
2136
+ curnode.demdelta=demdelta.array[i,j]
2137
+ curnode.slope=slopes.array[i,j] if slopes is not None else 0.0
2138
+
2139
+ curnode.slopecorr={}
2140
+ for curlist in LISTDEM:
2141
+ curnode.slopecorr[curlist]={}
2142
+ curnode.slopecorr[curlist]['parts']=[]
2143
+ curnode.slopecorr[curlist]['value']=curnode.slope
2144
+
2145
+ curnode.demcorr={}
2146
+ for curlist in LISTDEM:
2147
+ curnode.demcorr[curlist]={}
2148
+ curnode.demcorr[curlist]['parts']=[]
2149
+ curnode.demcorr[curlist]['value']=curnode.dem['dem_after_corr']
2150
+
2151
+ curnode.sub=int(self.subs_array.array[i,j])
2152
+ curnode.time=times.array[i,j] if times is not None else 0.0
2153
+ curnode.uparea=cnv.array[i,j] if cnv is not None else 0.0
2154
+
2155
+ if reaches is not None:
2083
2156
  curnode.river=not reaches.array.mask[i,j]
2084
2157
  if curnode.river:
2085
2158
  curnode.reach=int(reaches.array[i,j])
2086
- curnode.forced=False
2087
- curnode.up=[]
2088
- curnode.upriver=[]
2089
- curnode.strahler=0
2090
- curnode.reachlevel=0
2091
- nb+=1
2159
+ else:
2160
+ curnode.river=False
2161
+ curnode.reach=0
2162
+
2163
+ curnode.forced=False
2164
+
2165
+ curnode.up=[]
2166
+ curnode.upriver=[]
2167
+ curnode.strahler=0
2168
+ curnode.reachlevel=0
2169
+ # nb+=1
2170
+
2171
+ all_init = list(map(lambda p: init_node(*p), tqdm(indices, 'Initialization')))
2092
2172
 
2093
2173
  curdown:Node_Watershed
2094
2174
  #Liaison échanges forcés
2095
- incr=slopes.dx
2175
+ incr=self.header.dx
2096
2176
  for curexch in self.couplednodesij:
2097
2177
  i=int(curexch[0][0])
2098
2178
  j=int(curexch[0][1])
@@ -2135,27 +2215,49 @@ class Watershed:
2135
2215
  curdown.upriver.append(curnode)
2136
2216
  curnode.incrs=incr
2137
2217
  else:
2138
- self.outlet = curnode
2218
+ if self.outlet is None:
2219
+ self.outlet = curnode
2139
2220
 
2140
- #Rechreche de la pente dans les voisins en croix dans la topo non remaniée
2141
- for curnode in tqdm(self.nodes, 'Finding slope'):
2221
+ # Recherche de la pente dans les voisins en croix dans la topo non remaniée
2222
+ import concurrent.futures
2223
+
2224
+ def compute_sloped8(args):
2225
+ curnode, dem_before_corr, resolution = args
2142
2226
  if not curnode.forced:
2143
- i=curnode.i
2144
- j=curnode.j
2227
+ i = curnode.i
2228
+ j = curnode.j
2145
2229
 
2146
2230
  curtop = curnode.dem['dem_before_corr']
2147
2231
 
2148
- neigh = [[i-1,j], [i+1,j], [i,j-1], [i,j+1], [i-1,j-1], [i+1,j+1], [i+1,j-1], [i-1,j+1]]
2149
- diff = [dem_before_corr.array[curi,curj]-curtop if not dem_before_corr.array.mask[curi,curj] else 100000. for curi,curj in neigh ]
2232
+ neigh = [
2233
+ [i-1, j], [i+1, j], [i, j-1], [i, j+1],
2234
+ [i-1, j-1], [i+1, j+1], [i+1, j-1], [i-1, j+1]
2235
+ ]
2236
+ diff = [
2237
+ dem_before_corr.array[curi, curj] - curtop
2238
+ if not dem_before_corr.array.mask[curi, curj] else 100000.
2239
+ for curi, curj in neigh
2240
+ ]
2150
2241
  mindiff = np.min(diff)
2151
2242
 
2152
- fact=1.
2153
- if mindiff<0:
2243
+ fact = 1.
2244
+ if mindiff < 0:
2154
2245
  index = diff.index(mindiff)
2155
- if index>3:
2156
- fact=np.sqrt(2)
2246
+ if index > 3:
2247
+ fact = np.sqrt(2)
2248
+ return curnode, -mindiff / (resolution * fact)
2249
+ else:
2250
+ return curnode, 0.0
2251
+
2252
+ # Prepare arguments for multiprocessing
2253
+ args_list = [(curnode, dem_before_corr, self.resolution) for curnode in self.nodes]
2254
+
2255
+ with concurrent.futures.ProcessPoolExecutor() as executor:
2256
+ results = list(tqdm(executor.map(compute_sloped8, args_list), total=len(args_list), desc='Finding slope'))
2157
2257
 
2158
- curnode.sloped8 = -mindiff/(self.resolution*fact)
2258
+ # Assign results back to nodes
2259
+ for curnode, sloped8 in results:
2260
+ curnode.sloped8 = sloped8
2159
2261
 
2160
2262
  self.rivers=list(filter(lambda x: x.river,self.nodes))
2161
2263
  self.rivers.sort(key=lambda x: x.dem['dem_after_corr'])
@@ -2293,7 +2395,7 @@ class Watershed:
2293
2395
  demsubs = {}
2294
2396
 
2295
2397
  file_10m = os.path.join(self.dir_mnt_subpixels,'mnt10m.bin')
2296
- isOk, file_10m = check_path(file_10m, prefix=self.dir)
2398
+ isOk, file_10m = check_path(file_10m, prefix=self.directory)
2297
2399
  if isOk>=0:
2298
2400
  dem_10m=WolfArray(file_10m)
2299
2401
  demsubs["dem_10m"] = dem_10m
@@ -2301,7 +2403,7 @@ class Watershed:
2301
2403
  logging.warning(_('No 10m DEM found'))
2302
2404
 
2303
2405
  file_20m = os.path.join(self.dir_mnt_subpixels,'mnt20m.bin')
2304
- isOk, file_20m = check_path(file_20m, prefix=self.dir)
2406
+ isOk, file_20m = check_path(file_20m, prefix=self.directory)
2305
2407
  if isOk>=0:
2306
2408
  dem_20m=WolfArray(file_20m)
2307
2409
  demsubs["dem_20m"] = dem_20m
@@ -2637,7 +2739,7 @@ class Watershed:
2637
2739
  def update_times(self, wolf_time=None):
2638
2740
 
2639
2741
  if wolf_time is None:
2640
- wolf_time = WolfArray(self.dir+'\\Characteristic_maps\\Drainage_basin.time')
2742
+ wolf_time = WolfArray(self.directory+'\\Characteristic_maps\\Drainage_basin.time')
2641
2743
 
2642
2744
  for cur_node in self.nodes:
2643
2745
  cur_node.time = wolf_time[cur_node.i, cur_node.j]