Repository navigation
Sync main with anuga-community/anuga_core (3.3.10 → 4.1.0) - #301
Merged
Merged
Conversation
…own (#247) meson.build computed the version at build time by running _git_version.py, which runs `git describe`; an unpacked sdist has no .git, so a wheel built from it reported 0.0.0+unknown while the sdist's own metadata was right. A dist script (meson.add_dist_script, which meson-python's sdist build runs through `meson dist`) now writes the version into _version_static.txt at the root of the staged tree, and _git_version.py reads that file, next to itself, before trying git. Precedence is the ANUGA_VERSION override, then the static file, then git, then the fallback. The file is gitignored, so a checkout never has one and git stays the source there. git is also now run in the script's own directory rather than the current one, since dist scripts run from the build directory. Closes #247 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 9647606)
Release 4.0.1: install fixes on the 4.0 line
test_import_anuga_needs_no_triangulator compared the subprocess's whole stdout to "None". On two Linux CI runners `import anuga` printed a UCX transport warning from mpi4py's initialisation first, so the comparison failed although TRILIB was None as expected. Compare the last line only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
test_import_anuga_needs_no_triangulator compared the subprocess's whole stdout to "None". On two Linux CI runners `import anuga` printed a UCX transport warning from mpi4py's initialisation first, so the comparison failed although TRILIB was None as expected. Compare the last line only. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 8fabdba)
Test: tolerate stdout noise from import anuga in the lazy-backend test
Test: tolerate stdout noise from import anuga in the lazy-backend test (main)
The analytical, experimental and behaviour cases under validation_tests/ only ran by hand. They now run every night in validation.yml, on Linux with one Python, against main and develop, including the long HEC-RAS cases, using the same environment recipe as the nightly build. The job summary shows the VALIDATION SUMMARY table; the log and every plot the cases write are kept as an artifact for two weeks; a failing scheduled run opens or comments on a "Validation tests failing" issue. workflow_dispatch runs any ref with a chosen -alg, with or without the long cases, which is the way to validate a feature branch before merging. The suite's default algorithm is DE1 (validation_utilities/parameters.py), so that is the dispatch default too. Measured locally: 120 cases pass in 712 s at four threads without the long cases; the job timeout is three hours. Documented on the validation reference page. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CI: nightly validation run
The analytical, experimental and behaviour cases under validation_tests/ only ran by hand. They now run every night in validation.yml, on Linux with one Python, against main and develop, including the long HEC-RAS cases, using the same environment recipe as the nightly build. The job summary shows the VALIDATION SUMMARY table; the log and every plot the cases write are kept as an artifact for two weeks; a failing scheduled run opens or comments on a "Validation tests failing" issue. workflow_dispatch runs any ref with a chosen -alg, with or without the long cases, which is the way to validate a feature branch before merging. The suite's default algorithm is DE1 (validation_utilities/parameters.py), so that is the dispatch default too. Measured locally: 120 cases pass in 712 s at four threads without the long cases; the job timeout is three hours. Documented on the validation reference page. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 4f19ee6)
CI: nightly validation run (main)
…flow The fprintf rewrite in #349 also rewrote the stderr echo inside gpu_set_error, the very function it was routing the other sites to, into a call to itself. Any error recorded through it, an out-of-range inlet index for one, recursed until the stack ran out. The CI compiler warned (-Winfinite-recursion) but nothing read the warning. Restore the fprintf. A regression test drives a real error through the path: an inlet operator with a triangle index beyond the mesh is rejected by the C init and the wrapper raises with the recorded message. The static-analysis script now passes -Winfinite-recursion as well, so this class fails the CI job. On develop only; 4.0.1 predates #349. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`python -c "import anuga"` at the repository root imports the unbuilt source tree instead of the installed package (#237), which is what failed the first dispatch of the nightly validation run. Check from validation_tests/ instead, as the test steps in conda-setup.yml do from sandpit/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`python -c "import anuga"` at the repository root imports the unbuilt source tree instead of the installed package (#237), which is what failed the first dispatch of the nightly validation run. Check from validation_tests/ instead, as the test steps in conda-setup.yml do from sandpit/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 149022c)
Fix gpu_set_error recursing into itself; validation workflow import check
CI: run the validation workflow's import check from a subdirectory (main)
…idation page examples/notebooks/notebook_sediment_transport.ipynb, executed with outputs stored like the other notebooks, in two parts: scour of a sand bed in a sloping channel (the setup page's shortest program, with the concentration and bed change plotted on the mesh), then sediment settling out of still water compared against the exponential reference, the same case as the new sediment_settling validation test. Linked from the docs examples index and the notebooks README, and the sediment setup page points at both. The validation reference page gains a benchmark description for the case. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tion A new analytical case under validation_tests/analytical_exact. A tank of still water carries a uniform concentration of 100 micron sediment; with no flow nothing is entrained, and the only exchange is deposition [D-1] with a constant profile factor, so the concentration decays and the bed rises. The depth falls as the bed rises, which feeds back on the depth-averaged concentration; the reference integrates that coupled system with scipy to machine precision (and reduces to the exponential h0/(d* v_s) decay when the feedback is dropped). The case checks the deposition term, the sediment mass balance [G-3] and the bed update [G-4]. Checked at every output time: cell-mean concentration and bed rise against the reference (relative L1 < 1%; measured 1.6e-4 and 9.8e-5 with DE1), every cell on the same curve (spread 0), a motionless free surface (0), and sediment mass conserved between water column and bed (4e-8). Runs in a few seconds, so the nightly validation job picks it up at no real cost. Listed in the master validation report. The scripts read the tracer and the time-varying bed straight from the sww, since plot_utils.get_centroids collapses the bed to one slice. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sediment transport: a validation case and a notebook example
Wind_stress, Wind_stress_fast, Rainfall, Inflow, Barometric_pressure, Barometric_pressure_fast and General_forcing are gone from anuga.shallow_water.forcing, as announced in 4.0.0; Cross_section stays. The anuga.Inflow/Rainfall/Wind_stress exports and the pyproject filterwarnings that silenced their DeprecationWarnings go with them, along with the stale Culvert_flow filters. The only capability the operators lacked was a wind or pressure field read from an sww/tms file (use_coordinates=False, the _fast classes). Wind_stress_operator and Barometric_pressure_operator now take use_coordinates=False with a file_function, evaluated for every point in one vectorised step by the new evaluate_file_function_all_points helper. Tests: test_forcing.py rewritten around the operators (24 tests, same cases: constant/variable/file-driven wind, rainfall with polygons, starttime, georef and default rates, wind/pressure fields from file compared against the functions they were written from over an evolve), the inflow/rain tests in test_shallow_water_domain.py ported to Rate_operator.inflow/rainfall and their legacy-mode pins dropped. All pass under both compute modes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Remove the deprecated forcing-function classes (4.1)
…rm solution A tank of still water over a fixed bed that is flat on one half and slopes at 1e-3 on the other, 0.5 mm sand, no initial load. With the depth-slope closure the bed shear stress of a cell is a function of its depth and bed slope alone, so the flat half sits below the Shields threshold (the control) while the sloped half entrains via Smith-McLean [E-1]/[E-2] and relaxes to c_eq = E/(d* v_s) along the closed-form exponential with time constant h/(d* v_s). Checked per cell at every output time: relative L1 error 2.4e-4 in the interior, nothing entrained on the flat half, the end state at equilibrium to 1e-5, and no motion of the surface, bed or momenta. The bed is fixed on purpose: with it evolving, the far-wall cells (whose reconstructed slope the limiter zeroes) do not erode while their neighbours do, and the steps that open feed back into the depth-slope closure through the reconstructed bed edge values, so no cell keeps a known slope and there is no closed form. The eight kink and wall cells whose slope the limiter reduces are compared against the slope they were actually given, which the run records from the elevation edge values after the first step. Also adds the Ferguson & Church (2004) entry the sediment reports cite but the suite bibliography lacked, registers the case in the master report, and documents it on the validation and sediment pages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… own pass The slope for [T-7]/[T-7e] was read from the bed/stage EDGE values by the divergence theorem. The DE extrapolation rebuilds those every step as limited stage minus limited height, so the erosion stress was whatever the hydrodynamic limiter left: zero in the cells along a reflective wall (the ghost mirrors the interior, so the reconstruction sees no gradient toward it) and reduced wherever the limiter engages. On a uniformly sloping bed the wall cells never eroded while their neighbours did. S is now the least-squares gradient of the centroid values over the cell and its neighbours, one-sided at boundaries, so a plane gives its slope in every cell. Because that reads the neighbours and the source loop writes the bed, the slope is computed in a pass of its own into a new per-cell scratch array (sediment_slope_work), wired through the header, the Python allocation, both Cython bindings and the device mapping. Taken inline it was loop-order dependent and mode 1 and mode 2 disagreed at 1e-3 from the first step, which test_the_depth_slope_shear_closure_agrees caught. The bedload kernel's first pass is read-only and takes it inline. Tests: the edge-formula mirror is replaced by a centroid mirror, plus a regression on still water over a uniform slope, parametrised over bed evolution, that checks every cell entrains at the rate its own depth and the one slope give (wall cells included). Documented: 'depth_slope' with bed evolution on is self-amplifying (erosion -> rougher bed -> steeper local slopes -> more erosion); that is the closure, anugaSed contains it with a global clamp, and it is why the validation case holds the bed fixed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ntrol fraction With the slope now exact in every cell, the case no longer needs the flat half or the special treatment of the kink and wall cells: the bed is one plane, every cell is compared against its own closed-form curve at the constructed slope (worst cell 2.4e-4), and the threshold check moves to a second fraction of the same grain with tau_c* = 10, which must stay at zero. The bed stays fixed, for the closure's own feedback rather than for the discretisation; the analytic module and report say why. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sediment: exact slope for the depth-slope closure, and an erosion validation case
An Acknowledgements section in the README (which is also the PyPI project description), a matching section on the docs Background page with an anchor, a sentence on the docs landing page, a shared note included on the four GPU pages (offloading, GPU install, compute modes, profiling), and a line in the 4.0.0 release notes: the GPU and multicore solver was developed in collaboration with the Centre for Development of Advanced Computing (C-DAC), India, and the National Computational Infrastructure (NCI), Australia, whose Gadi supercomputer provided the GPU systems it was developed, tested and benchmarked on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…kh (C-DAC) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on contributors Names Samir Shaikh, Rutvik Gulhane and Parikshit (C-DAC) and Jorge Luis Gálvez Vallejo (NCI); places the C-DAC collaboration in its catchment flood prediction project (two-day forecasts) and the GPU hackathons from 2023. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… Das and Rutvik Gulhane Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
interior_regions vary the resolution by adding closed polygons to the mesh, and Triangle honours every one of their segments. When the outline is not a physical feature (an elevation band, a flood extent, a buffer), its geometry still forces small triangles, and the smallest triangle sets the timestep of the whole run. size_field gives the maximum triangle area as a function of position and adds no segments. It is applied through Triangle's user test (-u), which meshpy exposes and mesh_engine.generate_mesh previously always passed as None: a triangle is refined if its area exceeds the field at its centroid, as well as any region or global maximum area. It is either a callable f(x, y) in absolute coordinates or an anuga.Size_field raster. anuga.size_field_from_regions builds a graded raster from the same (polygon, maximum area) list as interior_regions, with a scanline fill and one distance transform per distinct resolution. relax_passes, and Pmesh.relax_worst_cells, then move the free vertices of the worst 0.5% of cells (Laplacian moves and steps in eight directions) wherever that raises min(radii, inradius) of the worst cell around the vertex. Vertices on segments stay put and the triangles are not reconnected. The kernel is a small Cython extension. Both arguments go through create_pmesh_from_regions, create_basic_mesh_from_regions, create_domain_from_regions and Pmesh.generate_mesh, and are remembered on the Pmesh so they apply when it is triangulated later by pmesh_to_mesh. Defaults leave existing meshes unchanged. An exception in the user test used to abort the interpreter from inside Triangle; it is now held and raised after the triangulation returns. The triangle backend has no user test, so a size field there is an error asking for meshpy. On a 1,407 km2 catchment (780,706 triangles, 30 m fine zone) this gives min radii 4.69 m against 0.65 m from tuned interior regions; the field takes 2.3 s to build, the mesh 2.9 s and 30 relaxation passes 1.1 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Avoids M_PI, which MSVC's math.h does not define by default. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A full run with DE_ader2 (otherwise run F settings) matches the DE1 run: flood-mark RMS 0.367 vs 0.368 m, no mark moving more than 0.05 m, Pioneer Rd gauge peak 4.09 vs 4.10 m at the same time and gauge RMS 0.31 m in both. Mass is conserved (9.8e-11 relative). The time step is the same, but each step is cheaper, so the run takes 6760 s instead of 9023 s (25% faster). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Towradgi report: results.tex for run F, and a figure script that matches it
Towradgi TOML: use DE_ader2 as the flow algorithm
Mesh resolution from a size field, and worst-cell relaxation
A pytest process that dies without running atexit handlers (SIGKILL, a timeout kill, a native runtime abort) left every <file>.sww.lock taken during the session in the working directory. An autouse fixture in the root conftest now releases this process's locks after each test, so a crash leaves at most the lock of the test that was running. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Tests: release SWW writer locks after each test
Animating a tracer over more than one frame failed in every worker with KeyError: 'tracer_<name>'. The workers number each frame by setting the plotter's counter attribute named in _COUNTER_ATTR, which had no tracer entries -- and could not, since SWW_plotter keeps tracer counters in the _tracer_frame_count dict. Set that dict's entry for tracer quantities. Also add the missing max_stage counter. It was not reachable yet, since max plots are single frames and are not sent to the workers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SWW_plotter read stage, xmomentum and ymomentum for every timestep and derived depth, velocity, speed and speed x depth for every timestep too: about eight arrays the size of the whole run, held for the plotter's life. anuga_sww_gui builds one plotter in the GUI and one in each of up to four animation workers, so a long run needed many GB. The (time, triangle) quantities are now FrameArrays (_sww_frames.py), which read from the file as they are used: one timestep for a[frame], a few triangles' timeseries for a[:, ids], and a stream over the timesteps for min, max and max(axis=0), whose results are cached. Anything else -- numpy functions, arithmetic, other ndarray methods -- gets the whole array, so existing callers keep working at the old cost. The file stays open between reads, reopens in a forked worker, and close() closes it. On a synthetic 64,800-triangle, 400-step file (312 MB), anuga_sww_gui gives the same colour limits, frames, timeseries and exports as before, with peak memory of 431 MB rather than 1,239 MB in the GUI and 308 MB rather than 2,051 MB in each animation worker. Opening the plotter takes 0.01 s rather than 1.1 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
anuga_sww_gui: animate tracers in the parallel frame workers
…mory # Conflicts: # anuga/utilities/tests/meson.build
SWW_plotter: read quantities a timestep at a time, not all at once
Older SWW files carry no timezone, and SWW_plotter failed opening them with "NetCDF: Attribute not found". Default to UTC, which is what the SWW writer uses when the domain has no timezone and what sww_merge assumes for files without one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SWW_plotter: open SWW files that have no timezone attribute
anuga_sww_gui draws max_* frames, and static elevation, in its own process,
where pyplot figures have a TkAgg toolbar. Closing a figure destroys that
toolbar, and clearing the figure afterwards updates it:
TclError: invalid command name ".!navigationtoolbar2tk.!button2"
so generating any max_* frame failed, with the PNG written but never loaded.
The save_max_*_frame methods cleared their figure after closing it; they now
just close it. The figure cache had the same problem: every save_* closes
its cached figure, and the next frame cleared and reused it, so a second
elevation or max tracer frame in the GUI failed too, and plot_*_frame after
a save returned a closed figure that a notebook would not show. A cached
figure is now reused only while pyplot still has it open. In the worker
processes (Agg) this costs nothing measurable: 100 ms a frame either way.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SWW_plotter: never draw on a figure pyplot has closed (fixes max frames in anuga_sww_gui)
The Visualisation section gains a table comparing the ways to look at .sww files: ANUGA Viewer, anuga_sww_gui, SWW_plotter, ParaView, the web viewer, QGIS and Domain_plotter. A new page covers the anuga-paraview package: the ParaView reader and the browser viewer for results on remote or headless machines. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs: add a "Choosing a viewer" table and a ParaView / web viewer page
Brings 4.0.1 and the fixes made on main into the line that becomes 4.1.0, so main can take 4.1.0 as a fast merge. Most of main's changes were already on develop through their develop-side PRs; what is new is the dependabot bump of the actions in docker-publish.yml and lint.yml. Conflicts resolved toward develop: - tools/install_anuga_nvc.sh: develop's GPU probe supersedes main's, and develop already sets CXX to nvc++ as main's ff74678 does. - docs/source/reference/validation.rst: both sides added the "Nightly run in CI" section, which merged into two copies. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds the TOML runner building culverts, weirs and sediment (#431), the anuga_sww_gui and SWW_plotter fixes (#441, #443, #444), lazy SWW_plotter reads (#442), the viewer docs (#445), TOML starttime for a burn-in (#433), the once-per-run enquiry point warning (#417), and the results of the independent size-field tests on #436. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Prepare 4.1.0: merge main into develop, and complete the release notes
Drops "(unreleased)" from the 4.1.0 heading, fills in the Thanks section, and sets CITATION.cff to version 4.1.0, released 2026-10-23. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Release 4.1.0: date, thanks, and CITATION.cff
Release 4.1.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings this repository's
mainup toanuga-community/anuga_core@main, the 4.1.0 release point (dc8098a). GAmainwas last synced at 3.3.10 (#300).The release tags
4.0.0,4.0.1and4.1.0have already been pushed to this repository, identical to those in anuga-community. As with 3.3.x, no GitHub Releases are created here. A bare tag doesn't trigger the PyPI publish workflow, which is gated on a published release. Publishing to PyPI, Docker and Zenodo is done fromanuga-community.What changes
1203 non-merge commits: the whole of 4.0.0, 4.0.1 and 4.1.0. The release notes in
RELEASE_NOTES.md, andUPGRADING_TO_4.0.md, describe them:87 files present on GA
mainwere removed upstream in that work, and they go with it.Note on history
This is a merge rather than a fast-forward. GA
maincarries two merge commits thatanuga-community/maindoes not: 9a7ef66 (#296) and c15aab5 (#300). Neither has content of its own. The diff from the merge base (98c3663) to GAmainis empty, so nothing on GAmainis lost by merging. This repository's ruleset blocks non-fast-forward pushes, hence the merge commit.🤖 Generated with Claude Code