Skip to content

Commit 2b4713d

Browse files
committed
feat(ana3AIMEC): add display labels for runout resolution types
feat(aimec): multi-layer simulation handling and input validation - Added support for resolving base `resType` to layer-suffixed columns in multi-layer simulations using the new `resolveResTypeColumn` function. - Introduced `computeBaseResTypeList` to validate and compute base `resType` names available for all simulations. - Updated `checkAIMECinputs` function to handle both single-layer and multi-layer simulations, with input validation and error handling when `runoutLayer` is not configured. refactor(aimec, com8MoTPSA): adjust logic and remove redundant parameters - Removed default fallback logic for `runoutResType` assignments in `ana3AIMEC.py` - Eliminated `simType` parameter from `copyRawToLayerPeakFiles` in `com8MoTPSA.py`
1 parent f2bb238 commit 2b4713d

File tree

9 files changed

+1131
-743
lines changed

9 files changed

+1131
-743
lines changed

avaframe/ana3AIMEC/aimecTools.py

Lines changed: 866 additions & 656 deletions
Large diffs are not rendered by default.

avaframe/ana3AIMEC/ana3AIMEC.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def fullAimecAnalysis(avalancheDir, cfg, inputDir='', demFileName=''):
6666
'demFileName': demFileName}
6767
pathDict = aimecTools.readAIMECinputs(avalancheDir, pathDict, cfgSetup.getboolean('defineRunoutArea'),
6868
dirName=anaMod)
69-
pathDict = aimecTools.checkAIMECinputs(cfgSetup, pathDict)
69+
pathDict = aimecTools.checkAIMECinputs(cfgSetup, pathDict, inputsDF)
7070
log.info("Running ana3AIMEC model on test case DEM \n %s \n with profile \n %s ",
7171
pathDict['demSource'], pathDict['profileLayer'])
7272
# Run AIMEC postprocessing
@@ -117,9 +117,10 @@ def mainAIMEC(pathDict, inputsDF, cfg):
117117
# get hash of the reference
118118
refSimRowHash = pathDict['refSimRowHash']
119119
# read reference file and raster and config
120-
# use resolved runoutResType from pathDict if available (layer-suffixed for multi-layer)
121-
runoutResType = pathDict.get('runoutResType', cfgSetup['runoutResType'])
122-
refResultSource = inputsDF.loc[refSimRowHash, runoutResType]
120+
runoutResType = pathDict['runoutResType']
121+
runoutLayer = pathDict.get('runoutLayer', '')
122+
refResTypeCol = aimecTools.resolveResTypeColumn(inputsDF.loc[refSimRowHash], runoutResType, runoutLayer)
123+
refResultSource = inputsDF.loc[refSimRowHash, refResTypeCol]
123124
refRaster = IOf.readRaster(refResultSource)
124125
refRasterData = refRaster['rasterData']
125126
refHeader = refRaster['header']
@@ -211,7 +212,14 @@ def mainAIMEC(pathDict, inputsDF, cfg):
211212
compResTypes1 = cfgPlots['compResType1'].split('|')
212213
compResTypes2 = cfgPlots['compResType2'].split('|')
213214
for indRes, compResType in enumerate(compResTypes1):
214-
outAimec.plotMaxValuesComp(pathDict, resAnalysisDF, compResType, compResTypes2[indRes],
215+
compResType2 = compResTypes2[indRes]
216+
missingCols = [c for c in [compResType, compResType2] if c not in resAnalysisDF.columns]
217+
if missingCols:
218+
log.warning("Skipping comparison plot %s vs %s: columns %s not available in results "
219+
"(result type not in resTypeList for all simulations)",
220+
compResType, compResType2, missingCols)
221+
continue
222+
outAimec.plotMaxValuesComp(pathDict, resAnalysisDF, compResType, compResType2,
215223
hue=cfgPlots['scenarioName'])
216224

217225
return rasterTransfo, resAnalysisDF, plotDict, newRasters
@@ -333,13 +341,15 @@ def postProcessAIMEC(cfg, rasterTransfo, pathDict, resAnalysisDF, newRasters, ti
333341
flagMass = cfgFlags.getboolean('flagMass')
334342
refSimRowHash = pathDict['refSimRowHash']
335343
resTypeList = pathDict['resTypeList']
344+
runoutLayer = pathDict.get('runoutLayer', '')
336345

337346
# apply domain transformation
338347
log.info('Analyzing data in path coordinate system')
339348

340349
for resType in resTypeList:
341350
log.debug("Assigning %s data to deskewed raster" % resType)
342-
inputFiles = resAnalysisDF.loc[simRowHash, resType]
351+
resTypeCol = aimecTools.resolveResTypeColumn(resAnalysisDF.loc[simRowHash], resType, runoutLayer)
352+
inputFiles = resAnalysisDF.loc[simRowHash, resTypeCol]
343353
if isinstance(inputFiles, pathlib.PurePath):
344354
rasterData = IOf.readRaster(inputFiles)
345355
newRaster = aimecTools.transform(rasterData, inputFiles, rasterTransfo, interpMethod)
@@ -382,20 +392,19 @@ def postProcessAIMEC(cfg, rasterTransfo, pathDict, resAnalysisDF, newRasters, ti
382392
simRowHash, rasterTransfo, newRaster, resType, resAnalysisDF
383393
)
384394

385-
# compute runout based on resolved runoutResType (layer-suffixed for multi-layer)
386-
resolvedRunoutResType = pathDict.get('runoutResType', cfgSetup['runoutResType'])
395+
# compute runout based on base runoutResType (resolver handles per-row column access)
396+
runoutResType = pathDict['runoutResType']
387397
resAnalysisDF = aimecTools.computeRunOut(cfgSetup, rasterTransfo, resAnalysisDF, newRasters, simRowHash,
388-
runoutResType=resolvedRunoutResType)
398+
runoutResType=runoutResType)
389399
runoutLine = aimecTools.computeRunoutLine(cfgSetup, rasterTransfo, newRasters, simRowHash, 'simulation', name='',
390-
runoutResType=resolvedRunoutResType)
400+
runoutResType=runoutResType)
391401

392402
if 'refPoint' in refDataTransformed:
393403
# compute differences between runout points
394404
resAnalysisDF = aimecTools.computeRunoutPointDiff(resAnalysisDF, refDataTransformed['refPoint'], simRowHash)
395405

396406
# plot comparison between runout lines
397-
resolvedRunoutResType = pathDict.get('runoutResType', cfgSetup['runoutResType'])
398-
outAimec.compareRunoutLines(cfgSetup, refDataTransformed, newRasters['newRaster'+resolvedRunoutResType.upper()],
407+
outAimec.compareRunoutLines(cfgSetup, refDataTransformed, newRasters['newRaster'+runoutResType.upper()],
399408
runoutLine, rasterTransfo, resAnalysisDF.loc[simRowHash], pathDict)
400409

401410
# analyze distribution of diffs between runout lines

avaframe/ana3AIMEC/dfa2Aimec.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# local modules
1111
from avaframe.in3Utils import fileHandlerUtils as fU
1212
from avaframe.in3Utils import cfgUtils
13+
from avaframe.ana3AIMEC import aimecTools
1314

1415
# create local logger
1516
# change log level in calling module to DEBUG to see log messages
@@ -147,8 +148,6 @@ def dfaBench2Aimec(avaDir, cfg, simNameRef='', simNameComp=''):
147148
# Load all infos on comparison module simulations
148149
compData, resTypeCompList = fU.makeSimFromResDF(avaDir, None, inputDir=inputDirComp, simName=simNameComp)
149150

150-
resTypeList = list(set(resTypeRefList).intersection(resTypeCompList))
151-
pathDict['resTypeList'] = resTypeList
152151
pathDict['colorParameter'] = colorParameter
153152
pathDict['refSimRowHash'] = refSimRowHash
154153
pathDict['refSimName'] = refSimName
@@ -182,6 +181,12 @@ def dfaBench2Aimec(avaDir, cfg, simNameRef='', simNameComp=''):
182181
message = ('Multiple rows of the dataFrame have the same simulation name.')
183182
log.warning(message)
184183

184+
# compute base-name resTypeList and validate via checkAIMECinputs
185+
# use raw column-name lists as initial resTypeList (will be overwritten by checkAIMECinputs)
186+
resTypeList = list(set(resTypeRefList).intersection(resTypeCompList))
187+
pathDict['resTypeList'] = resTypeList
188+
pathDict = aimecTools.checkAIMECinputs(cfgSetup, pathDict, inputsDF)
189+
185190
return inputsDF, pathDict
186191

187192

avaframe/com8MoTPSA/com8MoTPSA.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def com8MoTPSAMain(cfgMain, cfgInfo=None):
7171
com8MoTPSAPostprocess(simDict, cfgMain, inputSimFiles)
7272

7373

74-
def copyRawToLayerPeakFiles(workDir, simType, outputDirPeakFile):
74+
def copyRawToLayerPeakFiles(workDir, outputDirPeakFile):
7575
"""Rename and copy raw MoT-PSA output files to peakFiles with L1/L2 layer naming.
7676
7777
MoT-PSA produces raw suffixes (p1/p2_max, h1/h2_max, s1/s2_max) that map
@@ -84,8 +84,6 @@ def copyRawToLayerPeakFiles(workDir, simType, outputDirPeakFile):
8484
----------
8585
workDir : pathlib.Path
8686
simulation work directory containing raw MoT-PSA output files
87-
simType : str
88-
simulation type (e.g. "null", "ent") used in the rename pattern
8987
outputDirPeakFile : pathlib.Path
9088
target directory for renamed peak files
9189
"""
@@ -97,18 +95,11 @@ def copyRawToLayerPeakFiles(workDir, simType, outputDirPeakFile):
9795
]
9896
for globPattern, rawL1, rawL2, resType in layerRenameMap:
9997
rawFiles = list(workDir.glob(globPattern))
100-
# Replace raw L1 suffix with L1 layer + resType (e.g. null_psa_p1_max -> null_psa_L1_ppr)
98+
# Replace raw suffixes with layer naming (e.g. p1_max -> L1_ppr, p2_max -> L2_ppr)
10199
targetFiles = [
102-
pathlib.Path(str(f.name).replace(
103-
"%s_psa_%s" % (simType, rawL1), "%s_psa_L1_%s" % (simType, resType)))
100+
pathlib.Path(str(f.name).replace(rawL1, "L1_%s" % resType).replace(rawL2, "L2_%s" % resType))
104101
for f in rawFiles
105102
]
106-
# Replace raw L2 suffix with L2 layer + resType (e.g. null_psa_p2_max -> null_psa_L2_ppr)
107-
targetFiles = [
108-
pathlib.Path(str(f).replace(
109-
"%s_psa_%s" % (simType, rawL2), "%s_psa_L2_%s" % (simType, resType)))
110-
for f in targetFiles
111-
]
112103
# Prepend output directory and copy
113104
targetFiles = [outputDirPeakFile / f for f in targetFiles]
114105
for source, target in zip(rawFiles, targetFiles):
@@ -124,7 +115,7 @@ def com8MoTPSAPostprocess(simDict, cfgMain, inputSimFiles):
124115
Parameters
125116
----------
126117
simDict : dict
127-
simulation dictionary keyed by simKey, each value contains "simType"
118+
simulation dictionary
128119
cfgMain : configparser.ConfigParser
129120
main AvaFrame configuration (avalancheDir, plot flags)
130121
inputSimFiles : dict
@@ -140,14 +131,11 @@ def com8MoTPSAPostprocess(simDict, cfgMain, inputSimFiles):
140131
for key in simDict:
141132
workDir = pathlib.Path(avalancheDir) / "Work" / "com8MoTPSA" / str(key)
142133

143-
# identify simType
144-
simType = simDict[key]["simType"]
145-
146134
# Copy DataTime.txt
147135
dataTimeFile = workDir / "DataTime.txt"
148136
shutil.copy2(dataTimeFile, outputDir / (str(key) + "_DataTime.txt"))
149137

150-
copyRawToLayerPeakFiles(workDir, simType, outputDirPeakFile)
138+
copyRawToLayerPeakFiles(workDir, outputDirPeakFile)
151139

152140
# create plots and report
153141
modName = __name__.split(".")[-1]

avaframe/in3Utils/fileHandlerUtils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ def makeSimFromResDF(avaDir, comModule, inputDir="", simName=""):
669669
dataframe with for each simulation, the full file path, file name, release area scenario,
670670
simulation type (null, entres, etc.), model type (dfa, ref, etc.), simID,
671671
path to result files (ppr, pft, etc.), simulation name,
672-
cell size and optional name of avalanche, optional time step
672+
cell size and optional name of avalanche, optional time step, layer name
673673
resTypeListAll: list
674674
list of res types available for all simulations
675675
"""

0 commit comments

Comments
 (0)