Symptom
In the volume classification plots generated by
examples/classification/plot_paper_results.py:plot_volume_classification
(figures volume_classification_q[ahi].png), the two analytic boundary
curves do not enclose the per-pixel J_perp data:
- Dashed deeply-trapped boundary sits visibly below the lower edge
of the populated trapped band. Worst case is the QI config: dashed
line at J_perp ≈ 0.70, data lower edge at J_perp ≈ 0.85
(~0.15 offset).
- Solid trapped-passing boundary cuts through the upper edge of
the data rather than enclosing it from above.
- All three configurations under
examples/classification/configs/{qi,qh,qa}_volume.in show the same
pattern, just at different magnitudes.
The boundaries should enclose the trapped-classified pixels precisely;
they currently do not.
Likely cause: inconsistent normalization
In plot_paper_results.py, the boundaries are drawn as:
bmin_global = np.min(bminmax[:, 1])
ax.plot(bminmax[:, 0], bmin_global / bminmax[:, 1], "k", lw=1.5) # solid
ax.plot(bminmax[:, 0], bmin_global / bminmax[:, 2], "k--", lw=1.0) # dashed
i.e. both curves are normalized to the global minimum bmin over
all surfaces.
The per-particle J_perp plotted as image pixels comes from
class_parts.dat[:, 2], written by classification.f90:
perp_inv(ipart) = z(4)**2 * (1.d0 - z(5)**2) / bmod
i.e. v_perp^2 / B_local evaluated at each particle's starting point.
The two are not on the same scale. The boundary curves assume J_perp
is normalized so that a deeply-trapped particle at the surface bmin has
J_perp = bmin_global / bmin(s), but the per-particle quantity is
absolute v_perp^2 / B_local (or some other Fortran-side convention).
A global rescale by bmin_global is missing on one side, or the two
quantities are being computed against different references entirely.
The asymmetry across configs is consistent with this hypothesis: the
mismatch is largest where bmin(s) varies most across surfaces (QI),
smallest where the variation is mild (QH).
What to fix
Pick one canonical normalization and use it on both sides:
- Either change
plot_volume_classification to draw the boundaries
using the same reference field as perp_inv (e.g. drop the
bmin_global factor and use a normalization derived from each
particle's own bmod), or
- Change
classification.f90 to write a normalized perp_inv that
matches the bmin_global / bmin(s) convention used by the plot.
Either way, document the convention in a one-line comment next to
perp_inv = ... in classification.f90 and next to the boundary
plot lines so the two stay in sync.
Test
Regenerate the three volume plots from
examples/classification/configs/{qi,qh,qa}_volume.in after the fix
and verify that the dashed (deeply-trapped) and solid (trapped-passing)
curves enclose the non-NaN pixel region in all three cases.
Context
References
examples/classification/plot_paper_results.py — plot_volume_classification
src/classification.f90 — line ~154, perp_inv definition
examples/classification/configs/{qi,qh,qa}_volume.in
Symptom
In the volume classification plots generated by
examples/classification/plot_paper_results.py:plot_volume_classification(figures
volume_classification_q[ahi].png), the two analytic boundarycurves do not enclose the per-pixel
J_perpdata:of the populated trapped band. Worst case is the QI config: dashed
line at
J_perp ≈ 0.70, data lower edge atJ_perp ≈ 0.85(~0.15 offset).
the data rather than enclosing it from above.
examples/classification/configs/{qi,qh,qa}_volume.inshow the samepattern, just at different magnitudes.
The boundaries should enclose the trapped-classified pixels precisely;
they currently do not.
Likely cause: inconsistent normalization
In
plot_paper_results.py, the boundaries are drawn as:i.e. both curves are normalized to the global minimum
bminoverall surfaces.
The per-particle
J_perpplotted as image pixels comes fromclass_parts.dat[:, 2], written byclassification.f90:i.e.
v_perp^2 / B_localevaluated at each particle's starting point.The two are not on the same scale. The boundary curves assume
J_perpis normalized so that a deeply-trapped particle at the surface bmin has
J_perp = bmin_global / bmin(s), but the per-particle quantity isabsolute
v_perp^2 / B_local(or some other Fortran-side convention).A global rescale by
bmin_globalis missing on one side, or the twoquantities are being computed against different references entirely.
The asymmetry across configs is consistent with this hypothesis: the
mismatch is largest where
bmin(s)varies most across surfaces (QI),smallest where the variation is mild (QH).
What to fix
Pick one canonical normalization and use it on both sides:
plot_volume_classificationto draw the boundariesusing the same reference field as
perp_inv(e.g. drop thebmin_globalfactor and use a normalization derived from eachparticle's own
bmod), orclassification.f90to write a normalizedperp_invthatmatches the
bmin_global / bmin(s)convention used by the plot.Either way, document the convention in a one-line comment next to
perp_inv = ...inclassification.f90and next to the boundaryplot lines so the two stay in sync.
Test
Regenerate the three volume plots from
examples/classification/configs/{qi,qh,qa}_volume.inafter the fixand verify that the dashed (deeply-trapped) and solid (trapped-passing)
curves enclose the non-NaN pixel region in all three cases.
Context
bminmax.datgeneration fornum_surf=0were fixedin PR fix(classification): fast_class regression + JPP 2023 paper reproduction #323 (bugs Matlab interface working #2-4 in the PR description).
find_bminmaxcache initialization was fixed in PR find_bminmax: initialize cache in active tracing coordinates #348(
find_bminmax: initialize cache in active tracing coordinates),which only affects the
num_surf > 1initialization path andexplicitly does not touch the
num_surf=0classifier semantics.inconsistency that survives both fixes.
References
examples/classification/plot_paper_results.py—plot_volume_classificationsrc/classification.f90— line ~154,perp_invdefinitionexamples/classification/configs/{qi,qh,qa}_volume.in