Skip to content

LinearEuler3D: heterogeneous sound speed + impedance-matched Riemann flux#138

Merged
fluidnumericsJoe merged 1 commit into
mainfrom
feat/lineareuler3d-heterogeneous-c
Jul 13, 2026
Merged

LinearEuler3D: heterogeneous sound speed + impedance-matched Riemann flux#138
fluidnumericsJoe merged 1 commit into
mainfrom
feat/lineareuler3d-heterogeneous-c

Conversation

@fluidnumericsJoe

Copy link
Copy Markdown
Member

Summary

Brings the 3-D linear Euler model up to parity with LinearEuler2D so it can support heterogeneous media (the driver is 3-D ultrasound-computed-tomography forward modeling in SELF-UCT):

  • Sound speed as solution variable 6 (nvar 5 → 6), static in time (zero flux, zero source), mirroring the 2-D convention. The scalar attribute c remains as the reference value used by initial conditions (SphericalSoundWave fills variable 6 with it).
  • Impedance-matched (characteristic/Godunov) Riemann flux replacing the local Lax-Friedrichs solver, identical in form to riemannflux2d_LinearEuler2D_t: interface states resolved with the one-sided impedances Z = rho0*c, giving physically correct transmission/reflection at material interfaces in a heterogeneous c field.
  • GPU backend: fluxmethod reads the per-node c; the boundaryflux kernel implements the impedance-matched flux; both drop the scalar c argument (signatures now mirror the 2-D kernels). The radiation-BC kernel now takes the interior boundary state and copies c through to extBoundary (acoustic perturbation still zeroed) so face Riemann solves see a consistent sound speed.
  • CPU radiation BC registered in AdditionalInit_LinearEuler3D_t (previously radiation existed only in the GPU backend); the GPU AdditionalInit calls the parent and overwrites the registration with the kernel wrapper, mirroring the 2-D module structure.
  • Entropy function fixes: s(3)*(3) typo → s(3)*s(3), and the internal-energy term now uses the per-node sound speed.
  • Docs updated (docs/Models/linear-euler-3d-model.md).

Breaking change

LinearEuler3D grows from 5 to 6 solution variables and the GPU kernel signatures for fluxmethod_LinearEuler3D_gpu / boundaryflux_LinearEuler3D_gpu / hbc3d_radiation_lineareuler3d_gpu change. Downstream code that sets initial conditions directly must fill variable 6 with the sound speed. examples/linear_euler3d_spherical_soundwave_radiation.f90 needs no changes (it goes through SphericalSoundWave).

Testing

  • Full GPU build (CUDA 13.0, sm_103, FP32, examples ON) in the selfish:latest-x86-cuda130-sm103 toolchain container compiles and installs clean, including the 3-D example.
  • SELF-UCT (2-D + new 3-D AcousticTomography3D) builds and links against this branch's install.
  • fprettify --config-file ./fprettify.config --case 1 1 1 1 reports no diffs on the touched files.
  • No GPU on the build host — please let the Buildkite/Actions GPU pipelines exercise the runtime (the 3-D spherical-soundwave example is the relevant smoke test).

🤖 Generated with Claude Code

…flux

Bring the 3-D linear Euler model up to parity with LinearEuler2D:

- Carry the sound speed as solution variable 6 (nvar 5 -> 6), static in
  time (zero flux/source), so heterogeneous media are supported. The
  scalar attribute `c` remains as the reference value used by initial
  conditions (SphericalSoundWave fills variable 6 with it).
- Replace the local Lax-Friedrichs Riemann solver with the
  impedance-matched (characteristic/Godunov) flux used by the 2-D model:
  interface states resolved with the one-sided impedances Z = rho0*c, so
  material interfaces in a heterogeneous c field get the physically
  correct transmission/reflection.
- GPU backend: fluxmethod reads the per-node c (variable 6) and the
  boundaryflux kernel implements the impedance-matched flux; both drop
  the scalar `c` argument (signatures now mirror the 2-D kernels). The
  radiation BC kernel now takes the interior boundary state and copies c
  through to extBoundary so face Riemann solves see a consistent sound
  speed, with the acoustic perturbation still zeroed.
- Register a CPU radiation BC in AdditionalInit_LinearEuler3D_t
  (previously the radiation BC existed only in the GPU backend); the GPU
  AdditionalInit calls the parent and overwrites it with the kernel
  wrapper, mirroring the 2-D module structure.
- Fix the entropy function: s(3)*(3) typo -> s(3)*s(3), include the w
  contribution correctly, and use the per-node sound speed.
- Update the model documentation accordingly.

Motivation: 3-D ultrasound computed tomography forward modeling
(SELF-UCT AcousticTomography3D) needs spatially varying sound speed with
impedance-matched interface handling, exactly as the 2-D class has.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fluidnumericsJoe
fluidnumericsJoe merged commit cbfa8df into main Jul 13, 2026
11 checks passed
@fluidnumericsJoe
fluidnumericsJoe deleted the feat/lineareuler3d-heterogeneous-c branch July 13, 2026 19:44
fluidnumericsJoe added a commit that referenced this pull request Jul 18, 2026
…139)

* LinearEuler 2D/3D: variable background density via static nodal rho0

Promote the background density rho0 from a scalar model attribute to a
static per-node solution variable, mirroring the heterogeneous
sound-speed pattern from #138. This lets rho0 vary in space (e.g. across
material interfaces) alongside c, so heterogeneous media with both
density and sound-speed contrast are supported.

- 2D: nvar 5->6 (rho0 = variable 6), nstepped stays 4.
- 3D: nvar 6->7 (rho0 = variable 7); set nstepped=5 (previously unset,
  relying only on zero flux/source to hold the auxiliary fields static).
- Interior flux, entropy_func, and the impedance-matched Riemann flux now
  read per-node rho0. The Riemann solver uses per-side impedance
  Z = rho0*c, so material interfaces (density and/or sound-speed jumps)
  get the physically correct reflection/transmission; the reconstructed
  density/momentum/pressure fluxes use the face-averaged rho0 and c^2 (the
  same pragmatic treatment already used for c^2). The scalar rho0
  attribute is retained as the reference value that fills the field in the
  built-in initial conditions.
- GPU: fluxmethod/boundaryflux kernels read per-node rho0 and drop the
  scalar rho0 argument; BC kernels copy rho0 through to the exterior
  state (signatures now mirror the c handling in #138).
- Entropy stability: for piecewise-constant material regions aligned with
  element boundaries, element interiors have grad(rho0)=grad(c)=0 (so the
  flux-divergence form is exact) and the impedance-matched Riemann flux
  carries the entropy-stable interface dissipation.

Also in this change:
- Add a CPU radiation BC to the 2D model (previously only the GPU backend
  registered one); it zeros the acoustic perturbation and copies c and
  rho0, mirroring the 3D model. Register it in AdditionalInit_LinearEuler2D_t.
- Add a PML entropy_func override so the PML variant keeps using its scalar
  rho0 (its variable 6 is the auxiliary phi_rho, not rho0).
- Fix the 2D entropy_func s(3)*(3) typo (already fixed for 3D in #138).
- boneandmarrow example: stamp a per-material rho0 (muscle/bone/marrow)
  alongside c, exercising a genuinely heterogeneous impedance field.
- planewave examples: set the new rho0 variable in the initial condition
  and the prescribed boundary state.
- Update the 2D/3D model docs.

CPU (gfortran) build is clean and all 7 LinearEuler ctests pass;
boneandmarrow entropy is finite and monotonically decreasing. GPU kernels
to be validated by CI.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix LinearEuler doc staleness after variable-density change

- 2D model: the base LinearEuler2D_t now registers a CPU radiation
  handler (not GPU-only), so update the BC section accordingly.
- 3D model: remove two dead example links (spherical_soundwave_closeddomain
  and planewave_propagation examples do not exist); keep the radiation
  example, which is the only 3D example present.
- PML model: document the new entropy_func override and clarify that the
  PML variant keeps rho0 as a scalar (its slot 6 is phi_rho, whereas the
  parent model now carries rho0 as a per-node solution variable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant