wolfhece 2.2.28__py3-none-any.whl → 2.2.29__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.
- wolfhece/PyConfig.py +27 -3
- wolfhece/PyDraw.py +192 -20
- wolfhece/PyVertexvectors.py +155 -21
- wolfhece/PyWMS.py +6 -3
- wolfhece/__init__.py +27 -0
- wolfhece/acceptability/acceptability.py +25 -20
- wolfhece/acceptability/acceptability_gui.py +150 -92
- wolfhece/acceptability/func.py +169 -82
- wolfhece/apps/version.py +1 -1
- wolfhece/irm_qdf.py +71 -7
- wolfhece/lb7208_ntv2/__init__.py +0 -0
- wolfhece/lb7208_ntv2/be_ign_README.txt +36 -0
- wolfhece/lb7208_ntv2/be_ign_bd72lb72_etrs89lb08.tif +0 -0
- wolfhece/lb7208_ntv2/be_ign_hBG18.tif +0 -0
- wolfhece/mesh2d/gpu_2d.py +11 -2
- wolfhece/report/compare_arrays.py +268 -58
- wolfhece/report/simplesimgpu.py +25 -6
- wolfhece/scenario/config_manager.py +243 -7
- wolfhece/ui/wolf_multiselection_collapsiblepane.py +153 -1
- wolfhece/wolf_array.py +67 -62
- wolfhece/wolf_texture.py +4 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/METADATA +1 -1
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/RECORD +26 -22
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/WHEEL +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/top_level.txt +0 -0
wolfhece/acceptability/func.py
CHANGED
@@ -14,6 +14,7 @@ from typing import Union, Literal
|
|
14
14
|
from ..PyVertexvectors import Zones, zone, vector, wolfvertex, getIfromRGB
|
15
15
|
from ..PyTranslate import _
|
16
16
|
from ..scenario. config_manager import Config_Manager_2D_GPU
|
17
|
+
from ..eikonal import inpaint_waterlevel, inpaint_array
|
17
18
|
|
18
19
|
import subprocess
|
19
20
|
import geopandas as gpd
|
@@ -28,6 +29,7 @@ from tqdm import tqdm
|
|
28
29
|
from pyogrio import list_layers, read_dataframe
|
29
30
|
from enum import Enum
|
30
31
|
import numba as nb
|
32
|
+
import shutil
|
31
33
|
|
32
34
|
ENGINE = 'pyogrio' # or 'Fiona -- Pyogrio is faster
|
33
35
|
EXTENT = '.gpkg'
|
@@ -104,14 +106,14 @@ def empty_folder(folder):
|
|
104
106
|
fn = os.path.join(folder, files)
|
105
107
|
try:
|
106
108
|
if os.path.isfile(fn) or os.path.islink(fn):
|
107
|
-
os.unlink(fn)
|
109
|
+
os.unlink(fn)
|
108
110
|
elif os.path.isdir(fn):
|
109
|
-
shutil.rmtree(fn)
|
111
|
+
shutil.rmtree(fn)
|
110
112
|
except Exception as e:
|
111
113
|
print(f"Error when deleting file {fn}: {e}")
|
112
114
|
else:
|
113
115
|
print("The folder does not exist.")
|
114
|
-
|
116
|
+
|
115
117
|
class Accept_Manager():
|
116
118
|
"""
|
117
119
|
Structure to store the directories and names of the files.
|
@@ -207,6 +209,7 @@ class Accept_Manager():
|
|
207
209
|
self.IN_CSV = self.IN_DIR / "CSVs"
|
208
210
|
self.IN_WATER_DEPTH = self.IN_DIR / "WATER_DEPTH"
|
209
211
|
self.IN_EPU_STATIONS= self.IN_DIR / "EPU_STATIONS_NEW"
|
212
|
+
self.IN_SA_INTERP = None
|
210
213
|
|
211
214
|
self.ORIGINAL_GDB = self.IN_DATABASE / self._original_gdb
|
212
215
|
self.CAPA_WALLOON = self.IN_DATABASE / self._capa_walloon
|
@@ -410,7 +413,7 @@ class Accept_Manager():
|
|
410
413
|
if Study_area in self.get_list_studyareas(with_suffix=True) or Study_area+".shp" in self.get_list_studyareas(with_suffix=True):
|
411
414
|
self._study_area = Path(Study_area)
|
412
415
|
else:
|
413
|
-
logging.error("The study area does not exist in the study area directory")
|
416
|
+
logging.error(_("The study area does not exist in the study area directory"))
|
414
417
|
|
415
418
|
self.create_paths()
|
416
419
|
|
@@ -422,7 +425,7 @@ class Accept_Manager():
|
|
422
425
|
self.check_temporary()
|
423
426
|
self.check_outputs()
|
424
427
|
else:
|
425
|
-
logging.error("The scenario does not exist in the water depth directory")
|
428
|
+
logging.error(_("The scenario does not exist in the water depth directory"))
|
426
429
|
|
427
430
|
def get_files_in_rm_buildings(self) -> list[Path]:
|
428
431
|
return [Path(a) for a in glob.glob(str(self.IN_RM_BUILD_DIR / ("*"+ EXTENT)))]
|
@@ -471,7 +474,7 @@ class Accept_Manager():
|
|
471
474
|
if self.IN_SA_INTERP.exists() :
|
472
475
|
files = [Path(a) for a in glob.glob(str(self.IN_SA_INTERP / "*.tif"))]
|
473
476
|
else :
|
474
|
-
logging.error("No such scenario")
|
477
|
+
logging.error(_("No such scenario"))
|
475
478
|
return files
|
476
479
|
|
477
480
|
def get_sims_files_for_baseline(self) -> list[Path]:
|
@@ -481,7 +484,7 @@ class Accept_Manager():
|
|
481
484
|
track = Path(str(self.IN_SA_BASE_INTERP / "*.tif"))
|
482
485
|
files = [Path(a) for a in glob.glob(str(track))]
|
483
486
|
else :
|
484
|
-
logging.error("No _baseline interpolated free surfaces files")
|
487
|
+
logging.error(_("No _baseline interpolated free surfaces files"))
|
485
488
|
|
486
489
|
return files
|
487
490
|
|
@@ -576,7 +579,7 @@ class Accept_Manager():
|
|
576
579
|
# List files in directory
|
577
580
|
sims = self.get_sims_files_for_scenario()
|
578
581
|
sims_modif = [
|
579
|
-
os.path.join(os.path.dirname(path), os.path.basename(path).replace("Q", "T"))
|
582
|
+
os.path.join(os.path.dirname(path), os.path.basename(path).replace("Q", "T").split('_')[0])
|
580
583
|
for path in sims
|
581
584
|
]
|
582
585
|
|
@@ -590,7 +593,7 @@ class Accept_Manager():
|
|
590
593
|
idx_h = [Path(cursim).name.find(".tif") for cursim in sims_modif]
|
591
594
|
|
592
595
|
# create the list of return periods -- only the numeric part
|
593
|
-
sims = [int(Path(cursim).name[idx_T[i]+1:
|
596
|
+
sims = [int(Path(cursim).name[idx_T[i]+1:]) for i, cursim in enumerate(sims_modif)]
|
594
597
|
return sorted(sims)
|
595
598
|
|
596
599
|
def get_modifiedrasters(self):
|
@@ -653,51 +656,51 @@ class Accept_Manager():
|
|
653
656
|
|
654
657
|
err = False
|
655
658
|
if not self.IN_DATABASE.exists():
|
656
|
-
logging.error("INPUT : The database directory does not exist")
|
659
|
+
logging.error(_("INPUT : The database directory does not exist"))
|
657
660
|
err = True
|
658
661
|
|
659
662
|
if not self.IN_STUDY_AREA.exists():
|
660
|
-
logging.error("INPUT : The study area directory does not exist")
|
663
|
+
logging.error(_("INPUT : The study area directory does not exist"))
|
661
664
|
err = True
|
662
665
|
|
663
666
|
if not self.IN_CSV.exists():
|
664
|
-
logging.error("INPUT : The CSV directory does not exist")
|
667
|
+
logging.error(_("INPUT : The CSV directory does not exist"))
|
665
668
|
err = True
|
666
669
|
|
667
670
|
if not self.IN_WATER_DEPTH.exists():
|
668
|
-
logging.error("INPUT : The water depth directory does not exist")
|
671
|
+
logging.error(_("INPUT : The water depth directory does not exist"))
|
669
672
|
err = True
|
670
673
|
|
671
674
|
if not self.IN_EPU_STATIONS.exists():
|
672
|
-
logging.error("INPUT : The EPU stations directory does not exist")
|
675
|
+
logging.error(_("INPUT : The EPU stations directory does not exist"))
|
673
676
|
err = True
|
674
677
|
|
675
678
|
if self.Study_area is not None:
|
676
679
|
if not self.SA.exists():
|
677
|
-
logging.error("INPUT : The study area file does not exist")
|
680
|
+
logging.error(_("INPUT : The study area file does not exist"))
|
678
681
|
err = True
|
679
682
|
|
680
683
|
if not self.ORIGINAL_GDB.exists():
|
681
|
-
logging.error("INPUT : The original gdb file does not exist - Please pull it from the SPW-ARNE")
|
684
|
+
logging.error(_("INPUT : The original gdb file does not exist - Please pull it from the SPW-ARNE"))
|
682
685
|
err = True
|
683
686
|
|
684
687
|
if not self.CAPA_WALLOON.exists():
|
685
|
-
logging.error("INPUT : The Cadastre Walloon file does not exist - Please pull it from the SPW")
|
688
|
+
logging.error(_("INPUT : The Cadastre Walloon file does not exist - Please pull it from the SPW"))
|
686
689
|
err = True
|
687
690
|
|
688
691
|
if not self.PICC_WALLOON.exists():
|
689
|
-
logging.error("INPUT : The PICC Walloon file does not exist - Please pull it from the SPW website")
|
692
|
+
logging.error(_("INPUT : The PICC Walloon file does not exist - Please pull it from the SPW website"))
|
690
693
|
err = True
|
691
694
|
|
692
695
|
if not self.CE_IGN_TOP10V.exists():
|
693
|
-
logging.error("INPUT : The CE IGN top10v file does not exist - Please pull it from the IGN")
|
696
|
+
logging.error(_("INPUT : The CE IGN top10v file does not exist - Please pull it from the IGN"))
|
694
697
|
err = True
|
695
698
|
|
696
699
|
if self.scenario is None:
|
697
700
|
logging.debug("The scenario has not been defined")
|
698
701
|
else:
|
699
702
|
if not self.IN_SCEN_DIR.exists():
|
700
|
-
logging.error("The wd scenario directory does not exist")
|
703
|
+
logging.error(_("The wd scenario directory does not exist"))
|
701
704
|
err = True
|
702
705
|
|
703
706
|
return not err
|
@@ -756,15 +759,15 @@ class Accept_Manager():
|
|
756
759
|
""" Check if the necessary files are present before the database creation"""
|
757
760
|
|
758
761
|
if not self.is_valid_inputs:
|
759
|
-
logging.error("Theere are missing input directories - Please check carefully the input directories and the logs")
|
762
|
+
logging.error(_("Theere are missing input directories - Please check carefully the input directories and the logs"))
|
760
763
|
return False
|
761
764
|
|
762
765
|
if not self.is_valid_study_area:
|
763
|
-
logging.error("The study area file does not exist - Please create it")
|
766
|
+
logging.error(_("The study area file does not exist - Please create it"))
|
764
767
|
return False
|
765
768
|
|
766
769
|
if not self.is_valid_vulnerability_csv:
|
767
|
-
logging.error("The vulnerability CSV file does not exist - Please create it")
|
770
|
+
logging.error(_("The vulnerability CSV file does not exist - Please create it"))
|
768
771
|
return False
|
769
772
|
|
770
773
|
return True
|
@@ -772,11 +775,11 @@ class Accept_Manager():
|
|
772
775
|
def check_before_rasterize(self) -> bool:
|
773
776
|
|
774
777
|
if not self.TMP_CODEVULNE.exists():
|
775
|
-
logging.error("The final database with vulnerability levels does not exist")
|
778
|
+
logging.error(_("The final database with vulnerability levels does not exist"))
|
776
779
|
return False
|
777
780
|
|
778
781
|
if not self.TMP_WMODIF.exists():
|
779
|
-
logging.error("The vector data with modifications does not exist")
|
782
|
+
logging.error(_("The vector data with modifications does not exist"))
|
780
783
|
return False
|
781
784
|
|
782
785
|
return True
|
@@ -784,19 +787,19 @@ class Accept_Manager():
|
|
784
787
|
def check_before_vulnerability(self) -> bool:
|
785
788
|
|
786
789
|
if self.SA is None:
|
787
|
-
logging.error("The area of interest does not exist")
|
790
|
+
logging.error(_("The area of interest does not exist"))
|
788
791
|
return False
|
789
792
|
|
790
793
|
if self.IN_WATER_DEPTH is None:
|
791
|
-
logging.error("The water depth directory does not exist")
|
794
|
+
logging.error(_("The water depth directory does not exist"))
|
792
795
|
return False
|
793
796
|
|
794
797
|
if self.IN_SCEN_DIR is None:
|
795
|
-
logging.error("The wd scenario directory does not exist in the water depth directory")
|
798
|
+
logging.error(_("The wd scenario directory does not exist in the water depth directory"))
|
796
799
|
return False
|
797
800
|
|
798
801
|
if self.SA_MASKED_RIVER is None:
|
799
|
-
logging.error("The IGN raster does not exist")
|
802
|
+
logging.error(_("The IGN raster does not exist"))
|
800
803
|
return False
|
801
804
|
|
802
805
|
return True
|
@@ -804,11 +807,11 @@ class Accept_Manager():
|
|
804
807
|
def check_vuln_code_sa(self) -> bool:
|
805
808
|
|
806
809
|
if not self.SA_VULN.exists():#SA_VULN
|
807
|
-
logging.error("The vulnerability raster file does not exist")
|
810
|
+
logging.error(_("The vulnerability raster file does not exist"))
|
808
811
|
return False
|
809
812
|
|
810
813
|
if not self.SA_CODE.exists():
|
811
|
-
logging.error("The vulnerability code raster file does not exist")
|
814
|
+
logging.error(_("The vulnerability code raster file does not exist"))
|
812
815
|
return False
|
813
816
|
|
814
817
|
return True
|
@@ -816,11 +819,11 @@ class Accept_Manager():
|
|
816
819
|
def check_vuln_code_scenario(self) -> bool:
|
817
820
|
|
818
821
|
if not self.TMP_VULN.exists():
|
819
|
-
logging.error("The vulnerability raster file does not exist")
|
822
|
+
logging.error(_("The vulnerability raster file does not exist"))
|
820
823
|
return False
|
821
824
|
|
822
825
|
if not self.TMP_CODE.exists():
|
823
|
-
logging.error("The vulnerability code raster file does not exist")
|
826
|
+
logging.error(_("The vulnerability code raster file does not exist"))
|
824
827
|
return False
|
825
828
|
|
826
829
|
return True
|
@@ -913,15 +916,15 @@ class Accept_Manager():
|
|
913
916
|
vuln = self.get_files_in_rasters_vulne()
|
914
917
|
|
915
918
|
if len(code) == 0:
|
916
|
-
logging.error("The code rasters do not exist")
|
919
|
+
logging.error(_("The code rasters do not exist"))
|
917
920
|
return False
|
918
921
|
|
919
922
|
if len(vuln) == 0:
|
920
|
-
logging.error("The vulnerability rasters do not exist")
|
923
|
+
logging.error(_("The vulnerability rasters do not exist"))
|
921
924
|
return False
|
922
925
|
|
923
926
|
if len(code) != len(vuln):
|
924
|
-
logging.error("The number of code and vulnerability rasters do not match")
|
927
|
+
logging.error(_("The number of code and vulnerability rasters do not match"))
|
925
928
|
return False
|
926
929
|
|
927
930
|
# we take a reference raster
|
@@ -941,15 +944,15 @@ class Accept_Manager():
|
|
941
944
|
col_cur, row_cur = band_cur.XSize, band_cur.YSize
|
942
945
|
|
943
946
|
if geo_ref != geo_cur:
|
944
|
-
logging.error("The geotransforms do not match {}".format(cur))
|
947
|
+
logging.error(_("The geotransforms do not match {}".format(cur)))
|
945
948
|
diff.append(cur)
|
946
949
|
|
947
950
|
if proj_ref != proj_cur:
|
948
|
-
logging.error("The projections do not match {}".format(cur))
|
951
|
+
logging.error(_("The projections do not match {}".format(cur)))
|
949
952
|
diff.append(cur)
|
950
953
|
|
951
954
|
if col_ref != col_cur or row_ref != row_cur:
|
952
|
-
logging.error("The dimensions do not match {}".format(cur))
|
955
|
+
logging.error(_("The dimensions do not match {}".format(cur)))
|
953
956
|
diff.append(cur)
|
954
957
|
|
955
958
|
return diff
|
@@ -1052,77 +1055,157 @@ class Accept_Manager():
|
|
1052
1055
|
trace = None
|
1053
1056
|
if os.path.exists(self.OUT_MASKED_RIVER):
|
1054
1057
|
trace = self.OUT_MASKED_RIVER
|
1055
|
-
|
1058
|
+
elif os.path.exists(self.OUT_MASKED_RIVER_S):
|
1056
1059
|
trace = self.OUT_MASKED_RIVER_S
|
1057
1060
|
else :
|
1058
|
-
logging.error("No Masked_River_extent files. Please provide them.")
|
1061
|
+
logging.error(_("No Masked_River_extent files. Please provide them."))
|
1059
1062
|
return trace
|
1060
|
-
|
1063
|
+
|
1061
1064
|
# Interpolation
|
1062
|
-
#
|
1063
|
-
|
1065
|
+
# -------------
|
1066
|
+
|
1067
|
+
def batch_creation_and_interpolation_fotran_holes(self, checked_paths:list[Path], iftest:bool) -> tuple[bool, list[str]]:
|
1064
1068
|
"""Creates a batch file to launch holes.exe from the selected simulations and launches it.
|
1065
|
-
|
1066
|
-
|
1069
|
+
|
1070
|
+
- Every files in EXTRACTED_LAST_STEP are interpolated for tests (iftest==True).
|
1071
|
+
- Only the check simulations of the windows are interpolated for the GUI (iftest!=True).
|
1072
|
+
|
1073
|
+
:param checked_paths: list of paths to the checked simulations
|
1074
|
+
:param iftest: boolean to indicate if the function is called from the tests or not
|
1075
|
+
"""
|
1076
|
+
|
1067
1077
|
path_LastSteps = Path(self.IN_SA_EXTRACTED)
|
1068
|
-
|
1069
|
-
|
1078
|
+
|
1079
|
+
# Identifying the DEM and its mask
|
1080
|
+
C = None # DEM mask
|
1081
|
+
D = None # DEM
|
1070
1082
|
for file in os.listdir(Path(self.IN_SA_DEM)):
|
1071
1083
|
file_path = Path(self.IN_SA_DEM) / file
|
1072
1084
|
if file_path.is_file() and file.startswith("MNT_") and file_path.suffix == ".bin":
|
1073
1085
|
if "mask" not in file:
|
1074
1086
|
D = file_path
|
1075
1087
|
else:
|
1076
|
-
C = file_path
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1088
|
+
C = file_path
|
1089
|
+
|
1090
|
+
if D is None:
|
1091
|
+
return logging.error(_("DEM (.bin) not found in DEM_FILES. The file must begins by 'MNT_' and CANNOT include the word 'mask'"))
|
1092
|
+
|
1093
|
+
if C is None:
|
1094
|
+
return logging.error(_("DEM mask (.bin) not found in DEM_FILES. The file must begins by 'MNT_' and MUST include the word 'mask'"))
|
1095
|
+
|
1083
1096
|
path_Interp = Path(self.IN_SA_INTERP)
|
1084
1097
|
path_bat_file = os.path.join(self.IN_SCEN_DIR, "process_files.bat")
|
1085
|
-
|
1098
|
+
|
1086
1099
|
if os.path.exists(path_bat_file):
|
1087
1100
|
logging.info(f"The file {path_bat_file} already exists and will be replaced.")
|
1088
1101
|
os.remove(path_bat_file)
|
1089
|
-
|
1102
|
+
|
1103
|
+
path_code = os.path.join(self.IN_WATER_DEPTH, "holes.exe")
|
1104
|
+
|
1090
1105
|
A, B = [], []
|
1091
|
-
if iftest
|
1092
|
-
#no checked box in the tests
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
B = [os.path.join(path_Interp, os.path.splitext(os.path.basename(f))[0]) for f in A]
|
1097
|
-
|
1098
|
-
else :
|
1106
|
+
if iftest:
|
1107
|
+
# no checked box in the tests
|
1108
|
+
A = [path_LastSteps / f for f in os.listdir(path_LastSteps) if f.endswith('.bin') and not f.endswith('.bin.txt')]
|
1109
|
+
|
1110
|
+
else :
|
1099
1111
|
for path in checked_paths:
|
1100
|
-
parts = path.name.split("sim_")
|
1101
|
-
A.extend([
|
1102
|
-
|
1112
|
+
parts = path.name.split("sim_")
|
1113
|
+
A.extend([path_LastSteps / g for g in os.listdir(path_LastSteps) if g.endswith(f"{parts[1]}.bin")])
|
1114
|
+
|
1115
|
+
B = [path_Interp / f.stem for f in A]
|
1116
|
+
|
1103
1117
|
if not A or not B or not C or not D:
|
1104
|
-
return logging.error("Missing files.")
|
1118
|
+
return logging.error(_("Missing files."))
|
1119
|
+
|
1105
1120
|
with open(path_bat_file, "w") as bat_file:
|
1106
1121
|
for a, b in zip(A, B):
|
1107
1122
|
line = f'"{path_code}" filling in="{a}" out="{b}" mask="{C}" dem="{D} avoid_last=1"\n'
|
1108
1123
|
bat_file.write(line)
|
1109
|
-
|
1124
|
+
|
1110
1125
|
empty_folder(self.IN_SA_INTERP)
|
1111
|
-
path_bat_file =
|
1126
|
+
path_bat_file = self.IN_SCEN_DIR / "process_files.bat"
|
1112
1127
|
subprocess.run([path_bat_file], check=True)
|
1113
|
-
|
1128
|
+
|
1114
1129
|
renamed_files = []
|
1115
|
-
path_fichier=self.IN_SA_INTERP
|
1130
|
+
path_fichier = self.IN_SA_INTERP
|
1116
1131
|
for file in path_fichier.glob("*.tif"):
|
1117
|
-
if "_h" in file.name:
|
1132
|
+
if "_h" in file.name:
|
1118
1133
|
new_name = file.stem.split("_h")[0].replace(".bin", "") + ".tif"
|
1119
1134
|
file.rename(file.with_name(new_name))
|
1120
|
-
renamed_files.append(new_name)
|
1135
|
+
renamed_files.append(new_name)
|
1136
|
+
|
1121
1137
|
#deleting the other
|
1122
1138
|
for file in path_fichier.glob("*.tif"):
|
1123
1139
|
if "_combl" in file.name or file.name not in renamed_files:
|
1124
1140
|
file.unlink()
|
1125
|
-
|
1141
|
+
|
1142
|
+
return True, renamed_files
|
1143
|
+
|
1144
|
+
def batch_creation_and_interpolation_python_eikonal(self, checked_paths:list[Path], iftest:bool) -> tuple[bool, list[str]]:
|
1145
|
+
"""Creates a batch file to launch holes.exe from the selected simulations and launches it.
|
1146
|
+
|
1147
|
+
- Every files in EXTRACTED_LAST_STEP are interpolated for tests (iftest==True).
|
1148
|
+
- Only the check simulations of the windows are interpolated for the GUI (iftest!=True).
|
1149
|
+
|
1150
|
+
:param checked_paths: list of paths to the checked simulations
|
1151
|
+
:param iftest: boolean to indicate if the function is called from the tests or not
|
1152
|
+
"""
|
1153
|
+
|
1154
|
+
path_LastSteps = Path(self.IN_SA_EXTRACTED)
|
1155
|
+
|
1156
|
+
# Identifying the DEM and its mask
|
1157
|
+
C = None # DEM mask
|
1158
|
+
D = None # DEM
|
1159
|
+
for file in os.listdir(Path(self.IN_SA_DEM)):
|
1160
|
+
file_path = Path(self.IN_SA_DEM) / file
|
1161
|
+
if file_path.is_file() and file.startswith("MNT_") and file_path.suffix == ".bin":
|
1162
|
+
if "mask" not in file:
|
1163
|
+
D = file_path
|
1164
|
+
else:
|
1165
|
+
C = file_path
|
1166
|
+
|
1167
|
+
if D is None:
|
1168
|
+
return logging.error(_("DTM (.bin) not found in DTM_FILES. The file must begins by 'MNT_' and CANNOT include the word 'mask'"))
|
1169
|
+
|
1170
|
+
if C is None:
|
1171
|
+
return logging.error(_("DEM mask (.bin) not found in DEM_FILES. The file must begins by 'MNT_' and MUST include the word 'mask'"))
|
1172
|
+
|
1173
|
+
path_Interp = Path(self.IN_SA_INTERP)
|
1174
|
+
path_bat_file = os.path.join(self.IN_SCEN_DIR, "process_files.bat")
|
1175
|
+
|
1176
|
+
if os.path.exists(path_bat_file):
|
1177
|
+
logging.info(f"The file {path_bat_file} already exists and will be replaced.")
|
1178
|
+
os.remove(path_bat_file)
|
1179
|
+
|
1180
|
+
A, B = [], []
|
1181
|
+
if iftest:
|
1182
|
+
# no checked box in the tests
|
1183
|
+
A = [path_LastSteps / f for f in os.listdir(path_LastSteps) if f.endswith('.bin') and not f.endswith('.bin.txt')]
|
1184
|
+
|
1185
|
+
else :
|
1186
|
+
for path in checked_paths:
|
1187
|
+
parts = path.name.split("sim_")
|
1188
|
+
A.extend([path_LastSteps / g for g in os.listdir(path_LastSteps) if g.endswith(f"{parts[1]}.bin")])
|
1189
|
+
|
1190
|
+
B = [path_Interp / f.stem for f in A]
|
1191
|
+
|
1192
|
+
if not A or not B or not C or not D:
|
1193
|
+
return logging.error(_("Missing files."))
|
1194
|
+
|
1195
|
+
renamed_files = []
|
1196
|
+
for a, b in zip(A, B):
|
1197
|
+
wa_a = WolfArray(a)
|
1198
|
+
wa_c = WolfArray(C)
|
1199
|
+
wa_d = WolfArray(D)
|
1200
|
+
_t, _d, wh = inpaint_array(data = wa_a.array,
|
1201
|
+
where_compute = wa_c.array.data != wa_c.array.data[0,0],
|
1202
|
+
test = wa_d.array.data,
|
1203
|
+
ignore_last_patches= 1)
|
1204
|
+
|
1205
|
+
new_name = b.with_suffix(".tif")
|
1206
|
+
wa_a.write_all(new_name)
|
1207
|
+
renamed_files.append(new_name.name)
|
1208
|
+
|
1126
1209
|
return True, renamed_files
|
1127
1210
|
|
1128
1211
|
def clip_layer(layer:str,
|
@@ -1171,7 +1254,7 @@ def clip_layer(layer:str,
|
|
1171
1254
|
|
1172
1255
|
df.to_file(str(output_dir / (layer+EXTENT)), mode='w', engine=ENGINE)
|
1173
1256
|
except Exception as e:
|
1174
|
-
logging.error("Error while saving the clipped " + str(layer) + " to file")
|
1257
|
+
logging.error(_("Error while saving the clipped " + str(layer) + " to file"))
|
1175
1258
|
logging.error(e)
|
1176
1259
|
pass
|
1177
1260
|
|
@@ -1208,7 +1291,7 @@ def data_modification(layer:str,
|
|
1208
1291
|
|
1209
1292
|
# Read the data
|
1210
1293
|
df:gpd.GeoDataFrame = gpd.read_file(input_file, engine=ENGINE)
|
1211
|
-
nblines,
|
1294
|
+
nblines, notused = df.shape
|
1212
1295
|
|
1213
1296
|
if nblines>0:
|
1214
1297
|
op = manager.get_operand(input_file)
|
@@ -1333,7 +1416,7 @@ def data_modification(layer:str,
|
|
1333
1416
|
if manager.is_polygons(set(df.geom_type)):
|
1334
1417
|
df.to_file(output_file, engine=ENGINE)
|
1335
1418
|
else:
|
1336
|
-
logging.error("The layer does not contains polygons - " + str(layer))
|
1419
|
+
logging.error(_("The layer does not contains polygons - " + str(layer)))
|
1337
1420
|
else:
|
1338
1421
|
raise ValueError(f"The operand {op} is not recognized")
|
1339
1422
|
|
@@ -1341,7 +1424,7 @@ def data_modification(layer:str,
|
|
1341
1424
|
else:
|
1342
1425
|
# Normally, phase 1 does not create empty files
|
1343
1426
|
# But it is better to check... ;-)
|
1344
|
-
logging.error("skipped" + str(layer) + "due to no polygon in the study area")
|
1427
|
+
logging.error(_("skipped" + str(layer) + "due to no polygon in the study area"))
|
1345
1428
|
return "skipped" + str(layer) + "due to no polygon in the study area"
|
1346
1429
|
|
1347
1430
|
def compute_vulnerability(manager:Accept_Manager):
|
@@ -1636,6 +1719,10 @@ def compute_acceptability(manager:Accept_Manager,
|
|
1636
1719
|
|
1637
1720
|
points_accept = pd.read_csv(manager.POINTS_CSV)
|
1638
1721
|
|
1722
|
+
if interval not in points_accept["Interval"]:
|
1723
|
+
logging.error(_("The return period {} is not in the intermediate.csv file -- Please update it").format(interval))
|
1724
|
+
return None
|
1725
|
+
|
1639
1726
|
points_accept = points_accept[points_accept["Interval"]==interval] #les wd vs Ti matrices
|
1640
1727
|
points_accept = points_accept.reset_index()
|
1641
1728
|
|
@@ -1697,7 +1784,7 @@ def shp_to_raster(vector_fn:str | Path, raster_fn:str | Path, pixel_size:float =
|
|
1697
1784
|
raster_path = Path(raster_fn)
|
1698
1785
|
|
1699
1786
|
if not vector_path.exists():
|
1700
|
-
logging.error(f"The vector file {vector_path} does not exist")
|
1787
|
+
logging.error(_(f"The vector file {vector_path} does not exist"))
|
1701
1788
|
return
|
1702
1789
|
|
1703
1790
|
if raster_path.exists():
|
@@ -1807,7 +1894,7 @@ def vector_to_raster(layer:str,
|
|
1807
1894
|
# Open the data sources and read the extents
|
1808
1895
|
source_ds:ogr.DataSource = ogr.Open(vector_input)
|
1809
1896
|
if source_ds is None:
|
1810
|
-
logging.error(f"Could not open the data source {layer}")
|
1897
|
+
logging.error(_(f"Could not open the data source {layer}"))
|
1811
1898
|
return
|
1812
1899
|
source_layer = source_ds.GetLayer()
|
1813
1900
|
|
wolfhece/apps/version.py
CHANGED
wolfhece/irm_qdf.py
CHANGED
@@ -9,17 +9,22 @@ copying or distribution of this file, via any medium, is strictly prohibited.
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
#Code INS des communes belges
|
12
|
-
import
|
12
|
+
import re
|
13
13
|
from os import path, mkdir
|
14
14
|
from pathlib import Path
|
15
15
|
from time import sleep
|
16
|
+
from typing import Literal, Union
|
17
|
+
import logging
|
18
|
+
|
19
|
+
from tqdm import tqdm
|
16
20
|
import pandas as pd
|
17
21
|
import matplotlib.pyplot as plt
|
18
22
|
from scipy.optimize import minimize,curve_fit
|
19
23
|
from scipy.stats import gumbel_r,genextreme
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
import numpy as np
|
25
|
+
|
26
|
+
# We have tried pymupdf but its license is AGPL so it's more or less a no-go.
|
27
|
+
import pdfplumber
|
23
28
|
|
24
29
|
from .ins import Localities
|
25
30
|
from .PyTranslate import _
|
@@ -749,6 +754,12 @@ class QDF_Belgium():
|
|
749
754
|
return None
|
750
755
|
|
751
756
|
|
757
|
+
TRANSLATION_HEADER = {'année': 'year', 'janv.': 'January', 'févr.': 'February', 'mars': 'March',
|
758
|
+
'avr.': 'April', 'mai': 'May', 'juin': 'June',
|
759
|
+
'juil.': 'July', 'août': 'August', 'sept.': 'September',
|
760
|
+
'oct.': 'October', 'nov.': 'November', 'déc.': 'December'}
|
761
|
+
RE_REFERENCE = re.compile(r"\([0-9]+\)")
|
762
|
+
|
752
763
|
class Climate_IRM():
|
753
764
|
|
754
765
|
def __init__(self, store_path= 'irm', ins:Literal['2018', '2019', '2025', 2018, 2019, 2025] = 2018) -> None:
|
@@ -761,7 +772,7 @@ class Climate_IRM():
|
|
761
772
|
return self._climate_data[key]
|
762
773
|
|
763
774
|
@classmethod
|
764
|
-
def importfromwebsite(cls, store_path= 'irm', verbose:bool= False, waitingtime:float= .01, ins:Literal['2018', '2019', '2025', 2018, 2019, 2025] = 2018, ins_code: int = None):
|
775
|
+
def importfromwebsite(cls, store_path= 'irm', verbose:bool= False, waitingtime:float= .01, ins:Literal['2018', '2019', '2025', 2018, 2019, 2025] = 2018, ins_code: int = None, convert=False):
|
765
776
|
""" Import Excel files for one or all municipalities from the IRM website
|
766
777
|
|
767
778
|
:param store_path: Where to store the downloaded data. Directory will be created if it doesn't exists.
|
@@ -775,6 +786,7 @@ class Climate_IRM():
|
|
775
786
|
|
776
787
|
:param ins: The year of the INS codes to use.
|
777
788
|
:param code: Restricts the data download to a specific NIS code. `None` means full download.
|
789
|
+
:param convert: Converts the downloaded PDF to Excel files.
|
778
790
|
"""
|
779
791
|
import requests
|
780
792
|
|
@@ -800,9 +812,14 @@ class Climate_IRM():
|
|
800
812
|
if ins_code is not None and not path.exists(store_path):
|
801
813
|
mkdir(store_path)
|
802
814
|
|
803
|
-
|
815
|
+
pdf_file = path.join(store_path,str(myins)+".pdf")
|
816
|
+
file=open(pdf_file, 'wb')
|
804
817
|
file.write(response.content)
|
805
818
|
file.close()
|
819
|
+
|
820
|
+
if convert:
|
821
|
+
cls._convert_irm_file(pdf_file)
|
822
|
+
|
806
823
|
if verbose:
|
807
824
|
if callable(verbose):
|
808
825
|
verbose(key/len(codes_to_load))
|
@@ -812,4 +829,51 @@ class Climate_IRM():
|
|
812
829
|
#logging.error(response.content)
|
813
830
|
logging.error(f"Failed to load IRM data: {url} --> {response}")
|
814
831
|
|
815
|
-
|
832
|
+
if len(codes_to_load) >= 2:
|
833
|
+
sleep(waitingtime)
|
834
|
+
|
835
|
+
@classmethod
|
836
|
+
def _scrap_table(cls, t):
|
837
|
+
"""
|
838
|
+
Helper method to transform a table represented as a list of list to a
|
839
|
+
pandas DataFrame.
|
840
|
+
"""
|
841
|
+
|
842
|
+
def fix_cid(strings: list[str]):
|
843
|
+
# The CID thing is a known issue:
|
844
|
+
# https://github.com/euske/pdfminer/issues/122
|
845
|
+
return [s.replace('(cid:176)C ', '°C').replace('¢', "'") for s in strings]
|
846
|
+
|
847
|
+
nt = []
|
848
|
+
row_headers = []
|
849
|
+
for rndx in range(1, len(t)):
|
850
|
+
# In the row header, we remove the "references" like "(1)".
|
851
|
+
row_headers.append( RE_REFERENCE.sub("", t[rndx][0]) )
|
852
|
+
|
853
|
+
# The PDFs use different "minus" glyph instead of an ASCII one,
|
854
|
+
# let's fix it.
|
855
|
+
nt.append( list(map(lambda s:float(s.replace("−","-")), t[rndx][1:])))
|
856
|
+
|
857
|
+
columns_headers = map(TRANSLATION_HEADER.get, t[0][1:])
|
858
|
+
df = pd.DataFrame(nt, columns=fix_cid(columns_headers), index=fix_cid(row_headers))
|
859
|
+
return df
|
860
|
+
|
861
|
+
@classmethod
|
862
|
+
def _convert_irm_file(cls, pdf_file: Union[str, Path]):
|
863
|
+
"""
|
864
|
+
Scrap a PDF from IRM into two tables in a single Excel file with two
|
865
|
+
sheets.
|
866
|
+
"""
|
867
|
+
pdf_file = Path(pdf_file)
|
868
|
+
with pdfplumber.open(pdf_file) as pdf:
|
869
|
+
|
870
|
+
# Rain data
|
871
|
+
df = cls._scrap_table(pdf.pages[1].extract_table())
|
872
|
+
|
873
|
+
# Sun data
|
874
|
+
df_sun = cls._scrap_table(pdf.pages[4].extract_table())
|
875
|
+
|
876
|
+
dest_file = pdf_file.with_suffix('.xlsx')
|
877
|
+
with pd.ExcelWriter(dest_file) as writer: # doctest: +SKIP
|
878
|
+
df.to_excel(writer, sheet_name='Rain')
|
879
|
+
df_sun.to_excel(writer, sheet_name='Sun')
|
File without changes
|