Skip to content

Commit c4d8767

Browse files
committed
Initial Commit
1 parent 2cd97b4 commit c4d8767

9 files changed

Lines changed: 1453 additions & 0 deletions

File tree

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Introduction
2+
This repository contains the codes for the Geo-INQUIRE tool to compute the rainfall-induced landslide hazard over an area. This verison of the code assumes a constant 24-h rainfall acummulation over the entire area covered by the susceptibility map.
3+
4+
# Getting Started
5+
1. Installation process: The landslide hazard tool requires to have installed python and Poetry.
6+
2. Software dependencies: Python version and dependecies are specified in the Poetry .toml file.
7+
8+
## REQUIRED INPUT DATA AND FILES:
9+
Input files must be saved (before running the hazard tool) 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. Must be downloaded from map repository.
12+
- `StdMaxDayRain.txt`: Standard deviation of the maximum daily rainfall.
13+
14+
## RUN THE HAZARD TOOL:
15+
1. In place the tile of the susceptibiluty map covering the area you want to compute the hazard in the folder `./Tool-Hazard-Map/input`
16+
2. Modify the `input_variables.csv` excel with the 24 h rainfall acummulation in [mm] you want to check.
17+
2. The code you need to runn is stored in `./Tool-Hazard-Map/Code` folder
18+
3. Before you runn the code make sure you have activated the poetry enviroment: `poetry shell`
19+
4. From the `./Tool-Hazard-Map/Code` folder in the terminal run: `python Hazard.py`
20+
5. The outpurs are stored in the `../Results/constant/` folder.
21+
22+
## OUTPUT:
23+
Results from the Hazard Tool are saved in the following folder which is authomatically generated `../Results/constant/`
24+
1. Rainfall Hazard: Rainfall hazard class in .tif format. Saved as: `./RainHazard/*_RainHazard.tif`
25+
2. Hazard map: in .tif format. Saved as: `./Hazard/*_Hazard.tif`
26+
27+
23.04.2024
28+
29+
# Contribute
30+
Work in a separate branch. Do a pull request to merge with main. Merging with main requires review.

Tool-HazardMap/Code/Hazard.py

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
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

Comments
 (0)