Source code for ana1Tests.rotationTest

"""
Rotation test

This module runs a DFA simulation for different grid alignments
and compares the results
"""
import logging
import shutil
from datetime import datetime

# Local imports
# import config and init tools
from avaframe.in3Utils import fileHandlerUtils as fU
from avaframe.log2Report import generateReport as gR
from avaframe.in3Utils import geoTrans as gT
import avaframe.in2Trans.ascUtils as IOf
from avaframe.version import getVersion
# import analysis modules
from avaframe.ana1Tests import energyLineTest
# import plotting module
import avaframe.out3Plot.plotUtils as pU
# create local logger
log = logging.getLogger(__name__)


[docs]def mainRotationTest(avalancheDir, energyLineTestCfg, com1DFACfg, dem, simDF, resTypeList, flagMass, refSimRowHash, comModule): """This is the core function of the Rotation Test module This module runs the energy line test and rotates the simulation results for the aimec analysis Parameters ---------- avalancheDir : pathlib path path to avalanche directory energyLineTestCfg : configParser energy line test configuration object com1DFACfg : configParser com1DFA configuration object dem : dict dem dictionary simDF : dataFrame DFA simulation dataFrame resTypeList : list list of result types available flagMass : boolean should the aimec mass analysis be done refSimRowHash : str row index of the reference simulation in the simDF comModule : str computation module used for the DFA simulation Returns ------- simDF : dataFrame DFA simulation dataFrame updated with the energy line test results flagMass : boolean should the aimec mass analysis be done (switched to true if it is an entrainment simulation) """ # read energy line config. ToDo should we only read the DFAPath config and remove the energy line one? inDir = avalancheDir / 'Outputs' / 'com1DFA' outDir = avalancheDir / 'Outputs' / 'com1DFARotated' fU.makeADir(outDir) # get reference angle simName = simDF.loc[refSimRowHash, 'simName'] relName = (simName.split('_'))[0] thetaRef = float(relName[3:]) for rowSimHash in simDF.index: # rotate results to be able to proceed to the aimec analysis simName = simDF.loc[rowSimHash, 'simName'] # activate mass analysis if it is an entrainment simulation # (note this can be forced to be true with the flagMass) if 'ent' in simDF.loc[rowSimHash, 'simType']: flagMass = True # copy mass file massFile = list(inDir.glob('mass_*' + simName + '*.txt')) shutil.copy(massFile[0], outDir) # rotate simulation results (will be the input for the AIMEC analysis) rotateDFAResults(avalancheDir, simDF, rowSimHash, resTypeList, thetaRef, comModule) # make energy line analysis resultEnergyTest, savePath = energyLineTest.mainEnergyLineTest(avalancheDir, energyLineTestCfg, com1DFACfg, simName, dem) simDF.loc[rowSimHash, 'zEnd'] = resultEnergyTest['zEnd'] simDF.loc[rowSimHash, 'sEnd'] = resultEnergyTest['sEnd'] simDF.loc[rowSimHash, 'runoutAngle'] = resultEnergyTest['runoutAngle'] simDF.loc[rowSimHash, 'energyLinePlotPath'] = savePath # now compare energy line results of rotated sims to the reference sim for rowSimHash in simDF.index: simDF.loc[rowSimHash, 'zDiff'] = simDF.loc[rowSimHash, 'zEnd'] - simDF.loc[refSimRowHash, 'zEnd'] simDF.loc[rowSimHash, 'sDiff'] = simDF.loc[rowSimHash, 'sEnd'] - simDF.loc[refSimRowHash, 'sEnd'] simDF.loc[rowSimHash, 'runoutAngleDiff'] = simDF.loc[rowSimHash, 'runoutAngle'] - simDF.loc[refSimRowHash, 'runoutAngle'] return simDF, flagMass
[docs]def rotateDFAResults(avalancheDir, simDF, rowSimHash, resTypeList, thetaRef, comModule): """Rotate the DFA results Parameters ---------- avalancheDir : pathlib path path to avalanche directory simDF : dataFrame DFA simulation dataFrame rowSimHash : str row index (in the simDF dataframe) of the simulation to analyze resTypeList : list list of result types available thetaRef : float angle of the path of the reference simulation comModule : str computation module used for the DFA simulation Returns ------- saves the rotated rasters to avalancheDir / 'Outputs' / comModule + 'Rotated' / 'peakFiles' """ log.debug('Rotating simulation: %s' % rowSimHash) simName = simDF.loc[rowSimHash, 'simName'] relName = (simName.split('_'))[0] theta = float(relName[3:]) simDF.loc[rowSimHash, 'relAngle'] = theta thetaRot = theta - thetaRef for resType in resTypeList: fName = simDF.loc[rowSimHash, resType] rasterDict = IOf.readRaster(fName) rotatedRaster = gT.rotateRaster(rasterDict, thetaRot, deg=True) comRotated = comModule + 'Rotated' outDir = avalancheDir / 'Outputs' / comRotated / 'peakFiles' fU.makeADir(outDir) outFileName = outDir / fName.name IOf.writeResultToAsc(rotatedRaster['header'], rotatedRaster['rasterData'], outFileName, flip=False)
[docs]def initializeRotationTestReport(avalancheDir, resTypeList, comModule, refSimName, flagMass): """Initialize dictionary that is used for markdown report generation for rotation test Parameters ---------- avalancheDir : pathlib path path to avalanche directory resTypeList : list list of result types available comModule : str computation module name refSimName : str name of the reference simulation in the simDF flagMass : boolean Was a mass analysis conducted? Returns ------- reportRotationTest : dict report dictionary """ dateTimeInfo = datetime.now().strftime("%d/%m/%Y %H:%M:%S") reportRotationTest = {'headerLine': {'type': 'title', 'title': 'Rotation Test for DFA Simulation'}, 'avaName': {'type': 'avaName', 'name': str(avalancheDir)}, 'time': {'type': 'time', 'time': dateTimeInfo}, 'Simulation Parameters': { 'type': 'list', 'Program version': getVersion(), 'DFA module': comModule, 'Reference simulation': refSimName}, 'Rotation test input simulations': { 'type': 'pandasDF', 'column names': {'simName': 'Simulation name', 'releaseScenario': 'Release name', 'relAngle': 'Angle °'}}, 'Rotation test Energy line result table': { 'type': 'pandasDF', 'column names': {'simName': 'Simulation name', 'relAngle': 'Angle °', 'sDiff': 's Diff [m]', 'zDiff': 'z Diff [m]', 'runoutAngleDiff': 'angle Diff [°]'}}, 'Rotation test Energy line figures': {'type': 'image'}, 'Rotation test AIMEC result table': { 'type': 'pandasDF', 'column names': {'simName': 'Simulation name', 'relAngle': 'Angle °', 'sRunout': 'Runout [m]', 'TP': 'True positive area [-]', 'FP': 'False positive area [-]', 'FN': 'False negative area [-]'}}, 'Rotation test AIMEC figures': {'type': 'image'}} if flagMass: reportRotationTest['Rotation test AIMEC result table']['column names']['relMass'] = 'release mass [kg]' reportRotationTest['Rotation test AIMEC result table']['column names']['finalMass'] = 'final mass [kg]' reportRotationTest['Rotation test AIMEC result table']['column names']['entMass'] = 'entrained mass [kg]' resTypeList = list(set(resTypeList).intersection(['ppr', 'pfv', 'pft'])) for resType in resTypeList: colName = 'max%sCrossMax' % resType colLabel = 'Maximum %s' % resType unit = pU.cfgPlotUtils['unit' + resType] colLabel = '%s [%s]' % (colLabel, unit) reportRotationTest['Rotation test AIMEC result table']['column names'][colName] = colLabel return reportRotationTest
[docs]def buildRotationTestReport(avalancheDir, reportRotationTest, simDF, resAnalysisDF, aimecPlotDict, flagMass): """Write the rotation test report Parameters ---------- avalancheDir : pathlib path path to avalanche directory reportRotationTest : dict report dictionary simDF : dataFrame DFA simulation dataFrame resAnalysisDF : dataFrame aimec results dataFrame aimecPlotDict : dict aimec plots dictionary flagMass : boolean Was a mass analysis conducted? Returns ------- generates the markDown report """ outDir = avalancheDir / 'Outputs' / 'ana1Tests' / 'rotationTest' fU.makeADir(outDir) energyLinePlotsDF = simDF.set_index('simName')['energyLinePlotPath'] energyLinePlotsDict = energyLinePlotsDF.to_dict() inPlotsDict = {'energyLinePlots': energyLinePlotsDict} inPlotsDict.update(aimecPlotDict['slCompPlot']) inPlotsDict.update(aimecPlotDict['areasPlot']) if flagMass: inPlotsDict.update(aimecPlotDict['massAnalysisPlot']) simDF = simDF.sort_values(by=['relAngle'], ascending=True) resAnalysisDF = resAnalysisDF.sort_values(by=['relAngle'], ascending=True) reportRotationTest['Rotation test input simulations']['dataDF'] = simDF reportRotationTest['Rotation test Energy line result table']['dataDF'] = simDF reportRotationTest['Rotation test Energy line figures'].update(inPlotsDict['energyLinePlots']) reportRotationTest['Rotation test AIMEC result table']['dataDF'] = resAnalysisDF reportRotationTest['Rotation test AIMEC figures'].update( inPlotsDict['Aimec comparison of mean and max values along path']) reportRotationTest['Rotation test AIMEC figures'].update(inPlotsDict['Aimec area analysis']) if flagMass: reportRotationTest['Rotation test AIMEC figures'].update(inPlotsDict['Aimec mass analysis']) # add energy line and aimec results table to report gR.writeReport(outDir, [reportRotationTest], True, plotDict='', standaloneReport=True, reportName='rotationTestReport')