Skip to content

TASK-032: Pressure Field (Stage 5) - #45

Merged
AdamClemens merged 1 commit into
mainfrom
feat/task-032-pressure-field
Aug 29, 2026
Merged

TASK-032: Pressure Field (Stage 5)#45
AdamClemens merged 1 commit into
mainfrom
feat/task-032-pressure-field

Conversation

@AdamClemens

Copy link
Copy Markdown
Owner

Summary

Stage 5's third task, built directly after TASK-031 in the roadmap's own build order. PISO (TASK-027, Stage 4) already performs the solve this task's own criteria describe -- this task adds no new pressure-solving mechanism, only the properties Stage 4's own criteria never had cause to check, plus one genuinely missing API-level guard.

The local design question resolved: pressure gets a type of its own. PressureField(ScalarField) (scalar_field.py) is a thin marker subclass with no new behaviour. It lives in scalar_field.py, not engine/numerics/pressure_coupling.py (its one real producer) -- simulation.py needs to import it and cannot import from pressure_coupling.py without a circular import (that module already imports accumulate_flux_to_cells from simulation.py). Same reasoning that moved IncompatibleVelocityFieldError to vector_field.py in TASK-031a.

PISO.correct now constructs a PressureField instead of a plain ScalarField. No interface change: PressureCoupling.correct's own abstract signature stays tuple[VectorField, ScalarField], and a PressureField instance already satisfies it (valid covariant return narrowing under mypy --strict).

simulation.step gains a real isinstance check, raising a new PressureFieldTransportError if fields contains a PressureField -- stated at the API level deliberately, not the configuration level, since there's no configuration surface today that names which fields are transported (SimulationConfig seeds one scalar pattern and one velocity pattern, nothing more).

Test plan

Five new scenarios (tests/features/pressure_field.feature), checked against the real PISO/GreenGaussGradient machinery directly:

  • A divergence-free provisional velocity field (uniform, with zero-gradient boundaries -- exactly zero divergence by the discrete Gauss theorem's own closure identity, not a hand-crafted Dirichlet approximation) yields a pressure field constant to solver tolerance.
  • A provisional velocity field with real interior divergence, not axis-aligned, yields a pressure field that is not constant.
  • Adding a constant to the solved pressure field leaves the corrected velocity unchanged (the null-space remedy made observable, checked directly through GreenGaussGradient).
  • step rejects a fields mapping containing a PressureField with a named error, not silent transport.
  • A boundary configuration violating the zero-net-flux compatibility condition fails to load before any pressure solve is attempted (Stage 3's existing _validate_boundary_conditions_jointly, not reimplemented).

make ci green: 647 tests passing, mypy --strict clean, 100% coverage on every changed module, all doc/graph/scenario/status/config-template checks pass.

🤖 Generated with Claude Code

Stage 5's third task. PISO (TASK-027, Stage 4) already performs the
solve this task's own criteria describe -- this adds no new
pressure-solving mechanism, only the properties Stage 4's own criteria
never had cause to check, plus the one genuinely missing API-level
guard:

- PressureField(ScalarField) (scalar_field.py): a thin marker subclass
  resolving this task's own local design question ("pressure needs a
  type of its own"). Lives here, not in pressure_coupling.py (its one
  real producer), since simulation.py needs to import it and cannot
  import from pressure_coupling.py without a circular import -- the
  same reasoning that moved IncompatibleVelocityFieldError in TASK-031a.
- PISO.correct now constructs a PressureField instead of a plain
  ScalarField. No interface change: PressureCoupling.correct's own
  abstract signature stays tuple[VectorField, ScalarField], and a
  PressureField instance already satisfies it.
- simulation.step gains a real isinstance check, raising the new
  PressureFieldTransportError if fields contains a PressureField --
  stated at the API level, since there's no configuration surface that
  names which fields are transported.

Five new scenarios (tests/features/pressure_field.feature) prove: a
divergence-free provisional velocity yields pressure constant to
solver tolerance; a divergent one yields non-constant pressure; adding
a constant to the solved pressure leaves the corrected velocity
unchanged (the null-space remedy made observable); step rejects a
PressureField; and a boundary configuration violating the zero-net-flux
compatibility condition fails to load before any pressure solve is
attempted (Stage 3's existing check, not reimplemented).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@AdamClemens
AdamClemens merged commit edcbcbc into main Aug 29, 2026
2 checks passed
@AdamClemens
AdamClemens deleted the feat/task-032-pressure-field branch August 29, 2026 11:09
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