Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions avaframe/com3Hybrid/com3Hybrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
# import config and init tools
import avaframe.in2Trans.shpConversion as shpConv
from avaframe.in3Utils import cfgUtils
from avaframe.in3Utils import fileHandlerUtils as fU
from avaframe.in1Data import getInput

# import computation modules
from avaframe.com1DFA import com1DFA, particleTools
import avaframe.ana5Utils.DFAPathGeneration as DFAPath
from avaframe.com2AB import com2AB
from avaframe.com3Hybrid import com3Hybrid

# import analysis tools
from avaframe.out3Plot import outAB
Expand All @@ -41,8 +43,15 @@ def maincom3Hybrid(cfgMain, cfgHybrid):
"""
avalancheDir = cfgMain['MAIN']['avalancheDir']
demOri = getInput.readDEM(avalancheDir)
# get comDFA configuration path for hybrid model
hybridModelDFACfg = pathlib.Path('com3Hybrid', 'hybridModel_com1DFACfg.ini')

# setup outputs folder
oPath = pathlib.Path(avalancheDir, 'Outputs', 'com3Hybrid')
fU.makeADir(oPath)

# get comDFA configuration and save to file
hybridModelDFACfg = cfgUtils.getModuleConfig(com1DFA, fileOverride='', modInfo=False, toPrint=False,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is maybe a bit confusing to have both a fileOverride and a overrideConfig... Maybe we could rename this a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is your suggestion? I think it is actually pretty accurate the one thing is a file path that you have to provide the other is configparser object that has the override parameters in it..

onlyDefault=cfgHybrid['com1DFA_override']['defaultConfig'], overrideConfig=cfgHybrid)
hybridModelDFACfgFile = cfgUtils.writeCfgFile(avalancheDir, com1DFA, hybridModelDFACfg, fileName='com1DFA_settings', filePath=oPath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why write this one and not also the AB and pathGeneration cfgs to file?


# get initial mu value
muArray = np.array([cfgHybrid.getfloat('DFA', 'mu')])
Expand All @@ -54,21 +63,25 @@ def maincom3Hybrid(cfgMain, cfgHybrid):
iterate = True
resultsHybrid = {}
while iteration < nIterMax and iterate:
# update the com1DFA mu value
# update the com1DFA mu value in configuration file
updater = ConfigUpdater()
updater.read(hybridModelDFACfg)
updater.read(hybridModelDFACfgFile)
updater['GENERAL']['mu'].value = ('%.4f' % muArray[-1])
updater.update_file()

# Run dense flow with coulomb friction
dem, _, _, simDF = com1DFA.com1DFAMain(avalancheDir, cfgMain, cfgFile=hybridModelDFACfg)
dem, _, _, simDF = com1DFA.com1DFAMain(avalancheDir, cfgMain, cfgFile=hybridModelDFACfgFile)
simID = simDF.index[0]
particlesList, timeStepInfo = particleTools.readPartFromPickle(avalancheDir, simName=simID, flagAvaDir=True,
comModule='com1DFA')

# fetch configuration for DFAPathGeneration
hybridModelPathCfg= cfgUtils.getModuleConfig(DFAPath, fileOverride='', modInfo=False, toPrint=False,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar blocks of code found in 3 locations. Consider refactoring.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to come up with a good way to name these cfg objects. DFAPathcom3HybridCfg and com1DFAcom3HybridCfg and com2ABcom3HybridCfg or so no? And we always use the same method to name these files

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a good point!

onlyDefault=cfgHybrid['DFAPathGeneration_override']['defaultConfig'], overrideConfig=cfgHybrid)
# postprocess to extract path and energy line
avaProfileMass = DFAPath.getDFAPathFromPart(particlesList, addVelocityInfo=True)
# make a copy because extendDFAPathKernel might modify avaProfileMass
avaProfileMassExt = DFAPath.extendDFAPath(cfgHybrid['PATH'], avaProfileMass.copy(), dem, particlesList[0])
avaProfileMassExt = DFAPath.extendDFAPath(hybridModelPathCfg['PATH'], avaProfileMass.copy(), dem, particlesList[0])
avaProfileMassExtOri = copy.deepcopy(avaProfileMassExt)
avaProfileMassExtOri['x'] = avaProfileMassExtOri['x'] + demOri['header']['xllcenter']
avaProfileMassExtOri['y'] = avaProfileMassExtOri['y'] + demOri['header']['yllcenter']
Expand All @@ -78,14 +91,15 @@ def maincom3Hybrid(cfgMain, cfgHybrid):
shpConv.writeLine2SHPfile(avaProfileMassExtOri, name, pathAB)

# Run Alpha Beta
hybridModelABCfg = pathlib.Path('com3Hybrid', 'hybridModel_com2ABCfg.ini')
cfgAB = cfgUtils.getModuleConfig(com2AB, fileOverride=hybridModelABCfg)
cfgAB['ABSETUP']['path2Line'] = str(pathAB) + '.shp'
# first create configuration object for com2AB
hybridModelcom2ABCfg = cfgUtils.getModuleConfig(com2AB, fileOverride='', modInfo=False, toPrint=False,
onlyDefault=cfgHybrid['com1DFA_override']['defaultConfig'], overrideConfig=cfgHybrid)
hybridModelcom2ABCfg['ABSETUP']['path2Line'] = str(pathAB) + '.shp'
# take the path extracted from the DFA model as input
pathDict, demAB, splitPoint, eqParams, resAB = com2AB.com2ABMain(cfgAB, avalancheDir)
pathDict, demAB, splitPoint, eqParams, resAB = com2AB.com2ABMain(hybridModelcom2ABCfg, avalancheDir)
# make AB plot
reportDictList = []
_, plotFile, writeFile = outAB.writeABpostOut(pathDict, demAB, splitPoint, eqParams, resAB, cfgAB, reportDictList)
_, plotFile, writeFile = outAB.writeABpostOut(pathDict, demAB, splitPoint, eqParams, resAB, hybridModelcom2ABCfg, reportDictList)

# make custom com3 profile plot
alpha = resAB[name]['alpha']
Expand Down Expand Up @@ -113,6 +127,8 @@ def maincom3Hybrid(cfgMain, cfgHybrid):
outCom3Plots.hybridProfilePlot(avalancheDir, resultsHybrid)
outCom3Plots.hybridPathPlot(avalancheDir, dem, resultsHybrid, fields[0], particlesList[-1], muArray)

hybridModelCfgFile = cfgUtils.writeCfgFile(avalancheDir, com3Hybrid, cfgHybrid, fileName='com3Hybrid_settings', filePath=oPath)

log.debug('Alpha array is %s' % alphaArray)
log.debug('mu array is %s' % muArray)

Expand Down
91 changes: 80 additions & 11 deletions avaframe/com3Hybrid/com3HybridCfg.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,98 @@ nIterMax = 4
alphaThreshold = 0.1


# settings for path finding (these setting are used for path generation, as set in ana5Utils/DFAPathGenerationCfg.ini)
[PATH]
[DFA]
# starting value for bottom bed friction
mu = 0.4


[DFAPathGeneration_override]
defaultConfig = True
# the path extracted from the com1DFA simulation is re-sampled
# re-sampling step size is defined resampleDistance = nCellsResample x cellSize)
# this results in a path with a horizontal distance between points <= resampleDistance
nCellsResample = 5

# extension method at the top
# option 0: take the highest particle in the release
# option 1: find the point that will lead to the longest runout
extTopOption = 1

# for extending the path at the bottom, extend path towards the bottom of the runout in the
# direction extracted form the first/last points of the path (all points at a distance
# nCellsMinExtend x cellSize < distance < nCellsMaxExtend x cellSize from the start/end)
nCellsMinExtend = 2
nCellsMaxExtend = 20

# for the extrapolation at the bottom, add factBottomExt * sMax to the path
factBottomExt = 0.2
maxIterationExtBot = 10
nBottomExtPrecision = 10

[DFA]
# starting value for bottom bed friction
mu = 0.4
[com1DFA_override]
defaultConfig = True
#++++++++++++++++ Simulation type
# list of simulations that shall be performed (null, ent, res, entres, available (use all available input data))
simTypeList = null

#+++++++++++++ Output++++++++++++
# desired result Parameters (ppr, pft, pfv, pta, FT, FV, P, Vx, Vy, Vz, TA, particles) - separated by |
resType = particles
# saving time step, i.e. time in seconds (first and last time step are always saved)
# option 1: give an interval with start:interval in seconds (tStep = 0:5 - this will save desired results every 5 seconds for the full simulation)
# option 2: explicitly list all desired time steps (closest to actual computational time step) separated by | (example tSteps = 1|50.2|100)
# NOTE: initial and last time step are always saved!
tSteps = 0:5

#+++++Release thickness++++
# True if release thickness should be read from shapefile file; if False - relTh read from ini file
relThFromShp = False
# release thickness (only considered if relThFromShp=False)
relTh = 1
#+++++Entrainment thickness++++
# True if entrainment thickness should be read from shapefile file; if False - entTh read from ini file
entThFromShp = True
# entrainment thickness (only considered if entThFromShp=False)
entTh =

#++++++++++++Time stepping parameters
# to use a variable time step (time step depends on kernel radius)
sphKernelRadiusTimeStepping = True
# courant number if option cflTimeStepping is chosen.
# Upper time step limit coefficient if option sphKernelRadiusTimeStepping is chosen.
cMax = 0.02
# stopCriterion (based on massFlowing or kinEnergy)
stopCritType = massFlowing
# if based on massFlowing, specify the velocity threshold for flowing mass (m/s)
uFlowingThreshold = 0.0

#+++++++++++++SPH parameters
# SPH gradient option
# 0) No pressure gradients computed
# 1) SamosAT style (no reprojecion on the surface, dz = 0 and gz is used)
# 2) SamosAT done in the cartesian coord system (reprojecion on the surface, dz != 0 and g3 is used)
# 3) SamosAT but done in the local coord system (will hopefully allow us to add the earth pressure coef)
# and this time reprojecion on the surface, dz not 0 and g3 is used
sphOption = 2

#++++++++++++++++ Particles
# number of particles defined by: MPPDIR= mass per particle direct, MPPDH= mass per particles through release thickness,
# MPPKR= mass per particles through number of particles per kernel radius
massPerParticleDeterminationMethod = MPPKR

#+++++++++++++Flow model parameters+++++++++
# curvature acceleration coefficient
# take curvature term into account in the gravity acceleration term
# 0 if deactivated, 1 if activated
curvAcceleration = 0

#++++++++++++Friction model
# add the friction using an explicit formulation (1)
# 0 use an implicit method
explicitFriction = 1
# friction type (samosAT, Coulomb, Voellmy)
frictModel = Coulomb
#+++++++++++++General Friction parameters
# tan of bed friction angle used for: samosAT, Coulomb, Voellmy
mu = 0.6073

# which result parameters shall be included as plots in report, - separated by |
plotFields = ppr|pft|pfv|TA|pta


[com2AB_override]
defaultConfig = True
66 changes: 60 additions & 6 deletions avaframe/in3Utils/cfgUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def getGeneralConfig():
return cfg


def getModuleConfig(module, fileOverride='', modInfo=False, toPrint=True, onlyDefault=False):
def getModuleConfig(module, fileOverride='', modInfo=False, toPrint=True, onlyDefault=False, overrideConfig=''):
''' Returns the configuration for a given module
returns a configParser object

Expand All @@ -65,6 +65,8 @@ def getModuleConfig(module, fileOverride='', modInfo=False, toPrint=True, onlyDe
true if dictionary with info on differences to standard config
onlyDefault: bool
if True, only use the default configuration
overrideConfig: cfg
if not empty, override configuration parameters with override parameters
Comment on lines +68 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

back to my other comment, the naming is confusing, we have two override files given in input. Also update the doc string so it is clear what is happening here


Order is as follows:
fileOverride -> local_MODULECfg.ini -> MODULECfg.ini
Expand Down Expand Up @@ -106,12 +108,49 @@ def getModuleConfig(module, fileOverride='', modInfo=False, toPrint=True, onlyDe
# Finally read it
cfg, modDict = compareConfig(iniFile, modName, compare, modInfo, toPrint)

# override parameters with override information
if overrideConfig != '':
log.info('adding overrides now!')
cfg = getOverrideConfiguration(cfg, overrideConfig['%s_override' % modName])

if modInfo:
return cfg, modDict

return cfg


def getOverrideConfiguration(cfg, overrideParameters):
""" override configuration parameter values with the values provided in overrideParameters

Parameters
----------
cfg: configparer object
configuration of module
overrideParameters: configparser object
section with override parameter information

Returns
--------
cfg: configparser object
updated configuration of module
"""

# create list with parameters that become overridden
overrideKeys = [item for item in overrideParameters]

# loop through sections of the configuration of the module
for section in cfg.sections():
for key in cfg[section]:
if key in overrideKeys:
cfg.set(section, key, overrideParameters[key])
log.info('Override parameter: %s in section: %s with %s' % (key, section, str(overrideParameters[key])))
else:
overrideParameters[key] = cfg[section][key]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This updates the overrideParameters (which is the override cfg object) without you returning it as an output... I works but I am not a big fan of something happening without me knowing it. Should we change this?
If not at least mention this in the function description and add a comment here

log.debug('Added %s: %s to override parameters ' % (key, cfg[section][key]))

return cfg


def getDefaultModuleConfig(module, toPrint=True):
''' Returns the default configuration for a given module
returns a configParser object
Expand Down Expand Up @@ -240,7 +279,7 @@ def compareConfig(iniFile, modName, compare, modInfo=False, toPrint=True):
return cfg, modDict


def writeCfgFile(avaDir, module, cfg, fileName=''):
def writeCfgFile(avaDir, module, cfg, fileName='', filePath=''):
""" Save configuration used to text file in Outputs as moduleName_settings.ini
or optional in Outputs/moduleName/configurationFiles/filenName.ini

Expand All @@ -254,6 +293,8 @@ def writeCfgFile(avaDir, module, cfg, fileName=''):
configuration settings
fileName: str
name of saved configuration file - optional
filePath: str or pathlib path
path where file should be saved to except file name - optional

"""

Expand All @@ -264,18 +305,31 @@ def writeCfgFile(avaDir, module, cfg, fileName=''):
# write to file
if fileName != '':
# set outputs
outDir = pathlib.Path(avaDir, 'Outputs', modName, 'configurationFiles')
fU.makeADir(outDir)
if filePath == '':
outDir = pathlib.Path(avaDir, 'Outputs', modName, 'configurationFiles')
fU.makeADir(outDir)
else:
if filePath.is_dir():
outDir = pathlib.Path(filePath)
else:
message = '%s is not a valid location for saving cfg file' % str(filePath)
log.error(message)
raise NotADirectoryError(message)
cfg.optionxform = str
with open(pathlib.Path(outDir, '%s.ini' % (fileName)), 'w') as conf:
pathToFile = pathlib.Path(outDir, '%s.ini' % (fileName))
with open(pathToFile, 'w') as conf:
cfg.write(conf)
else:
# set outputs
outDir = pathlib.Path(avaDir, 'Outputs')
fU.makeADir(outDir)
cfg.optionxform = str
with open(pathlib.Path(outDir, '%s_settings.ini' % (modName)), 'w') as conf:
pathToFile = pathlib.Path(outDir, '%s_settings.ini' % (modName))
with open(pathToFile, 'w') as conf:
cfg.write(conf)

return pathToFile


def readCfgFile(avaDir, module='', fileName=''):
""" Read configuration from ini file, if module is provided, module configuration is read from Ouputs,
Expand Down