Skip to content

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

Merged
fluidnumericsJoe merged 2 commits into
mainfrom
feat/lineareuler-variable-density
Jul 18, 2026
Merged

LinearEuler 2D/3D: variable background density via static nodal rho0#139
fluidnumericsJoe merged 2 commits into
mainfrom
feat/lineareuler-variable-density

Conversation

@fluidnumericsJoe

Copy link
Copy Markdown
Member

Summary

Adds support for a spatially-varying background density rho0 to the LinearEuler 2D and 3D models, so heterogeneous media with both density and sound-speed contrast are supported. This mirrors the heterogeneous sound-speed pattern merged in #138: rho0 is promoted from a scalar model attribute to a static per-node solution variable (zero flux, zero source, excluded from time integration via nstepped).

  • 2D: nvar 5→6 (rho0 = variable 6), nstepped stays 4.
  • 3D: nvar 6→7 (rho0 = variable 7); also sets nstepped=5 (previously unset — the 3D model relied solely on zero flux/source to hold c static).

The interior flux, entropy_func, and the impedance-matched Riemann flux now read the per-node rho0. The Riemann solver uses the 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 used to fill the field in the built-in initial conditions.

Entropy stability

For piecewise-constant material regions aligned with element boundaries (the target regime — e.g. tissue/bone imaging), element interiors have ∇rho0 = ∇c = 0 so the flux-divergence form is exactly entropy-conservative, and the impedance-matched Riemann flux carries the entropy-stable interface dissipation. (A fully entropy-conservative split-form treatment for smoothly-varying media on ECDGModel is tracked separately as SELF-24.)

Changes

  • 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 LinearEuler3D: heterogeneous sound speed + impedance-matched Riemann flux #138).
  • New CPU radiation BC for the 2D model (previously only the GPU backend registered one): zeros the acoustic perturbation and copies c and rho0, mirroring the 3D model.
  • PML: added an entropy_func override so the PML variant keeps using its scalar rho0 (its variable 6 is the auxiliary phi_rho, not rho0).
  • Fixed the 2D entropy_func s(3)*(3) typo (already fixed for 3D in LinearEuler3D: heterogeneous sound speed + impedance-matched Riemann flux #138).
  • boneandmarrow example: stamps a per-material rho0 (muscle/bone/marrow) alongside c, exercising a genuinely heterogeneous impedance field.
  • planewave examples: set the new rho0 variable in the IC and the prescribed boundary state.
  • Updated the 2D/3D model docs.

Testing

CPU (gfortran, GPU OFF) build is clean; all 7 LinearEuler ctests pass:

lineareuler2d_pml_absorption ...................... Passed
linear_euler2d_spherical_soundwave_closeddomain ... Passed
linear_euler2d_planewave_reflection ............... Passed
linear_euler2d_planewave_propagation .............. Passed
linear_euler2d_pml_planewave ...................... Passed
linear_euler2d_boneandmarrow ...................... Passed
linear_euler3d_spherical_soundwave_radiation ...... Passed

linear_euler2d_boneandmarrow (variable density + variable sound speed) entropy is finite and monotonically decreasing (final/initial ≈ 0.998), with the rho0 field correctly heterogeneous (min=0.93, max=1.8).

GPU kernel changes were not exercised by the CPU build — relying on Buildkite GPU CI to validate.

🤖 Generated with Claude Code

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>
@makeplane

makeplane Bot commented Jul 17, 2026

Copy link
Copy Markdown

Linked to Plane Work Item(s)

References

This comment was auto-generated by Plane

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

- 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>
@fluidnumericsJoe
fluidnumericsJoe merged commit 02ff656 into main Jul 18, 2026
11 checks passed
@fluidnumericsJoe
fluidnumericsJoe deleted the feat/lineareuler-variable-density branch July 18, 2026 12:08
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