Files
Entropyk/_bmad-output/implementation-artifacts/0-2-phantom-gradient-regularization-standard.md
sepehr 88620790d6 Complete Story 0.2 phantom-gradient regularization standard.
Add analytic derivatives and C1 tests for smooth_max/min/clamp, document epsilon/width guidance, and declare flow_regularization as the HX reference pattern without changing component physics.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-18 16:33:48 +02:00

286 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
story_key: 0-2-phantom-gradient-regularization-standard
epic: 0
story: 2
source: _bmad-output/planning-artifacts/epics-solver-hp.md
baseline_commit: f88cd7f7d83c8c25bf8d4262742fb9736c3bf7c7
depends_on: 0-1-jacobian-killing-pattern-audit-fd-test-harness
---
# Story 0.2: Phantom-Gradient Regularization Standard
Status: review
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
<!-- Ultimate context engine analysis completed - comprehensive developer guide created -->
## Story
As a component developer,
I want a standardized C¹ regularization toolkit (smooth max/min/clamp with documented ε) generalizing the existing `flow_regularization.rs` pattern,
so that fixes are uniform and derivative-safe instead of ad-hoc.
## Acceptance Criteria
1. **Core C¹ toolkit is complete, tested, and derivative-safe.**
- **Given** the `entropyk-core` crate
- **When** the toolkit lands (or is completed if already present)
- **Then** `smooth_max` / `smooth_min` / `smooth_clamp` (C¹ or smoother, parameterized sharpness/width) are available alongside existing `smooth_abs`, with **derivative-continuity unit tests**
- **And** ε / width selection guidance is documented (physical scale of the blended region)
2. **`flow_regularization.rs` relationship is resolved without physics churn.**
- **Given** the existing `crates/components/src/heat_exchanger/flow_regularization.rs`
- **When** reviewed
- **Then** it is either unified into the toolkit **or** documented as the **reference implementation** for mass-flow activity / zero-flow blending
- **And** no existing component behavior changes in this story (**toolkit + docs only**)
## Tasks / Subtasks
- [x] **Task 1: Inventory what already exists — do not reinvent** (AC: #1, #2)
- [x] 1.1 Confirm primitives in `crates/core/src/smoothing.rs`: `smooth_max`, `smooth_min`, `smooth_abs` (+ derivative), `smooth_clamp`, plus `smoothstep` / `cubic_blend` family.
- [x] 1.2 Confirm HX-specific adapters in `flow_regularization.rs` already call `smooth_abs` — keep them in `entropyk-components` (domain-specific, not core).
- [x] 1.3 Gap check (expected at story creation):
| Gap | Expected action |
|---|---|
| No public `smooth_clamp_derivative` | **Add** analytic ∂/∂x (+ FD unit test) — required by Stories 0.3/0.4 Jacobian paths |
| `smooth_max` / `smooth_min` derivatives only inline in tests | **Add** public `smooth_max_da` / `smooth_min_da` (or named `*_derivative` w.r.t. first arg) + FD tests |
| No dedicated C¹ join tests for `smooth_clamp` | **Add** FD slope continuity at the four junctions (`lo`, `lo+width`, `hi-width`, `hi`) |
| No general ε/width guidance doc | **Add** rustdoc module section + short markdown standard (see Task 3) |
| `flow_regularization` not formally declared “reference” | **Document** — do **not** move into core |
- [x] **Task 2: Complete the toolkit APIs in `entropyk-core`** (AC: #1)
- [x] 2.1 Add analytic derivatives needed by consumers:
- `smooth_clamp_derivative(x, lo, hi, width) -> f64`
- `smooth_max` / `smooth_min` first-arg (or both-arg) derivatives — match existing formulas already verified in unit tests
- [x] 2.2 Keep APIs pure `f64`, `#[inline]`, zero-alloc, no new crate deps.
- [x] 2.3 Guard invalid parameters without panic: `width <= 0`, `hi < lo`, `k <= 0`, `eps <= 0` — document degenerate behavior (hard clamp / hard max / hard abs) and cover with tests. Prefer non-panicking fallbacks consistent with existing `normalize` zero-width handling.
- [x] 2.4 Re-export path unchanged: `entropyk_core::smoothing::*` via existing `pub mod smoothing` in `crates/core/src/lib.rs`. No facade/`entropyk` re-export required unless already present.
- [x] **Task 3: Document the Phantom-Gradient Regularization Standard** (AC: #1, #2)
- [x] 3.1 Add a focused doc (preferred path): `docs/components/phantom-gradient-regularization.md` **OR** expand `docs/components/flow-regularization.md` with a top-level “Standard” section that links to `smoothing.rs`. Prefer a **dedicated** short doc if the flow doc stays HX-specific.
- [x] 3.2 Document **ε / width selection guidance** with physical meaning:
| Primitive | Parameter | Meaning | Rule of thumb |
|---|---|---|---|
| `smooth_abs(x, eps)` | `eps` | value at `x=0`; blend half-width | ~1% of characteristic \|x\| scale, or smaller if kink is far from operating region |
| `smooth_max` / `smooth_min` | `k` | overshoot at equality = `k/2` | `k` ≪ \|ab\| in the region you care about; never so large it shifts equilibrium |
| `smooth_clamp` | `width` | transition length at each bound | `width ≤ (hilo)/2`; pick so Newton steps near bound still see ∂/∂x ∈ (0,1) over a physically small band (e.g. opening width `1e-3``1e-2` for [0,1]) |
| `flow_activity` | `m_eps` | mass-flow activity scale | keep `DEFAULT_M_EPS_KG_S = 1e-4` as HX reference; do not change the constant in this story |
- [x] 3.3 Explicit decision (write it into the doc):
- **Canonical general toolkit:** `entropyk_core::smoothing`
- **Reference specialized pattern:** `heat_exchanger::flow_regularization` (activity / duty / transport blend) — **not** duplicated into core
- **Banned in residual/Jacobian paths on Newton unknowns:** bare `.clamp(` / hard `.max(0)` / early `Ok(0.0)` that zeros informative derivatives (fixes deferred to 0.3/0.4)
- [x] 3.4 Cross-link from `docs/audits/jacobian-killing-pattern-audit.md` deferred table: mark Story 0.2 standard as landed when done (update the “deferred” row only — do not re-audit).
- [x] 3.5 English technical docs; keep code comments English.
- [x] **Task 4: Derivative-continuity unit tests** (AC: #1)
- [x] 4.1 Extend `crates/core/src/smoothing.rs` `#[cfg(test)]`:
- FD match for `smooth_clamp_derivative` across interior, both ramps, and far exterior.
- Slope continuity of `smooth_clamp` across junctions (sample FD slope just inside/outside joins; assert small jump).
- FD match for new `smooth_max` / `smooth_min` derivative helpers.
- [x] 4.2 Do **not** require `check_jacobian_health` for this story — that harness is component-level (Story 0.1). Core unit FD helpers already in `smoothing.rs` tests are the right layer.
- [x] 4.3 Keep using relative/absolute tolerances consistent with existing tests (`~1e-5` FD match for analytic derivatives).
- [x] **Task 5: Hard scope boundary — toolkit only** (AC: #2)
- [x] 5.1 **DO NOT** modify production residual/Jacobian physics in:
- `valve_flow.rs`
- `isenthalpic_expansion_valve.rs`
- `heat_exchanger/two_phase_dp.rs`
- `heat_exchanger/condenser.rs`
- any other component clamp site
- [x] 5.2 **DO NOT** change `DEFAULT_M_EPS_KG_S` / `DEFAULT_M_SCALE_KG_S` or HX residual formulas.
- [x] 5.3 **DO NOT** change `n_equations()` anywhere.
- [x] 5.4 Allowed touch list is essentially: `smoothing.rs` (+ tests), docs under `docs/components/` and a small audit cross-link, optional rustdoc polish on `flow_regularization.rs` module docs pointing to the standard.
- [x] **Task 6: Validation** (AC: #1, #2)
- [x] 6.1 `cargo test -p entropyk-core` green (includes new smoothing tests / doctests).
- [x] 6.2 `cargo test -p entropyk-components` green — proves no accidental physics regressions from doc-only / non-touch policy.
- [x] 6.3 Diff review: production component residual files should show **zero** physics diffs attributable to this story.
## Dev Notes
### Context & Positioning
- **Epic 0** — Physical Regularization & Jacobian Health. Prerequisite for primary KPI **NFR11** (≥95% first-try convergence). Robustness before speed.
- **FR19** — informative non-zero C¹ Jacobians across the full physical domain via standardized phantom-gradient regularization.
- **FR20** — FD harness (already delivered in Story 0.1); CI gate is Story **0.5**.
- **This story owns the standard + toolkit completeness.** Stories **0.3** (valve/EXV) and **0.4** (HX quality/actuators/MSH) **consume** `smooth_clamp` / `smooth_max` / `smooth_abs` to fix P0 killers.
- Source of truth for solver-HP scope: `_bmad-output/planning-artifacts/epics-solver-hp.md` (supersedes legacy PRD/architecture for this epic).
### CRITICAL: Toolkit already largely exists — complete, don't recreate
```text
CANONICAL LOCATION (reuse):
crates/core/src/smoothing.rs
smooth_max(a, b, k)
smooth_min(a, b, k)
smooth_abs(x, eps) + smooth_abs_derivative
smooth_clamp(x, lo, hi, width) // value exists; derivative API missing
smoothstep / smootherstep / cubic_blend / quintic_blend (+ derivatives)
HX REFERENCE PATTERN (keep in components — do not move to core):
crates/components/src/heat_exchanger/flow_regularization.rs
flow_activity / effective_duty / blend_transport_residual
uses entropyk_core::smoothing::smooth_abs
VERIFICATION HARNESS (Story 0.1 — do not reimplement):
crates/components/src/jacobian_fd.rs
docs/audits/jacobian-killing-pattern-audit.md
```
**Anti-patterns to prevent:**
- Creating a second `smoothing` / `regularization` module under `components/`
- Copy-pasting `tanh` / `LogSumExp` soft-max when `smooth_max` already exists
- “Unifying” by moving `flow_activity` into core (wrong layer — HX residual units / m_scale)
- Replacing component clamps in this story (that is 0.3/0.4)
- Calling `JacobianMatrix::numerical` (forward FD Newton fallback) for anything here
### Architecture Compliance
- **Exact analytic Jacobians** (`project-context.md` / AGENTS.md): production assembly stays analytic; FD only in tests.
- **C¹ residual policy:** any clamp/branch on a Newton unknown must use toolkit primitives so ∂R/∂x stays informative and continuous.
- **DoF invariant:** regularization never changes `n_equations()`.
- **Zero panic** in library code; public APIs need rustdoc + examples.
- Hot path: pure functions, no allocation, no dynamic dispatch.
- Layering: `entropyk-core` must not depend on `entropyk-components`.
### Technical Requirements
- **Language:** Rust edition 2021, crate `entropyk-core` (+ docs only elsewhere).
- **Deps:** no new crates. Existing workspace/`approx` patterns for tests as already used in core.
- **`smooth_clamp` construction (already implemented — preserve semantics):**
```rust
// Lower ramp then upper ramp via smoothstep — output always in [lo, hi], C¹ joins.
let lower = lo + (x - lo) * smoothstep(lo, lo + width, x);
hi + (lower - hi) * smoothstep(hi, hi - width, lower)
```
Derivative must follow the chain rule through both ramps; unit-test against central FD.
- **`smooth_max` analytic ∂/∂a (already proven in tests):**
```text
0.5 * (1 + (a-b) / sqrt((a-b)² + k²))
```
- Prefer exporting named derivative functions over forcing callers to re-derive formulas (Story 0.3 will clamp EXV opening in both residual and Jacobian).
### Current toolkit gaps (verified 2026-07-18)
| Item | Status |
|---|---|
| `smooth_max` / `smooth_min` / `smooth_abs` / `smooth_clamp` values | Present |
| `smooth_abs_derivative` | Present |
| Public `smooth_clamp_derivative` | **Missing — add** |
| Public `smooth_max`/`smooth_min` derivatives | **Missing — add** (formulas exist in tests) |
| FD C¹ junction tests for `smooth_clamp` | **Missing — add** (current test only saturates/bounds) |
| General ε/width selection doc | **Missing — add** (`flow-regularization.md` covers HX m_eps only) |
| Formal “reference vs unify” decision for `flow_regularization` | **Missing — document as reference** |
### Downstream contract (write APIs for these consumers)
| Future story | Will need |
|---|---|
| 0.3 Valve / EXV | `smooth_clamp` + derivative for opening ∈ [0,1]; smooth ΔP blend (may use `smooth_max`/`smooth_abs`) |
| 0.4 HX | `smooth_clamp` for quality / fan / flood; reuse `flow_regularization` patterns |
| 0.5 CI gate | Assumes toolkit stable; no API churn after this story |
Recommended default widths for docs/examples (not applied to components here):
- Opening / quality ∈ [0,1]: `width = 1e-3` … `1e-2`
- Fan actuator ∈ [0, 1.5]: `width ≈ 1e-2`
- Flood level ∈ [0, 0.98]: `width ≈ 1e-2` (keep `width ≤ (hilo)/2`)
### File Structure Requirements
| File | Action |
|---|---|
| `crates/core/src/smoothing.rs` | **UPDATE** — add missing derivative APIs + C¹/FD tests; expand module rustdoc with ε guidance |
| `crates/core/src/lib.rs` | **UPDATE only if** export changes needed (likely unchanged) |
| `docs/components/phantom-gradient-regularization.md` | **CREATE** (preferred) — standard + ε table + reference decision |
| `docs/components/flow-regularization.md` | **UPDATE** — link to standard; declare HX module as specialized reference |
| `crates/components/src/heat_exchanger/flow_regularization.rs` | **UPDATE docs only** (optional module-doc pointer) — **no formula changes** |
| `docs/audits/jacobian-killing-pattern-audit.md` | **UPDATE** — mark 0.2 standard row as done / link to new doc |
| `valve_flow.rs` / EXV / `two_phase_dp.rs` / `condenser.rs` | **DO NOT CHANGE** physics |
### Testing Requirements
- Unit tests live next to primitives in `smoothing.rs` (existing pattern with local `fd` helper).
- Must prove:
1. Analytic derivatives match central FD.
2. `smooth_clamp` slope is continuous at bound joins (C¹).
3. Degenerate parameters do not panic.
- Run:
```bash
cargo test -p entropyk-core
cargo test -p entropyk-components
```
- Do not flip Story 0.1 detection tests to “must be clean” — killers remain until 0.3/0.4.
### Previous Story Intelligence
From **`0-1-jacobian-killing-pattern-audit-fd-test-harness`** (status: review):
- Shared harness: `jacobian_fd::check_jacobian_health` — central FD, flags analytic≈0 while FD informative.
- Audit catalogue confirms P0 killers; maps EXV opening clamps → **Story 0.2 `smooth_clamp` as the intended replacement API**, applied later in **0.3**.
- Explicitly noted: `smooth_*` already in core — Story 0.2 is **unify/document/ε-guidance**, not greenfield.
- Scope discipline that worked: observe/fix tooling without changing production physics. **Reuse that discipline here.**
- Epic typo note still valid for 0.3: only `valve_mass_flow_dp_up` exists (no `dp_down`).
- Numbering collision: `0-1-fix-failing-tests` is a **different**, already-done DoF story — ignore for this work.
### Git Intelligence
- Recent commits are FMI/docs-heavy (`f88cd7f` baseline). Smoothing + `flow_regularization` landed earlier (`3358b74` lineage) — brownfield completion, not invention.
- No commit yet closes the ε-standard doc or `smooth_clamp_derivative` gap.
### Project Context Reference
- `project-context.md` / `AGENTS.md`: exact Jacobians; Component trait; English technical docs; zero panic.
- Epic/FRs: `_bmad-output/planning-artifacts/epics-solver-hp.md` — Epic 0, Story 0.2, FR19, FR20, NFR11.
- Supporting: `docs/audits/jacobian-killing-pattern-audit.md`, `docs/components/flow-regularization.md`, `docs/adr/ADR-0001-multi-circuit-heat-exchanger-architecture.md` (smooth_abs / no hard zero-flow branch).
### References
- [Source: `_bmad-output/planning-artifacts/epics-solver-hp.md` — Epic 0, Story 0.2, FR19, NFR11]
- [Source: `crates/core/src/smoothing.rs` — existing C¹/C∞ toolkit]
- [Source: `crates/components/src/heat_exchanger/flow_regularization.rs` — HX reference pattern]
- [Source: `docs/components/flow-regularization.md` — m_eps defaults, DoF rule]
- [Source: `docs/audits/jacobian-killing-pattern-audit.md` — deferred 0.2 work + P0 map]
- [Source: `_bmad-output/implementation-artifacts/0-1-jacobian-killing-pattern-audit-fd-test-harness.md` — prior story learnings]
- [Source: `crates/components/src/jacobian_fd.rs` — verification harness (do not reimplement)]
## Dev Agent Record
### Agent Model Used
Cursor Grok 4.5 (bmad-dev-story)
### Debug Log References
- `cargo test -p entropyk-core` — 164 lib + 41 doctests passed (incl. new smoothing derivative / C¹ / degenerate tests)
- `cargo test -p entropyk-components` — lib 910 passed; jacobian_health_sweep 8 passed; doctests 70 passed
- Story-owned production touch limited to `flow_regularization.rs` module docs (+4 lines); no clamp→smooth physics changes
### Completion Notes List
- Added public `smooth_max_derivative`, `smooth_min_derivative`, `smooth_clamp_derivative` with chain-rule / analytic formulas; FD-matched in unit tests.
- Documented ε/width guidance in module rustdoc and `docs/components/phantom-gradient-regularization.md`.
- Declared `flow_regularization` as HX **reference** pattern (not moved to core); linked from flow-regularization.md + audit deferred table (0.2 landed).
- Degenerate parameters (`k/eps/width <= 0`, inverted bounds) fall back to hard max/min/abs/clamp without panic.
- Scope held: valve/EXV/HX clamp physics untouched for Stories 0.3/0.4.
### File List
- `crates/core/src/smoothing.rs` (UPDATE)
- `crates/components/src/heat_exchanger/flow_regularization.rs` (UPDATE — module docs only)
- `docs/components/phantom-gradient-regularization.md` (NEW)
- `docs/components/flow-regularization.md` (UPDATE)
- `docs/audits/jacobian-killing-pattern-audit.md` (UPDATE — deferred table)
- `_bmad-output/implementation-artifacts/sprint-status.yaml` (UPDATE — story status)
- `_bmad-output/implementation-artifacts/0-2-phantom-gradient-regularization-standard.md` (UPDATE — this file)
### Change Log
- 2026-07-18: Completed phantom-gradient regularization standard — derivative APIs, C¹ tests, ε docs, flow_regularization reference decision; status → review
## Story Completion Status
- Status: **review**
- Note: All tasks complete; ACs satisfied; ready for `code-review`