wolfhece 2.1.25__py3-none-any.whl → 2.1.28__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.
@@ -7,6 +7,42 @@ import glob
7
7
  from pathlib import Path
8
8
  import logging
9
9
  from tqdm import tqdm
10
+ from pyogrio import list_layers, read_dataframe
11
+ from enum import Enum
12
+ import numba as nb
13
+
14
+ ENGINE = 'pyogrio' # or 'Fiona -- Pyogrio is faster
15
+ EXTENT = '.gpkg'
16
+ class Modif_Type(Enum):
17
+ """
18
+ Enum class for the type of modification
19
+ """
20
+
21
+ WALOUS = 'Walous layers changed to PICC buidings'
22
+ POINT2POLY_EPURATION = 'Change BDREF based on AJOUT_PDET sent by Perrine (SPI)'
23
+ POINT2POLY_PICC = 'Convert the points to polygons based on PICC'
24
+ POINT2POLY_CAPAPICC = 'Convert the points to polygons based on PICC and CaPa'
25
+ INHABITED = 'Select only inhabited buildings'
26
+ ROAD = 'Create a buffer around the roads'
27
+ COPY = 'Copy the data'
28
+
29
+ class Vulnerability_csv():
30
+
31
+ def __init__(self, file:Path) -> None:
32
+ self.file = file
33
+ self.data = pd.read_csv(file, sep=",", encoding='latin-1')
34
+
35
+ def get_layers(self) -> list:
36
+ return [a[1] for a in self.data["Path"].str.split('/')]
37
+
38
+ def get_vulnerability_level(self, layer:str) -> str:
39
+ idx = self.get_layers().index(layer)
40
+ return self.data.iloc[idx]["Vulne"]
41
+
42
+ def get_vulnerability_code(self, layer:str) -> str:
43
+ idx = self.get_layers().index(layer)
44
+ return self.data.iloc[idx]["Code"]
45
+
10
46
 
11
47
  def get_data_type(fname:Path):
12
48
 
@@ -97,6 +133,10 @@ class Accept_Manager():
97
133
  CaPa_Walloon:str = 'Cadastre_Walloon.gpkg',
98
134
  PICC_Walloon:str = 'PICC_vDIFF.gdb',
99
135
  CE_IGN_top10v:str = 'CE_IGN_TOP10V/CE_IGN_TOP10V.shp',
136
+ EPU_Stations:str = 'AJOUT_PDET_EPU_DG03_STATIONS.shp',
137
+ Ponderation_csv:str = 'Ponderation.csv',
138
+ Vulnerability_csv:str = 'Vulnerability.csv',
139
+ Intermediate_csv:str = 'Intermediate.csv'
100
140
  ) -> None:
101
141
 
102
142
  self.old_dir:Path = Path(os.getcwd())
@@ -123,39 +163,54 @@ class Accept_Manager():
123
163
  self.IN_STUDY_AREA = self.IN_DIR / "STUDY_AREA"
124
164
  self.IN_CSV = self.IN_DIR / "CSVs"
125
165
  self.IN_WATER_DEPTH = self.IN_DIR / "WATER_DEPTH"
166
+ self.IN_EPU_STATIONS= self.IN_DIR / "EPU_STATIONS_NEW"
126
167
 
127
168
  self.ORIGINAL_GDB = self.IN_DATABASE / self._original_gdb
128
169
  self.CAPA_WALLOON = self.IN_DATABASE / self._capa_walloon
129
170
  self.PICC_WALLOON = self.IN_DATABASE / self._picc_walloon
130
171
  self.CE_IGN_TOP10V = self.IN_DATABASE / self._ce_ign_top10v
172
+ self.EPU_STATIONS = self.IN_EPU_STATIONS / EPU_Stations
131
173
 
132
- self.VULNERABILITY_CSV = self.IN_CSV / "Vulnerability.csv"
133
- self.POINTS_CSV = self.IN_CSV / "Intermediate.csv"
134
- # self.PONDERATION_CSV = self.IN_CSV / "Ponderation.csv"
174
+ self.VULNERABILITY_CSV = self.IN_CSV / Vulnerability_csv
175
+ self.POINTS_CSV = self.IN_CSV / Intermediate_csv
176
+ self.PONDERATION_CSV = self.IN_CSV / Ponderation_csv
135
177
 
136
- self._CSVs = [self.VULNERABILITY_CSV, self.POINTS_CSV] #, self.PONDERATION_CSV]
178
+ self._CSVs = [self.VULNERABILITY_CSV, self.POINTS_CSV]
137
179
  self._GPKGs= [self.CAPA_WALLOON, self.PICC_WALLOON]
138
180
  self._GDBs = [self.ORIGINAL_GDB]
139
- self._SHPs = [self.CE_IGN_TOP10V]
181
+ self._SHPs = [self.CE_IGN_TOP10V, self.EPU_STATIONS]
140
182
  self._ALLS = self._CSVs + self._GPKGs + self._GDBs + self._SHPs
141
183
 
142
184
  self.TMP_DIR = self.main_dir / "TEMP"
143
185
 
144
- self.TMP_DATABASE = self.TMP_DIR / "DATABASES"
145
-
146
186
  self.OUT_DIR = self.main_dir / "OUTPUT"
147
187
 
188
+ self.points2polys = []
189
+ self.lines2polys = []
190
+
148
191
  self.create_paths()
149
192
  self.create_paths_scenario()
150
193
 
151
194
  def create_paths(self):
152
195
  """ Create the paths for the directories and files """
153
196
 
197
+ self.points2polys = []
198
+ self.lines2polys = []
199
+
154
200
  if self._study_area is not None:
155
201
 
156
202
  self.Study_area:Path = Path(self._study_area)
157
203
 
158
- self.TMP_STUDYAREA = self.TMP_DATABASE / self.Study_area.stem
204
+ self.TMP_STUDYAREA = self.TMP_DIR / self.Study_area.stem
205
+ self.TMP_DATABASE = self.TMP_STUDYAREA / "DATABASES"
206
+
207
+ self.TMP_CLIPGDB = self.TMP_DATABASE / "CLIP_GDB"
208
+ self.TMP_CADASTER = self.TMP_DATABASE / "CLIP_CADASTER"
209
+ self.TMP_PICC = self.TMP_DATABASE / "CLIP_PICC"
210
+ self.TMP_IGNCE = self.TMP_DATABASE / "CLIP_IGN_CE"
211
+ self.TMP_WMODIF = self.TMP_DATABASE / "WITH_MODIF"
212
+ self.TMP_CODEVULNE = self.TMP_DATABASE / "CODE_VULNE"
213
+
159
214
  self.TMP_VULN_DIR = self.TMP_STUDYAREA / "VULNERABILITY"
160
215
  self.TMP_RASTERS = self.TMP_VULN_DIR / "RASTERS"
161
216
  self.TMP_RASTERS_CODE = self.TMP_RASTERS / "Code"
@@ -164,12 +219,13 @@ class Accept_Manager():
164
219
  self.OUT_STUDY_AREA = self.OUT_DIR / self.Study_area.stem
165
220
 
166
221
  self.SA = self.IN_STUDY_AREA / self.Study_area
167
- self.SA_DATABASE = self.TMP_STUDYAREA / "database.gpkg"
168
- self.SA_CAPA = self.TMP_STUDYAREA / "CaPa.gpkg"
169
- self.SA_PICC = self.TMP_STUDYAREA / "PICC.gpkg"
222
+
223
+ # self.SA_DATABASE = self.TMP_STUDYAREA / "database.gpkg"
224
+ # self.SA_CAPA = self.TMP_STUDYAREA / "CaPa.gpkg"
225
+ # self.SA_PICC = self.TMP_STUDYAREA / "PICC.gpkg"
170
226
  self.SA_FINAL = self.TMP_STUDYAREA / "database_final.gpkg"
171
227
  self.SA_FINAL_V = self.TMP_STUDYAREA / "database_final_V.gpkg"
172
- self.SA_MASKED_RIVER = self.TMP_STUDYAREA / "CE_IGN_TOP10V.tiff"
228
+ self.SA_MASKED_RIVER = self.TMP_IGNCE / "CE_IGN_TOP10V.tiff"
173
229
 
174
230
  self.SA_VULN = self.TMP_VULN_DIR / "Vulnerability.tiff"
175
231
  self.SA_CODE = self.TMP_VULN_DIR / "Vulnerability_Code.tiff"
@@ -179,6 +235,12 @@ class Accept_Manager():
179
235
  self._scenario = None
180
236
 
181
237
  self.TMP_STUDYAREA = None
238
+ self.TMP_DATABASE = None
239
+ self.TMP_CADASTER = None
240
+ self.TMP_PICC = None
241
+ self.TMP_IGNCE = None
242
+ self.TMP_WMODIF = None
243
+ self.TMP_CODEVULNE = None
182
244
  self.TMP_VULN_DIR = None
183
245
  self.TMP_RASTERS = None
184
246
  self.TMP_RASTERS_CODE = None
@@ -204,7 +266,7 @@ class Accept_Manager():
204
266
  self.check_outputs()
205
267
 
206
268
  def create_paths_scenario(self):
207
-
269
+
208
270
  if self._scenario is not None:
209
271
 
210
272
  self.scenario:str = str(self._scenario)
@@ -300,10 +362,25 @@ class Accept_Manager():
300
362
  logging.error("The scenario does not exist in the water depth directory")
301
363
 
302
364
  def get_files_in_rm_buildings(self) -> list[Path]:
303
- return [Path(a) for a in glob.glob(str(self.IN_RM_BUILD_DIR / "*.shp"))]
365
+ return [Path(a) for a in glob.glob(str(self.IN_RM_BUILD_DIR / ("*"+ EXTENT)))]
304
366
 
305
367
  def get_files_in_rasters_vulne(self) -> list[Path]:
306
368
  return [Path(a) for a in glob.glob(str(self.TMP_RASTERS_VULNE / "*.tiff"))]
369
+
370
+ def get_layers_in_gdb(self) -> list[str]:
371
+ return [a[0] for a in list_layers(str(self.ORIGINAL_GDB))]
372
+
373
+ def get_layer_types_in_gdb(self) -> list[str]:
374
+ return [a[1] for a in list_layers(str(self.ORIGINAL_GDB))]
375
+
376
+ def get_layers_in_clipgdb(self) -> list[str]:
377
+ return [Path(a).stem for a in glob.glob(str(self.TMP_CLIPGDB / ("*"+ EXTENT)))]
378
+
379
+ def get_layers_in_wmodif(self) -> list[str]:
380
+ return [Path(a).stem for a in glob.glob(str(self.TMP_WMODIF / ("*"+ EXTENT)))]
381
+
382
+ def get_layers_in_codevulne(self) -> list[str]:
383
+ return [Path(a).stem for a in glob.glob(str(self.TMP_CODEVULNE / ("*"+ EXTENT)))]
307
384
 
308
385
  def get_files_in_rasters_code(self) -> list[Path]:
309
386
  return [Path(a) for a in glob.glob(str(self.TMP_RASTERS_CODE / "*.tiff"))]
@@ -343,23 +420,114 @@ class Accept_Manager():
343
420
  return cursim
344
421
 
345
422
  return None
423
+
424
+ def get_types_in_file(self, file:str) -> list[str]:
425
+ """ Get the types of the geometries in the Shape file """
426
+
427
+ return [a[1] for a in list_layers(str(file))]
428
+
429
+ def is_type_unique(self, file:str) -> bool:
430
+ """ Check if the file contains only one type of geometry """
431
+
432
+ types = self.get_types_in_file(file)
433
+ return len(types) == 1
434
+
435
+ def is_polygons(self, set2test:set) -> bool:
436
+ """ Check if the set contains only polygons """
437
+
438
+ set2test = list(set2test)
439
+ firstone = set2test[0]
440
+ if 'Polygon' in firstone:
441
+ for curtype in set2test:
442
+ if 'Polygon' not in curtype:
443
+ return False
444
+ return True
445
+ else:
446
+ return False
447
+
448
+ def is_same_types(self, file:str) -> tuple[bool, str]:
449
+ """ Check if the file contains only the same type of geometry """
450
+
451
+ types = self.get_types_in_file(file)
452
+
453
+ if len(types) == 1:
454
+ if 'Point' in types[0]:
455
+ return True, 'Point'
456
+ elif 'Polygon' in types[0]:
457
+ return True, 'Polygon'
458
+ elif 'LineString' in types[0]:
459
+ return True, 'LineString'
460
+ else:
461
+ raise ValueError(f"The type of geometry {types[0]} is not recognized")
462
+ else:
463
+ firstone = types[0]
464
+ if 'Point' in firstone:
465
+ for curtype in types:
466
+ if 'Point' not in curtype:
467
+ return False, None
468
+ return True, 'Point'
469
+
470
+ elif 'Polygon' in firstone:
471
+ for curtype in types:
472
+ if 'Polygon' not in curtype:
473
+ return False, None
474
+
475
+ return True, 'Polygon'
476
+
477
+ elif 'LineString' in firstone:
478
+ for curtype in types:
479
+ if 'LineString' not in curtype:
480
+ return False, None
481
+
482
+ return True, 'LineString'
483
+ else:
484
+ raise ValueError(f"The type of geometry {firstone} is not recognized")
485
+
346
486
 
347
487
  def get_return_periods(self) -> list[int]:
488
+ """
489
+ Get the return periods from the simulations
490
+
491
+ :return list[int]: the **sorted list** of return periods
492
+ """
348
493
 
494
+ # List files in directory
349
495
  sims = self.get_sims_files_for_scenario()
350
496
 
351
497
  if len(sims)==0:
352
498
  logging.error("No simulations found")
353
499
  return None
354
500
 
501
+ # Two cases:
502
+ # - Return periods are named as T2.tif, T5.tif, T10.tif, ...
503
+ # - Return periods are named as *_T2_h.tif, *_T5_h.tif, *_T10_h.tif, ...
355
504
  if "_h.tif" in sims[0].name:
356
- idx_T = [cursim.stem.find("_T") for cursim in sims]
357
- idx_h = [cursim.stem.find("_h.tif") for cursim in sims]
358
- sims = [int(cursim.stem[idx_T[i]+2:idx_h[i]-1]) for i, cursim in enumerate(sims)]
505
+
506
+ # Searching for the position of the return period in the name
507
+ idx_T = [cursim.name.find("_T") for cursim in sims]
508
+ idx_h = [cursim.name.find("_h.tif") for cursim in sims]
509
+
510
+ assert len(idx_T) == len(idx_h), "The number of T and h are not the same"
511
+ for curT, curh in zip(idx_T, idx_h):
512
+ assert curT != -1, "The T is not found"
513
+ assert curh != -1, "The h is not found"
514
+ assert curh > curT, "The h is before the T"
515
+
516
+ # Create the list of return periods -- only the numeric part
517
+ sims = [int(cursim.name[idx_T[i]+2:idx_h[i]]) for i, cursim in enumerate(sims)]
359
518
  else:
360
- idx_T = [cursim.stem.find("T") for cursim in sims]
361
- idx_h = [cursim.stem.find(".tif") for cursim in sims]
362
- sims = [int(cursim.stem[idx_T[i]+1:idx_h[i]]) for i, cursim in enumerate(sims)]
519
+ # searching for the position of the return period in the name
520
+ idx_T = [cursim.name.find("T") for cursim in sims]
521
+ idx_h = [cursim.name.find(".tif") for cursim in sims]
522
+
523
+ assert len(idx_T) == len(idx_h), "The number of T and h are not the same"
524
+ for curT, curh in zip(idx_T, idx_h):
525
+ assert curT != -1, "The T is not found"
526
+ assert curh != -1, "The h is not found"
527
+ assert curh > curT, "The h is before the T"
528
+
529
+ # create the list of return periods -- only the numeric part
530
+ sims = [int(cursim.name[idx_T[i]+1:idx_h[i]]) for i, cursim in enumerate(sims)]
363
531
 
364
532
  return sorted(sims)
365
533
 
@@ -376,8 +544,12 @@ class Accept_Manager():
376
544
 
377
545
  pond.append(1./float(rt[0]) + (1./float(rt[0]) - 1./float(rt[1]))/2.)
378
546
  for i in range(1, len(rt)-1):
547
+ # Full formula
379
548
  # pond.append((1./float(rt[i-1]) - 1./float(rt[i]))/2. + (1./float(rt[i]) - 1./float(rt[i+1]))/2.)
549
+
550
+ # More compact formula
380
551
  pond.append((1./float(rt[i-1]) - 1./float(rt[i+1]))/2.)
552
+
381
553
  pond.append(1./float(rt[-1]) + (1./float(rt[-2]) - 1./float(rt[-1]))/2.)
382
554
 
383
555
  return pd.DataFrame(pond, columns=["Ponderation"], index=rt)
@@ -419,6 +591,10 @@ class Accept_Manager():
419
591
  logging.error("INPUT : The water depth directory does not exist")
420
592
  err = True
421
593
 
594
+ if not self.IN_EPU_STATIONS.exists():
595
+ logging.error("INPUT : The EPU stations directory does not exist")
596
+ err = True
597
+
422
598
  if self.Study_area is not None:
423
599
  if not self.SA.exists():
424
600
  logging.error("INPUT : The study area file does not exist")
@@ -441,7 +617,7 @@ class Accept_Manager():
441
617
  err = True
442
618
 
443
619
  if self.scenario is None:
444
- logging.warning("The scenario has not been defined")
620
+ logging.debug("The scenario has not been defined")
445
621
  else:
446
622
  if not self.IN_SCEN_DIR.exists():
447
623
  logging.error("The scenario directory does not exist")
@@ -457,11 +633,20 @@ class Accept_Manager():
457
633
  """
458
634
 
459
635
  self.TMP_DIR.mkdir(parents=True, exist_ok=True)
460
- self.TMP_DATABASE.mkdir(parents=True, exist_ok=True)
461
636
 
462
637
  if self.Study_area is not None:
463
638
  self.TMP_STUDYAREA.mkdir(parents=True, exist_ok=True)
639
+ self.TMP_DATABASE.mkdir(parents=True, exist_ok=True)
640
+ self.TMP_CLIPGDB.mkdir(parents=True, exist_ok=True)
641
+ self.TMP_CADASTER.mkdir(parents=True, exist_ok=True)
642
+ self.TMP_WMODIF.mkdir(parents=True, exist_ok=True)
643
+ self.TMP_CODEVULNE.mkdir(parents=True, exist_ok=True)
644
+ self.TMP_PICC.mkdir(parents=True, exist_ok=True)
645
+ self.TMP_IGNCE.mkdir(parents=True, exist_ok=True)
464
646
  self.TMP_VULN_DIR.mkdir(parents=True, exist_ok=True)
647
+ self.TMP_RASTERS.mkdir(parents=True, exist_ok=True)
648
+ self.TMP_RASTERS_CODE.mkdir(parents=True, exist_ok=True)
649
+ self.TMP_RASTERS_VULNE.mkdir(parents=True, exist_ok=True)
465
650
 
466
651
  if self.scenario is not None:
467
652
  self.TMP_SCEN_DIR.mkdir(parents=True, exist_ok=True)
@@ -533,12 +718,12 @@ class Accept_Manager():
533
718
 
534
719
  def check_before_rasterize(self) -> bool:
535
720
 
536
- if not self.SA_FINAL_V.exists():
721
+ if not self.TMP_CODEVULNE.exists():
537
722
  logging.error("The final database with vulnerability levels does not exist")
538
723
  return False
539
724
 
540
- if not self.SA.exists():
541
- logging.error("The study area file does not exist")
725
+ if not self.TMP_WMODIF.exists():
726
+ logging.error("The vector data with modifications does not exist")
542
727
  return False
543
728
 
544
729
  return True
@@ -587,44 +772,145 @@ class Accept_Manager():
587
772
 
588
773
  return True
589
774
 
590
- # Step 1, Clip GDB data
775
+ def compare_original_clipped_layers(self) -> str:
776
+ """ Compare the original layers with the clipped ones """
777
+
778
+ layers = self.get_layers_in_gdb()
779
+ layers_clip = self.get_layers_in_clipgdb()
780
+
781
+ ret = 'These layers have not been clipped:\n'
782
+ for layer in layers:
783
+ if layer not in layers_clip:
784
+ ret += " - {}\n".format(layer)
785
+
786
+ ret += '\nThese layers have been clipped but are not present in the GDB:\n'
787
+ for layer in layers_clip:
788
+ if layer not in layers:
789
+ ret += " - {}\n".format(layer)
790
+
791
+ ret+='\n'
792
+
793
+ return ret
794
+
795
+ def compare_clipped_raster_layers(self) -> str:
796
+ """ Compare the clipped layers with the rasterized ones """
797
+
798
+ layers = self.get_layers_in_clipgdb()
799
+ layers_rast = self.get_layers_in_codevulne()
800
+
801
+ ret = 'These layers {} have not been rasterized:\n'
802
+ for layer in layers:
803
+ if layer not in layers_rast:
804
+ ret += " - {}\n".format(layer)
805
+
806
+ ret += '\nThese layers have been rasterized but are not in the orginal GDB:\n'
807
+ for layer in layers_rast:
808
+ if layer not in layers:
809
+ ret += " - {}\n".format(layer)
810
+
811
+ ret+='\n'
812
+
813
+ return ret
814
+
815
+ def get_operand(self, file:str) -> Modif_Type:
816
+ """ Get the operand based on the layer name """
817
+ LAYERS_WALOUS = ["WALOUS_2018_LB72_112",
818
+ "WALOUS_2018_LB72_31",
819
+ "WALOUS_2018_LB72_32",
820
+ "WALOUS_2018_LB72_331",
821
+ "WALOUS_2018_LB72_332",
822
+ "WALOUS_2018_LB72_333",
823
+ "WALOUS_2018_LB72_34"]
824
+
825
+ ret, curtype = self.is_same_types(file)
826
+ layer = Path(file).stem
827
+
828
+ if not ret:
829
+ raise ValueError("The layer contains different types of geometries")
830
+
831
+ if layer in LAYERS_WALOUS:
832
+ return Modif_Type.WALOUS
833
+
834
+ elif curtype=="Point":
835
+
836
+ self.points2polys.append(layer)
837
+
838
+ if layer =="BDREF_DGO3_PASH__SCHEMA_STATIONS_EPU":
839
+ return Modif_Type.POINT2POLY_EPURATION
840
+ elif layer =="INFRASIG_SOINS_SANTE__ETAB_AINES":
841
+ return Modif_Type.POINT2POLY_PICC
842
+ else:
843
+ return Modif_Type.POINT2POLY_CAPAPICC
844
+
845
+ elif layer =="Hab_2018_CABU":
846
+ return Modif_Type.INHABITED
847
+
848
+ elif layer =="INFRASIG_ROUTE_RES_ROUTIER_TE_AXES":
849
+
850
+ self.lines2polys.append(layer)
851
+
852
+ return Modif_Type.ROAD
853
+
854
+ else:
855
+ return Modif_Type.COPY
591
856
 
592
- def gpd_clip(layer:str,
857
+
858
+ def clip_layer(layer:str,
593
859
  file_path:str,
594
860
  Study_Area:str,
595
- geopackage:str):
861
+ output_dir:str):
596
862
  """
597
- Clip the input data based on the selected bassin and saves it in a separate database
863
+ Clip the input data based on the selected bassin and saves it
864
+ in separate shape files.
865
+
866
+ As shape file doen not support DateTime, the columns with DateTime
867
+ are converted to string.
598
868
 
599
869
  :param layer: the layer name in the GDB file
600
870
  :param file_path: the path to the GDB file
601
871
  :param Study_Area: the path to the study area shapefile
602
- :param geopackage: the path to the geopackage file
872
+ :param output_dir: the path to the output directory
603
873
  """
604
874
 
605
875
  layer = str(layer)
606
876
  file_path = str(file_path)
607
877
  Study_Area = str(Study_Area)
608
- geopackage = str(geopackage)
878
+ output_dir = Path(output_dir)
609
879
 
610
- St_Area = gpd.read_file(Study_Area)
880
+ St_Area = gpd.read_file(Study_Area, engine=ENGINE)
611
881
 
612
882
  logging.info(layer)
613
883
 
614
884
  # The data is clipped during the reading
615
885
  # **It is more efficient than reading the entire data and then clipping it**
616
- df:gpd.GeoDataFrame = gpd.read_file(file_path, layer=layer, mask=St_Area)
886
+ #
887
+ # FIXME: "read_dataframe" is used directly rather than "gpd.read_file" cause
888
+ # the "layer" parameter is well transmitted to the "read_dataframe" function...
889
+ df:gpd.GeoDataFrame = read_dataframe(file_path, layer=layer, mask=St_Area['geometry'][0])
890
+
891
+ if len(df) == 0:
892
+ logging.warning("No data found for layer " + str(layer))
893
+ return "No data found for layer " + str(layer)
617
894
 
618
895
  # Force Lambert72 -> EPSG:31370
619
896
  df.to_crs("EPSG:31370", inplace=True)
620
-
621
- df.to_file(geopackage, layer=layer, mode='w')
622
-
623
- return "Saved the clipped " +str(layer)+ " to GPKG"
624
-
625
- def data_modification(input_database:str,
626
- layer:str,
627
- output_database:str,
897
+ try:
898
+ date_columns = df.select_dtypes(include=['datetimetz']).columns.tolist()
899
+ if len(date_columns)>0:
900
+ df[date_columns] = df[date_columns].astype(str)
901
+
902
+ df.to_file(str(output_dir / (layer+EXTENT)), mode='w', engine=ENGINE)
903
+ except Exception as e:
904
+ logging.error("Error while saving the clipped " + str(layer) + " to file")
905
+ logging.error(e)
906
+ pass
907
+
908
+ logging.info("Saved the clipped " + str(layer) + " to file")
909
+ return "Saved the clipped " +str(layer)+ " to file"
910
+
911
+
912
+ def data_modification(layer:str,
913
+ manager:Accept_Manager,
628
914
  picc:gpd.GeoDataFrame,
629
915
  capa:gpd.GeoDataFrame ):
630
916
  """
@@ -642,163 +928,153 @@ def data_modification(input_database:str,
642
928
  df1:gpd.GeoDataFrame
643
929
  df2:gpd.GeoDataFrame
644
930
 
645
- LAYERS_WALOUS = ["WALOUS_2018_LB72_112",
646
- "WALOUS_2018_LB72_31",
647
- "WALOUS_2018_LB72_32",
648
- "WALOUS_2018_LB72_331",
649
- "WALOUS_2018_LB72_332",
650
- "WALOUS_2018_LB72_333",
651
- "WALOUS_2018_LB72_34"]
652
-
653
- input_database = str(input_database)
654
931
  layer = str(layer)
655
- output_database = str(output_database)
656
-
657
- df:gpd.GeoDataFrame = gpd.read_file(input_database, layer = layer)
658
- x1,y1 = df.shape
659
- a = df.geom_type.unique()
660
- #print(layers[i])
661
- x,=a.shape
662
- if x1>0:
663
- if layer in LAYERS_WALOUS: #Walous layers changed to PICC buidings
664
- #print("walous")
665
-
666
- assert picc.crs == df.crs, "CRS of PICC and input data do not match"
667
-
668
- df1= gpd.sjoin(picc, df, how="inner", predicate="intersects" )
669
- cols=df.columns
670
- cols = np.append(cols, "GEOREF_ID")
671
- cols = np.append(cols, "NATUR_CODE")
672
- df1=df1[cols]
673
- df1.to_file(output_database,layer=layer)
674
- elif layer =="BDREF_DGO3_PASH__SCHEMA_STATIONS_EPU": #Change BDREF based on AJOUT_PDET sent by Perrine
675
- #print("yes")
676
- df1 = gpd.read_file(os.getcwd()+"//INPUT//EPU_STATIONS_NEW//AJOUT_PDET_EPU_DG03_STATIONS.shp")
677
-
678
- assert df1.crs == df.crs, "CRS of AJOUT_PDET and input data do not match"
679
-
680
- df2 = gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
681
- df2.to_file(output_database, layer=layer)
682
- elif layer =="INFRASIG_SOINS_SANTE__ETAB_AINES":
683
-
684
- assert capa.crs == df.crs, "CRS of CaPa and input data do not match"
685
-
686
- df1= gpd.sjoin(capa, df, how="inner", predicate="intersects" )
687
- cols=df.columns
688
- #print(cols)
689
- cols = np.append(cols, "CaPaKey")
690
- #print(cols)
691
- df1=df1[cols]
692
- df2=gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
693
- cols = np.append(cols, "GEOREF_ID")
694
- cols = np.append(cols, "NATUR_CODE")
695
- #df2=df2[cols]
696
- #print(df2.columns)
697
- df2.to_file(output_database, layer=layer)
698
-
699
- elif a[0,]=="Point" and layer!="BDREF_DGO3_PASH__SCHEMA_STATIONS_EPU" and layer!="INFRASIG_SOINS_SANTE__ETAB_AINES":
700
-
701
- assert capa.crs == df.crs, "CRS of CaPa and input data do not match"
702
- assert picc.crs == df.crs, "CRS of PICC and input data do not match"
703
-
704
- df1= gpd.sjoin(capa, df, how="inner", predicate="intersects" )
705
- cols=df.columns
706
- #print(cols)
707
- cols = np.append(cols, "CaPaKey")
708
- #print(cols)
709
- df1=df1[cols]
710
- df2=gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
711
- cols = np.append(cols, "GEOREF_ID")
712
- cols = np.append(cols, "NATUR_CODE")
713
- df2=df2[cols]
714
- #print(df2.columns)
715
- df2.to_file(output_database, layer=layer)
716
- #print(layers[i])
717
- elif layer =="Hab_2018_CABU":
718
- df1=df[df["NbsHabTOT"]>0]
719
- #print(df1.shape)
720
- df1.to_file(output_database, layer=layer)
721
- elif layer =="INFRASIG_ROUTE_RES_ROUTIER_TE_AXES":
722
- df1=df.buffer(6, cap_style=2)
723
- df1.to_file(output_database, layer=layer)
724
- else:
725
- df.to_file(output_database, layer=layer)
726
- else:
727
- logging.info("skipped" + str(layer) + "due to no polygon in the study area")
728
932
 
729
- def vector_to_raster(layer:str,
730
- vector_input:Path,
731
- extent:Path,
732
- attribute:str,
733
- pixel_size:float):
734
- """
735
- Convert a vector layer to a raster tiff file
933
+ dir_input = manager.TMP_CLIPGDB
934
+ dir_output = manager.TMP_WMODIF
736
935
 
737
- :param layer: the layer name in the GDB file
738
- :param vector_input: the path to the vector file
739
- :param extent: the path to the extent file
740
- :param attribute: the attribute to rasterize
741
- :param pixel_size: the pixel size of the raster
936
+ input_file = str(dir_input / (layer + EXTENT))
937
+ output_file = str(dir_output / (layer + EXTENT))
742
938
 
743
- """
939
+ # Read the data
940
+ df:gpd.GeoDataFrame = gpd.read_file(input_file, engine=ENGINE)
941
+ nblines, _ = df.shape
744
942
 
745
- old_dir = os.getcwd()
943
+ if nblines>0:
944
+ op = manager.get_operand(input_file)
746
945
 
747
- layer = str(layer)
748
- vector_input = Path(vector_input)
749
- extent = Path(extent)
750
- attribute = str(attribute)
751
- pixel_size = float(pixel_size)
946
+ if op == Modif_Type.WALOUS:
947
+ # Walous layers changed to PICC buidings
752
948
 
753
- OUT_DIR = vector_input.parent / "VULNERABILITY/RASTERS" / attribute
754
- OUT_NAME = layer + ".tiff"
949
+ assert picc.crs == df.crs, "CRS of PICC and input data do not match"
755
950
 
756
- OUT_DIR.mkdir(parents=True, exist_ok=True)
951
+ assert "GEOREF_ID" in picc.columns, "The PICC file does not contain the GEOREF_ID column"
952
+ assert "NATUR_CODE" in picc.columns, "The PICC file does not contain the NATUR_CODE column"
757
953
 
758
- if (OUT_DIR/OUT_NAME).exists():
759
- os.remove(OUT_DIR/OUT_NAME)
954
+ df1 = gpd.sjoin(picc, df, how="inner", predicate="intersects" )
955
+ cols = df.columns
760
956
 
761
- os.chdir(OUT_DIR)
957
+ cols = np.append(cols, "GEOREF_ID")
958
+ cols = np.append(cols, "NATUR_CODE")
762
959
 
763
- NoData_value = 0
960
+ df1 = df1[cols]
961
+
962
+ if df1.shape[0] > 0:
963
+ assert manager.is_polygons(set(df1.geom_type)), f"The layer does not contains polygons - {op}"
964
+ df1.to_file(output_file, engine=ENGINE)
965
+ else:
966
+ logging.warning("No data found for layer " + str(layer))
764
967
 
765
- extent_ds:ogr.DataSource = ogr.Open(str(extent))
766
- extent_layer = extent_ds.GetLayer()
968
+ elif op == Modif_Type.POINT2POLY_EPURATION:
969
+ # Change BDREF based on AJOUT_PDET sent by Perrine (SPI)
970
+
971
+ # The original layer is a point layer.
972
+ # The EPU_STATIONS shape file (from SPI) is a polygon layer.
767
973
 
768
- x_min, x_max, y_min, y_max = extent_layer.GetExtent()
974
+ df1 = gpd.read_file(str(manager.EPU_STATIONS), engine=ENGINE)
769
975
 
770
- x_min = float(int(x_min))
771
- x_max = float(np.ceil(x_max))
772
- y_min = float(int(y_min))
773
- y_max = float(np.ceil(y_max))
976
+ assert df1.crs == df.crs, "CRS of AJOUT_PDET and input data do not match"
774
977
 
775
- # Open the data sources and read the extents
776
- source_ds:ogr.DataSource = ogr.Open(str(vector_input))
777
- source_layer = source_ds.GetLayer(layer)
978
+ df2 = gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
778
979
 
779
- # Create the destination data source
780
- x_res = int((x_max - x_min) / pixel_size)
781
- y_res = int((y_max - y_min) / pixel_size)
782
- target_ds:gdal.Driver = gdal.GetDriverByName('GTiff').Create(str(OUT_NAME),
783
- x_res, y_res, 1,
784
- gdal.GDT_Byte,
785
- options=["COMPRESS=LZW"])
980
+ if df2.shape[0] > 0:
981
+ assert manager.is_polygons(set(df2.geom_type)), f"The layer does not contains polygons - {op}"
982
+ df2.to_file(output_file, engine=ENGINE)
983
+ else:
984
+ logging.warning("No data found for layer " + str(layer))
786
985
 
787
- target_ds.SetGeoTransform((x_min, pixel_size, 0, y_max, 0, -pixel_size))
788
- srs = osr.SpatialReference()
789
- srs.ImportFromEPSG(31370)
790
- target_ds.SetProjection(srs.ExportToWkt())
986
+ elif op == Modif_Type.POINT2POLY_PICC:
987
+ # Select the polygons that contains the points
988
+ # in theCadaster and PICC files
791
989
 
792
- band = target_ds.GetRasterBand(1)
793
- band.SetNoDataValue(NoData_value)
990
+ assert capa.crs == df.crs, "CRS of CaPa and input data do not match"
991
+ assert "CaPaKey" in capa.columns, "The CaPa file does not contain the CaPaKey column"
794
992
 
795
- # Rasterize the areas
796
- gdal.RasterizeLayer(target_ds, [1], source_layer, options=["ATTRIBUTE="+attribute, "ALL_TOUCHED=TRUE"])
797
- target_ds = None
993
+ df1= gpd.sjoin(capa, df, how="inner", predicate="intersects" )
994
+ cols=df.columns
995
+
996
+ cols = np.append(cols, "CaPaKey")
997
+ df1=df1[cols]
998
+ df2=gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
999
+
1000
+ if df2.shape[0] > 0:
1001
+ assert manager.is_polygons(set(df2.geom_type)), f"The layer does not contains polygons - {op}"
1002
+ df2.to_file(output_file, engine=ENGINE)
1003
+ else:
1004
+ logging.warning("No data found for layer " + str(layer))
1005
+
1006
+ elif op == Modif_Type.POINT2POLY_CAPAPICC:
1007
+
1008
+ # Select the polygons that contains the points
1009
+ # in theCadaster and PICC files
1010
+
1011
+ assert capa.crs == df.crs, "CRS of CaPa and input data do not match"
1012
+ assert picc.crs == df.crs, "CRS of PICC and input data do not match"
1013
+
1014
+ # Join the Layer and CaPa DataFrames : https://geopandas.org/en/stable/docs/reference/api/geopandas.sjoin.html
1015
+ # ‘inner’: use intersection of keys from both dfs; retain only left_df geometry column
1016
+ # "intersects" : Binary predicate. Valid values are determined by the spatial index used.
1017
+ df1= gpd.sjoin(capa, df, how="inner", predicate="intersects" )
1018
+
1019
+ # Retain only the columns of the input data
1020
+ cols = df.columns
1021
+ # but add the CaPaKey
1022
+ cols = np.append(cols, "CaPaKey")
1023
+
1024
+ df1 = df1[cols]
1025
+
1026
+ # Join the df1 and PICC DataFrames : https://geopandas.org/en/stable/docs/reference/api/geopandas.sjoin.html
1027
+ df2 = gpd.sjoin(picc, df1, how="inner", predicate="intersects" )
1028
+
1029
+ # Add only the GEOREF_ID and NATUR_CODE columns from PICC
1030
+ cols = np.append(cols, "GEOREF_ID")
1031
+ cols = np.append(cols, "NATUR_CODE")
1032
+
1033
+ df2 = df2[cols]
1034
+
1035
+ if df2.shape[0] > 0:
1036
+ assert manager.is_polygons(set(df2.geom_type)), f"The layer does not contains polygons - {op}"
1037
+ df2.to_file(output_file, engine=ENGINE)
1038
+ else:
1039
+ logging.warning("No data found for layer " + str(layer))
798
1040
 
799
- os.chdir(old_dir)
1041
+ elif op == Modif_Type.INHABITED:
1042
+ # Select only the buildings with a number of inhabitants > 0
1043
+ df1=df[df["NbsHabTOT"]>0]
800
1044
 
801
- def Comp_Vulnerability(dirsnames:Accept_Manager):
1045
+ if df1.shape[0] > 0:
1046
+ assert manager.is_polygons(set(df1.geom_type)), f"The layer does not contains polygons - {op}"
1047
+ df1.to_file(output_file, engine=ENGINE)
1048
+ else:
1049
+ logging.warning("No data found for layer " + str(layer))
1050
+
1051
+ elif op == Modif_Type.ROAD:
1052
+ # Create a buffer around the roads
1053
+ df1=df.buffer(distance=6, cap_style=2)
1054
+
1055
+ if df1.shape[0] > 0:
1056
+ assert set(df1.geom_type) == {'Polygon'}, f"The layer does not contains polygons - {op}"
1057
+ df1.to_file(output_file, engine=ENGINE)
1058
+ else:
1059
+ logging.warning("No data found for layer " + str(layer))
1060
+
1061
+ elif op == Modif_Type.COPY:
1062
+ # just copy the data if it is polygons
1063
+ if manager.is_polygons(set(df.geom_type)):
1064
+ df.to_file(output_file, engine=ENGINE)
1065
+ else:
1066
+ logging.error("The layer does not contains polygons - " + str(layer))
1067
+ else:
1068
+ raise ValueError(f"The operand {op} is not recognized")
1069
+
1070
+ return "Data modification done for " + str(layer)
1071
+ else:
1072
+ # Normally, phase 1 does not create empty files
1073
+ # But it is better to check... ;-)
1074
+ logging.error("skipped" + str(layer) + "due to no polygon in the study area")
1075
+ return "skipped" + str(layer) + "due to no polygon in the study area"
1076
+
1077
+ def compute_vulnerability(manager:Accept_Manager):
802
1078
  """
803
1079
  Compute the vulnerability for the Study Area
804
1080
 
@@ -807,45 +1083,77 @@ def Comp_Vulnerability(dirsnames:Accept_Manager):
807
1083
  :param dirsnames: the Dirs_Names object from the calling function
808
1084
  """
809
1085
 
810
- rasters_vuln = dirsnames.get_files_in_rasters_vulne()
811
- rasters_code = dirsnames.get_files_in_rasters_code()
1086
+ vuln_csv = Vulnerability_csv(manager.VULNERABILITY_CSV)
1087
+
1088
+ rasters_vuln = manager.get_files_in_rasters_vulne()
812
1089
 
813
1090
  logging.info("Number of files",len(rasters_vuln))
814
1091
 
815
- ds:gdal.Dataset = gdal.Open(str(rasters_vuln[0]))
816
- ds1:gdal.Dataset = gdal.Open(str(rasters_code[0]))
1092
+ ds:gdal.Dataset = gdal.OpenEx(str(rasters_vuln[0]), gdal.GA_ReadOnly, open_options=["SPARSE_OK=TRUE"])
817
1093
 
818
- tmp_vuln = np.array(ds.GetRasterBand(1).ReadAsArray())
819
- tmp_code = np.array(ds1.GetRasterBand(1).ReadAsArray())
1094
+ tmp_vuln = ds.GetRasterBand(1)
820
1095
 
821
- x, y = tmp_vuln.shape
1096
+ # REMARK: The XSize and YSize are the number of columns and rows
1097
+ col, row = tmp_vuln.XSize, tmp_vuln.YSize
822
1098
 
823
1099
  logging.info("Computing Vulnerability")
824
1100
 
825
- array_vuln = np.zeros((x, y), dtype=np.int8)
826
- array_code = np.zeros((x, y), dtype=np.int8)
827
-
828
- for i in tqdm(range(len(rasters_vuln))):
1101
+ array_vuln = np.ones((row, col), dtype=np.int8)
1102
+
1103
+ # Create a JIT function to update the arrays
1104
+ # Faster than the classical Python loop or Numpy
1105
+ @nb.jit(nopython=True, boundscheck=False, inline='always')
1106
+ # @cuda.jit(device=True, inline=True)
1107
+ def update_arrays_jit(tmp_vuln, array_vuln):
1108
+ for i in range(tmp_vuln.shape[0]):
1109
+ for j in range(tmp_vuln.shape[1]):
1110
+ if tmp_vuln[i, j] >= array_vuln[i, j]:
1111
+ array_vuln[i, j] = tmp_vuln[i, j]
1112
+
1113
+ return array_vuln
1114
+
1115
+ @nb.jit(nopython=True, boundscheck=False, inline='always')
1116
+ # @cuda.jit(device=True, inline=True)
1117
+ def update_arrays_jit_coo(row, col, locvuln, array_vuln):
1118
+ for i,j in zip(row, col):
1119
+ if locvuln >= array_vuln[i, j]:
1120
+ array_vuln[i, j] = locvuln
1121
+
1122
+ return array_vuln
1123
+
1124
+ for i in tqdm(range(len(rasters_vuln)), 'Computing Vulnerability : '):
829
1125
  logging.info("Computing layer {} / {}".format(i, len(rasters_vuln)))
830
- ds = gdal.Open(str(rasters_vuln[i]))
831
- ds1 = gdal.Open(str(rasters_code[i]))
832
-
833
- tmp_vuln = ds.GetRasterBand(1).ReadAsArray()
834
- tmp_code = ds1.GetRasterBand(1).ReadAsArray()
835
-
836
- ij = np.where(tmp_vuln >= array_vuln)
837
- array_vuln[ij] = tmp_vuln.max()
838
- array_code[ij] = tmp_code.max()
839
-
840
- ij = np.where(array_vuln == 0)
841
- array_vuln[ij] = 1
842
- array_code[ij] = 1
1126
+
1127
+ locvuln = vuln_csv.get_vulnerability_level(rasters_vuln[i].stem)
1128
+
1129
+ if locvuln == 1:
1130
+ logging.info("No need to apply the matrice, the vulnerability is 1 which is the lower value")
1131
+ continue
1132
+
1133
+ if rasters_vuln[i].with_suffix('.npz').exists():
1134
+ ij_npz = np.load(rasters_vuln[i].with_suffix('.npz'))
1135
+ ii = ij_npz['row']
1136
+ jj = ij_npz['col']
1137
+ # We use the jit
1138
+ update_arrays_jit_coo(ii, jj, locvuln, array_vuln)
1139
+
1140
+ else:
1141
+ ds = gdal.OpenEx(str(rasters_vuln[i]), open_options=["SPARSE_OK=TRUE"])
1142
+ tmp_vuln = ds.GetRasterBand(1).ReadAsArray()
1143
+ # We use the jit
1144
+ update_arrays_jit(tmp_vuln, array_vuln)
843
1145
 
844
- dst_filename= str(dirsnames.SA_VULN)
1146
+ logging.info("Saving the computed vulnerability")
1147
+ dst_filename= str(manager.SA_VULN)
845
1148
  y_pixels, x_pixels = array_vuln.shape # number of pixels in x
846
1149
 
847
1150
  driver = gdal.GetDriverByName('GTiff')
848
- dataset = driver.Create(dst_filename, x_pixels, y_pixels, gdal.GDT_Byte, 1, options=["COMPRESS=LZW"])
1151
+ dataset = driver.Create(dst_filename,
1152
+ x_pixels, y_pixels,
1153
+ gdal.GDT_Byte,
1154
+ 1,
1155
+ options=["COMPRESS=LZW"])
1156
+
849
1157
  dataset.GetRasterBand(1).WriteArray(array_vuln.astype(np.int8))
850
1158
  # follow code is adding GeoTranform and Projection
851
1159
  geotrans = ds.GetGeoTransform() # get GeoTranform from existed 'data0'
@@ -855,11 +1163,83 @@ def Comp_Vulnerability(dirsnames:Accept_Manager):
855
1163
  dataset.FlushCache()
856
1164
  dataset = None
857
1165
 
1166
+ logging.info("Computed Vulnerability for the Study Area - Done")
1167
+
1168
+ def compute_code(manager:Accept_Manager):
1169
+ """
1170
+ Compute the code for the Study Area
1171
+
1172
+ This function **will not modify** the data by the removed buildings/scenarios.
1173
+
1174
+ :param dirsnames: the Dirs_Names object from the calling function
1175
+ """
1176
+
1177
+ vuln_csv = Vulnerability_csv(manager.VULNERABILITY_CSV)
1178
+
1179
+ rasters_code = manager.get_files_in_rasters_code()
1180
+
1181
+ logging.info("Number of files",len(rasters_code))
1182
+
1183
+ ds:gdal.Dataset = gdal.OpenEx(str(rasters_code[0]), gdal.GA_ReadOnly, open_options=["SPARSE_OK=TRUE"])
1184
+
1185
+ tmp_code = ds.GetRasterBand(1)
858
1186
 
859
- dst_filename= str(dirsnames.SA_CODE)
1187
+ # REMARK: The XSize and YSize are the number of columns and rows
1188
+ col, row = tmp_code.XSize, tmp_code.YSize
1189
+
1190
+ logging.info("Computing Code")
1191
+
1192
+ array_code = np.ones((row, col), dtype=np.int8)
1193
+
1194
+ # Create a JIT function to update the arrays
1195
+ # Faster than the classical Python loop or Numpy
1196
+ @nb.jit(nopython=True, boundscheck=False, inline='always')
1197
+ # @cuda.jit(device=True, inline=True)
1198
+ def update_arrays_jit(tmp_code, loccode, array_code):
1199
+ for i in range(tmp_code.shape[0]):
1200
+ for j in range(tmp_code.shape[1]):
1201
+ if tmp_code[i, j] >= array_code[i, j]:
1202
+ array_code[i, j] = loccode
1203
+
1204
+ return array_code
1205
+
1206
+ @nb.jit(nopython=True, boundscheck=False, inline='always')
1207
+ # @cuda.jit(device=True, inline=True)
1208
+ def update_arrays_jit_coo(row, col, loccode, array_code):
1209
+ for i,j in zip(row, col):
1210
+ if loccode >= array_code[i, j]:
1211
+ array_code[i, j] = loccode
1212
+
1213
+ return array_code
1214
+
1215
+ for i in tqdm(range(len(rasters_code)), 'Computing Code : '):
1216
+ logging.info("Computing layer {} / {}".format(i, len(rasters_code)))
1217
+
1218
+ loccode = vuln_csv.get_vulnerability_code(rasters_code[i].stem)
1219
+
1220
+ if rasters_code[i].with_suffix('.npz').exists():
1221
+ ij_npz = np.load(rasters_code[i].with_suffix('.npz'))
1222
+ ii = ij_npz['row']
1223
+ jj = ij_npz['col']
1224
+ # We use the jit
1225
+ update_arrays_jit_coo(ii, jj, loccode, array_code)
1226
+
1227
+ else:
1228
+ ds = gdal.OpenEx(str(rasters_code[i]), open_options=["SPARSE_OK=TRUE"])
1229
+ tmp_code = ds.GetRasterBand(1).ReadAsArray()
1230
+ # We use the jit
1231
+ update_arrays_jit(tmp_code, loccode, array_code)
1232
+
1233
+ logging.info("Saving the computed codes")
1234
+ dst_filename= str(manager.SA_CODE)
860
1235
  y_pixels, x_pixels = array_code.shape # number of pixels in x
861
1236
  driver = gdal.GetDriverByName('GTiff')
862
- dataset = driver.Create(dst_filename, x_pixels, y_pixels, gdal.GDT_Byte, 1, options=["COMPRESS=LZW"])
1237
+ dataset = driver.Create(dst_filename,
1238
+ x_pixels, y_pixels,
1239
+ gdal.GDT_Byte,
1240
+ 1,
1241
+ options=["COMPRESS=LZW"])
1242
+
863
1243
  dataset.GetRasterBand(1).WriteArray(array_code.astype(np.int8))
864
1244
  # follow code is adding GeoTranform and Projection
865
1245
  geotrans = ds.GetGeoTransform() # get GeoTranform from existed 'data0'
@@ -869,9 +1249,9 @@ def Comp_Vulnerability(dirsnames:Accept_Manager):
869
1249
  dataset.FlushCache()
870
1250
  dataset = None
871
1251
 
872
- logging.info("Computed Vulnerability for the Study Area - Done")
1252
+ logging.info("Computed Code for the Study Area - Done")
873
1253
 
874
- def Comp_Vulnerability_Scen(dirsnames:Accept_Manager):
1254
+ def compute_vulnerability4scenario(manager:Accept_Manager):
875
1255
  """ Compute the vulnerability for the scenario
876
1256
 
877
1257
  This function **will modify** the data by the removed buildings/scenarios.
@@ -881,16 +1261,16 @@ def Comp_Vulnerability_Scen(dirsnames:Accept_Manager):
881
1261
  :param dirsnames: the Dirs_Names object from the calling function
882
1262
  """
883
1263
 
884
- array_vuln = gdal.Open(str(dirsnames.SA_VULN))
1264
+ array_vuln = gdal.Open(str(manager.SA_VULN))
885
1265
  geotrans = array_vuln.GetGeoTransform() # get GeoTranform from existed 'data0'
886
1266
  proj = array_vuln.GetProjection() # you can get from a exsited tif or import
887
1267
 
888
1268
  array_vuln = np.array(array_vuln.GetRasterBand(1).ReadAsArray())
889
1269
 
890
- array_code = gdal.Open(str(dirsnames.SA_CODE))
1270
+ array_code = gdal.Open(str(manager.SA_CODE))
891
1271
  array_code = np.array(array_code.GetRasterBand(1).ReadAsArray())
892
1272
 
893
- Rbu = dirsnames.get_files_in_rm_buildings()
1273
+ Rbu = manager.get_files_in_rm_buildings()
894
1274
 
895
1275
  if len(Rbu)>0:
896
1276
  for curfile in Rbu:
@@ -901,7 +1281,7 @@ def Comp_Vulnerability_Scen(dirsnames:Accept_Manager):
901
1281
  array_vuln[ij] = 1
902
1282
  array_code[ij] = 1
903
1283
 
904
- dst_filename= str(dirsnames.TMP_VULN)
1284
+ dst_filename= str(manager.TMP_VULN)
905
1285
  y_pixels, x_pixels = array_vuln.shape # number of pixels in x
906
1286
 
907
1287
  driver = gdal.GetDriverByName('GTiff')
@@ -914,7 +1294,7 @@ def Comp_Vulnerability_Scen(dirsnames:Accept_Manager):
914
1294
  dataset = None
915
1295
 
916
1296
 
917
- dst_filename= str(dirsnames.TMP_CODE)
1297
+ dst_filename= str(manager.TMP_CODE)
918
1298
  y_pixels, x_pixels = array_code.shape # number of pixels in x
919
1299
  driver = gdal.GetDriverByName('GTiff')
920
1300
  dataset = driver.Create(dst_filename, x_pixels, y_pixels, gdal.GDT_Byte, 1, options=["COMPRESS=LZW"])
@@ -925,9 +1305,9 @@ def Comp_Vulnerability_Scen(dirsnames:Accept_Manager):
925
1305
  dataset.FlushCache()
926
1306
  dataset = None
927
1307
 
928
- logging.info("Computed Vulnerability for the scenario")
1308
+ logging.info("Computed Vulnerability and code for the scenario")
929
1309
 
930
- def match_vuln_modrec(inRas:Path, outRas:Path, MODREC:Path):
1310
+ def match_vulnerability2sim(inRas:Path, outRas:Path, MODREC:Path):
931
1311
  """
932
1312
  Clip the raster to the MODREC/simulation extent
933
1313
 
@@ -951,7 +1331,7 @@ def match_vuln_modrec(inRas:Path, outRas:Path, MODREC:Path):
951
1331
  ds = gdal.Translate(outRas, ds, projWin = [minx, maxy, maxx, miny])
952
1332
  ds = None
953
1333
 
954
- def VulMod(dirsnames:Accept_Manager,
1334
+ def compute_acceptability(manager:Accept_Manager,
955
1335
  model_h:np.ndarray,
956
1336
  vulnerability:np.ndarray,
957
1337
  interval:int,
@@ -973,7 +1353,7 @@ def VulMod(dirsnames:Accept_Manager,
973
1353
 
974
1354
  logging.info(interval)
975
1355
 
976
- Qfile = pd.read_csv(dirsnames.POINTS_CSV)
1356
+ Qfile = pd.read_csv(manager.POINTS_CSV)
977
1357
 
978
1358
  Qfile = Qfile[Qfile["Interval"]==interval]
979
1359
  Qfile = Qfile.reset_index()
@@ -1003,7 +1383,7 @@ def VulMod(dirsnames:Accept_Manager,
1003
1383
  accept[ij[0][loc_ij], ij[1][loc_ij]] = loc_accept[idx]
1004
1384
 
1005
1385
  #save raster
1006
- dst_filename = str(dirsnames.TMP_QFILES / "Q{}.tif".format(interval))
1386
+ dst_filename = str(manager.TMP_QFILES / "Q{}.tif".format(interval))
1007
1387
 
1008
1388
  y_pixels, x_pixels = accept.shape # number of pixels in x
1009
1389
  driver = gdal.GetDriverByName('GTiff')
@@ -1018,7 +1398,12 @@ def VulMod(dirsnames:Accept_Manager,
1018
1398
 
1019
1399
  def shp_to_raster(vector_fn:str, raster_fn:str, pixel_size:float = 1.):
1020
1400
  """
1021
- Convert a vector layer to a raster tiff file
1401
+ Convert a vector layer to a raster tiff file.
1402
+
1403
+ The raster will contain only 2 values : 0 and 1
1404
+
1405
+ - 1 : the inside of the vector layer
1406
+ - 0 : the rest == NoData/NullValue
1022
1407
 
1023
1408
  :param vector_fn: the path to the vector file
1024
1409
  :param raster_fn: the path to the raster file
@@ -1029,7 +1414,7 @@ def shp_to_raster(vector_fn:str, raster_fn:str, pixel_size:float = 1.):
1029
1414
  vector_fn = str(vector_fn)
1030
1415
  raster_fn = str(raster_fn)
1031
1416
 
1032
- NoData_value = np.nan
1417
+ NoData_value = 0 # np.nan is not necessary a good idea
1033
1418
  # Open the data sources and read the extents
1034
1419
  source_ds = ogr.Open(vector_fn)
1035
1420
  source_layer = source_ds.GetLayer()
@@ -1043,8 +1428,13 @@ def shp_to_raster(vector_fn:str, raster_fn:str, pixel_size:float = 1.):
1043
1428
  # Create the destination data source
1044
1429
  x_res = int((x_max - x_min) / pixel_size)
1045
1430
  y_res = int((y_max - y_min) / pixel_size)
1046
- target_ds = gdal.GetDriverByName('GTiff').Create(raster_fn, x_res, y_res, 1, gdal.GDT_Float64,
1047
- options=["COMPRESS=LZW"])
1431
+
1432
+ target_ds = gdal.GetDriverByName('GTiff').Create(raster_fn,
1433
+ x_res, y_res,
1434
+ 1,
1435
+ gdal.GDT_Byte,
1436
+ options=["COMPRESS=LZW",
1437
+ 'SPARSE_OK=TRUE'])
1048
1438
 
1049
1439
  target_ds.SetGeoTransform((x_min, pixel_size, 0, y_max, 0, -pixel_size))
1050
1440
  srs = osr.SpatialReference()
@@ -1053,6 +1443,92 @@ def shp_to_raster(vector_fn:str, raster_fn:str, pixel_size:float = 1.):
1053
1443
  band = target_ds.GetRasterBand(1)
1054
1444
  band.SetNoDataValue(NoData_value)
1055
1445
  # Rasterize the areas
1056
- gdal.RasterizeLayer(target_ds, [1], source_layer,None, None, [1], options=["ALL_TOUCHED=TRUE"])
1446
+ gdal.RasterizeLayer(target_ds,
1447
+ bands = [1],
1448
+ layer = source_layer,
1449
+ burn_values = [1],
1450
+ options=["ALL_TOUCHED=TRUE"])
1057
1451
  target_ds = None
1058
1452
  vector_fn = raster_fn = None
1453
+
1454
+ def vector_to_raster(layer:str,
1455
+ manager:Accept_Manager,
1456
+ attribute:str,
1457
+ pixel_size:float,
1458
+ convert_to_sparse:bool = True):
1459
+ """
1460
+ Convert a vector layer to a raster tiff file
1461
+
1462
+ :param layer: the layer name in the GDB file
1463
+ :param vector_input: the path to the vector file
1464
+ :param extent: the path to the extent file
1465
+ :param attribute: the attribute to rasterize
1466
+ :param pixel_size: the pixel size of the raster
1467
+
1468
+ """
1469
+
1470
+ layer = str(layer)
1471
+
1472
+ vector_input = str(manager.TMP_CODEVULNE / (layer + EXTENT))
1473
+ extent = str(manager.SA)
1474
+ attribute = str(attribute)
1475
+ pixel_size = float(pixel_size)
1476
+
1477
+ out_file = manager.TMP_RASTERS / attribute / (layer + ".tiff")
1478
+
1479
+ if out_file.exists():
1480
+ os.remove(out_file)
1481
+
1482
+ out_file = str(out_file)
1483
+
1484
+ NoData_value = 0
1485
+
1486
+ extent_ds:ogr.DataSource = ogr.Open(extent)
1487
+ extent_layer = extent_ds.GetLayer()
1488
+
1489
+ x_min, x_max, y_min, y_max = extent_layer.GetExtent()
1490
+
1491
+ x_min = float(int(x_min))
1492
+ x_max = float(np.ceil(x_max))
1493
+ y_min = float(int(y_min))
1494
+ y_max = float(np.ceil(y_max))
1495
+
1496
+ # Open the data sources and read the extents
1497
+ source_ds:ogr.DataSource = ogr.Open(vector_input)
1498
+ if source_ds is None:
1499
+ logging.error(f"Could not open the data source {layer}")
1500
+ return
1501
+ source_layer = source_ds.GetLayer()
1502
+
1503
+ # Create the destination data source
1504
+ x_res = int((x_max - x_min) / pixel_size)
1505
+ y_res = int((y_max - y_min) / pixel_size)
1506
+ target_ds:gdal.Driver = gdal.GetDriverByName('GTiff').Create(out_file,
1507
+ x_res, y_res, 1,
1508
+ gdal.GDT_Byte,
1509
+ options=["COMPRESS=DEFLATE",
1510
+ 'SPARSE_OK=TRUE',])
1511
+
1512
+ target_ds.SetGeoTransform((x_min, pixel_size, 0, y_max, 0, -pixel_size))
1513
+ srs = osr.SpatialReference()
1514
+ srs.ImportFromEPSG(31370)
1515
+ target_ds.SetProjection(srs.ExportToWkt())
1516
+
1517
+ band = target_ds.GetRasterBand(1)
1518
+ band.SetNoDataValue(NoData_value)
1519
+
1520
+ # Rasterize the areas
1521
+ gdal.RasterizeLayer(target_ds, [1],
1522
+ source_layer,
1523
+ options=["ATTRIBUTE="+attribute,
1524
+ "ALL_TOUCHED=TRUE"])
1525
+
1526
+ if convert_to_sparse:
1527
+ # Convert the raster to a npz containing the row and col of the non-null values
1528
+ array = band.ReadAsArray()
1529
+ ij = np.nonzero(array)
1530
+ np.savez_compressed(Path(out_file).with_suffix('.npz'), row=ij[0].astype(np.int32), col=ij[1].astype(np.int32))
1531
+
1532
+ target_ds = None
1533
+
1534
+ return 0