Skip to content

[ana5]: add general thalweg extension & resampling - #1323

Open
PaulaSp3 wants to merge 1 commit into
masterfrom
PS_FP_thalweg
Open

[ana5]: add general thalweg extension & resampling#1323
PaulaSp3 wants to merge 1 commit into
masterfrom
PS_FP_thalweg

Conversation

@PaulaSp3

@PaulaSp3 PaulaSp3 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

The goal is to derive a thalweg profile from very general thalweg data (containing x and y coordinates).

This changed in each file:

  • ana5Utils/DFAPathGeneration.py:

    • black formatter
    • extendProfileTop : add extension option that extends the path to the top similar as the bottom extension that depends on the flow/ path direction
      (for option 2, the code is very similar as in extendProfileBottom, should we summarize both in one function with options/different handling for top nd bottom extension?)
    • extendProfileBottom: add possibility to consider lower left center when reading z values from DEM
    • resamplePath : add parameter in configfile that can change the degree of the spline
  • ana5Utils/DFAPathGenerationCfg.ini:

    • add parameter in configfile that can change the degree of the spline (for resampling a path)
  • ana5Utils/preparePathGeneral.py
    functions to prepare a path/thalweg that has only x and y coordinates:

    • extend path to top and bottom
    • resample path
    • read z values along path (from DEM)
    • compute s values along path
  • out3Plot/outCom3Plots.py

    • black formatter
    • generateCom1DFAPathPlot: put the avalanche thalweg location plot into a separate function avalancheThalwegPlot

PR Checklist

Please confirm before requesting review:

  • I ran pytest locally without fails
  • I added/updated tests where needed
  • I updated documentation where needed

Confirm before the final merge/rebase into master

  • Commits are sensibly squashed and rebased onto latest master
  • Standardtest run without difference (with recompiled cython code)

@PaulaSp3
PaulaSp3 requested review from awirb and fso42 July 31, 2026 10:27
@PaulaSp3 PaulaSp3 self-assigned this Jul 31, 2026
@PaulaSp3 PaulaSp3 added the enhancement New feature or request label Jul 31, 2026
@PaulaSp3 PaulaSp3 linked an issue Jul 31, 2026 that may be closed by this pull request
7 tasks
@PaulaSp3 PaulaSp3 changed the title [ana5]: add general thalweg generation [ana5]: add general thalweg extension & resampling Jul 31, 2026
@PaulaSp3 PaulaSp3 linked an issue Jul 31, 2026 that may be closed by this pull request
14 tasks
@qltysh

qltysh Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Analysis for project AvaFrame

❌ 12 blocking issues (14 total)

Tool Category Rule Count
ripgrep Lint # TODO: for option 2, the code is very similar as in extendProfileBottom, should we summarize both in one function with options/different handling for top nd bottom extension? 4
ruff Style Incorrect formatting, autoformat by running qlty fmt. 3
ruff Lint Do not use bare except 2
ruff Lint Ambiguous variable name: l 2
ruff Lint f-string without any placeholders 1
qlty Structure Function with high complexity (count = 34): extendProfileTop 1
qlty Structure Deeply nested control flow (level = 4) 1

@qltysh one-click actions:

  • Auto-fix formatting (qlty fmt && git push)

profile["z"] = np.append(zExtTop, profile["z"])
profile["s"] = np.append(0, profile["s"] + ds)
if debugPlot:
debPlot.plotPathExtTop(profile, particlesIni, xFirst, yFirst, zFirst, dz1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Function with high complexity (count = 34): extendProfileTop [qlty:function-complexity]

log.warning("Skip top extension of thalweg since profile contains only one point.")
return profile

# TODO: for option 2, the code is very similar as in extendProfileBottom, should we summarize both in one function with options/different handling for top nd bottom extension?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

# TODO: for option 2, the code is very similar as in extendProfileBottom, should we summarize both in one function with options/different handling for top nd bottom extension? [ripgrep:TODO]

Comment thread avaframe/ana5Utils/DFAPathGeneration.py Outdated
log.error(message)
raise ValueError(message)
if cfg is None:
message = f"If extTopOption = 2, the cfg needs to be provided"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

f-string without any placeholders [ruff:F541]

Suggested change
message = f"If extTopOption = 2, the cfg needs to be provided"
message = "If extTopOption = 2, the cfg needs to be provided"

else:
# remember last point found inside
factFirst = factExt
factExt = factExt + stepSize

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Deeply nested control flow (level = 4) [qlty:nested-control-flow]

title = ('com3HybRasterPlot')
l = ax.legend(loc='lower left')
title = "com3HybRasterPlot"
l = ax.legend(loc="lower left")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ambiguous variable name: l [ruff:E741]

Comment thread avaframe/out3Plot/outCom3Plots.py Outdated
Comment thread avaframe/out3Plot/outCom3Plots.py Outdated
else:
extentPlot = extent

# TODO: restore changes and rebase master!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

# TODO: restore changes and rebase master! [ripgrep:TODO]

@@ -0,0 +1,205 @@
"""Tests for module preparePathGeneral"""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Found 2 issues:

1. Incorrect formatting, autoformat by running qlty fmt. [ruff:fmt]


2. Incorrect formatting, autoformat by running qlty fmt. [black:fmt]

@qltysh

qltysh Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Qlty


Coverage Impact

This PR will not change total coverage.

Modified Components (1)

RatingComponent% Diff
Coverage rating: C Coverage rating: C
com1DFA90.0%

Modified Files with Diff Coverage (3)

RatingFile% DiffUncovered Line #s
Coverage rating: A Coverage rating: A
avaframe/com1DFA/DFAtools.py90.0%183
Coverage rating: C Coverage rating: C
avaframe/ana5Utils/DFAPathGeneration.py72.6%54-132, 180-198...
New Coverage rating: B
avaframe/ana5Utils/preparePathGeneral.py83.0%48-61
Total74.8%
🤖 Increase coverage with AI coding...
In the `PS_FP_thalweg` branch, add test coverage for this new code:

- `avaframe/ana5Utils/DFAPathGeneration.py` -- Lines 54-132, 180-198, 534-536, 548-564, 568-573, 583-585, 734, 1046-1047, and 1089-1150
- `avaframe/ana5Utils/preparePathGeneral.py` -- Line 48-61
- `avaframe/com1DFA/DFAtools.py` -- Line 183

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@PaulaSp3
PaulaSp3 force-pushed the PS_FP_thalweg branch 2 times, most recently from 7c42103 to ea6399c Compare August 13, 2026 11:24
)

# extend the bottom
profile = DFAPathGeneration.extendProfileBottom(cfgPathGen["PATH"], demDict, profile, considerLLC=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not 100 % sure if the indices that come out are correct or whether they are shifted by one. Can you check?

  • pathExtension sets indStartMassAverage = 1 and indEndMassAverage = size(x) - 2 before the extension calls
    (preparePathGeneral.py:119-120)
  • extendProfileTop (option 2) prepends a single point and extendProfileBottom appends a single one, at least in
    the normal case
  • The indices are consumed later by resamplePath on the post-extension profile, via s0 and sEnd

And that's then shifted by one? But maybe I did not follow correctly?

indEndCandidates = np.argwhere(avaProfile["s"] >= sEnd + resampleDistance / 3)
indEnd = indEndCandidates[0][0] - 1 if len(indEndCandidates) > 0 else np.size(avaProfile["s"]) - 1
avaProfile['indEndMassAverage'] = indEnd
except:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What are you trying to catch here? If there's a real error, it will be masked here...

return outPath


def avalancheThalwegPlot(ax, fieldRaster, dem, avaProfileMass, splitPoint=None, avalancheDir="", cmapHS=None):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

docstring is missing

for inputPara in ["alpha", "exponent", "zDeltaMax"]:
try:
profileExtended[inputPara] = profile[inputPara]
except:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this be a except KeyError? since real error should be shown

# skip profile that only contains one point
if len(profileAveraged["x"]) <= 2:
profileExtended["indStartMassAverage"] = 0
profileExtended["indEndMassAverage"] = max(len(profileExtended["x"]) - 1, 1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Single Points gets '1', but he profile Array only has 0. Do we need to catch this?

return profileAveraged, profileExtended


def replaceResampledProfileCore(profile, profileResample):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove, it's dead code an in git anyways

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[com4]: thalweg identification [com4], [ana5]: Add Flowpy thalweg postprocessing

2 participants