Skip to content

Recompute Krook argument after interpolation#183

Closed
krystophny wants to merge 1 commit into
feat/flux-pumping/wp5-collision-scalefrom
fix/flux-pumping/wp5-recompute-z0
Closed

Recompute Krook argument after interpolation#183
krystophny wants to merge 1 commit into
feat/flux-pumping/wp5-collision-scalefrom
fix/flux-pumping/wp5-recompute-z0

Conversation

@krystophny

@krystophny krystophny commented Jul 13, 2026

Copy link
Copy Markdown
Member

Recomputes the derived Krook argument z0 from interpolated omega_E, k_parallel, collision frequency, and thermal velocity on the solver grid. Previously KIM interpolated z0 itself across the k_parallel=0 singularity; a four-point polynomial stencil could produce order-1e12 values where the defining formula gives order 1e-3.

The invariant is now z0 = -(omega_E - omega - i nu)/(|k_parallel| sqrt(2) v_T) at every solver-grid point. Primitive profile interpolation, collision formulas, units, resonance convention, and boundary conditions are unchanged.

Verification

Before: the synthetic coarse-to-solver-grid regression failed because interpolated z0 violated its defining formula.

After: the focused regression passes; the full CMake build and all 30 CTest tests pass; bare fo passes Static, Build, Tests, and Lint.

At omega=1e5 and collision scale 1, the fix removes the Krook overflow and reduces the 64-point hat peak from 1.9e10 to 7e-3 statV. A controlled refinement excludes an earlier nominal 128-point run that accidentally retained omega=0. The valid gauge-removed 64-to-128 profile change is 0.093, but 128-to-256 changes by 7.32 and the peak grows from 7.1e-3 to 1.15e-1 statV. The Krook hat basis is therefore not grid-convergent and is not promoted to CTest.

Relation to Markus's Fokker-Planck periodic branch

This PR fixes an independent hat-path correctness defect: interpolate primitive quantities and recompute the singular derived Krook argument z0. That invariant stands regardless of which periodic implementation survives. It may land independently when its own stack and CI are green; it does not count as FP validation.

@marjohma

Copy link
Copy Markdown
Member

Closing: the wp5 flux-pumping stack is retired, but this fix was worth keeping — the bug was still present verbatim on feature/kim-forced-periodicity. The z0 recompute is extracted to #225, rebased onto the forced-periodicity lineage and detached from the wp5 driver (#182's collision-scale knob came along, since this was stacked on it).

The invariant is unchanged; the new test_collision_scale_z0 regression was watched fail on the pre-fix code (36% relative z0 error at k_par = 2e-4) before landing. Thanks for tracing this one — the interpolate-primitives-recompute-derived rule is exactly what the periodized-background path needed too.

@marjohma marjohma closed this Jul 15, 2026
marjohma added a commit that referenced this pull request Jul 15, 2026
)

## Summary

Extracts the two salvageable pieces of the retired wp5 flux-pumping
stack onto the forced-periodicity lineage. The rest of that stack
(#177#181, #184) is closed as superseded.

## Krook argument `z0` (was #183)

`interpolate_plasma_backs` interpolated the **derived** `z0` alongside
the primitives. `z0` carries a `1/|k_parallel|` singularity at the
resonance, so a four-point Lagrange stencil spanning `k_parallel = 0`
returns values that violate its own defining formula. The fix
interpolates primitives only and recomputes

    z0 = -(omega_E - omega - i nu) / (|k_parallel| sqrt(2) v_T)

on the target grid — the same invariant the periodized-background path
already follows.

**Scope:** `z0` is consumed only by `Krook_kernel_plasma_prefacs.f90`.
The Fokker-Planck path recomputes `x1/x2/A1/A2/I^{kl}` after
interpolation and never reads `z0`, so **FP results are bit-unchanged**.
This repairs the Krook hat path, whose nml still marks it `(unstable)` —
plausibly part of why.

## Collision-frequency scale (was #182)

New positive `&KIM_CONFIG` key `collision_frequency_scale` multiplying
the calculated electron and ion collision frequencies before `z0` and
the FP susceptibility inputs are assembled. Default `1.0` leaves every
collision formula, profile, unit, and output unchanged. Non-positive
values are rejected at startup; the value is displayed when it differs
from 1.0 and stored in HDF5 provenance. Same shape as the existing
`ion_flr_scale_factor` knob. No benchmark-acceptance claim — it is a
sensitivity parameter.

## Tests

`test_collision_scale_z0` (new) asserts the `z0` invariant on a stencil
straddling `k_parallel = 0` and away from it, and that the scale reaches
both `nu` and `z0` (including the imaginary part of `z0` tracking it).

Developed red-first: against the pre-fix code the test fails with a
**36% relative `z0` error at k_par = 2e-4** (`got (-0.0983, 0.0129)` vs
`want (-0.4543, 0.0599)`), growing without bound toward the resonance.

## Validation

- `make` — clean build
- `ctest -E
'test_rhs_balance|test_periodic_convergence|test_periodic_vs_global'` —
**32/32 passed**

Known red gates excluded as usual: the pre-existing `test_rhs_balance`
baseline failure, the periodization-deformation gate, and the
periodic-vs-global 5% gate — none touched by this change.

Supersedes #182, #183.
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.

2 participants