Skip to content

Lane cc pn - #98

Open
beykyle wants to merge 11 commits into
mainfrom
lane-cc-pn
Open

beykyle wants to merge 11 commits into
mainfrom
lane-cc-pn

Conversation

@beykyle

@beykyle beykyle commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Add Lane coupled (p,n)

Workspace.tmatrix() and .xs() take optional U1_central and U1_spin_orbit.
When None, each defaults independently to -(U_n - U_p) * isovector_factor;
when given, the array is used as-is in the radial integral.

Add tests for default equivalence, independent defaults, linear scaling
of T with U1, and shape validation. Add a channel-energy vs midpoint-energy
U1 comparison to the CHEX validation notebook (not asserted against CHEX).
Channels in one partial wave share a physical channel radius but may have
different wavenumbers, reduced masses and Sommerfeld parameters (e.g. the
p and n channels of Lane (p,n)_IAS). Previously every channel's
Coulomb-Hankel functions were evaluated at k_0 a, surface derivatives were
taken in s = k_0 r without the mu_0/mu_i Bloch factor, and S was the raw
amplitude ratio.

- get_partial_wave_channels tabulates each channel at rho_i = k_i a,
  keyed by (eta, rho)
- Solver.solve scales channel derivatives by v_i/v_0, returns the
  flux-normalized S and R in the rho-derivative convention

All changes are the identity for a single channel or equal k and mu.
Add tests: uncoupled different-k channels reproduce single-channel solves,
unitary/symmetric S for real coupling, and channel-radius independence.
jitr.xs.lane_pn.Workspace solves the 2x2 proton/neutron coupled channels
for each (l, j), coupled by the isovector transition potential U1, with
the incoming wave in the proton channel. It returns the full R- and
flux-normalized S-matrices (rsmatrix) and builds the differential and
angle-integrated (p,n) cross sections from S_np. The API mirrors the DWBA
workspace, including the optional U1_central/U1_spin_orbit.

Factor the potential validation, default U1 recipe, isovector factor and
spin-1/2 CG/Y_lm transition geometry out of quasielastic_pn into shared
helpers; DWBA output is unchanged (max rel diff 3e-15).

Tests: CC(eps U1)/eps^2 converges to DWBA as O(eps^2), partial-wave and
angle-integrated cross sections agree, S is unitary and symmetric for real
potentials, j-independence without spin-orbit, default/explicit U1.
Add a section computing the Lane coupled-channels (p,n)_IAS cross section
with jitr.xs.lane_pn.Workspace, with the same potentials and kinematics as the
DWBA, plotted against DWBA, CHEX and data (not asserted against CHEX).
For 48Ca(p,n) at 35 MeV, CC is ~1% below DWBA (sigma_pn 7.55 vs 7.65 mb).
Review of the coupled-channels branch found that solve(..., wavefunction=True)
returned wrong interior coefficients for every multichannel solve: the
outgoing term in the Bloch surface source contracted the S-matrix with the
channel index instead of the incoming weights. Interior and exterior
wavefunctions disagreed by O(100%); single-channel results were unaffected.

Wavefunctions.uext() also raised TypeError unconditionally (Channels has no
__len__), passed a float l to the Coulomb functions, evaluated every channel
in the channel-0 coordinate, and used the flux-normalized S in the raw-S
asymptotic form. All fixed; it now takes the S returned by solve.

Add tests/test_wavefunction_continuity.py pinning interior/exterior continuity
at the channel radius for 1 and 3 channels with several incoming weights, and
for two channels with different k and mu.

Also from review: raise on the N - Z = 1 divergence of isovector_factor,
replace the four-deep selection loop in quasielastic_pn.xs with the einsum it
was equivalent to (DWBA output unchanged, 1.5e-15), hoist Y_lm out of the j
loop, name the (eta, rho) table keys, and document the unused Elab/Ecm
parameters of get_partial_wave_channels.
48Ca(p,n)48Sc(IAS) DWBA at Elab(p) = 25 and 35 MeV, from decks contributed by
Jin Lei (Tongji University) and re-run locally with Frescox 7.2-20-ga7f491.
These are the first non-elastic regression cases and the first external check
on the spin-flip terms of the (p,n) amplitude: Frescox does its own
channel-spin algebra, so it is independent of jitR and CHEX. jitR reproduces
both to better than 1.3e-4 at every angle; with the pre-fix Clebsch-Gordan
argument order both cases fail.

Harness: build_case dispatches on observable_type, BuiltCase grows a dsdo
extractor (the (p,n) workspace returns a bare array, elastic an ElasticXS),
and _build_quasielastic_pn_case builds both channels from the deck's own lab
energies. U1_central is left to jitR's default isovector difference, which
equals the deck's tabulated form factor to 6e-9; U1_spin_orbit is zero
because a Frescox KIND=1 form factor is central only.

tools/make_pn_formfactor.py regenerates the form factor from the KD02
parameters, and documents two Frescox conventions: the header must carry
explicit LOP/DER or the form factor is dropped silently and the cross section
comes out identically zero, and FSCALE = sqrt(2)*sqrt(4 pi) cancels against
Frescox's own KIND=1 coupling coefficient rather than being a free
normalization.

This branch has not been deployed

No deployments
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