Skip to content

Commit db4517d

Browse files
dwolfschfso42
authored andcommitted
spatial Voellmy friction model: add VariableVoellmyShapeToRaster to generate rasters from shapes
Adds functionality for generating raster files for mu and xsi values from a DEM and shapefiles including: A main script to rasterize mu and xsi based on polygon shapefiles and attribute fields. A corresponding run script and configuration file for user customization.
1 parent 21e4b94 commit db4517d

File tree

6 files changed

+188
-2
lines changed

6 files changed

+188
-2
lines changed

avaframe/avaframeCfg.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[MAIN]
66
# Path to avalanche directory
7-
avalancheDir = data/avaParabola
7+
avalancheDir =
88

99
# number of CPU cores to use for the computation of com1DFA
1010
# possible values are:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
The VariableVoellmyShapeToRaster.py script allows the user to define spatially different values for the voellmy Parameters mu and xsi, with the use of polygon shapefiles. For the extent of a DEM raster, all the areas that are not covered by a polygon get assigned a default mu or xsi value. The script then converts this Information into a raster mu and a raster xsi file, which can then be used in Avaframe Simulation runs, using the "spatialVoellmy" friction model.
2+
3+
First, set up the Config File and provide inputs:
4+
•Config File:
5+
oIn the first step, the Config File needs to be configured and all input files have to be provided
6+
Main Config (avaframeCfg.ini):
7+
•Set the path to the avalanche directory
8+
oInputs:
9+
All the Input Files are automatically fetched through the set avalanche directory. It is not necessary to provide a file path.
10+
dem: DEM Raster that is later on used for the avaframe simulation. This is needed, because the mu and xsi output rasters need to be the exact same size. Has to lie in avadir/Inputs.
11+
mu_shapefile: Mu shapefile, that is then converted to a raster file. Be aware, that the attribute has to be named “mu” and the file name has to end with “_mu”. Has to lie in avadir/Inputs/POLYGONS.
12+
xsi_shapefile: Xsi shapefile, that is then converted to a raster file. Be aware, that the attribute has to be named “xsi” and the file name has to end with “_xsi”. Has to lie in avadir/Inputs/POLYGONS.
13+
oDefaults:
14+
default_mu: this is the default mu value, that gets assigned to all areas in the raster, that are not covered by shapefile-polygons
15+
default_xsi: this is the default xsi value, that gets assigned to all areas in the raster, that are not covered by shapefile-polygons
16+
oOutputs:
17+
For the variable Voellmy calculations in the com1DFA algorithm to work, it is mandatory, that the files are stored in: avaframe\data\*yourAvalancheDir*\Inputs\RASTERS\
18+
mu_raster: Output for the generated mu raster file stored as *_mu.asc
19+
xsi_raster: Output for the generated xsi raster file stored as *_xi.asc
20+
21+
•RunScript:
22+
oOnce everything is set up, run the script “runVariableVoellmyShapeToRaster.py”
23+
oIf libraries are missing use: pip install *name of missing library
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
2+
import rasterio
3+
import numpy as np
4+
import pathlib
5+
from rasterio.features import rasterize
6+
from shapely.geometry import shape, mapping
7+
from in2Trans.shpConversion import SHP2Array
8+
from in1Data.getInput import getAndCheckInputFiles
9+
import logging
10+
11+
# Configure logging
12+
logging.basicConfig(level=logging.DEBUG)
13+
log = logging.getLogger(__name__)
14+
15+
def generateMuXsiRasters(avadir, variableVoellmyCfg):
16+
"""
17+
Generate raster files for \u03bc and \u03be based on input DEM and shapefiles.
18+
19+
Parameters
20+
----------
21+
avadir : str
22+
Path to the avalanche directory.
23+
variableVoellmyCfg : Config Parser Object
24+
variableVoellmyCfg Configuration File
25+
26+
Returns
27+
-------
28+
None
29+
"""
30+
avadir = pathlib.Path(avadir)
31+
32+
config = variableVoellmyCfg # Directly use the ConfigParser object
33+
34+
inputDir = avadir / "Inputs"
35+
outputDir = avadir / "Inputs" # Output directory is Inputs, because Outputs of this Script will be used as Inputs for AvaFrame
36+
37+
demPath, _ = getAndCheckInputFiles(inputDir, '', 'DEM', fileExt='asc')
38+
muShapefile, _ = getAndCheckInputFiles(inputDir, 'POLYGONS', '\u03bc Shapefile', fileExt='shp', fileSuffix='_mu')
39+
xsiShapefile, _ = getAndCheckInputFiles(inputDir, 'POLYGONS', '\u03be Shapefile', fileExt='shp', fileSuffix='_xsi')
40+
41+
muOutputPath = outputDir / "RASTERS" / "raster_mu.asc"
42+
xsiOutputPath = outputDir / "RASTERS" /"raster_xi.asc"
43+
44+
defaultMu = float(config['DEFAULTS']['default_mu'])
45+
defaultXsi = float(config['DEFAULTS']['default_xsi'])
46+
47+
# Read DEM
48+
with rasterio.open(demPath) as demSrc:
49+
demData = demSrc.read(1)
50+
demTransform = demSrc.transform
51+
demCrs = demSrc.crs
52+
demShape = demData.shape
53+
54+
def rasterizeShapefile(shapefilePath, defaultValue, attributeName):
55+
if not shapefilePath:
56+
return np.full(demShape, defaultValue, dtype=np.float32)
57+
58+
shpData = SHP2Array(shapefilePath)
59+
shapes = []
60+
for i in range(shpData['nFeatures']):
61+
start = int(shpData['Start'][i])
62+
length = int(shpData['Length'][i])
63+
coords = [(shpData['x'][j], shpData['y'][j]) for j in range(start, start + length)]
64+
poly = shape({'type': 'Polygon', 'coordinates': [coords]})
65+
value = shpData['attributes'][i][attributeName]
66+
shapes.append((mapping(poly), value))
67+
68+
return rasterize(shapes, out_shape=demShape, transform=demTransform, fill=defaultValue, all_touched=True, dtype=np.float32)
69+
70+
log.info("Rasterizing \u03bc shapefile.")
71+
muRaster = rasterizeShapefile(muShapefile, defaultMu, "mu")
72+
73+
log.info("Rasterizing \u03be shapefile.")
74+
xsiRaster = rasterizeShapefile(xsiShapefile, defaultXsi, "xsi")
75+
76+
def saveRaster(outputPath, data):
77+
with rasterio.open(outputPath, 'w', driver='GTiff', height=data.shape[0], width=data.shape[1], count=1, dtype=data.dtype, crs=demCrs, transform=demTransform) as dst:
78+
dst.write(data, 1)
79+
80+
log.info("Saving \u03bc raster to %s", muOutputPath)
81+
saveRaster(muOutputPath, muRaster)
82+
83+
log.info("Saving \u03be raster to %s", xsiOutputPath)
84+
saveRaster(xsiOutputPath, xsiRaster)
85+
86+
log.info("Raster generation completed.")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[DEFAULTS]
2+
# Default \u03bc value for areas not covered by shapefiles
3+
default_mu = 0.1
4+
5+
# Default \u03be value for areas not covered by shapefiles
6+
default_xsi = 300.0

avaframe/in2Trans/shpConversion.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ def SHP2Array(infile, defname=None):
126126
start = 0
127127
nParts = []
128128

129+
# New: Create an empty list to store attributes
130+
attributes = []
131+
129132
for n, (item, rec) in enumerate(zip(shps, sf.records())):
130133
pts = item.points
131134
# if feature has no points - ignore
@@ -145,9 +148,14 @@ def SHP2Array(infile, defname=None):
145148
# check if records are available and extract
146149
if records:
147150
# loop through fields
151+
# Extract attributes for the feature
152+
attr_dict = {}
148153
for (name, typ, size, deci), value in zip(sf.fields[1:], records[n].record):
149154
# get entity name
150155
name = name.lower()
156+
attr_dict[name] = value # Store attributes in dictionary
157+
158+
# Specific field handling (existing code)
151159
if name == "name":
152160
layername = str(value)
153161
if (name == "thickness") or (name == "d0"):
@@ -183,13 +191,15 @@ def SHP2Array(infile, defname=None):
183191
if name == "iso":
184192
iso = value
185193
if name == "layer":
186-
layerN = value
194+
layerN = value
187195
# if name is still empty go through file again and take Layer instead
188196
if (type(layername) is bytes) or (layername is None):
189197
for (name, typ, size, deci), value in zip(sf.fields[1:], records[n].record):
190198
if name == "Layer":
191199
layername = value
192200

201+
attributes.append(attr_dict) # Add the attribute dictionary to the list
202+
193203
# if layer still not defined, use generic
194204
if layername is None:
195205
layername = defname
@@ -243,6 +253,7 @@ def SHP2Array(infile, defname=None):
243253
SHPdata["tilt"] = tiltList
244254
SHPdata["direc"] = direcList
245255
SHPdata["offset"] = offsetList
256+
SHPdata["attributes"] = attributes # Add attributes to SHPdata
246257

247258
sf.close()
248259

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
import argparse
3+
import pathlib
4+
import time
5+
from avaframe.in3Utils import cfgUtils
6+
from avaframe.in3Utils import logUtils
7+
import avaframe.in3Utils.initializeProject as initProj
8+
from com6RockAvalanche import variableVoellmyShapeToRaster
9+
from com6RockAvalanche.variableVoellmyShapeToRaster import generateMuXsiRasters
10+
11+
def runMuXsiWorkflow(avadir=''):
12+
"""
13+
Run the workflow to generate \u03bc and \u03be rasters.
14+
15+
Parameters
16+
----------
17+
avadir : str
18+
Path to the avalanche directory containing input and output folders.
19+
20+
Returns
21+
-------
22+
None
23+
"""
24+
startTime = time.time()
25+
logName = 'runMuXsi'
26+
27+
# Load general configuration file
28+
cfgMain = cfgUtils.getGeneralConfig()
29+
if avadir:
30+
cfgMain['MAIN']['avalancheDir'] = avadir
31+
else:
32+
avadir = cfgMain['MAIN']['avalancheDir']
33+
34+
avadir = pathlib.Path(avadir)
35+
36+
# Start logging
37+
log = logUtils.initiateLogger(avadir, logName)
38+
log.info('MAIN SCRIPT')
39+
log.info('Using avalanche directory: %s', avadir)
40+
41+
# Clean input directory(ies) of old work files
42+
initProj.cleanSingleAvaDir(avadir, deleteOutput=False)
43+
44+
# Load module-specific configuration for Variable Voellmy
45+
variableVoellmyCfg = cfgUtils.getModuleConfig(variableVoellmyShapeToRaster)
46+
47+
# Run the raster generation process
48+
generateMuXsiRasters(avadir, variableVoellmyCfg)
49+
50+
endTime = time.time()
51+
log.info("Took %6.1f seconds to calculate.", (endTime - startTime))
52+
log.info('Workflow completed successfully.')
53+
54+
if __name__ == '__main__':
55+
parser = argparse.ArgumentParser(description='Run \u03bc and \u03be raster generation workflow')
56+
parser.add_argument('avadir', metavar='a', type=str, nargs='?', default='',
57+
help='Path to the avalanche directory')
58+
59+
args = parser.parse_args()
60+
runMuXsiWorkflow(str(args.avadir))

0 commit comments

Comments
 (0)