[ana5] Add extBottomOption to extend the DFA path to the deposit front#1296
[ana5] Add extBottomOption to extend the DFA path to the deposit front#1296NUForever wants to merge 2 commits into
Conversation
…posit front The mass-averaged path ends short of the deposit once the front decelerates, and the existing bottom extension extrapolates a straight line of fixed relative length (factBottomExt * sMax) clipped at the DEM border, independently of where the avalanche actually stopped. This adds extBottomOption = 1: the front of the deposit is located in the peak flow thickness field (flow-thickness-weighted centroid of the flow cells in the lowest part of the flow elevation range, with a lowest-cell fallback for flat deposits) and the path is extended to it along a Dijkstra least-cost path over the DEM, penalizing uphill steps and cells away from the flow footprint. The distance from the flow is computed in meters (distance_transform_edt with sampling=cellsize) so the penalties are resolution independent. Default behaviour is unchanged (extBottomOption = 0); the option is dispatched in extendDFAPath, which gains an optional fieldFT argument, and the pft field is read in generatePathAndSplitpoint only when the option is active. Used for the corridor-scale thalweg extraction on Route 115-CH (Chile), validated there against 208 manually delineated reference thalwegs (median endpoint distance 64 m).
fso42
left a comment
There was a problem hiding this comment.
Thank you Ivan for your PR. I have 2 comments, one is only minor.
| # peak flow thickness field, only needed when extending the path to the deposit front | ||
| fieldFT = None | ||
| if cfgDFAPath['PATH'].getint('extBottomOption', fallback=0) == 1: | ||
| fieldFT = readPeakFT(avalancheDir, simName) |
There was a problem hiding this comment.
In your readPeakFT function, makeSimDF(inputDir, …) is used, which parses all peak files. Since we are inside the simDF.loop, this happens for each sim and is just a re-reading and re-parsing. The data frame could be build before the loop and passed as argument, if possible.
There was a problem hiding this comment.
Good catch, fixed in eb692ff. makeSimDF is now called once before the simulation loop in generatePathAndSplitpoint and the resulting dataframe is passed to readPeakFT, so the peak files are parsed a single time for the whole run instead of once per simulation.
| elev = demRaster[rows, cols] | ||
| lowBand = elev <= elev.min() + lowFrontFraction * (elev.max() - elev.min()) | ||
| weight = fieldFT[rows, cols] * lowBand | ||
| frontRow = int(round(np.sum(rows * weight) / weight.sum())) |
There was a problem hiding this comment.
If I understood this correctly, then weight.sum() is never zero, correct? Otherweise a divide-by-zero guard would be necessary. If my understanding is correct, then it is not needed, but maybe a quick comment would help future maintainers
There was a problem hiding this comment.
You understood it correctly, weight.sum() is always positive: the lowest flow cell is always in lowBand and, being a flow cell, has fieldFT > ftThreshold >= 0, so its weight is strictly positive. I added a comment to that effect in eb692ff instead of a guard.
Move the makeSimDF call out of the per-simulation loop in generatePathAndSplitpoint: the peak files are parsed once and the dataframe is passed to readPeakFT, instead of re-reading and re-parsing all peak files for every simulation. Document why findFlowFront needs no divide-by-zero guard on the flow-weight sum.
What this adds
A new option
extBottomOptioninDFAPathGenerationcontrolling how themass-averaged path is extended at the bottom:
extBottomOption = 0(default, unchanged): the current fixed-lengthextrapolation (
extendProfileBottom), which extends the path in thedirection of its last points by
factBottomExt * sMax, clipped at theDEM border.
extBottomOption = 1(new): extend the path to the front of thesimulated deposit.
Motivation
The mass-averaged path ends short of the deposit once the front
decelerates. The default bottom extension extrapolates a straight line of
fixed relative length, independently of where the avalanche actually
stopped, so the path end does not coincide with the simulated runout.
Targeting the deposit front yields a path that ends at the simulated
runout, which is useful for corridor-scale and road-crossing analyses.
How it works
(
pft) as the flow-thickness-weighted centroid of the flow cells in thelowest part of the flow elevation range (
findFlowFront), with alowest-cell fallback for flat deposits and a snap to the deposit when the
centroid falls between disjoint lobes.
over the DEM (
leastCostPath). The cost of a step is its horizontallength plus a penalty on the positive elevation gain and on the distance
from the flow footprint, so the extension descends along the deposit.
Distances use meters (
distance_transform_edtwithsampling=cellsize)so the penalties are resolution independent.
available, the path falls back to the fixed-length extension, so the
AIMEC buffer is preserved.
The option is dispatched in
extendDFAPath(which gains an optionalfieldFTargument, mirroring the existingextTopOption); thepftfieldis read in
generatePathAndSplitpointonly when the option is active. Newparameters live in
DFAPathGenerationCfg.ini(ftThreshold,lowFrontFraction,upSlopePenalty,flowDistPenalty) andresTypegains
pft.Default behaviour
Unchanged. With
extBottomOption = 0(the default) the existing pipelineis not affected.
Tests
Unit tests added for
findFlowFront(front band, flat deposit, two-lobesnap, no flow),
leastCostPath(channel routing, unreachable goal behindnodata),
extendProfileToFront(extension to the front, both fallbacks)and
readPeakFT(lookup by name and by hash, missing field). Docs updatedin
docs/moduleAna5Utils.rst.Context
Developed for the corridor-scale thalweg extraction on Route 115-CH (Chile)
and validated there against 208 manually delineated reference thalwegs
(median endpoint distance 64 m).