Skip to content

Commit d0b39ae

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 bff5409 commit d0b39ae

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
@@ -94,6 +94,9 @@ def SHP2Array(infile, defname=None):
9494
start = 0
9595
nParts = []
9696

97+
# New: Create an empty list to store attributes
98+
attributes = []
99+
97100
for n, (item, rec) in enumerate(zip(shps, sf.records())):
98101
pts = item.points
99102
# if feature has no points - ignore
@@ -113,9 +116,14 @@ def SHP2Array(infile, defname=None):
113116
# check if records are available and extract
114117
if records:
115118
# loop through fields
119+
# Extract attributes for the feature
120+
attr_dict = {}
116121
for (name, typ, size, deci), value in zip(sf.fields[1:], records[n].record):
117122
# get entity name
118123
name = name.lower()
124+
attr_dict[name] = value # Store attributes in dictionary
125+
126+
# Specific field handling (existing code)
119127
if name == "name":
120128
layername = str(value)
121129
if (name == "thickness") or (name == "d0"):
@@ -132,13 +140,15 @@ def SHP2Array(infile, defname=None):
132140
if name == "iso":
133141
iso = value
134142
if name == "layer":
135-
layerN = value
143+
layerN = value
136144
# if name is still empty go through file again and take Layer instead
137145
if (type(layername) is bytes) or (layername is None):
138146
for (name, typ, size, deci), value in zip(sf.fields[1:], records[n].record):
139147
if name == "Layer":
140148
layername = value
141149

150+
attributes.append(attr_dict) # Add the attribute dictionary to the list
151+
142152
# if layer still not defined, use generic
143153
if layername is None:
144154
layername = defname
@@ -173,6 +183,7 @@ def SHP2Array(infile, defname=None):
173183
SHPdata["layerName"] = layerNameList
174184
SHPdata["nParts"] = nParts
175185
SHPdata["nFeatures"] = len(Start)
186+
SHPdata["attributes"] = attributes # Add attributes to SHPdata
176187

177188
sf.close()
178189

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)