1+ """
2+ Hazard.py
3+
4+ Implements the calculation of the hazard of the GIRI model for the cases:
5+ 1) Generic rainfall, constat over an area. Specified by user in .csv file.
6+ as a subclass of HazardProcessor
7+
8+ INPUT:
9+ Required input files to be saved in the ../Data/ folder:
10+ - input_variables.csv: csv file where input rainfall can be specified.
11+ - *_sus.tif: Tile of the susceptibility map over hazard will be computed.
12+ Must be downloaded from map repository.
13+ - StdMaxDayRain.txt: Standar deviation of the maximum daily rainfall.
14+
15+ OUTPUT:
16+ Results saved in ../Results/constant/ folder
17+ - Rainfall Hazard: Rainfall hazard class in .tif format. Saved as: ./RainHazard/{}_RainHazard.tif
18+ - Hazard map: in .tif format. Saved as: ./Hazard/{}_Hazard.tif
19+
20+ Rosa M Palau (NGI) 08.04.2024
21+ """
22+
23+ import numpy as np
24+ import rasterio
25+ from rasterio .enums import Resampling
26+ from rasterio .mask import mask
27+ from rasterio .transform import rowcol
28+ from rasterio .windows import Window
29+ import geojson
30+ import json
31+ #from shapely.geometry import shape, mapping, Point, LineString
32+ #from shapely.ops import unary_union
33+
34+ from pyproj import Proj , Transformer
35+
36+ from pathlib import Path
37+
38+ from HazardProcessor import HazardProcessor
39+
40+ ## Define input parameters
41+ KWARGS = {
42+ "sclass" : [1 , 2 , 3 , 4 , 5 ],
43+ "I_lim" : [0.3 , 2.0 , 3.7 , 5.0 ],
44+ "epsg_wgs84" : 4326 ,
45+ 'MULTIPROCESSING' : False ,
46+ 'MAX_NUMBER_OF_PROCESSES' : 10 ,
47+ }
48+
49+ class CalcHazard (HazardProcessor ):
50+ def __init__ (self , ** kwargs ):
51+ super ().__init__ (** kwargs )
52+
53+ def read_raster (self , path_map ):
54+ """
55+ Implements rasterio open to read a raster map. Saves variables which are interesting
56+ INPUT:
57+ -path_map: file of the susceptibility map
58+ """
59+ # function to read raster maps with rasterio
60+
61+ with rasterio .open (path_map ) as src_dataset :
62+ print ("Reading data: {}" .format (path_map ))
63+ kwds = src_dataset .profile
64+ features_in = src_dataset .read (1 , masked = True ).astype (float ).filled (np .nan )
65+ bbox = src_dataset .bounds
66+
67+ top = bbox .top
68+ bottom = bbox .bottom
69+ left = bbox .left
70+ right = bbox .right
71+
72+ ncols = kwds ["width" ]
73+ nrows = kwds ["height" ]
74+
75+ return (features_in , ncols , nrows , kwds , bbox )
76+
77+ def read_susceptibility_classified (self , file_susc ):
78+ """
79+ Reads susceptibility map using rasterio.
80+ INPUT:
81+ -file_susc: file of the susceptibility map
82+ """
83+
84+ # read raster
85+ susc_class , ncols , nrows , kwds , bbox = self .read_raster (file_susc )
86+ dx = kwds ["transform" ][0 ]
87+
88+ crs = kwds ["crs" ]
89+ #nodata = kwds["nodata"]
90+ #transform = kwds["transform"]
91+
92+ return (susc_class , ncols , nrows , kwds , bbox , crs )
93+
94+ def Resample (self , in_file , target_ncols , target_nrows , target_bbox ):
95+ """
96+ Resamples raster map to get the resolution and shape of another raster map. Uses rasterio.
97+ INPUT:
98+ -in_file: file we want to resample
99+ -target_ncols, target_nrows: number of columns and number of rows of the other map
100+ (we want to copy / other map)
101+ -target_bbox: bounding box of tthe other map (map we want to copy)
102+ """
103+ # Use rasterio to resample de rainfall data
104+ with rasterio .open (in_file ) as source_ds :
105+ # Crop the source raster using the target extent
106+ window = source_ds .window (* target_bbox )
107+ source_data = source_ds .read (window = window )
108+
109+ # Resample the cropped source raster to match the resolution of the target raster
110+ resampled_data = source_ds .read (
111+ out_shape = (source_ds .count , target_nrows , target_ncols ),
112+ resampling = Resampling .bilinear
113+ )
114+
115+ resampled_data = resampled_data .squeeze () ## Squeeze the resampled data to remove the first axis
116+
117+ return (resampled_data )
118+
119+ def OpenRainNorm (self , bbox_susc , ncols_susc , nrows_susc ):
120+ """
121+ Opens rainfall data that is required for the normalization of the rain.
122+ INPUT:
123+ -bbox_susc: bounding box of susceptibility map
124+ -ncols_susc, nrows_susc: umber of columns and number of rows of susc map
125+ """
126+
127+ # files to read
128+ file_mean_day_rain = self .path_data / "MeanMaxDayRain.asc"
129+ file_std_day_rain = self .path_data / "StdMaxDayRain.txt"
130+
131+ # read rasters, crop and re-sample to match resolution of target raster.
132+ MeanRain = self .Resample (file_mean_day_rain , ncols_susc , nrows_susc , bbox_susc )
133+ StdRain = self .Resample (file_std_day_rain , ncols_susc , nrows_susc , bbox_susc )
134+
135+ return (MeanRain , StdRain )
136+
137+
138+ def CreateCntRain (self , ncols , nrows ):
139+ """
140+ Creates am empty array like the input-susceptibility map filled with constant user-defined
141+ 24 h rainfall acummmulation value.
142+ INPUT:
143+ -ncols, nrows: number of columns and number of rows
144+ """
145+
146+ acum24 = np .full ((nrows , ncols ), self .in_acum )
147+ return (acum24 )
148+
149+
150+ def ComputeRainCnt (self , MeanRain , StdRain , acum24 ):
151+ # Normalize
152+ I24norm_da = (acum24 - MeanRain )/ StdRain
153+
154+ return (I24norm_da )
155+
156+ def ComputeRainHazard (self , I24norm_da , I_lim , file_name1 , ncols , nrows , kwds ):
157+ """
158+ Implements computation of the rainfall hazard.
159+ INPUT:
160+ -I24norm_da, normalized rainfall map array
161+ -I_lim: input array with limits of the rainfall hazard classes
162+ -file_name1, input name of he susceptibility map sheet
163+ -ncols, nrows: number of columns and number of rows
164+ -kwds
165+ """
166+
167+ aux = I24norm_da # raster array
168+ #time_coord = aux.time
169+
170+ RainHazard_aux = np .zeros_like (aux )
171+
172+ # Assign rain hazard
173+ for ii in range (len (I_lim )):
174+ if ii == 0 :
175+ mask = (aux <= ii )
176+ RainHazard_aux = np .where (mask , ii + 1 , RainHazard_aux )
177+ else :
178+ if ii < 3 :
179+ mask = (aux <= ii ) & (aux > ii - 1 )
180+ RainHazard_aux = np .where (mask , ii + 1 , RainHazard_aux )
181+ else :
182+ mask = (aux <= ii ) & (aux > ii - 1 )
183+ RainHazard_aux = np .where (mask , ii + 1 , RainHazard_aux )
184+
185+ mask = (aux > ii )
186+ RainHazard_aux = np .where (mask , ii + 2 , RainHazard_aux )
187+
188+ # Save to file
189+ folder_out = self .path_out / self .mode
190+ if not folder_out .exists (): # Create the folder if it doesn't exist
191+ folder_out .mkdir (parents = True , exist_ok = True )
192+
193+ folder_out = self .path_out / self .mode / "RainHazard"
194+ if not folder_out .exists (): # Create the folder if it doesn't exist
195+ folder_out .mkdir (parents = True , exist_ok = True )
196+
197+ prefix = file_name1 .split ('_' )[0 ]
198+
199+ file_save_name = prefix + "_RainHazard.tif"
200+ file_save = folder_out / file_save_name
201+
202+ # Save Rain Hazard raster
203+ outfile = file_save
204+ with rasterio .open (outfile , "w" , ** kwds ) as dst_dataset :
205+ dst_dataset .write (RainHazard_aux , 1 )
206+
207+ return (RainHazard_aux )
208+
209+ def ComputeHazard (self , susc_da , RainHazard_aux , file_name1 , kwds ):
210+ """
211+ Implements computation of the hazard matrix.
212+ INPUT:
213+ -susc_da, Susceptibility map array
214+ -RainHazard_aux, rainfall hazard array
215+ -file_name1, input name of he susceptibility map sheet
216+ -kwds
217+ """
218+
219+ # Hazard matrix
220+ hazard_aux = np .zeros_like (susc_da ) # initialise array to store the hazard
221+
222+ # Check hazard by going through hazard matrix
223+ hazard_aux = np .where (np .isnan (susc_da ), np .nan , hazard_aux )
224+
225+ mask = (susc_da == 2 ) & (RainHazard_aux == 2 )
226+ hazard_aux = np .where (mask , 1 , hazard_aux )
227+ mask = (susc_da == 2 ) & (RainHazard_aux == 3 )
228+ hazard_aux = np .where (mask , 2 , hazard_aux )
229+ mask = (susc_da == 2 ) & (RainHazard_aux == 4 )
230+ hazard_aux = np .where (mask , 3 , hazard_aux )
231+ mask = (susc_da == 2 ) & (RainHazard_aux == 5 )
232+ hazard_aux = np .where (mask , 5 , hazard_aux )
233+
234+ mask = (susc_da == 3 ) & (RainHazard_aux == 2 )
235+ hazard_aux = np .where (mask , 2 , hazard_aux )
236+ mask = (susc_da == 3 ) & (RainHazard_aux == 3 )
237+ hazard_aux = np .where (mask , 3 , hazard_aux )
238+ mask = (susc_da == 3 ) & (RainHazard_aux == 4 )
239+ hazard_aux = np .where (mask , 5 , hazard_aux )
240+ mask = (susc_da == 3 ) & (RainHazard_aux == 5 )
241+ hazard_aux = np .where (mask , 10 , hazard_aux )
242+
243+ mask = (susc_da == 4 ) & (RainHazard_aux == 2 )
244+ hazard_aux = np .where (mask , 3 , hazard_aux )
245+ mask = (susc_da == 4 ) & (RainHazard_aux == 3 )
246+ hazard_aux = np .where (mask , 5 , hazard_aux )
247+ mask = (susc_da == 4 ) & (RainHazard_aux == 4 )
248+ hazard_aux = np .where (mask , 10 , hazard_aux )
249+ mask = (susc_da == 4 ) & (RainHazard_aux == 5 )
250+ hazard_aux = np .where (mask , 15 , hazard_aux )
251+
252+ mask = (susc_da == 5 ) & (RainHazard_aux == 2 )
253+ hazard_aux = np .where (mask , 5 , hazard_aux )
254+ mask = (susc_da == 5 ) & (RainHazard_aux == 3 )
255+ hazard_aux = np .where (mask , 10 , hazard_aux )
256+ mask = (susc_da == 5 ) & (RainHazard_aux == 4 )
257+ hazard_aux = np .where (mask , 15 , hazard_aux )
258+ mask = (susc_da == 5 ) & (RainHazard_aux == 5 )
259+ hazard_aux = np .where (mask , 20 , hazard_aux )
260+
261+ # Save to file
262+ folder_out = self .path_out / self .mode / "Hazard"
263+ if not folder_out .exists (): # Create the folder if it doesn't exist
264+ folder_out .mkdir (parents = True , exist_ok = True )
265+
266+ prefix = file_name1 .split ('_' )[0 ]
267+
268+ file_save_name = prefix + "_Hazard.tif"
269+ file_save = folder_out / file_save_name
270+
271+ # Save Rain Hazard raster
272+ outfile = file_save
273+ with rasterio .open (outfile , "w" , ** kwds ) as dst_dataset :
274+ dst_dataset .write (hazard_aux , 1 )
275+
276+ return (hazard_aux )
277+
278+ def CompGiriHazard (self , file_susc , file_name1 , sema = None ):
279+ """
280+ Implements different steps for hazard computation.
281+ INPUT:
282+ -file_susc: file of the susceptibility map
283+ -file_name1: name of he susceptibility map sheet
284+ """
285+ # read susceptibility raster
286+ susc , ncols , nrows , kwds , bbox , crs = self .read_susceptibility_classified (file_susc )
287+
288+ # Check if we use constant user-defined rain or an input rainfall map.
289+ if self .mode == "constant" :
290+ # Create rainfall grid.
291+ acum24 = self .CreateCntRain (ncols , nrows )
292+ if self .mode == "input map" :
293+ #Read rainfall acummulation map
294+ acum24 = self .ReadInRainMap (bbox , ncols , nrows )
295+
296+ # Compute mean and sd to normalize rain.
297+ MeanRain , StdRain = self .OpenRainNorm (bbox , ncols , nrows )
298+
299+ # Normalize rain.
300+ I24norm = self .ComputeRainCnt (MeanRain , StdRain , acum24 )
301+
302+ # Compute rainfall hazard.
303+ print ("Computing rainfall hazard" )
304+ RainHazard = self .ComputeRainHazard (I24norm , self .I_lim , file_name1 , ncols , nrows , kwds )
305+
306+ # Compute landslide hazard.
307+ print ("Computing hazard" )
308+ LandsHazard = self .ComputeHazard (susc , RainHazard , file_name1 , kwds )
309+
310+ if sema is not None :
311+ sema .release () # Release will add 1 to sema.
312+
313+ if __name__ == '__main__' :
314+ CalcHazard (** KWARGS )
315+
316+
317+
318+
0 commit comments