From e2ad3b536b81f2386bda9435a727f19d1c896222 Mon Sep 17 00:00:00 2001 From: beykyle Date: Tue, 9 Jun 2026 21:26:02 -0400 Subject: [PATCH 01/10] Switch assembler to symmetric MeV form; divide by m0 in spectrum path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit assemble_block_hamiltonian now builds H in MeV by scaling each channel's kinetic block by m_c and leaving V untouched. mass_factor_override accepts a scalar or (N_c,) array for per-channel overrides. _spectrum_eigh and _spectrum_eig divide the assembled MeV block by m0 to recover fm⁻² eigenvalues so all downstream observables are unchanged. Co-Authored-By: Claude Sonnet 4.6 --- src/lax/solvers/assembly.py | 48 ++++++++++++++++++------------------- src/lax/solvers/spectrum.py | 14 +++++++++-- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/lax/solvers/assembly.py b/src/lax/solvers/assembly.py index eee392d..7d15385 100644 --- a/src/lax/solvers/assembly.py +++ b/src/lax/solvers/assembly.py @@ -16,15 +16,16 @@ def assemble_block_hamiltonian( potential: jax.Array, mass_factor_override: float | jax.Array | None = None, ) -> jax.Array: - """Assemble the Bloch-augmented block Hamiltonian in fm⁻² units. + """Assemble the Bloch-augmented block Hamiltonian in MeV units. Builds the ``(N_c·N, N_c·N)`` matrix whose eigendecomposition drives - all spectral observables. Diagonal blocks contain ``T+L``, the - centrifugal term, the channel threshold, and the diagonal potential; - off-diagonal blocks contain the coupling potential. [DESIGN.md §11.5] + all spectral observables. Diagonal blocks contain + ``m_c·(T+L) + E_c·I``; off-diagonal blocks contain the coupling + potential. [DESIGN.md §11.5] - All quantities are converted from MeV to fm⁻² by dividing by - ``channel.mass_factor`` (ℏ²/2μ in MeV·fm²). + Each channel's kinetic block is scaled by ``m_c`` (ℏ²/2μ in MeV·fm²) + so that the assembled matrix is in MeV throughout. The potential ``V`` + is added without rescaling — it must already be in MeV. Parameters ---------- @@ -38,15 +39,16 @@ def assemble_block_hamiltonian( Assembled potential in MeV. Shape ``(N_c, N_c, N)`` for local or ``(N_c, N_c, N, N)`` for non-local. mass_factor_override - When not ``None``, overrides ``channel.mass_factor`` for every - channel block. Supply a scalar JAX float when using an - energy-dependent μ(E) — the value is traced and vmapped normally. - All channels are assumed to share the same reduced mass. + When not ``None``, overrides ``channel.mass_factor`` for the + kinetic scaling. Accepts either a scalar (uniform override for + all channels) or a JAX array of shape ``(N_c,)`` for per-channel + values. Supply a traced scalar when using an energy-dependent + μ(E) so it vmaps correctly. Returns ------- jax.Array - Block Hamiltonian, shape ``(N_c·N, N_c·N)``, in fm⁻². + Block Hamiltonian, shape ``(N_c·N, N_c·N)``, in MeV. """ channel_count = len(channels) @@ -59,13 +61,15 @@ def assemble_block_hamiltonian( blocks: list[jax.Array] = [] for channel_index in range(channel_count): row_blocks: list[jax.Array] = [] - mass_factor: float | jax.Array = ( - mass_factor_override - if mass_factor_override is not None - else channels[channel_index].mass_factor - ) + if mass_factor_override is not None: + if jnp.ndim(mass_factor_override) == 0: + m_c = mass_factor_override + else: + m_c = mass_factor_override[channel_index] + else: + m_c = channels[channel_index].mass_factor angular_momentum = channels[channel_index].l - threshold = channels[channel_index].threshold / mass_factor + threshold = channels[channel_index].threshold for coupled_index in range(channel_count): block: jax.Array = jnp.zeros( (basis_size, basis_size), @@ -74,8 +78,7 @@ def assemble_block_hamiltonian( if channel_index == coupled_index: block = ( block - + t_plus_l - + angular_momentum * (angular_momentum + 1) * inv_r2 + + m_c * (t_plus_l + angular_momentum * (angular_momentum + 1) * inv_r2) + threshold * jnp.eye( basis_size, @@ -83,12 +86,9 @@ def assemble_block_hamiltonian( ) ) if potential.ndim == 3: - block = ( - block - + _diagonal_from_vector(potential[channel_index, coupled_index]) / mass_factor - ) + block = block + _diagonal_from_vector(potential[channel_index, coupled_index]) else: - block = block + potential[channel_index, coupled_index] / mass_factor + block = block + potential[channel_index, coupled_index] row_blocks.append(block) blocks.append(jnp.concatenate(row_blocks, axis=1)) matrix: jax.Array = jnp.concatenate(blocks, axis=0) diff --git a/src/lax/solvers/spectrum.py b/src/lax/solvers/spectrum.py index c9d610d..5101077 100644 --- a/src/lax/solvers/spectrum.py +++ b/src/lax/solvers/spectrum.py @@ -144,9 +144,14 @@ def _spectrum_eigh( ) -> Spectrum: """Return the Hermitian spectrum for one potential.""" - hamiltonian = assemble_block_hamiltonian( + H_MeV = assemble_block_hamiltonian( mesh, operators, channels, potential, mass_factor_override ) + if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: + m0 = mass_factor_override + else: + m0 = channels[0].mass_factor + hamiltonian = H_MeV / m0 eigensystem = cast( tuple[jax.Array, jax.Array], jnp.linalg.eigh(hamiltonian), @@ -172,9 +177,14 @@ def _spectrum_eig( ) -> Spectrum: """Return the complex-symmetric spectrum for one potential.""" - hamiltonian = assemble_block_hamiltonian( + H_MeV = assemble_block_hamiltonian( mesh, operators, channels, potential, mass_factor_override ) + if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: + m0 = mass_factor_override + else: + m0 = channels[0].mass_factor + hamiltonian = H_MeV / m0 eigenvalues, eigenvectors = _eig_via_callback(hamiltonian) bilinear_norm = jnp.sqrt(jnp.diag(eigenvectors.T @ eigenvectors)) eigenvectors_normalized = eigenvectors / bilinear_norm[None, :] From f8c780a156fcf1833dd3e4dc7062654b68f4c353 Mon Sep 17 00:00:00 2001 From: beykyle Date: Tue, 9 Jun 2026 21:53:38 -0400 Subject: [PATCH 02/10] Add Interaction type, builders, and unified direct-path API (Phase 10 tasks 2-3) - Add `Interaction` pytree dataclass to `types.py` with static `energy_dependent` flag - Add `operators/interaction.py`: pickle-safe `_InteractionFromBlock/Array/Funcs` callables with `make_interaction_from_{block,array,funcs}` factories exposed on `Solver` - Rewrite `linear_solve.py` direct path: `C = H_MeV - E*I`, `Q' = sqrt(m_c)*Q`, `R = Q'^T C^{-1} Q' / a`; add `_SMatrixDirectObservable`, `_PhasesDirectObservable`, `_WavefunctionDirectKernel` with JIT-compiled entry points - Extend `Solver` and `compile.py` to wire `smatrix_direct`, `phases_direct`, `wavefunction_direct`, and `interaction_from_*` fields - Fix test manual formulas to use MeV assembler convention throughout Co-Authored-By: Claude Sonnet 4.6 --- src/lax/__init__.py | 3 +- src/lax/boundary/_types.py | 82 ++++++- src/lax/compile.py | 51 +++++ src/lax/operators/__init__.py | 13 +- src/lax/operators/interaction.py | 275 ++++++++++++++++++++++++ src/lax/solvers/__init__.py | 11 +- src/lax/solvers/linear_solve.py | 331 +++++++++++++++++++++++++---- src/lax/types.py | 23 ++ tests/unit/test_solver_direct.py | 17 +- tests/unit/test_solver_spectrum.py | 37 ++-- 10 files changed, 775 insertions(+), 68 deletions(-) create mode 100644 src/lax/operators/interaction.py diff --git a/src/lax/__init__.py b/src/lax/__init__.py index db9f629..a712178 100644 --- a/src/lax/__init__.py +++ b/src/lax/__init__.py @@ -20,11 +20,12 @@ from lax.boundary._types import Solver from lax.compile import compile from lax.operators.potential import assemble_local, assemble_nonlocal -from lax.types import ChannelSpec, MeshSpec +from lax.types import ChannelSpec, Interaction, MeshSpec from lax.wavefunction import make_wavefunction_source __all__ = [ "ChannelSpec", + "Interaction", "MeshSpec", "Solver", "assemble_local", diff --git a/src/lax/boundary/_types.py b/src/lax/boundary/_types.py index 91b340e..77eddcc 100644 --- a/src/lax/boundary/_types.py +++ b/src/lax/boundary/_types.py @@ -192,7 +192,9 @@ def __call__(self, potential: jax.Array) -> jax.Array: Parameters ---------- potential - Local potential array, shape ``(N_c, N_c, N)``. + Assembled potential array, shape ``(N_c, N_c, N)`` / ``(N_c, N_c, N, N)`` + for energy-independent V, or an :class:`~lax.Interaction` object + (dispatch is handled transparently at the Python level). Returns ------- @@ -202,6 +204,72 @@ def __call__(self, potential: jax.Array) -> jax.Array: ... +class SMatrixDirectObservable(Protocol): + """Callable that computes the direct S-matrix via per-energy linear solves.""" + + def __call__(self, potential: jax.Array) -> jax.Array: + """Evaluate the S-matrix on the compile-time energy grid. + + Parameters + ---------- + potential + Assembled potential or :class:`~lax.Interaction`. + + Returns + ------- + jax.Array + S-matrix on the compile-time grid, shape ``(N_E, N_c, N_c)``, complex. + """ + ... + + +class PhasesDirectObservable(Protocol): + """Callable that computes direct phase shifts via per-energy linear solves.""" + + def __call__(self, potential: jax.Array) -> jax.Array: + """Evaluate phase shifts on the compile-time energy grid. + + Parameters + ---------- + potential + Assembled potential or :class:`~lax.Interaction`. + + Returns + ------- + jax.Array + Phase shifts, shape ``(N_E, N_c)``, in radians. + """ + ... + + +class WavefunctionDirectObservable(Protocol): + """Callable that reconstructs the wavefunction via a direct linear solve.""" + + def __call__( + self, + potential: jax.Array, + source: jax.Array, + energy_index: int, + ) -> jax.Array: + """Solve ``C(E_i) ψ = source`` for the internal wavefunction. + + Parameters + ---------- + potential + Assembled potential or :class:`~lax.Interaction`. + source + Mesh-space driving term, shape ``(N_c·N,)``. + energy_index + Index into the compile-time energy grid (Python int). + + Returns + ------- + jax.Array + Internal wavefunction coefficient vector, shape ``(N_c·N,)``. + """ + ... + + class DirectGridObservable(Protocol): """Callable for aligned-grid observables from per-energy potential batches.""" @@ -693,6 +761,12 @@ class Solver: rmatrix_direct_grid: DirectGridObservable | None = None smatrix_direct_grid: DirectGridObservable | None = None phases_direct_grid: DirectGridObservable | None = None + smatrix_direct: SMatrixDirectObservable | None = None + phases_direct: PhasesDirectObservable | None = None + wavefunction_direct: WavefunctionDirectObservable | None = None + interaction_from_block: Callable | None = None + interaction_from_array: Callable | None = None + interaction_from_funcs: Callable | None = None interpolate_rmatrix: InterpolatorBuilder | None = None interpolate_smatrix: InterpolatorBuilder | None = None interpolate_phases: InterpolatorBuilder | None = None @@ -732,6 +806,9 @@ def __repr__(self) -> str: "smatrix_grid", "phases_grid", "rmatrix_direct", + "smatrix_direct", + "phases_direct", + "wavefunction_direct", ) _transform_names = ( "to_grid_vector", @@ -774,5 +851,8 @@ def __repr__(self) -> str: "SpectrumKernel", "SpectrumObservable", "TransformMatrices", + "PhasesDirectObservable", + "SMatrixDirectObservable", + "WavefunctionDirectObservable", "WavefunctionObservable", ] diff --git a/src/lax/compile.py b/src/lax/compile.py index 3e035ed..710bcea 100644 --- a/src/lax/compile.py +++ b/src/lax/compile.py @@ -31,22 +31,33 @@ InterpolatorBuilder, Mesh, OperatorMatrices, + PhasesDirectObservable, RMatrixObservable, + SMatrixDirectObservable, Solver, SpectrumGridObservable, SpectrumKernel, SpectrumObservable, TransformMatrices, + WavefunctionDirectObservable, WavefunctionObservable, ) from lax.meshes import build_mesh +from lax.operators.interaction import ( + make_interaction_from_array, + make_interaction_from_block, + make_interaction_from_funcs, +) from lax.solvers import ( bind_direct_grid_observables, bind_grid_observables, bind_interpolators, bind_observables, + make_direct_wavefunction_kernel, + make_phases_direct_observable, make_rmatrix_direct_grid_observable, make_rmatrix_direct_kernel, + make_smatrix_direct_observable, make_spectrum_kernel, ) from lax.transforms import ( @@ -104,6 +115,12 @@ class _ObservableBundle: rmatrix_direct_grid: DirectGridObservable | None smatrix_direct_grid: DirectGridObservable | None phases_direct_grid: DirectGridObservable | None + smatrix_direct: SMatrixDirectObservable | None + phases_direct: PhasesDirectObservable | None + wavefunction_direct: WavefunctionDirectObservable | None + interaction_from_block: object | None + interaction_from_array: object | None + interaction_from_funcs: object | None interpolate_rmatrix: InterpolatorBuilder | None interpolate_smatrix: InterpolatorBuilder | None interpolate_phases: InterpolatorBuilder | None @@ -522,6 +539,9 @@ def _bind_solver_observables( rmatrix_direct_grid_fn: DirectGridObservable | None = None smatrix_direct_grid_fn: DirectGridObservable | None = None phases_direct_grid_fn: DirectGridObservable | None = None + smatrix_direct_fn: SMatrixDirectObservable | None = None + phases_direct_fn: PhasesDirectObservable | None = None + wavefunction_direct_fn: WavefunctionDirectObservable | None = None if "rmatrix_direct" in request.solvers: rmatrix_direct_fn = make_rmatrix_direct_kernel( mesh, @@ -530,6 +550,17 @@ def _bind_solver_observables( energies, boundary, ) + from lax.solvers.linear_solve import _DirectRMatrixKernel # noqa: PLC0415 + + if isinstance(rmatrix_direct_fn, _DirectRMatrixKernel): + smatrix_direct_fn = make_smatrix_direct_observable(rmatrix_direct_fn, boundary) + phases_direct_fn = make_phases_direct_observable(smatrix_direct_fn) + wavefunction_direct_fn = make_direct_wavefunction_kernel( + mesh, + operators, + request.channels, + energies, + ) if has_energy_grid: rmatrix_direct_grid_fn = make_rmatrix_direct_grid_observable( mesh, @@ -554,6 +585,14 @@ def _bind_solver_observables( interpolate_phases_fn, ) = bind_interpolators(energies) + interaction_from_block_fn = None + interaction_from_array_fn = None + interaction_from_funcs_fn = None + if has_energy_grid: + interaction_from_block_fn = make_interaction_from_block(mesh, request.channels, energies) + interaction_from_array_fn = make_interaction_from_array(mesh, request.channels, energies) + interaction_from_funcs_fn = make_interaction_from_funcs(mesh, request.channels, energies) + return _ObservableBundle( spectrum=spectrum_fn, rmatrix=rmatrix_fn, @@ -569,6 +608,12 @@ def _bind_solver_observables( rmatrix_direct_grid=rmatrix_direct_grid_fn, smatrix_direct_grid=smatrix_direct_grid_fn, phases_direct_grid=phases_direct_grid_fn, + smatrix_direct=smatrix_direct_fn, + phases_direct=phases_direct_fn, + wavefunction_direct=wavefunction_direct_fn, + interaction_from_block=interaction_from_block_fn, + interaction_from_array=interaction_from_array_fn, + interaction_from_funcs=interaction_from_funcs_fn, interpolate_rmatrix=interpolate_rmatrix_fn, interpolate_smatrix=interpolate_smatrix_fn, interpolate_phases=interpolate_phases_fn, @@ -616,6 +661,12 @@ def _assemble_solver( rmatrix_direct_grid=observables.rmatrix_direct_grid, smatrix_direct_grid=observables.smatrix_direct_grid, phases_direct_grid=observables.phases_direct_grid, + smatrix_direct=observables.smatrix_direct, + phases_direct=observables.phases_direct, + wavefunction_direct=observables.wavefunction_direct, + interaction_from_block=observables.interaction_from_block, + interaction_from_array=observables.interaction_from_array, + interaction_from_funcs=observables.interaction_from_funcs, interpolate_rmatrix=observables.interpolate_rmatrix, interpolate_smatrix=observables.interpolate_smatrix, interpolate_phases=observables.interpolate_phases, diff --git a/src/lax/operators/__init__.py b/src/lax/operators/__init__.py index 1975617..bbd8ed2 100644 --- a/src/lax/operators/__init__.py +++ b/src/lax/operators/__init__.py @@ -1,5 +1,16 @@ """Operator assembly helpers.""" +from lax.operators.interaction import ( + make_interaction_from_array, + make_interaction_from_block, + make_interaction_from_funcs, +) from lax.operators.potential import assemble_local, assemble_nonlocal -__all__ = ["assemble_local", "assemble_nonlocal"] +__all__ = [ + "assemble_local", + "assemble_nonlocal", + "make_interaction_from_array", + "make_interaction_from_block", + "make_interaction_from_funcs", +] diff --git a/src/lax/operators/interaction.py b/src/lax/operators/interaction.py new file mode 100644 index 0000000..0149b80 --- /dev/null +++ b/src/lax/operators/interaction.py @@ -0,0 +1,275 @@ +"""Factories for building Interaction blocks from potential terms.""" +from __future__ import annotations + +from dataclasses import dataclass + +import jax +import jax.numpy as jnp +import numpy as np + +from lax.boundary._types import Mesh +from lax.types import ChannelSpec, Interaction + + +@dataclass(frozen=True) +class _InteractionFromBlock: + """Pickle-safe callable that wraps a pre-assembled block as an Interaction.""" + + N: int + N_c: int + N_E: int + + def __call__( + self, + block: jax.Array, + *, + energy_dependent: bool = False, + ) -> Interaction: + """Wrap a pre-assembled ``(M, M)`` or ``(N_E, M, M)`` block.""" + + M = self.N_c * self.N + expected_shape = (self.N_E, M, M) if energy_dependent else (M, M) + if block.shape != expected_shape: + raise ValueError( + f"Expected block shape {expected_shape}, got {block.shape}." + ) + return Interaction(block=block, energy_dependent=energy_dependent) + + +@dataclass(frozen=True) +class _InteractionFromArray: + """Pickle-safe callable that assembles an Interaction from (form-factor, coupling) terms.""" + + N: int + N_c: int + N_E: int + gauss_scale: jax.Array # (N, N) = sqrt(λ_i λ_j) * a + + def _validate_A(self, A: jax.Array, label: str) -> None: + if A.shape != (self.N_c, self.N_c): + raise ValueError( + f"{label}: coupling matrix A must be ({self.N_c},{self.N_c}), " + f"got {A.shape}." + ) + if not jnp.allclose(A, A.T, atol=1e-12): + raise ValueError(f"{label}: coupling matrix A must be symmetric.") + + def __call__( + self, + local: list[tuple[jax.Array, jax.Array]] = (), + nonlocal_: list[tuple[jax.Array, jax.Array]] = (), + energy_dependent: bool = False, + ) -> Interaction: + """Build Interaction from (form_factor, coupling_matrix) term lists. + + Each local term: (g, A) where g has shape (N,) or (N_E, N). + Each nonlocal term: (g, A) where g has shape (N, N) or (N_E, N, N). + A has shape (N_c, N_c) and must be symmetric. + + Local term contributes ``A[c,cp] * g_n`` to the (c,cp) diagonal block. + Nonlocal term contributes ``A[c,cp] * sqrt(λ_i λ_j) * a * g[i,j]`` + to the full (c,cp) block. + """ + N = self.N + N_c = self.N_c + N_E = self.N_E + M = N_c * N + dtype = jnp.float64 + all_terms = list(local) + list(nonlocal_) + if all_terms: + g0, _ = all_terms[0] + dtype = jnp.asarray(g0).dtype + + if energy_dependent: + block = jnp.zeros((N_E, M, M), dtype=dtype) + else: + block = jnp.zeros((M, M), dtype=dtype) + + for term_idx, (g, A) in enumerate(local): + g = jnp.asarray(g) + A = jnp.asarray(A) + self._validate_A(A, f"local term {term_idx}") + if energy_dependent: + if g.ndim != 2 or g.shape != (N_E, N): + raise ValueError( + f"local term {term_idx}: energy_dependent=True requires g shape " + f"({N_E}, {N}), got {g.shape}." + ) + for c in range(N_c): + for cp in range(N_c): + if A[c, cp] == 0: + continue + row_start = c * N + col_start = cp * N + diag_blocks = jax.vmap(jnp.diag)(A[c, cp] * g) # (N_E, N, N) + block = block.at[ + :, row_start:row_start + N, col_start:col_start + N + ].add(diag_blocks) + else: + if g.ndim != 1 or g.shape != (N,): + raise ValueError( + f"local term {term_idx}: energy_dependent=False requires g shape " + f"({N},), got {g.shape}." + ) + for c in range(N_c): + for cp in range(N_c): + if A[c, cp] == 0: + continue + row_start = c * N + col_start = cp * N + block = block.at[ + row_start:row_start + N, col_start:col_start + N + ].add(jnp.diag(A[c, cp] * g)) + + for term_idx, (g, A) in enumerate(nonlocal_): + g = jnp.asarray(g) + A = jnp.asarray(A) + self._validate_A(A, f"nonlocal term {term_idx}") + if energy_dependent: + if g.ndim != 3 or g.shape != (N_E, N, N): + raise ValueError( + f"nonlocal term {term_idx}: energy_dependent=True requires g shape " + f"({N_E}, {N}, {N}), got {g.shape}." + ) + scaled = g * self.gauss_scale[None, :, :] # (N_E, N, N) + for c in range(N_c): + for cp in range(N_c): + if A[c, cp] == 0: + continue + row_start = c * N + col_start = cp * N + block = block.at[ + :, row_start:row_start + N, col_start:col_start + N + ].add(A[c, cp] * scaled) + else: + if g.ndim != 2 or g.shape != (N, N): + raise ValueError( + f"nonlocal term {term_idx}: energy_dependent=False requires g shape " + f"({N}, {N}), got {g.shape}." + ) + scaled = g * self.gauss_scale # (N, N) + for c in range(N_c): + for cp in range(N_c): + if A[c, cp] == 0: + continue + row_start = c * N + col_start = cp * N + block = block.at[ + row_start:row_start + N, col_start:col_start + N + ].add(A[c, cp] * scaled) + + first_block = block[0] if energy_dependent else block + if not jnp.allclose(first_block, first_block.T, atol=1e-10): + raise ValueError("Assembled Interaction block is not symmetric.") + + return Interaction(block=block, energy_dependent=energy_dependent) + + +@dataclass(frozen=True) +class _InteractionFromFuncs: + """Pickle-safe callable that evaluates potential functions then delegates to array builder.""" + + N: int + N_E: int + radii: jax.Array # (N,) + energies: jax.Array # (N_E,) + array_builder: _InteractionFromArray + + def __call__( + self, + local: list = (), + nonlocal_: list = (), + energy_dependent: bool = False, + ) -> Interaction: + """Build Interaction from callable (form_factor_fn, coupling_matrix) terms. + + Local fn signatures: + g(r) — energy-independent; r shape (N,), returns (N,) + g(r, E) — energy-dependent; r shape (N,), E scalar, returns (N,) + Nonlocal fn signatures: + g(r, r') — energy-independent; r,r' shape (N,N), returns (N,N) + g(r, r', E) — energy-dependent; r,r' shape (N,N), E scalar, returns (N,N) + """ + r = self.radii + N_E = self.N_E + ri, rj = jnp.meshgrid(r, r, indexing="ij") # (N, N) + + local_arrays = [] + for g_fn, A in local: + if energy_dependent: + g_arr = jnp.stack( + [g_fn(r, float(self.energies[ie])) for ie in range(N_E)] + ) # (N_E, N) + else: + g_arr = g_fn(r) # (N,) + local_arrays.append((g_arr, A)) + + nonlocal_arrays = [] + for g_fn, A in nonlocal_: + if energy_dependent: + g_arr = jnp.stack( + [g_fn(ri, rj, float(self.energies[ie])) for ie in range(N_E)] + ) # (N_E, N, N) + else: + g_arr = g_fn(ri, rj) # (N, N) + nonlocal_arrays.append((g_arr, A)) + + return self.array_builder( + local=local_arrays, + nonlocal_=nonlocal_arrays, + energy_dependent=energy_dependent, + ) + + +def make_interaction_from_block( + mesh: Mesh, + channels: tuple[ChannelSpec, ...], + energies: jax.Array, +) -> _InteractionFromBlock: + """Return a pickle-safe callable that wraps a pre-assembled block as an Interaction.""" + + N = mesh.n + N_c = len(channels) + N_E = len(energies) + return _InteractionFromBlock(N=N, N_c=N_c, N_E=N_E) + + +def make_interaction_from_array( + mesh: Mesh, + channels: tuple[ChannelSpec, ...], + energies: jax.Array, +) -> _InteractionFromArray: + """Return a pickle-safe callable that assembles an Interaction from (g, A) term lists.""" + + N = mesh.n + N_c = len(channels) + N_E = len(energies) + lam = mesh.weights # (N,) + a = float(mesh.scale) + lami, lamj = jnp.meshgrid(lam, lam, indexing="ij") + gauss_scale = jnp.sqrt(lami * lamj) * a # (N, N) + return _InteractionFromArray(N=N, N_c=N_c, N_E=N_E, gauss_scale=gauss_scale) + + +def make_interaction_from_funcs( + mesh: Mesh, + channels: tuple[ChannelSpec, ...], + energies: jax.Array, +) -> _InteractionFromFuncs: + """Return a pickle-safe callable that evaluates functions then builds an Interaction.""" + + array_builder = make_interaction_from_array(mesh, channels, energies) + return _InteractionFromFuncs( + N=mesh.n, + N_E=len(energies), + radii=mesh.radii, + energies=energies, + array_builder=array_builder, + ) + + +__all__ = [ + "make_interaction_from_array", + "make_interaction_from_block", + "make_interaction_from_funcs", +] diff --git a/src/lax/solvers/__init__.py b/src/lax/solvers/__init__.py index d454b0e..58ba657 100644 --- a/src/lax/solvers/__init__.py +++ b/src/lax/solvers/__init__.py @@ -1,7 +1,13 @@ """Solver assembly and runtime-kernel construction.""" from lax.solvers.assembly import assemble_block_hamiltonian, build_Q -from lax.solvers.linear_solve import make_rmatrix_direct_grid_observable, make_rmatrix_direct_kernel +from lax.solvers.linear_solve import ( + make_direct_wavefunction_kernel, + make_phases_direct_observable, + make_rmatrix_direct_grid_observable, + make_rmatrix_direct_kernel, + make_smatrix_direct_observable, +) from lax.solvers.observables import ( bind_direct_grid_observables, bind_grid_observables, @@ -17,7 +23,10 @@ "bind_interpolators", "bind_observables", "build_Q", + "make_direct_wavefunction_kernel", + "make_phases_direct_observable", "make_rmatrix_direct_grid_observable", "make_rmatrix_direct_kernel", + "make_smatrix_direct_observable", "make_spectrum_kernel", ] diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index 698d331..d1a8db9 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -3,7 +3,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import cast +from typing import TYPE_CHECKING, cast import jax import jax.numpy as jnp @@ -17,10 +17,31 @@ OperatorMatrices, PropagationMatrices, ) +from lax.spectral.matching import phases_from_S, smatrix_from_R from lax.types import ChannelSpec from .assembly import assemble_block_hamiltonian, build_Q +if TYPE_CHECKING: + from lax.types import Interaction + + +def _build_q_prime( + q: jax.Array, + channels: tuple[ChannelSpec, ...], + basis_size: int, +) -> jax.Array: + """Build Q' = diag(repeat(sqrt(m_c), N)) @ Q. + + Q has shape (N_c·N, N_c). Each channel block c is scaled by sqrt(m_c) + so that R = Q'^T C_MeV^{-1} Q' / a equals the old fm⁻² result for + uniform μ and generalises to per-channel μ. [DESIGN.md §11.5] + """ + m_c = np.asarray([c.mass_factor for c in channels], dtype=np.float64) + scale = np.repeat(np.sqrt(m_c), basis_size) # (N_c·N,) NumPy array + q_prime: jax.Array = jnp.asarray(scale[:, None], dtype=q.dtype) * q + return q_prime + @dataclass(frozen=True) class _DirectRMatrixKernel: @@ -31,13 +52,56 @@ class _DirectRMatrixKernel: channels: tuple[ChannelSpec, ...] energies: jax.Array q: jax.Array + q_prime: jax.Array channel_radius: float matrix_size: int mass_factor: float boundary: BoundaryValues | None def __call__(self, potential: jax.Array) -> jax.Array: - """Evaluate the direct R-matrix on the compile-time energy grid.""" + """Evaluate the direct R-matrix on the compile-time energy grid. + + Accepts either a raw potential array ``(N_c, N_c, N)`` / ``(N_c, N_c, N, N)`` + or an :class:`~lax.Interaction` object. When an ``Interaction`` with + ``energy_dependent=True`` is passed the per-energy block is used. + """ + from lax.types import Interaction # noqa: PLC0415 + + if isinstance(potential, Interaction): + if potential.energy_dependent: + return cast( + jax.Array, + _RMATRIX_DIRECT_GRID_JIT( + potential.block, + self.mesh, + self.operators, + self.channels, + self.energies, + self.q, + self.q_prime, + self.channel_radius, + self.matrix_size, + self.mass_factor, + self.boundary, + None, + ), + ) + else: + return cast( + jax.Array, + _RMATRIX_DIRECT_JIT( + potential.block, + self.mesh, + self.operators, + self.channels, + self.energies, + self.q_prime, + self.channel_radius, + self.matrix_size, + self.mass_factor, + self.boundary, + ), + ) return cast( jax.Array, @@ -47,7 +111,7 @@ def __call__(self, potential: jax.Array) -> jax.Array: self.operators, self.channels, self.energies, - self.q, + self.q_prime, self.channel_radius, self.matrix_size, self.mass_factor, @@ -65,6 +129,7 @@ class _DirectRMatrixGridObservable: channels: tuple[ChannelSpec, ...] energies: jax.Array q: jax.Array + q_prime: jax.Array channel_radius: float matrix_size: int mass_factor: float @@ -83,6 +148,7 @@ def __call__(self, potentials: jax.Array) -> jax.Array: self.channels, self.energies, self.q, + self.q_prime, self.channel_radius, self.matrix_size, self.mass_factor, @@ -92,6 +158,91 @@ def __call__(self, potentials: jax.Array) -> jax.Array: ) +@dataclass(frozen=True) +class _SMatrixDirectObservable: + """Pickle-safe direct S-matrix observable derived from rmatrix_direct.""" + + rmatrix_direct: _DirectRMatrixKernel + boundary: BoundaryValues + + def __call__(self, potential: jax.Array) -> jax.Array: + """Evaluate the S-matrix on the compile-time energy grid.""" + + r = self.rmatrix_direct(potential) + return cast(jax.Array, _DIRECT_SMATRIX_JIT(r, self.boundary)) + + +@dataclass(frozen=True) +class _PhasesDirectObservable: + """Pickle-safe direct phase-shift observable derived from smatrix_direct.""" + + smatrix_direct: _SMatrixDirectObservable + + def __call__(self, potential: jax.Array) -> jax.Array: + """Evaluate phase shifts on the compile-time energy grid.""" + + s = self.smatrix_direct(potential) + return cast(jax.Array, _DIRECT_PHASES_JIT(s)) + + +@dataclass(frozen=True) +class _WavefunctionDirectKernel: + """Pickle-safe wavefunction kernel on the direct (linear-solve) path.""" + + mesh: Mesh + operators: OperatorMatrices + channels: tuple[ChannelSpec, ...] + energies: jax.Array + matrix_size: int + + def __call__( + self, + potential: jax.Array, + source: jax.Array, + energy_index: int, + ) -> jax.Array: + """Solve ``C(E_i) x = source`` for the internal wavefunction. + + Parameters + ---------- + potential + Assembled potential or :class:`~lax.Interaction`. Shape + ``(N_c, N_c, N)`` / ``(N_c, N_c, N, N)`` (energy-independent) or + ``(N_E, N_c, N_c, N)`` / ``(N_E, N_c, N_c, N, N)`` (energy-dependent). + Also accepts an ``Interaction`` object. + source + Mesh-space driving term, shape ``(N_c·N,)``. + energy_index + Index into the compile-time energy grid (compile-time constant). + + Returns + ------- + jax.Array + Wavefunction coefficient vector, shape ``(N_c·N,)``. + """ + from lax.types import Interaction # noqa: PLC0415 + + if isinstance(potential, Interaction): + block = potential.block[energy_index] if potential.energy_dependent else potential.block + elif potential.ndim in {4, 5}: + block = potential[energy_index] + else: + block = potential + + return cast( + jax.Array, + _WAVEFUNCTION_DIRECT_JIT( + block, + source, + self.energies[energy_index], + self.mesh, + self.operators, + self.channels, + self.matrix_size, + ), + ) + + def make_rmatrix_direct_kernel( mesh: Mesh, operators: OperatorMatrices, @@ -101,9 +252,10 @@ def make_rmatrix_direct_kernel( ) -> DirectRMatrixKernel: """Build a JIT-compiled ``rmatrix_direct(V) → R`` kernel for the compile-time grid. - The returned kernel solves ``C(E) X = Q`` for each compile-time energy via + The returned kernel solves ``C(E) X = Q'`` for each compile-time energy via ``jnp.linalg.solve``, bypassing the eigendecomposition. Supports real and complex potentials, local and non-local, propagated and non-propagated meshes. + Also accepts :class:`~lax.Interaction` objects directly. [DESIGN.md §11.3] Parameters @@ -128,9 +280,10 @@ def make_rmatrix_direct_kernel( """ q = build_Q(mesh, channels) + q_prime = _build_q_prime(q, channels, mesh.n) channel_radius = mesh.scale matrix_size = mesh.n * len(channels) - mass_factor = _uniform_mass_factor(channels) + mass_factor = channels[0].mass_factor # used by propagated path only return cast( DirectRMatrixKernel, _DirectRMatrixKernel( @@ -139,6 +292,7 @@ def make_rmatrix_direct_kernel( channels=channels, energies=energies, q=q, + q_prime=q_prime, channel_radius=channel_radius, matrix_size=matrix_size, mass_factor=mass_factor, @@ -186,9 +340,10 @@ def make_rmatrix_direct_grid_observable( """ q = build_Q(mesh, channels) + q_prime = _build_q_prime(q, channels, mesh.n) channel_radius = mesh.scale matrix_size = mesh.n * len(channels) - mass_factor = _uniform_mass_factor(channels) + mass_factor = channels[0].mass_factor # used by propagated path only return cast( DirectGridObservable, _DirectRMatrixGridObservable( @@ -197,6 +352,7 @@ def make_rmatrix_direct_grid_observable( channels=channels, energies=energies, q=q, + q_prime=q_prime, channel_radius=channel_radius, matrix_size=matrix_size, mass_factor=mass_factor, @@ -206,13 +362,56 @@ def make_rmatrix_direct_grid_observable( ) +def make_smatrix_direct_observable( + rmatrix_kernel: _DirectRMatrixKernel, + boundary: BoundaryValues | None, +) -> _SMatrixDirectObservable | None: + """Build a direct S-matrix observable from a direct R-matrix kernel.""" + + if boundary is None: + return None + return _SMatrixDirectObservable(rmatrix_direct=rmatrix_kernel, boundary=boundary) + + +def make_phases_direct_observable( + smatrix_observable: _SMatrixDirectObservable | None, +) -> _PhasesDirectObservable | None: + """Build a direct phase-shift observable from a direct S-matrix observable.""" + + if smatrix_observable is None: + return None + return _PhasesDirectObservable(smatrix_direct=smatrix_observable) + + +def make_direct_wavefunction_kernel( + mesh: Mesh, + operators: OperatorMatrices, + channels: tuple[ChannelSpec, ...], + energies: jax.Array, +) -> _WavefunctionDirectKernel: + """Build a direct wavefunction kernel ``(V, source, i) → ψ``. + + Solves ``C(E_i) ψ = source`` where ``C = H_MeV − E_i · I`` using + ``jnp.linalg.solve``. [DESIGN.md §11.3] + """ + + matrix_size = mesh.n * len(channels) + return _WavefunctionDirectKernel( + mesh=mesh, + operators=operators, + channels=channels, + energies=energies, + matrix_size=matrix_size, + ) + + def _rmatrix_direct( potential: jax.Array, mesh: Mesh, operators: OperatorMatrices, channels: tuple[ChannelSpec, ...], energies: jax.Array, - q: jax.Array, + q_prime: jax.Array, channel_radius: float, matrix_size: int, mass_factor: float, @@ -224,13 +423,19 @@ def _rmatrix_direct( ``mesh.propagation``, and to the local or non-local potential path depending on ``potential.ndim``. + The Hamiltonian is assembled in MeV (symmetric form), and the C matrix + is ``H_MeV − E·I``. The surface projector ``Q'`` carries the per-channel + sqrt(m_c) factor so that ``R = Q'^T C^{-1} Q' / a`` equals the fm⁻² result + for uniform μ and generalises to per-channel μ. [DESIGN.md §11.5] + Parameters ---------- potential Assembled potential in MeV. Local: ``(N_c, N_c, N)``; non-local: ``(N_c, N_c, N, N)``. - mesh, operators, channels, energies, q, channel_radius, matrix_size, mass_factor, boundary + mesh, operators, channels, energies, q_prime, channel_radius, matrix_size, mass_factor, boundary Compile-time cached data forwarded from the kernel dataclass. + ``mass_factor`` is used only on the propagated path (fm⁻² units). Returns ------- @@ -285,8 +490,8 @@ def propagated_one_energy( ) def one_energy(energy: jax.Array) -> jax.Array: - energy_dimless = energy / mass_factor - matrix = hamiltonian - energy_dimless * jnp.eye( + # Hamiltonian is in MeV; C = H_MeV − E·I. + matrix = hamiltonian - energy * jnp.eye( matrix_size, dtype=hamiltonian.dtype, ) @@ -294,10 +499,10 @@ def one_energy(energy: jax.Array) -> jax.Array: jax.Array, jnp.linalg.solve( matrix, - q, + q_prime, ), ) - values: jax.Array = (q.T @ solved) / channel_radius + values: jax.Array = (q_prime.T @ solved) / channel_radius return values result: jax.Array = jax.vmap(one_energy)(energies) @@ -311,6 +516,7 @@ def _rmatrix_direct_grid( channels: tuple[ChannelSpec, ...], energies: jax.Array, q: jax.Array, + q_prime: jax.Array, channel_radius: float, matrix_size: int, mass_factor: float, @@ -328,8 +534,10 @@ def _rmatrix_direct_grid( potentials Per-energy potentials in MeV. Local: ``(N_E, N_c, N_c, N)``; non-local: ``(N_E, N_c, N_c, N, N)``. - mesh, operators, channels, energies, q, channel_radius, matrix_size, mass_factor, boundary - Compile-time cached data. + mesh, operators, channels, energies, q, q_prime, channel_radius, matrix_size, mass_factor, boundary + Compile-time cached data. ``q`` is the unscaled surface projector used + when ``mass_factor_grid`` overrides the per-channel values at JIT time. + ``mass_factor`` is used only on the propagated path. Returns ------- @@ -385,8 +593,8 @@ def one_energy(potential: jax.Array, energy: jax.Array) -> jax.Array: channels, potential, ) - energy_dimless = energy / mass_factor - matrix = hamiltonian - energy_dimless * jnp.eye( + # Hamiltonian is in MeV; C = H_MeV − E·I. + matrix = hamiltonian - energy * jnp.eye( matrix_size, dtype=hamiltonian.dtype, ) @@ -394,10 +602,10 @@ def one_energy(potential: jax.Array, energy: jax.Array) -> jax.Array: jax.Array, jnp.linalg.solve( matrix, - q, + q_prime, ), ) - return (q.T @ solved) / channel_radius + return (q_prime.T @ solved) / channel_radius def one_energy_with_mu( potential: jax.Array, @@ -411,19 +619,21 @@ def one_energy_with_mu( potential, mass_factor_override=mu, ) - energy_dimless = energy / mu - matrix = hamiltonian - energy_dimless * jnp.eye( + # Hamiltonian assembled with override μ is in MeV; C = H_MeV − E·I. + # Q' = sqrt(μ)·Q (uniform μ per energy step). + matrix = hamiltonian - energy * jnp.eye( matrix_size, dtype=hamiltonian.dtype, ) + q_prime_mu: jax.Array = jnp.sqrt(mu) * q solved = cast( jax.Array, jnp.linalg.solve( matrix, - q, + q_prime_mu, ), ) - return (q.T @ solved) / channel_radius + return (q_prime_mu.T @ solved) / channel_radius if mass_factor_grid is not None: return jax.vmap(one_energy_with_mu)( @@ -437,6 +647,54 @@ def one_energy_with_mu( ) +def _wavefunction_direct( + potential: jax.Array, + source: jax.Array, + energy: jax.Array, + mesh: Mesh, + operators: OperatorMatrices, + channels: tuple[ChannelSpec, ...], + matrix_size: int, +) -> jax.Array: + """Solve ``(H_MeV − E·I) ψ = source`` for the internal wavefunction.""" + + hamiltonian = assemble_block_hamiltonian(mesh, operators, channels, potential) + matrix = hamiltonian - energy * jnp.eye(matrix_size, dtype=hamiltonian.dtype) + result: jax.Array = cast(jax.Array, jnp.linalg.solve(matrix, source)) + return result + + +def _direct_smatrix_grid( + r_grid: jax.Array, + boundary: BoundaryValues, +) -> jax.Array: + """Match an (N_E, N_c, N_c) R-matrix grid to the S-matrix grid.""" + + return cast(jax.Array, jax.vmap(smatrix_from_R)(r_grid, boundary)) + + +def _direct_phases_grid(s_grid: jax.Array) -> jax.Array: + """Extract phase shifts from an (N_E, N_c, N_c) S-matrix grid.""" + + return cast(jax.Array, jax.vmap(phases_from_S)(s_grid)) + + +_RMATRIX_DIRECT_JIT = jax.jit( + _rmatrix_direct, + static_argnames=("channels", "matrix_size"), +) +_RMATRIX_DIRECT_GRID_JIT = jax.jit( + _rmatrix_direct_grid, + static_argnames=("channels", "matrix_size"), +) +_WAVEFUNCTION_DIRECT_JIT = jax.jit( + _wavefunction_direct, + static_argnames=("channels", "matrix_size"), +) +_DIRECT_SMATRIX_JIT = jax.jit(_direct_smatrix_grid) +_DIRECT_PHASES_JIT = jax.jit(_direct_phases_grid) + + def _propagated_rmatrix_at_energy( potential: jax.Array, propagation: PropagationMatrices, @@ -591,25 +849,10 @@ def _surface_projector( return projector -_RMATRIX_DIRECT_JIT = jax.jit( - _rmatrix_direct, - static_argnames=("channels", "matrix_size"), -) -_RMATRIX_DIRECT_GRID_JIT = jax.jit( - _rmatrix_direct_grid, - static_argnames=("channels", "matrix_size"), -) - - -def _uniform_mass_factor(channels: tuple[ChannelSpec, ...]) -> float: - """Return the shared mass factor expected by the MVP direct solver path.""" - - mass_factor = channels[0].mass_factor - for channel in channels[1:]: - if channel.mass_factor != mass_factor: - msg = "The MVP direct solver path requires a uniform mass_factor across channels." - raise ValueError(msg) - return mass_factor - - -__all__ = ["make_rmatrix_direct_grid_observable", "make_rmatrix_direct_kernel"] +__all__ = [ + "make_direct_wavefunction_kernel", + "make_phases_direct_observable", + "make_rmatrix_direct_grid_observable", + "make_rmatrix_direct_kernel", + "make_smatrix_direct_observable", +] diff --git a/src/lax/types.py b/src/lax/types.py index a3424ca..cffb1fd 100644 --- a/src/lax/types.py +++ b/src/lax/types.py @@ -5,6 +5,9 @@ from dataclasses import dataclass, field from typing import Literal +import jax +import jax.numpy as jnp + type MeshFamily = Literal["legendre", "laguerre"] type Regularization = Literal[ "x", @@ -84,8 +87,28 @@ class ChannelSpec: mass_factor: float +@jax.tree_util.register_dataclass +@dataclass(frozen=True) +class Interaction: + """Assembled coupled-channel potential block in MeV. + + block : (M, M) or (N_E, M, M) where M = N_c·N + Local terms on the per-channel diagonal, non-local terms as full + Gauss-scaled blocks. Symmetric. Mass-independent — per-channel mass + factors are applied by the solver, never folded into this block. + Excludes kinetic, centrifugal, threshold, and energy terms. + energy_dependent : bool (static) + True iff ``block`` has a leading (N_E,) axis aligned with the + compile-time energy grid. + """ + + block: jax.Array + energy_dependent: bool = field(metadata={"static": True}) + + __all__ = [ "ChannelSpec", + "Interaction", "MeshFamily", "MeshFamilyT", "MeshSpec", diff --git a/tests/unit/test_solver_direct.py b/tests/unit/test_solver_direct.py index e408b50..00912fa 100644 --- a/tests/unit/test_solver_direct.py +++ b/tests/unit/test_solver_direct.py @@ -45,14 +45,18 @@ def test_make_rmatrix_direct_kernel_matches_manual_linear_solve() -> None: ) result = np.asarray(kernel(potential)) + # Manual computation using MeV form: H_MeV = m_c*(T+L) + V; C = H_MeV − E·I; + # R = Q'^T C^{-1} Q' / a where Q' = sqrt(m_c) · Q. hamiltonian = np.asarray( assemble_block_hamiltonian(solver.mesh, solver.operators, solver.channels, potential) ) q = np.asarray(build_Q(solver.mesh, solver.channels)) + m_c = channels[0].mass_factor + q_prime = np.sqrt(m_c) * q expected = [] for energy in np.asarray(solver.energies): - matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * (energy / channels[0].mass_factor) - expected.append((q.T @ np.linalg.solve(matrix, q)) / solver.mesh.scale) + matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * energy + expected.append((q_prime.T @ np.linalg.solve(matrix, q_prime)) / solver.mesh.scale) assert np.allclose(result, np.stack(expected)) @@ -191,7 +195,9 @@ def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: result = np.asarray(solver.rmatrix_direct_grid(potentials)) expected = [] + m_c = solver.channels[0].mass_factor q = np.asarray(build_Q(solver.mesh, solver.channels)) + q_prime = np.sqrt(m_c) * q for index, energy in enumerate(np.asarray(energies)): hamiltonian = np.asarray( assemble_block_hamiltonian( @@ -201,10 +207,9 @@ def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: potentials[index], ) ) - matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * ( - energy / solver.channels[0].mass_factor - ) - expected.append((q.T @ np.linalg.solve(matrix, q)) / solver.mesh.scale) + # MeV form: C = H_MeV − E·I; R = Q'^T C^{-1} Q' / a. + matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * energy + expected.append((q_prime.T @ np.linalg.solve(matrix, q_prime)) / solver.mesh.scale) assert np.allclose(result, np.stack(expected), atol=1.0e-10, rtol=1.0e-10) diff --git a/tests/unit/test_solver_spectrum.py b/tests/unit/test_solver_spectrum.py index 0211a01..e6ec724 100644 --- a/tests/unit/test_solver_spectrum.py +++ b/tests/unit/test_solver_spectrum.py @@ -45,17 +45,18 @@ def test_build_q_places_boundary_values_in_channel_blocks() -> None: def test_assemble_block_hamiltonian_scales_threshold_and_local_potential() -> None: - """Assembly preserves the fm^-2 threshold and local-potential scaling.""" + """Assembly uses the symmetric MeV form: m_c·(T+L) + E_threshold·I + V (untouched).""" mesh, operators = build_legendre_x(n=3, scale=5.0, operators={"T+L", "1/r^2"}) channels = (ChannelSpec(l=0, threshold=2.0, mass_factor=4.0),) local_potential = jnp.asarray([[[1.0, 3.0, 5.0]]]) hamiltonian = np.asarray(assemble_block_hamiltonian(mesh, operators, channels, local_potential)) + m_c = channels[0].mass_factor expected = ( - np.asarray(operators.TpL) - + np.eye(3) * (channels[0].threshold / channels[0].mass_factor) - + np.diag(np.array([1.0, 3.0, 5.0]) / channels[0].mass_factor) + m_c * np.asarray(operators.TpL) + + np.eye(3) * channels[0].threshold + + np.diag(np.array([1.0, 3.0, 5.0])) ) assert np.allclose(hamiltonian, expected) @@ -70,8 +71,10 @@ def test_make_spectrum_kernel_matches_direct_eigh() -> None: kernel = make_spectrum_kernel(mesh, operators, channels, keep_eigenvectors=True) spectrum = kernel(potential) - hamiltonian = assemble_block_hamiltonian(mesh, operators, channels, potential) - expected_eigenvalues, expected_eigenvectors = np.linalg.eigh(np.asarray(hamiltonian)) + # Assembler returns H_MeV; spectrum path divides by m0 before eigh → fm⁻² eigenvalues. + m0 = channels[0].mass_factor + hamiltonian = np.asarray(assemble_block_hamiltonian(mesh, operators, channels, potential)) / m0 + expected_eigenvalues, expected_eigenvectors = np.linalg.eigh(hamiltonian) expected_surface_amplitudes = expected_eigenvectors.T @ np.asarray(build_Q(mesh, channels)) assert np.allclose(np.asarray(spectrum.eigenvalues), expected_eigenvalues) @@ -95,7 +98,9 @@ def test_make_spectrum_kernel_matches_complex_symmetric_eig() -> None: method="eig", keep_eigenvectors=True, )(potential) - hamiltonian = np.asarray(assemble_block_hamiltonian(mesh, operators, channels, potential)) + # Assembler returns H_MeV; spectrum path divides by m0 before eig → fm⁻² eigenvalues. + m0 = channels[0].mass_factor + hamiltonian = np.asarray(assemble_block_hamiltonian(mesh, operators, channels, potential)) / m0 expected_eigenvalues, expected_eigenvectors = np.linalg.eig(hamiltonian.astype(np.complex128)) order = np.argsort(expected_eigenvalues.real) expected_eigenvalues = expected_eigenvalues[order] @@ -268,9 +273,12 @@ def test_closed_channel_decoupling_matches_direct_bloch_updated_rmatrix() -> Non hamiltonian = np.asarray(assemble_block_hamiltonian(mesh, operators, channels, potential)) q = np.asarray(build_Q(mesh, channels)) - base_matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * (energy / channels[0].mass_factor) - base_solved = np.linalg.solve(base_matrix, q) - raw_rmatrix = (q.T @ base_solved) / mesh.scale + m_c = channels[0].mass_factor + q_prime = np.sqrt(m_c) * q + # MeV form: C = H_MeV - E*I; R = Q'^T C^{-1} Q' / a where Q' = sqrt(m_c)*Q + base_matrix = hamiltonian - np.eye(hamiltonian.shape[0]) * energy + base_solved = np.linalg.solve(base_matrix, q_prime) + raw_rmatrix = (q_prime.T @ base_solved) / mesh.scale bloch = np.asarray( _closed_channel_bloch( boundary.H_plus[0], @@ -288,13 +296,14 @@ def test_closed_channel_decoupling_matches_direct_bloch_updated_rmatrix() -> Non ) bloch_matrix = np.diag(bloch) + # Bloch correction in MeV form: scale by m_c updated_matrix = ( hamiltonian - - (q @ bloch_matrix @ q.T) / mesh.scale - - np.eye(hamiltonian.shape[0]) * (energy / channels[0].mass_factor) + - m_c * (q @ bloch_matrix @ q.T) / mesh.scale + - np.eye(hamiltonian.shape[0]) * energy ) - solved = np.linalg.solve(updated_matrix, q) - direct_rmatrix = (q.T @ solved) / mesh.scale + solved = np.linalg.solve(updated_matrix, q_prime) + direct_rmatrix = (q_prime.T @ solved) / mesh.scale assert np.allclose(decoupled[0, 0], direct_rmatrix[0, 0], atol=5.0e-5, rtol=5.0e-5) From 987b917e73326514f306d90fbb6a7639ea449dde Mon Sep 17 00:00:00 2001 From: beykyle Date: Tue, 9 Jun 2026 22:43:34 -0400 Subject: [PATCH 03/10] =?UTF-8?q?Extend=20mass=5Ffactor=5Fgrid=20to=20(N?= =?UTF-8?q?=5FE,=20N=5Fc)=20for=20per-channel=20per-energy=20=CE=BC=20(Pha?= =?UTF-8?q?se=2010=20task=204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `boundary/coulomb.py`: index as `mass_factor_grid[energy_index, channel_index]` so each channel can have its own energy-dependent mass factor at boundary values - `compile.py`: add `_broadcast_mass_factor_grid` that normalizes scalar / (N_E,) / (N_E, N_c) inputs to the canonical (N_E, N_c) NumPy array; update `compile()` docstring and validation accordingly - `linear_solve.py`: `one_energy_with_mu` now receives `mu_row: (N_c,)` per energy step; builds `Q' = diag(repeat(sqrt(mu_row), N)) @ Q` for per-channel scaling and passes the vector to `assemble_block_hamiltonian(mass_factor_override=mu_row)` - Tests: scalar/2D broadcasts reproduce uniform baseline; wrong-length raises; decoupled two-channel solver with unequal μ reproduces single-channel diagonal elements Co-Authored-By: Claude Sonnet 4.6 --- src/lax/boundary/coulomb.py | 13 +-- src/lax/compile.py | 79 ++++++++++---- src/lax/solvers/linear_solve.py | 11 +- tests/unit/test_solver_direct.py | 176 +++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+), 32 deletions(-) diff --git a/src/lax/boundary/coulomb.py b/src/lax/boundary/coulomb.py index cc9e083..aa1619f 100644 --- a/src/lax/boundary/coulomb.py +++ b/src/lax/boundary/coulomb.py @@ -53,10 +53,11 @@ def compute_boundary_values( ``mpmath`` decimal precision. The default of 40 provides ample guard digits against cancellation near resonances. mass_factor_grid - Per-energy ℏ²/2μ values in MeV·fm², shape ``(N_E,)``. When - provided, overrides ``channel.mass_factor`` in the wave-number and - Sommerfeld-parameter computation at each energy. Pass ``None`` to - use the scalar ``ChannelSpec.mass_factor`` uniformly. + Per-energy, per-channel ℏ²/2μ values in MeV·fm², shape + ``(N_E, N_c)``. When provided, ``mass_factor_grid[ie, ic]`` + overrides ``channels[ic].mass_factor`` in the wave-number and + Sommerfeld-parameter computation for energy index ``ie``. Pass + ``None`` to use the scalar ``ChannelSpec.mass_factor`` uniformly. Returns ------- @@ -79,9 +80,9 @@ def compute_boundary_values( for energy_index, energy in enumerate(energies): for channel_index, channel in enumerate(channels): - # Use per-energy mass_factor when provided; fall back to ChannelSpec value. + # Use per-energy, per-channel mass_factor when provided. effective_mass_factor = ( - float(mass_factor_grid[energy_index]) + float(mass_factor_grid[energy_index, channel_index]) if mass_factor_grid is not None else channel.mass_factor ) diff --git a/src/lax/compile.py b/src/lax/compile.py index 710bcea..ecd58c7 100644 --- a/src/lax/compile.py +++ b/src/lax/compile.py @@ -191,22 +191,22 @@ def compile( dps Decimal precision for the ``mpmath`` boundary-value calculation. mass_factor_grid - Per-energy ℏ²/2μ values in MeV·fm², shape ``(N_E,)``, or ``None`` - to use the scalar ``ChannelSpec.mass_factor`` uniformly. When provided, - ``len(mass_factor_grid)`` must equal ``len(energies)``. + Per-energy (and optionally per-channel) ℏ²/2μ values in MeV·fm². + Accepted shapes (all broadcast to the canonical ``(N_E, N_c)`` form): - This enables problems where the effective reduced mass depends on energy - (e.g. relativistic kinematics, energy-dependent folding potentials). - The grid is used in three places: + * ``None`` — use each channel's ``ChannelSpec.mass_factor`` uniformly. + * scalar — the same value for all energies and channels. + * shape ``(N_E,)`` — one value per energy, shared across channels. + * shape ``(N_E, N_c)`` — fully independent per ``(energy, channel)`` pair. + + When provided, ``len(mass_factor_grid)`` along the first axis must equal + ``len(energies)``. The grid is used in two places: 1. **Boundary values** — wave numbers and Sommerfeld parameters at each - compile-time energy use ``mass_factor_grid[i]``. - 2. **Hamiltonian assembly** — pass ``mass_factor`` to ``solver.spectrum`` - at runtime: ``jax.vmap(lambda V, mu: solver.spectrum(V, mass_factor=mu))(V_grid, mu_grid)``. - 3. **Aligned-grid observables** — ``solver.phases_grid``, - ``solver.smatrix_grid``, and ``solver.rmatrix_grid`` use the stored - grid so the spectral denominator ``ε_k − E_i/μ(E_i)`` is correct at - each energy point. + ``(energy, channel)`` pair use ``mass_factor_grid[ie, ic]``. + 2. **Aligned-grid observables** — ``rmatrix_direct_grid`` (and its + derived ``smatrix``/``phases`` variants) assemble the Hamiltonian + with the per-energy per-channel mass factor at each grid point. Returns ------- @@ -232,19 +232,18 @@ def compile( grid=grid, momenta=momenta, ) + mass_factor_grid_np: np.ndarray | None if mass_factor_grid is not None: if energies is None: msg = "`energies` is required when `mass_factor_grid` is provided." raise ValueError(msg) - if len(mass_factor_grid) != len(energies): - msg = ( - f"`mass_factor_grid` length {len(mass_factor_grid)} must equal " - f"`energies` length {len(energies)}." - ) - raise ValueError(msg) - mass_factor_grid_np = ( - np.asarray(mass_factor_grid, dtype=np.float64) if mass_factor_grid is not None else None - ) + n_e = len(np.asarray(energies)) + n_c = len(tuple(channels)) + mass_factor_grid_np = _broadcast_mass_factor_grid( + np.asarray(mass_factor_grid, dtype=np.float64), n_e, n_c + ) + else: + mass_factor_grid_np = None boundary, energies_array = _prepare_boundary_data( channels=request.channels, energies=energies, @@ -686,6 +685,42 @@ def _to_jax_array(values: np.ndarray) -> jax.Array: return array +def _broadcast_mass_factor_grid( + arr: np.ndarray, + n_energies: int, + n_channels: int, +) -> np.ndarray: + """Broadcast user-supplied mass_factor_grid to canonical (N_E, N_c) shape. + + Accepts scalar, ``(N_E,)``, or ``(N_E, N_c)`` input. Returns a + C-contiguous ``float64`` array of shape ``(N_E, N_c)``. + """ + + if arr.ndim == 0: + return np.full((n_energies, n_channels), float(arr), dtype=np.float64) + if arr.ndim == 1: + if arr.shape[0] != n_energies: + msg = ( + f"`mass_factor_grid` length {arr.shape[0]} must equal " + f"`energies` length {n_energies}." + ) + raise ValueError(msg) + return np.broadcast_to(arr[:, None], (n_energies, n_channels)).copy() + if arr.ndim == 2: + if arr.shape != (n_energies, n_channels): + msg = ( + f"`mass_factor_grid` shape {arr.shape} must be " + f"({n_energies}, {n_channels}) = (N_E, N_c)." + ) + raise ValueError(msg) + return arr.copy() + msg = ( + "`mass_factor_grid` must be scalar, shape (N_E,), or shape (N_E, N_c), " + f"got ndim={arr.ndim}." + ) + raise ValueError(msg) + + def _default_method(V_is_complex: bool) -> Method: """Choose the default solver method from potential type and active backend.""" diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index d1a8db9..d4b70eb 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -610,22 +610,24 @@ def one_energy(potential: jax.Array, energy: jax.Array) -> jax.Array: def one_energy_with_mu( potential: jax.Array, energy: jax.Array, - mu: jax.Array, + mu_row: jax.Array, # (N_c,) per-channel mass factors ) -> jax.Array: hamiltonian = assemble_block_hamiltonian( mesh, operators, channels, potential, - mass_factor_override=mu, + mass_factor_override=mu_row, ) # Hamiltonian assembled with override μ is in MeV; C = H_MeV − E·I. - # Q' = sqrt(μ)·Q (uniform μ per energy step). + # Q' = diag(repeat(sqrt(mu_row), N))·Q — per-channel scaling. matrix = hamiltonian - energy * jnp.eye( matrix_size, dtype=hamiltonian.dtype, ) - q_prime_mu: jax.Array = jnp.sqrt(mu) * q + n = mesh.n + scale = jnp.repeat(jnp.sqrt(mu_row), n) # (N_c·N,) + q_prime_mu: jax.Array = scale[:, None] * q solved = cast( jax.Array, jnp.linalg.solve( @@ -636,6 +638,7 @@ def one_energy_with_mu( return (q_prime_mu.T @ solved) / channel_radius if mass_factor_grid is not None: + # mass_factor_grid is (N_E, N_c); vmap slices to (N_c,) per energy step. return jax.vmap(one_energy_with_mu)( potentials, energies, diff --git a/tests/unit/test_solver_direct.py b/tests/unit/test_solver_direct.py index 00912fa..4215f94 100644 --- a/tests/unit/test_solver_direct.py +++ b/tests/unit/test_solver_direct.py @@ -294,3 +294,179 @@ def test_direct_grid_observables_match_spectral_grid_for_real_energy_dependent_p assert np.allclose(direct_r, spectral_r, atol=1.0e-10, rtol=1.0e-10) assert np.allclose(direct_s, spectral_s, atol=1.0e-10, rtol=1.0e-10) assert np.allclose(direct_phases, spectral_phases, atol=1.0e-10, rtol=1.0e-10) + + +# --------------------------------------------------------------------------- +# Task 4: per-channel and energy-dependent mass_factor_grid +# --------------------------------------------------------------------------- + + +def test_mass_factor_grid_broadcast_scalar_reproduces_uniform() -> None: + """Scalar mass_factor_grid broadcasts and reproduces the uniform compile.""" + + energies = jnp.asarray([0.25, 0.75]) + m = 2.0 + solver_uniform = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=7.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + ) + solver_grid = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=7.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + mass_factor_grid=jnp.full((2,), m), # (N_E,) — broadcasts to (N_E, N_c) + ) + + potentials = jax.vmap(lambda e: _make_energy_dependent_potential(solver_uniform, e))(energies) + + assert solver_uniform.rmatrix_direct_grid is not None + assert solver_grid.rmatrix_direct_grid is not None + + r_uniform = np.asarray(solver_uniform.rmatrix_direct_grid(potentials)) + r_grid = np.asarray(solver_grid.rmatrix_direct_grid(potentials)) + + assert np.allclose(r_uniform, r_grid, atol=1.0e-12, rtol=1.0e-12) + + +def test_mass_factor_grid_2d_reproduces_uniform() -> None: + """(N_E, N_c) mass_factor_grid with uniform values reproduces the baseline.""" + + energies = jnp.asarray([0.25, 0.75]) + m = 2.0 + solver_uniform = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=7.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + ) + solver_grid = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=7.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + mass_factor_grid=jnp.full((2, 1), m), # explicit (N_E, N_c) shape + ) + + potentials = jax.vmap(lambda e: _make_energy_dependent_potential(solver_uniform, e))(energies) + + assert solver_uniform.rmatrix_direct_grid is not None + assert solver_grid.rmatrix_direct_grid is not None + + r_uniform = np.asarray(solver_uniform.rmatrix_direct_grid(potentials)) + r_grid = np.asarray(solver_grid.rmatrix_direct_grid(potentials)) + + assert np.allclose(r_uniform, r_grid, atol=1.0e-12, rtol=1.0e-12) + + +def test_mass_factor_grid_rejects_wrong_shape() -> None: + """mass_factor_grid with mismatched N_E raises ValueError.""" + + with pytest.raises(ValueError, match="must equal"): + lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=7.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=2.0),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=jnp.asarray([0.5]), + energy_dependent=True, + mass_factor_grid=jnp.asarray([2.0, 2.0]), # wrong length + ) + + +def test_per_channel_mass_factor_grid_decoupled_matches_single_channel() -> None: + """Per-channel mass_factor_grid: each diagonal element matches the single-channel case. + + For a block-diagonal (decoupled) potential, R[c,c] depends only on channel + c's mass factor. We verify that giving channel 0 mass μ₁ and channel 1 + mass μ₂ reproduces the single-channel result for each channel independently. + """ + + energies = jnp.asarray([0.5, 1.0]) + m0, m1 = 2.0, 5.0 + n = 5 + scale = 7.0 + + # Two-channel solver with per-channel mass factors at each energy. + mu_grid = jnp.tile(jnp.asarray([[m0, m1]]), (len(energies), 1)) # (N_E, 2) + two_ch = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=n, scale=scale), + channels=( + lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m0), + lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m1), + ), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + mass_factor_grid=mu_grid, + ) + + # Single-channel reference solvers. + ch0_solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=n, scale=scale), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m0),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + ) + ch1_solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=n, scale=scale), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=m1),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + method="linear_solve", + energy_dependent=True, + ) + + # Decoupled diagonal potential: channel 0 gets g0, channel 1 gets g1. + radii = two_ch.mesh.radii + g0 = -0.5 * jnp.exp(-(radii / 2.5) ** 2) * m0 + g1 = -0.3 * jnp.exp(-(radii / 3.0) ** 2) * m1 + zeros = jnp.zeros_like(g0) + + def two_ch_pot(_energy: jax.Array) -> jax.Array: + return jnp.array([[g0, zeros], [zeros, g1]]) # (2, 2, N) + + def ch0_pot(_energy: jax.Array) -> jax.Array: + return jnp.array([[[*g0]]]) # (1, 1, N) + + def ch1_pot(_energy: jax.Array) -> jax.Array: + return jnp.array([[[*g1]]]) # (1, 1, N) + + two_pots = jax.vmap(two_ch_pot)(energies) + ch0_pots = jax.vmap(ch0_pot)(energies) + ch1_pots = jax.vmap(ch1_pot)(energies) + + assert two_ch.rmatrix_direct_grid is not None + assert ch0_solver.rmatrix_direct_grid is not None + assert ch1_solver.rmatrix_direct_grid is not None + + r_two = np.asarray(two_ch.rmatrix_direct_grid(two_pots)) # (N_E, 2, 2) + r_ch0 = np.asarray(ch0_solver.rmatrix_direct_grid(ch0_pots)) # (N_E, 1, 1) + r_ch1 = np.asarray(ch1_solver.rmatrix_direct_grid(ch1_pots)) # (N_E, 1, 1) + + # Diagonal elements of decoupled two-channel solver must match single-channel results. + assert np.allclose(r_two[:, 0, 0], r_ch0[:, 0, 0], atol=1.0e-10, rtol=1.0e-10) + assert np.allclose(r_two[:, 1, 1], r_ch1[:, 0, 0], atol=1.0e-10, rtol=1.0e-10) + # Off-diagonal must be zero for a decoupled potential. + assert np.allclose(r_two[:, 0, 1], 0.0, atol=1.0e-10) + assert np.allclose(r_two[:, 1, 0], 0.0, atol=1.0e-10) From bda162b040b7be75aadc60557615a484fca89c71 Mon Sep 17 00:00:00 2001 From: beykyle Date: Tue, 9 Jun 2026 23:20:00 -0400 Subject: [PATCH 04/10] Add Interaction dispatch fix, wavefunction_direct round-trip test, builder tests (Tasks 5-6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `assembly.py`: handle ndim=2 potential (pre-assembled (M,M) Interaction.block) by slicing sub-blocks instead of channel-index scalar access; fixes Interaction dispatch through assemble_block_hamiltonian - `linear_solve.py`: remove ambiguous ndim-based energy indexing in wavefunction_direct for raw arrays (user must slice energy-dependent arrays before calling); scale result by m₀ so wavefunction_direct matches spectral Green's function convention G = (H_fm2 - E/m)^{-1} = m·(H_MeV - E·I)^{-1} - `wavefunction.py`: add docstring note showing the direct-path wavefunction_direct API - New `tests/unit/test_interaction_builders.py`: round-trips for from_block, from_array (local + nonlocal), from_funcs; symmetry-validation error; energy-dependent shape; end-to-end rmatrix_direct(Interaction) == rmatrix_direct(raw_V) - `test_solver_direct.py`: wavefunction_direct(interaction, src, i) == wavefunction(spec, E, src) round-trip test at 1e-10 tolerance Co-Authored-By: Claude Sonnet 4.6 --- src/lax/solvers/assembly.py | 6 + src/lax/solvers/linear_solve.py | 14 +- src/lax/wavefunction.py | 6 + tests/unit/test_interaction_builders.py | 254 ++++++++++++++++++++++++ tests/unit/test_solver_direct.py | 46 +++++ 5 files changed, 322 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_interaction_builders.py diff --git a/src/lax/solvers/assembly.py b/src/lax/solvers/assembly.py index 7d15385..306dd52 100644 --- a/src/lax/solvers/assembly.py +++ b/src/lax/solvers/assembly.py @@ -87,6 +87,12 @@ def assemble_block_hamiltonian( ) if potential.ndim == 3: block = block + _diagonal_from_vector(potential[channel_index, coupled_index]) + elif potential.ndim == 2: + # Pre-assembled (M, M) block (e.g. from Interaction.block): extract sub-block + # by slicing rather than channel indexing. + rs = channel_index * basis_size + cs = coupled_index * basis_size + block = block + potential[rs : rs + basis_size, cs : cs + basis_size] else: block = block + potential[channel_index, coupled_index] row_blocks.append(block) diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index d4b70eb..9674cdc 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -224,9 +224,9 @@ def __call__( if isinstance(potential, Interaction): block = potential.block[energy_index] if potential.energy_dependent else potential.block - elif potential.ndim in {4, 5}: - block = potential[energy_index] else: + # Raw array: pass as-is. For energy-dependent arrays the caller must + # slice to the desired energy before calling (potential[energy_index]). block = potential return cast( @@ -659,11 +659,17 @@ def _wavefunction_direct( channels: tuple[ChannelSpec, ...], matrix_size: int, ) -> jax.Array: - """Solve ``(H_MeV − E·I) ψ = source`` for the internal wavefunction.""" + """Solve the internal wavefunction on the MeV direct path. + + Computes ``m₀ · (H_MeV − E·I)⁻¹ source`` where ``m₀ = channels[0].mass_factor``. + The ``m₀`` factor makes the result equal to the fm⁻² spectral Green's function: + ``G_spectral = (H_fm2 − E/m)⁻¹ = m · (H_MeV − E·I)⁻¹``. + """ hamiltonian = assemble_block_hamiltonian(mesh, operators, channels, potential) matrix = hamiltonian - energy * jnp.eye(matrix_size, dtype=hamiltonian.dtype) - result: jax.Array = cast(jax.Array, jnp.linalg.solve(matrix, source)) + m0 = channels[0].mass_factor # evaluated at JIT-trace time (static) + result: jax.Array = cast(jax.Array, m0 * jnp.linalg.solve(matrix, source)) return result diff --git a/src/lax/wavefunction.py b/src/lax/wavefunction.py index e007ee3..f71eb61 100644 --- a/src/lax/wavefunction.py +++ b/src/lax/wavefunction.py @@ -71,6 +71,12 @@ def make_wavefunction_source( >>> spec = solver.spectrum(V) >>> src = lax.make_wavefunction_source(solver, channel_index=0, energy_index=5) >>> psi = solver.wavefunction(spec, energies[5], src) + + For the direct (linear-solve) path — no eigendecomposition required — compile + with ``solvers=("rmatrix_direct",)`` and use:: + + interaction = solver.interaction_from_block(V[0, 0]) # (M, M) block + psi = solver.wavefunction_direct(interaction, src, energy_index=5) """ boundary: BoundaryValues | None = solver.boundary if boundary is None: diff --git a/tests/unit/test_interaction_builders.py b/tests/unit/test_interaction_builders.py new file mode 100644 index 0000000..cfec85c --- /dev/null +++ b/tests/unit/test_interaction_builders.py @@ -0,0 +1,254 @@ +"""Tests for make_interaction_from_{block,array,funcs} builder factories.""" +from __future__ import annotations + +import jax.numpy as jnp +import numpy as np +import pytest + +import lax as lm +from lax.operators import assemble_local, assemble_nonlocal, make_interaction_from_array, make_interaction_from_block, make_interaction_from_funcs + +pytest.importorskip("jax") + + +def _make_mesh_channels(): + mesh = lm.MeshSpec("legendre", "x", n=6, scale=5.0) + channels = (lm.ChannelSpec(l=0, threshold=0.0, mass_factor=41.472),) + energies = jnp.asarray([1.0, 3.0]) + solver = lm.compile( + mesh=mesh, + channels=channels, + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=energies, + energy_dependent=True, + ) + return solver + + +# --------------------------------------------------------------------------- +# make_interaction_from_block +# --------------------------------------------------------------------------- + + +def test_interaction_from_block_wraps_matrix() -> None: + """Wrapping a (M, M) block stores it verbatim with energy_dependent=False.""" + + solver = _make_mesh_channels() + N = solver.mesh.n + M = N * len(solver.channels) + + V_block = jnp.eye(M) * 0.5 + assert solver.interaction_from_block is not None + interaction = solver.interaction_from_block(V_block, energy_dependent=False) + + assert interaction.energy_dependent is False + assert np.allclose(np.asarray(interaction.block), np.asarray(V_block)) + + +def test_interaction_from_block_energy_dependent() -> None: + """Energy-dependent (N_E, M, M) blocks are stored with energy_dependent=True.""" + + solver = _make_mesh_channels() + N_E = len(solver.energies) + M = solver.mesh.n * len(solver.channels) + + V_block = jnp.ones((N_E, M, M)) * 0.1 + assert solver.interaction_from_block is not None + interaction = solver.interaction_from_block(V_block, energy_dependent=True) + + assert interaction.energy_dependent is True + assert interaction.block.shape == (N_E, M, M) + + +def test_interaction_from_block_rejects_wrong_shape() -> None: + """Wrong block shape raises ValueError.""" + + solver = _make_mesh_channels() + M = solver.mesh.n * len(solver.channels) + + with pytest.raises(ValueError, match="shape"): + assert solver.interaction_from_block is not None + solver.interaction_from_block(jnp.zeros((M + 1, M)), energy_dependent=False) + + +# --------------------------------------------------------------------------- +# make_interaction_from_array — local term round-trip +# --------------------------------------------------------------------------- + + +def test_interaction_from_array_local_matches_assemble_local() -> None: + """Local term builds the same (M, M) diagonal block as assemble_local.""" + + solver = _make_mesh_channels() + radii = np.asarray(solver.mesh.radii) + g = jnp.asarray(np.exp(-0.5 * radii)) # (N,) form-factor + + # Interaction builder: one local term with coupling A = [[1.0]] + A = np.array([[1.0]]) + assert solver.interaction_from_array is not None + interaction = solver.interaction_from_array( + local=[(g, A)], + energy_dependent=False, + ) + + # assemble_local returns (1, 1, N); the block should be diag(g) + V_raw = assemble_local(solver.mesh, lambda r: g) # (1, 1, N) + expected = np.diag(np.asarray(g)) + + assert np.allclose(np.asarray(interaction.block), expected, atol=1e-13) + # Also verify it matches the V_raw diagonal + assert np.allclose(np.asarray(interaction.block), np.diag(np.asarray(V_raw[0, 0])), atol=1e-13) + + +# --------------------------------------------------------------------------- +# make_interaction_from_array — nonlocal term round-trip +# --------------------------------------------------------------------------- + + +def test_interaction_from_array_nonlocal_matches_assemble_nonlocal() -> None: + """Nonlocal term builds the same (M, M) block as assemble_nonlocal.""" + + solver = _make_mesh_channels() + radii = np.asarray(solver.mesh.radii) + ri, rj = np.meshgrid(radii, radii, indexing="ij") + K = jnp.asarray(np.exp(-0.5 * (ri + rj))) # (N, N) kernel values + + A = np.array([[1.0]]) + assert solver.interaction_from_array is not None + interaction = solver.interaction_from_array( + nonlocal_=[(K, A)], + energy_dependent=False, + ) + + # assemble_nonlocal applies sqrt(w_i * w_j) * a scaling; the block should match + V_raw = assemble_nonlocal(solver.mesh, lambda r1, r2: jnp.asarray(np.exp(-0.5 * (np.asarray(r1) + np.asarray(r2))))) + expected = np.asarray(V_raw[0, 0]) # (N, N) + + assert np.allclose(np.asarray(interaction.block), expected, atol=1e-13) + + +# --------------------------------------------------------------------------- +# make_interaction_from_array — symmetry validation +# --------------------------------------------------------------------------- + + +def test_interaction_from_array_rejects_asymmetric_coupling() -> None: + """Asymmetric coupling matrix A raises ValueError.""" + + solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=5.0), + channels=( + lm.ChannelSpec(l=0, threshold=0.0, mass_factor=41.472), + lm.ChannelSpec(l=0, threshold=0.0, mass_factor=41.472), + ), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=jnp.asarray([1.0]), + energy_dependent=True, + ) + N = solver.mesh.n + g = jnp.ones(N) + A_asymmetric = np.array([[1.0, 2.0], [0.0, 1.0]]) # not symmetric + + assert solver.interaction_from_array is not None + with pytest.raises(ValueError, match="symmetric"): + solver.interaction_from_array(local=[(g, A_asymmetric)], energy_dependent=False) + + +# --------------------------------------------------------------------------- +# make_interaction_from_array — energy-dependent +# --------------------------------------------------------------------------- + + +def test_interaction_from_array_energy_dependent_shape() -> None: + """energy_dependent=True produces block of shape (N_E, M, M).""" + + solver = _make_mesh_channels() + N_E = len(solver.energies) + N = solver.mesh.n + + g_grid = jnp.ones((N_E, N)) # (N_E, N) energy-dependent local form-factor + A = np.array([[1.0]]) + + assert solver.interaction_from_array is not None + interaction = solver.interaction_from_array( + local=[(g_grid, A)], + energy_dependent=True, + ) + + M = N * len(solver.channels) + assert interaction.energy_dependent is True + assert interaction.block.shape == (N_E, M, M) + + +# --------------------------------------------------------------------------- +# make_interaction_from_funcs — matches interaction_from_array +# --------------------------------------------------------------------------- + + +def test_interaction_from_funcs_matches_from_array() -> None: + """interaction_from_funcs evaluating a lambda equals interaction_from_array with sampled values.""" + + solver = _make_mesh_channels() + radii = np.asarray(solver.mesh.radii) + + def local_fn(r: jnp.ndarray) -> jnp.ndarray: + return jnp.asarray(np.exp(-0.5 * np.asarray(r))) + + g_sampled = local_fn(jnp.asarray(radii)) + A = np.array([[1.0]]) + + assert solver.interaction_from_funcs is not None + assert solver.interaction_from_array is not None + + interaction_funcs = solver.interaction_from_funcs( + local=[(local_fn, A)], + energy_dependent=False, + ) + interaction_array = solver.interaction_from_array( + local=[(g_sampled, A)], + energy_dependent=False, + ) + + assert np.allclose( + np.asarray(interaction_funcs.block), + np.asarray(interaction_array.block), + atol=1e-13, + ) + + +# --------------------------------------------------------------------------- +# End-to-end: rmatrix_direct(interaction) matches rmatrix_direct(raw_V) +# --------------------------------------------------------------------------- + + +def test_rmatrix_direct_interaction_matches_raw_array() -> None: + """rmatrix_direct(Interaction) produces the same R-matrix as rmatrix_direct(raw_V).""" + + alpha, beta = 0.2316053, 1.3918324 + HBAR2_2MU = 41.472 + + def yamaguchi_kernel(r1: jnp.ndarray, r2: jnp.ndarray) -> jnp.ndarray: + return -2.0 * beta * (alpha + beta) ** 2 * jnp.exp(-beta * (r1 + r2)) * HBAR2_2MU + + solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=10, scale=8.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=HBAR2_2MU),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=jnp.asarray([0.1, 5.0]), + ) + + V_raw = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) # (1, 1, N, N) + + assert solver.rmatrix_direct is not None + assert solver.interaction_from_block is not None + + # Build Interaction from the pre-assembled block + interaction = solver.interaction_from_block(V_raw[0, 0], energy_dependent=False) + + r_raw = np.asarray(solver.rmatrix_direct(V_raw)) + r_interaction = np.asarray(solver.rmatrix_direct(interaction)) + + assert np.allclose(r_raw, r_interaction, atol=1.0e-12, rtol=1.0e-12) diff --git a/tests/unit/test_solver_direct.py b/tests/unit/test_solver_direct.py index 4215f94..24d55ff 100644 --- a/tests/unit/test_solver_direct.py +++ b/tests/unit/test_solver_direct.py @@ -470,3 +470,49 @@ def ch1_pot(_energy: jax.Array) -> jax.Array: # Off-diagonal must be zero for a decoupled potential. assert np.allclose(r_two[:, 0, 1], 0.0, atol=1.0e-10) assert np.allclose(r_two[:, 1, 0], 0.0, atol=1.0e-10) + + +# --------------------------------------------------------------------------- +# Task 5: wavefunction_direct round-trip vs spectral wavefunction +# --------------------------------------------------------------------------- + + +def test_wavefunction_direct_matches_spectral_wavefunction() -> None: + """wavefunction_direct(interaction, source, i) equals spectral wavefunction(spec, E, source).""" + + alpha = 0.2316053 + beta = 1.3918324 + energies = jnp.asarray([1.0, 5.0]) + + def yamaguchi_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: + return -2.0 * beta * (alpha + beta) ** 2 * jnp.exp(-beta * (r1 + r2)) * HBAR2_2MU + + solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=10, scale=8.0), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=HBAR2_2MU),), + operators=("T+L",), + solvers=("spectrum", "wavefunction", "rmatrix_direct"), + energies=energies, + ) + + V_raw = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) # (1, 1, N, N) + spec = solver.spectrum(V_raw) + + assert solver.wavefunction is not None + assert solver.wavefunction_direct is not None + assert solver.interaction_from_block is not None + + # Build Interaction from the pre-assembled (M, M) nonlocal block. + # For N_c=1, M=N, so V_raw[0, 0] is already (M, M). + interaction = solver.interaction_from_block(V_raw[0, 0], energy_dependent=False) + + for energy_index in range(len(energies)): + energy = float(energies[energy_index]) + src = lm.make_wavefunction_source(solver, channel_index=0, energy_index=energy_index) + + psi_spec = np.asarray(solver.wavefunction(spec, energy, src)) + psi_dir = np.asarray(solver.wavefunction_direct(interaction, src, energy_index)) + + assert np.allclose(psi_spec, psi_dir, atol=1.0e-10, rtol=1.0e-10), ( + f"wavefunction_direct mismatch at energy_index={energy_index}" + ) From cd165353f5be4610e24c496df46a35bd796bf2ee Mon Sep 17 00:00:00 2001 From: beykyle Date: Wed, 10 Jun 2026 02:05:44 -0400 Subject: [PATCH 05/10] change potential API --- examples/alpha_pb_demo.ipynb | 113 ++++++----- .../descouvemont_closed_channels_demo.ipynb | 183 ++++------------- examples/descouvemont_np_demo.ipynb | 131 +++++------- examples/descouvemont_o16_ca44_demo.ipynb | 109 ++++------ examples/energy_dependent_demo.ipynb | 109 +++++----- examples/fourier_demo.ipynb | 17 +- examples/hydrogen_demo.ipynb | 18 +- examples/yamaguchi_demo.ipynb | 16 +- src/lax/__init__.py | 3 - src/lax/boundary/_types.py | 1 + src/lax/compile.py | 53 ++--- src/lax/models/optical.py | 5 +- src/lax/operators/__init__.py | 3 - src/lax/operators/interaction.py | 117 +++++++++-- src/lax/solvers/linear_solve.py | 148 +++++++++----- src/lax/solvers/spectrum.py | 31 +-- src/lax/types.py | 21 +- src/lax/wavefunction.py | 2 +- tests/benchmarks/test_alpha_pb_optical.py | 34 ++-- .../benchmarks/test_coupled_closed_channel.py | 35 ++-- .../test_descouvemont_closed_channels.py | 53 +++-- tests/benchmarks/test_descouvemont_np.py | 28 ++- .../benchmarks/test_descouvemont_o16_ca44.py | 27 ++- tests/benchmarks/test_phase8_meshes.py | 6 +- tests/benchmarks/test_yamaguchi.py | 25 ++- tests/benchmarks/test_yamaguchi_fourier.py | 3 +- tests/unit/test_interaction_builders.py | 31 +-- tests/unit/test_solver_direct.py | 186 ++++++++++-------- tests/unit/test_solver_pickle.py | 56 +++--- tests/unit/test_solver_spectrum.py | 12 +- tests/unit/test_spectral.py | 13 +- 31 files changed, 827 insertions(+), 762 deletions(-) diff --git a/examples/alpha_pb_demo.ipynb b/examples/alpha_pb_demo.ipynb index cd9ed8a..37351fd 100644 --- a/examples/alpha_pb_demo.ipynb +++ b/examples/alpha_pb_demo.ipynb @@ -57,7 +57,9 @@ "CHANNEL_RADIUS = 14.0\n", "\n", "\n", - "def optical_potential_parts(r: jnp.ndarray, imag_depth: float) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray, jnp.ndarray]:\n", + "def optical_potential_parts(\n", + " r: jnp.ndarray, imag_depth: float\n", + ") -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray, jnp.ndarray]:\n", " v0 = 100.0\n", " radius = 1.1132 * (208.0 ** (1.0 / 3.0) + 4.0 ** (1.0 / 3.0))\n", " diffuseness = 0.5803\n", @@ -114,7 +116,7 @@ " )\n", " smatrix = lm.spectral.smatrix_from_R(r_values[energy_index], boundary)\n", " smatrices.append(np.asarray(smatrix))\n", - " return np.stack(smatrices)\n" + " return np.stack(smatrices)" ] }, { @@ -146,7 +148,9 @@ ], "source": [ "r_plot = np.linspace(0.25, 18.0, 500)\n", - "total, nuclear_real, nuclear_imag, coulomb = optical_potential_parts(jnp.asarray(r_plot), imag_depth=10.0)\n", + "total, nuclear_real, nuclear_imag, coulomb = optical_potential_parts(\n", + " jnp.asarray(r_plot), imag_depth=10.0\n", + ")\n", "\n", "fig, axes = plt.subplots(1, 2, figsize=(13, 4.6))\n", "axes[0].plot(r_plot, np.asarray(nuclear_real), label=\"real nuclear\", linewidth=2.2)\n", @@ -162,7 +166,7 @@ "axes[1].set_xlabel(\"r [fm]\")\n", "axes[1].set_ylabel(\"MeV\")\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -183,38 +187,30 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "f2d9fbd0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Energy Appendix A S(E) eig S(E) direct S(E)\n", - " 10.0 1.000000+0.000000j 1.000000+0.000000j 1.000000+0.000000j\n", - " 20.0 1.000000+0.000001j 1.000000+0.000001j 1.000000+0.000001j\n", - " 30.0 0.998930+0.009050j 0.998996+0.008555j 0.998996+0.008555j\n", - " 40.0 0.650810+0.295600j 0.666935+0.297765j 0.666935+0.297765j\n", - " 50.0 0.064367+0.041130j 0.080228+0.044648j 0.080228+0.044648j\n", - "\n", - "max |eig - Appendix A| = 1.627e-02\n", - "max |direct - Appendix A| = 1.627e-02\n", - "max |eig - direct| = 4.148e-12\n" - ] - } - ], + "outputs": [], "source": [ "solver_real = real_solver(\"eigh\", (\"spectrum\", \"smatrix\"))\n", "solver_complex_eig = complex_solver(\"eig\", (\"spectrum\", \"smatrix\"))\n", "solver_complex_direct = complex_solver(\"linear_solve\", (\"rmatrix_direct\",))\n", "\n", - "potential_real = lm.assemble_local(solver_real.mesh, lambda r: jnp.real(optical_potential(r, imag_depth=0.0)))\n", - "potential_complex = lm.assemble_local(solver_complex_eig.mesh, lambda r: optical_potential(r, imag_depth=10.0))\n", + "potential_real = solver_real.potential(lambda r: jnp.real(optical_potential(r, imag_depth=0.0)))\n", + "potential_complex_eig = solver_complex_eig.potential(\n", + " lambda r: optical_potential(r, imag_depth=10.0)\n", + ")\n", + "potential_complex_direct = solver_complex_direct.potential(\n", + " lambda r: optical_potential(r, imag_depth=10.0)\n", + ")\n", "\n", "smatrix_real = np.asarray(solver_real.smatrix(solver_real.spectrum(potential_real)))[:, 0, 0]\n", - "smatrix_complex_eig = np.asarray(solver_complex_eig.smatrix(solver_complex_eig.spectrum(potential_complex)))[:, 0, 0]\n", - "smatrix_complex_direct = smatrix_from_direct_rmatrix(solver_complex_direct, potential_complex)[:, 0, 0]\n", + "smatrix_complex_eig = np.asarray(\n", + " solver_complex_eig.smatrix(solver_complex_eig.spectrum(potential_complex_eig))\n", + ")[:, 0, 0]\n", + "smatrix_complex_direct = smatrix_from_direct_rmatrix(\n", + " solver_complex_direct, potential_complex_direct\n", + ")[:, 0, 0]\n", "\n", "print(\"Energy Appendix A S(E) eig S(E) direct S(E)\")\n", "for energy, appendix_value, eig_value, direct_value in zip(\n", @@ -232,7 +228,9 @@ "print()\n", "print(f\"max |eig - Appendix A| = {np.max(np.abs(smatrix_complex_eig - APPENDIX_A_S)):.3e}\")\n", "print(f\"max |direct - Appendix A| = {np.max(np.abs(smatrix_complex_direct - APPENDIX_A_S)):.3e}\")\n", - "print(f\"max |eig - direct| = {np.max(np.abs(smatrix_complex_eig - smatrix_complex_direct)):.3e}\")\n" + "print(\n", + " f\"max |eig - direct| = {np.max(np.abs(smatrix_complex_eig - smatrix_complex_direct)):.3e}\"\n", + ")" ] }, { @@ -266,15 +264,29 @@ "axes[0].set_ylabel(r\"$S_{20}(E)$\")\n", "axes[0].legend(ncol=2, fontsize=9)\n", "\n", - "axes[1].plot(OPTICAL_ENERGIES, np.abs(smatrix_real), marker=\"o\", label=\"real spectrum |S|\", linewidth=2.2)\n", - "axes[1].plot(OPTICAL_ENERGIES, np.abs(smatrix_complex_eig), marker=\"s\", label=\"complex eig |S|\", linewidth=2.0)\n", - "axes[1].plot(OPTICAL_ENERGIES, np.abs(smatrix_complex_direct), marker=\"^\", label=\"complex direct |S|\", linewidth=2.0)\n", + "axes[1].plot(\n", + " OPTICAL_ENERGIES, np.abs(smatrix_real), marker=\"o\", label=\"real spectrum |S|\", linewidth=2.2\n", + ")\n", + "axes[1].plot(\n", + " OPTICAL_ENERGIES,\n", + " np.abs(smatrix_complex_eig),\n", + " marker=\"s\",\n", + " label=\"complex eig |S|\",\n", + " linewidth=2.0,\n", + ")\n", + "axes[1].plot(\n", + " OPTICAL_ENERGIES,\n", + " np.abs(smatrix_complex_direct),\n", + " marker=\"^\",\n", + " label=\"complex direct |S|\",\n", + " linewidth=2.0,\n", + ")\n", "axes[1].set_title(\"Magnitude across the three validated paths\")\n", "axes[1].set_xlabel(\"Energy [MeV]\")\n", "axes[1].set_ylabel(r\"$|S_{20}(E)|$\")\n", "axes[1].legend()\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -325,7 +337,9 @@ " solvers.append(\n", " lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", - " channels=(lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),),\n", + " channels=(\n", + " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),\n", + " ),\n", " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"smatrix\", \"phases\"),\n", " energies=fine_energies,\n", @@ -333,35 +347,26 @@ " method=\"eig\",\n", " z1z2=(2, 82),\n", " )\n", - " )\n" + " )" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "phase-scan-solve", "metadata": { "tags": [ "skip-benchmark" ] }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 6.16 s, sys: 60.8 ms, total: 6.22 s\n", - "Wall time: 1.47 s\n" - ] - } - ], + "outputs": [], "source": [ "%%time\n", "phase_curves = {}\n", "abs_s_curves = {}\n", "\n", "for solver, angular_momentum in zip(solvers, partial_waves):\n", - " potential = lm.assemble_local(solver.mesh, lambda r: optical_potential(r, imag_depth=10.0))\n", + " potential = solver.potential(lambda r: optical_potential(r, imag_depth=10.0))\n", " spectrum = solver.spectrum(potential)\n", " phase_curves[angular_momentum] = np.asarray(solver.phases(spectrum)[:, 0]) * (180.0 / np.pi)\n", " abs_s_curves[angular_momentum] = np.abs(np.asarray(solver.smatrix(spectrum)[:, 0, 0]))" @@ -391,8 +396,16 @@ "source": [ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))\n", "for angular_momentum in partial_waves:\n", - " axes[0].plot(np.asarray(fine_energies), phase_curves[angular_momentum], label=fr\"$\\ell={angular_momentum}$\")\n", - " axes[1].plot(np.asarray(fine_energies), abs_s_curves[angular_momentum], label=fr\"$\\ell={angular_momentum}$\")\n", + " axes[0].plot(\n", + " np.asarray(fine_energies),\n", + " phase_curves[angular_momentum],\n", + " label=rf\"$\\ell={angular_momentum}$\",\n", + " )\n", + " axes[1].plot(\n", + " np.asarray(fine_energies),\n", + " abs_s_curves[angular_momentum],\n", + " label=rf\"$\\ell={angular_momentum}$\",\n", + " )\n", "\n", "axes[0].set_title(\"Optical-model phase shifts from the spectrum path\")\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", @@ -404,7 +417,7 @@ "axes[1].set_ylabel(r\"$|S_\\ell(E)|$\")\n", "axes[1].legend(ncol=2, fontsize=9)\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -437,4 +450,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/descouvemont_closed_channels_demo.ipynb b/examples/descouvemont_closed_channels_demo.ipynb index 830e9c7..225add3 100644 --- a/examples/descouvemont_closed_channels_demo.ipynb +++ b/examples/descouvemont_closed_channels_demo.ipynb @@ -50,28 +50,29 @@ " search_roots = [Path.cwd().resolve(), *Path.cwd().resolve().parents]\n", " search_roots.append(Path(lm.__file__).resolve().parents[2])\n", " for root in search_roots:\n", - " candidate = root / 'tests' / 'benchmarks' / 'data'\n", + " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = 'Could not locate tests/benchmarks/data from the current notebook environment.'\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", - "fixture = json.loads((benchmark_data_dir() / 'descouvemont_alpha_c12.json').read_text())\n", - "reference = fixture['references'][2]\n", + "\n", + "fixture = json.loads((benchmark_data_dir() / \"descouvemont_alpha_c12.json\").read_text())\n", + "reference = fixture[\"references\"][2]\n", "\n", "model = lm.models.ALPHA_C12_ROTOR_MODEL\n", "channels = lm.models.channels_from_rotor_model(model)\n", "potential_fn = lm.models.make_rotor_coupled_optical_potential(model)\n", - "energies = np.asarray(reference['energies'], dtype=np.float64)\n", + "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "\n", "[\n", " {\n", - " 'index': index,\n", - " 'label': channel.label,\n", - " 'threshold_mev': channel.threshold,\n", + " \"index\": index,\n", + " \"label\": channel.label,\n", + " \"threshold_mev\": channel.threshold,\n", " }\n", " for index, channel in enumerate(model.channels)\n", - "]\n" + "]" ] }, { @@ -93,118 +94,10 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "f11bfae6", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'energy_mev': 4.0,\n", - " 'open_channels': 1,\n", - " 'first_column_amplitudes': [0.6152452019477478],\n", - " 'reference_amplitudes': [0.61525],\n", - " 'first_column_phases': [-0.10040099553955889],\n", - " 'reference_phases': [-0.1004]},\n", - " {'energy_mev': 8.0,\n", - " 'open_channels': 4,\n", - " 'first_column_amplitudes': [0.18113338586808958,\n", - " 0.06676881880206278,\n", - " 0.04891285380772651,\n", - " 0.02464281295881678],\n", - " 'reference_amplitudes': [0.18113, 0.066769, 0.048913, 0.024643],\n", - " 'first_column_phases': [-1.0734136563296082,\n", - " -0.15641436683964904,\n", - " -0.10244864824239609,\n", - " -0.40517842335839993],\n", - " 'reference_phases': [-1.0734, -0.15641, -0.10245, -0.40518]},\n", - " {'energy_mev': 12.0,\n", - " 'open_channels': 4,\n", - " 'first_column_amplitudes': [0.08731028282186133,\n", - " 0.04282902876542858,\n", - " 0.04038842323678676,\n", - " 0.07359658622029483],\n", - " 'reference_amplitudes': [0.08731, 0.042829, 0.040388, 0.073597],\n", - " 'first_column_phases': [1.0616500039115735,\n", - " -1.4260519482446978,\n", - " -0.9378204449600998,\n", - " -0.7288781788068251],\n", - " 'reference_phases': [1.0617, -1.4261, -0.93782, -0.72888]},\n", - " {'energy_mev': 16.0,\n", - " 'open_channels': 8,\n", - " 'first_column_amplitudes': [0.04312427290879202,\n", - " 0.02705736380546722,\n", - " 0.029530080328067244,\n", - " 0.03445031114223769,\n", - " 0.002943341405143428,\n", - " 0.0010488635103655347,\n", - " 0.00018491270345264772,\n", - " 2.4996509417765206e-05],\n", - " 'reference_amplitudes': [0.043124,\n", - " 0.027057,\n", - " 0.02953,\n", - " 0.03445,\n", - " 0.0029433,\n", - " 0.0010489,\n", - " 0.00018491,\n", - " 2.4997e-05],\n", - " 'first_column_phases': [0.3317365830210329,\n", - " 0.42457343456962765,\n", - " 1.263185180829759,\n", - " -1.2680450113950492,\n", - " -0.6592364857599589,\n", - " -0.9734061953458073,\n", - " -1.3553384038389678,\n", - " 1.5187625776585374],\n", - " 'reference_phases': [0.33174,\n", - " 0.42457,\n", - " 1.2632,\n", - " -1.268,\n", - " -0.65924,\n", - " -0.97341,\n", - " -1.3553,\n", - " 1.5188]},\n", - " {'energy_mev': 20.0,\n", - " 'open_channels': 8,\n", - " 'first_column_amplitudes': [0.028037481312540757,\n", - " 0.019166590323178544,\n", - " 0.019079610487088786,\n", - " 0.020026860963515088,\n", - " 0.004758198092616515,\n", - " 0.006384234705649651,\n", - " 0.009467095627423306,\n", - " 0.0058584135635828295],\n", - " 'reference_amplitudes': [0.028037,\n", - " 0.019167,\n", - " 0.01908,\n", - " 0.020027,\n", - " 0.0047582,\n", - " 0.0063842,\n", - " 0.0094671,\n", - " 0.0058584],\n", - " 'first_column_phases': [-0.41740711536410763,\n", - " -0.5137798985717684,\n", - " 0.4237767959863514,\n", - " 1.0519642837302572,\n", - " 0.7729346014298463,\n", - " 1.3272784034670413,\n", - " 1.4670283336589118,\n", - " 1.2879595625464193],\n", - " 'reference_phases': [-0.41741,\n", - " -0.51378,\n", - " 0.42378,\n", - " 1.052,\n", - " 0.77293,\n", - " 1.3273,\n", - " 1.467,\n", - " 1.288]}]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "def boundary_at_energy(boundary: BoundaryValues, energy_index: int) -> BoundaryValues:\n", " k_values = None if boundary.k is None else boundary.k[energy_index]\n", @@ -220,43 +113,53 @@ "\n", "solver = lm.compile(\n", " mesh=lm.MeshSpec(\n", - " 'legendre',\n", - " 'x',\n", - " n=int(reference['n_basis']),\n", - " scale=float(reference['scale']),\n", - " extras={'n_intervals': int(reference['n_intervals'])},\n", + " \"legendre\",\n", + " \"x\",\n", + " n=int(reference[\"n_basis\"]),\n", + " scale=float(reference[\"scale\"]),\n", + " extras={\"n_intervals\": int(reference[\"n_intervals\"])},\n", " ),\n", " channels=channels,\n", - " operators=('T+L', '1/r^2'),\n", - " solvers=('rmatrix_direct',),\n", + " operators=(\"T+L\", \"1/r^2\"),\n", + " solvers=(\"rmatrix_direct\",),\n", " energies=energies,\n", - " method='linear_solve',\n", + " method=\"linear_solve\",\n", " V_is_complex=True,\n", " z1z2=(model.projectile_charge, model.target_charge),\n", ")\n", - "potential = lm.assemble_local(solver.mesh, potential_fn, n_channels=len(channels))\n", - "r_values = solver.rmatrix_direct(potential)\n", + "\n", + "# Build the interaction block from the 3-arg potential function.\n", + "import jax.numpy as jnp\n", + "\n", + "n_c = len(channels)\n", + "N = solver.mesh.n\n", + "r = solver.mesh.radii\n", + "block = jnp.zeros((n_c * N, n_c * N), dtype=jnp.complex128)\n", + "for c in range(n_c):\n", + " for cp in range(n_c):\n", + " g = potential_fn(r, c, cp)\n", + " block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g))\n", + "interaction = solver.interaction_from_block(block, energy_dependent=False)\n", + "r_values = solver.rmatrix_direct(interaction)\n", "\n", "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(\n", - " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", - " )\n", + " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", " rows.append(\n", " {\n", - " 'energy_mev': float(energy),\n", - " 'open_channels': open_count,\n", - " 'first_column_amplitudes': amplitudes.tolist(),\n", - " 'reference_amplitudes': reference['amplitudes'][energy_index],\n", - " 'first_column_phases': phases.tolist(),\n", - " 'reference_phases': reference['phases'][energy_index],\n", + " \"energy_mev\": float(energy),\n", + " \"open_channels\": open_count,\n", + " \"first_column_amplitudes\": amplitudes.tolist(),\n", + " \"reference_amplitudes\": reference[\"amplitudes\"][energy_index],\n", + " \"first_column_phases\": phases.tolist(),\n", + " \"reference_phases\": reference[\"phases\"][energy_index],\n", " }\n", " )\n", "\n", - "rows\n" + "rows" ] }, { @@ -311,4 +214,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/descouvemont_np_demo.ipynb b/examples/descouvemont_np_demo.ipynb index 2a15eb4..d9e3d5b 100644 --- a/examples/descouvemont_np_demo.ipynb +++ b/examples/descouvemont_np_demo.ipynb @@ -53,43 +53,34 @@ " search_roots = [Path.cwd().resolve(), *Path.cwd().resolve().parents]\n", " search_roots.append(Path(lm.__file__).resolve().parents[2])\n", " for root in search_roots:\n", - " candidate = root / 'tests' / 'benchmarks' / 'data'\n", + " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = 'Could not locate tests/benchmarks/data from the current notebook environment.'\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", - "fixture = json.loads((benchmark_data_dir() / 'descouvemont_np_j1.json').read_text())\n", - "reference = fixture['references'][0]\n", "\n", - "energies = np.asarray(reference['energies'], dtype=np.float64)\n", + "fixture = json.loads((benchmark_data_dir() / \"descouvemont_np_j1.json\").read_text())\n", + "reference = fixture[\"references\"][0]\n", + "\n", + "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "channels = lm.models.reid_np_j1_channels()\n", - "mesh = lm.MeshSpec('legendre', 'x', n=int(reference['n_basis']), scale=float(reference['scale']))\n", + "mesh = lm.MeshSpec(\"legendre\", \"x\", n=int(reference[\"n_basis\"]), scale=float(reference[\"scale\"]))\n", "\n", "{\n", - " 'energies_mev': energies.tolist(),\n", - " 'channels': [\n", - " {'index': index, 'l': channel.l, 'threshold_mev': channel.threshold}\n", + " \"energies_mev\": energies.tolist(),\n", + " \"channels\": [\n", + " {\"index\": index, \"l\": channel.l, \"threshold_mev\": channel.threshold}\n", " for index, channel in enumerate(channels)\n", " ],\n", - "}\n" + "}" ] }, { "cell_type": "markdown", "id": "9a63283cbaf04dbcab1f6479b197f3a8", "metadata": {}, - "source": [ - "## The public interaction helpers\n", - "\n", - "`lax.models.reid_soft_core_triplet_components(...)` returns the three radial pieces of the Reid soft-core triplet interaction:\n", - "\n", - "- a central term,\n", - "- a tensor term, which is what mixes the `S` and `D` waves,\n", - "- and a spin-orbit term.\n", - "\n", - "The public helper `lax.models.reid_np_j1_potential(...)` combines those pieces into the `2 × 2` local potential that `lax.assemble_local(...)` expects.\n" - ] + "source": "## The public interaction helpers\n\n`lax.models.reid_soft_core_triplet_components(...)` returns the three radial pieces of the Reid soft-core triplet interaction:\n\n- a central term,\n- a tensor term, which is what mixes the `S` and `D` waves,\n- and a spin-orbit term.\n\nThe public helper `lax.models.reid_np_j1_potential(...)` combines those pieces into the `2 × 2` local potential that `solver.interaction_from_array(...)` accepts as individual matrix-element callbacks." }, { "cell_type": "code", @@ -130,19 +121,18 @@ "source": [ "sample_radii = np.asarray([0.5, 1.0, 2.0, 4.0, 6.0], dtype=np.float64)\n", "central, tensor, spin_orbit = [\n", - " np.asarray(values)\n", - " for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", + " np.asarray(values) for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", "]\n", "\n", "[\n", " {\n", - " 'r_fm': float(radius),\n", - " 'central_mev': float(v_c),\n", - " 'tensor_mev': float(v_t),\n", - " 'spin_orbit_mev': float(v_ls),\n", + " \"r_fm\": float(radius),\n", + " \"central_mev\": float(v_c),\n", + " \"tensor_mev\": float(v_t),\n", + " \"spin_orbit_mev\": float(v_ls),\n", " }\n", " for radius, v_c, v_t, v_ls in zip(sample_radii, central, tensor, spin_orbit, strict=True)\n", - "]\n" + "]" ] }, { @@ -157,61 +147,28 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "8edb47106e1a46a883d545849b8ab81b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'energy_mev': 12.0,\n", - " 'computed_phase_11': 1.426802321548842,\n", - " 'reference_phase_11': 1.4256,\n", - " 'computed_phase_22': -0.04821679281684692,\n", - " 'reference_phase_22': -0.048047,\n", - " 'computed_abs_s12': 0.06752880533251353,\n", - " 'reference_abs_s12': 0.067922},\n", - " {'energy_mev': 24.0,\n", - " 'computed_phase_11': 1.1066156952811463,\n", - " 'reference_phase_11': 1.1052,\n", - " 'computed_phase_22': -0.11575721162017312,\n", - " 'reference_phase_22': -0.11502,\n", - " 'computed_abs_s12': 0.08181710503621159,\n", - " 'reference_abs_s12': 0.082249},\n", - " {'energy_mev': 36.0,\n", - " 'computed_phase_11': 0.9035668007316203,\n", - " 'reference_phase_11': 0.90165,\n", - " 'computed_phase_22': -0.17111315489885345,\n", - " 'reference_phase_22': -0.16959,\n", - " 'computed_abs_s12': 0.09926983274850994,\n", - " 'reference_abs_s12': 0.099708},\n", - " {'energy_mev': 48.0,\n", - " 'computed_phase_11': 0.7516447570422756,\n", - " 'reference_phase_11': 0.74889,\n", - " 'computed_phase_22': -0.21677919342563037,\n", - " 'reference_phase_22': -0.21425,\n", - " 'computed_abs_s12': 0.11531856718426074,\n", - " 'reference_abs_s12': 0.11575}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "solver = lm.compile(\n", " mesh=mesh,\n", " channels=channels,\n", - " operators=('T+L', '1/r^2'),\n", - " solvers=('spectrum', 'smatrix'),\n", + " operators=(\"T+L\", \"1/r^2\"),\n", + " solvers=(\"spectrum\", \"smatrix\"),\n", " energies=energies,\n", - " method='eigh',\n", + " method=\"eigh\",\n", ")\n", - "potential = lm.assemble_local(\n", - " solver.mesh,\n", - " lm.models.reid_np_j1_potential,\n", - " n_channels=len(channels),\n", + "assert solver.interaction_from_array is not None\n", + "r = solver.mesh.radii\n", + "potential = solver.interaction_from_array(\n", + " local=[\n", + " (lm.models.reid_np_j1_potential(r, 0, 0), np.array([[1.0, 0.0], [0.0, 0.0]])),\n", + " (lm.models.reid_np_j1_potential(r, 0, 1), np.array([[0.0, 1.0], [1.0, 0.0]])),\n", + " (lm.models.reid_np_j1_potential(r, 1, 1), np.array([[0.0, 0.0], [0.0, 1.0]])),\n", + " ],\n", + " energy_dependent=False,\n", ")\n", "spectrum = solver.spectrum(potential)\n", "smatrices = np.asarray(solver.smatrix(spectrum))\n", @@ -220,25 +177,25 @@ "for energy, smatrix, ref_phase_11, ref_phase_22, ref_eta_12 in zip(\n", " energies,\n", " smatrices,\n", - " reference['phase_11'],\n", - " reference['phase_22'],\n", - " reference['eta_12'],\n", + " reference[\"phase_11\"],\n", + " reference[\"phase_22\"],\n", + " reference[\"eta_12\"],\n", " strict=True,\n", "):\n", " params = lm.spectral.coupled_channel_parameters_from_S(smatrix)\n", " rows.append(\n", " {\n", - " 'energy_mev': float(energy),\n", - " 'computed_phase_11': float(np.asarray(params.phase_2)),\n", - " 'reference_phase_11': float(ref_phase_11),\n", - " 'computed_phase_22': float(np.asarray(params.phase_1)),\n", - " 'reference_phase_22': float(ref_phase_22),\n", - " 'computed_abs_s12': float(abs(smatrix[0, 1])),\n", - " 'reference_abs_s12': float(ref_eta_12),\n", + " \"energy_mev\": float(energy),\n", + " \"computed_phase_11\": float(np.asarray(params.phase_2)),\n", + " \"reference_phase_11\": float(ref_phase_11),\n", + " \"computed_phase_22\": float(np.asarray(params.phase_1)),\n", + " \"reference_phase_22\": float(ref_phase_22),\n", + " \"computed_abs_s12\": float(abs(smatrix[0, 1])),\n", + " \"reference_abs_s12\": float(ref_eta_12),\n", " }\n", " )\n", "\n", - "rows\n" + "rows" ] }, { @@ -279,4 +236,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/descouvemont_o16_ca44_demo.ipynb b/examples/descouvemont_o16_ca44_demo.ipynb index 8c20cf5..28893a8 100644 --- a/examples/descouvemont_o16_ca44_demo.ipynb +++ b/examples/descouvemont_o16_ca44_demo.ipynb @@ -46,28 +46,29 @@ " search_roots = [Path.cwd().resolve(), *Path.cwd().resolve().parents]\n", " search_roots.append(Path(lm.__file__).resolve().parents[2])\n", " for root in search_roots:\n", - " candidate = root / 'tests' / 'benchmarks' / 'data'\n", + " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = 'Could not locate tests/benchmarks/data from the current notebook environment.'\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", - "fixture = json.loads((benchmark_data_dir() / 'descouvemont_o16_ca44.json').read_text())\n", - "reference = fixture['references'][2]\n", + "\n", + "fixture = json.loads((benchmark_data_dir() / \"descouvemont_o16_ca44.json\").read_text())\n", + "reference = fixture[\"references\"][2]\n", "\n", "model = lm.models.O16_CA44_ROTOR_MODEL\n", "channels = lm.models.channels_from_rotor_model(model)\n", "potential_fn = lm.models.make_rotor_coupled_optical_potential(model)\n", - "energies = np.asarray(reference['energies'], dtype=np.float64)\n", + "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "\n", "[\n", " {\n", - " 'index': index,\n", - " 'label': channel.label,\n", - " 'threshold_mev': channel.threshold,\n", + " \"index\": index,\n", + " \"label\": channel.label,\n", + " \"threshold_mev\": channel.threshold,\n", " }\n", " for index, channel in enumerate(model.channels)\n", - "]\n" + "]" ] }, { @@ -89,44 +90,10 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "id": "8dd0d8092fe74a7c96281538738b07e2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'energy_mev': 34.0,\n", - " 'open_channels': 4,\n", - " 'entrance_column_amplitudes': [0.9937028246982015,\n", - " 0.020814210442039505,\n", - " 0.010999860109644493,\n", - " 0.007914467638345631],\n", - " 'reference_amplitudes': [0.9937, 0.020814, 0.011, 0.0079145],\n", - " 'entrance_column_phases': [0.014832351416879854,\n", - " -0.6550106547776863,\n", - " -0.6688024245411548,\n", - " -0.6776179703030561],\n", - " 'reference_phases': [0.014832, -0.65501, -0.6688, -0.67762]},\n", - " {'energy_mev': 44.0,\n", - " 'open_channels': 4,\n", - " 'entrance_column_amplitudes': [0.5375661268016084,\n", - " 0.1617722139591586,\n", - " 0.20847610347962534,\n", - " 0.2117678810307326],\n", - " 'reference_amplitudes': [0.53757, 0.16177, 0.20848, 0.21177],\n", - " 'entrance_column_phases': [0.18360050729099467,\n", - " 0.2480836179569414,\n", - " 0.034416526304467135,\n", - " -0.076024332613703],\n", - " 'reference_phases': [0.1836, 0.24808, 0.034417, -0.076024]}]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "def boundary_at_energy(boundary: BoundaryValues, energy_index: int) -> BoundaryValues:\n", " k_values = None if boundary.k is None else boundary.k[energy_index]\n", @@ -142,43 +109,53 @@ "\n", "solver = lm.compile(\n", " mesh=lm.MeshSpec(\n", - " 'legendre',\n", - " 'x',\n", - " n=int(reference['n_basis']),\n", - " scale=float(reference['scale']),\n", - " extras={'n_intervals': int(reference['n_intervals'])},\n", + " \"legendre\",\n", + " \"x\",\n", + " n=int(reference[\"n_basis\"]),\n", + " scale=float(reference[\"scale\"]),\n", + " extras={\"n_intervals\": int(reference[\"n_intervals\"])},\n", " ),\n", " channels=channels,\n", - " operators=('T+L', '1/r^2'),\n", - " solvers=('rmatrix_direct',),\n", + " operators=(\"T+L\", \"1/r^2\"),\n", + " solvers=(\"rmatrix_direct\",),\n", " energies=energies,\n", - " method='linear_solve',\n", + " method=\"linear_solve\",\n", " V_is_complex=True,\n", " z1z2=(model.projectile_charge, model.target_charge),\n", ")\n", - "potential = lm.assemble_local(solver.mesh, potential_fn, n_channels=len(channels))\n", - "r_values = solver.rmatrix_direct(potential)\n", + "\n", + "# Build the interaction block from the 3-arg potential function.\n", + "import jax.numpy as jnp\n", + "\n", + "n_c = len(channels)\n", + "N = solver.mesh.n\n", + "r = solver.mesh.radii\n", + "block = jnp.zeros((n_c * N, n_c * N), dtype=jnp.complex128)\n", + "for c in range(n_c):\n", + " for cp in range(n_c):\n", + " g = potential_fn(r, c, cp)\n", + " block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g))\n", + "interaction = solver.interaction_from_block(block, energy_dependent=False)\n", + "r_values = solver.rmatrix_direct(interaction)\n", "\n", "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(\n", - " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", - " )\n", + " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", " rows.append(\n", " {\n", - " 'energy_mev': float(energy),\n", - " 'open_channels': open_count,\n", - " 'entrance_column_amplitudes': amplitudes.tolist(),\n", - " 'reference_amplitudes': reference['amplitudes'][energy_index],\n", - " 'entrance_column_phases': phases.tolist(),\n", - " 'reference_phases': reference['phases'][energy_index],\n", + " \"energy_mev\": float(energy),\n", + " \"open_channels\": open_count,\n", + " \"entrance_column_amplitudes\": amplitudes.tolist(),\n", + " \"reference_amplitudes\": reference[\"amplitudes\"][energy_index],\n", + " \"entrance_column_phases\": phases.tolist(),\n", + " \"reference_phases\": reference[\"phases\"][energy_index],\n", " }\n", " )\n", "\n", - "rows\n" + "rows" ] }, { @@ -215,4 +192,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/energy_dependent_demo.ipynb b/examples/energy_dependent_demo.ipynb index 50af4af..9df1e9f 100644 --- a/examples/energy_dependent_demo.ipynb +++ b/examples/energy_dependent_demo.ipynb @@ -35,7 +35,7 @@ "import numpy as np\n", "\n", "import lax as lm\n", - "import lax.constants as C\n" + "import lax.constants as C" ] }, { @@ -47,15 +47,17 @@ "source": [ "# --- System parameters -----------------------------------------------\n", "HBAR2_2MU = C.hbar2_over_2mu(1.008665, 1.008665) # n-n MeV·fm²\n", - "A = 2.0 # Gaussian range [fm]\n", - "V1 = 60.0 # depth at E=0 [MeV]\n", - "V2 = -0.5 # linear E-dependence [MeV/MeV]\n", + "A = 2.0 # Gaussian range [fm]\n", + "V1 = 60.0 # depth at E=0 [MeV]\n", + "V2 = -0.5 # linear E-dependence [MeV/MeV]\n", + "\n", "\n", "def gaussian_depth(energy: float | jnp.ndarray) -> float | jnp.ndarray:\n", " return V1 + V2 * energy\n", "\n", + "\n", "def gaussian_potential(radii: jnp.ndarray, energy: float) -> jnp.ndarray:\n", - " return -gaussian_depth(energy) * jnp.exp(-(radii / A) ** 2)\n" + " return -gaussian_depth(energy) * jnp.exp(-((radii / A) ** 2))" ] }, { @@ -86,55 +88,40 @@ } ], "source": [ - "N_COARSE = 16 # coarse grid for the energy-dependent solve\n", - "N_FINE = 200 # dense reference grid (energy-independent solve at each E)\n", + "N_COARSE = 16 # coarse grid for the energy-dependent solve\n", + "N_FINE = 200 # dense reference grid (energy-independent solve at each E)\n", "\n", "energies_coarse = jnp.linspace(1.0, 30.0, N_COARSE)\n", - "energies_fine = jnp.linspace(1.0, 30.0, N_FINE)\n", + "energies_fine = jnp.linspace(1.0, 30.0, N_FINE)\n", "\n", "solver = lm.compile(\n", - " mesh=lm.MeshSpec('legendre', 'x', n=20, scale=10.0),\n", + " mesh=lm.MeshSpec(\"legendre\", \"x\", n=20, scale=10.0),\n", " channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=HBAR2_2MU),),\n", - " solvers=('spectrum', 'phases'),\n", + " solvers=(\"spectrum\", \"phases\"),\n", " energies=energies_coarse,\n", " energy_dependent=True,\n", ")\n", - "print(solver)\n" + "print(solver)" ] }, { "cell_type": "markdown", "id": "2bd8fd80", "metadata": {}, - "source": [ - "## Build the energy-dependent potential grid\n", - "\n", - "For each grid energy assemble `V(r; E_i)` as a `(1, 1, N)` array, then\n", - "stack into `(N_E, 1, 1, N)` for `jax.vmap`." - ] + "source": "## Build the energy-dependent potential grid\n\nUse `solver.potential(fn, energy_dependent=True)` to build an\nenergy-dependent `Interaction` whose `.block` has shape `(N_E, M, M)`.\nPass `.block` to `jax.vmap(solver.spectrum)` for the diagonal\n`(spec_i, E_i)` pairing." }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "9ceb753f", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "V_grid shape: (16, 1, 1, 20)\n" - ] - } - ], + "outputs": [], "source": [ - "def make_local_potential(energy: jnp.ndarray) -> jnp.ndarray:\n", - " \"\"\"Return shape (1, 1, N) potential for one energy.\"\"\"\n", - " return lm.assemble_local(solver.mesh, lambda r: gaussian_potential(r, float(energy)))\n", - "\n", - "# Build the full (N_E, 1, 1, N) potential grid\n", - "V_grid = jnp.stack([make_local_potential(e) for e in energies_coarse]) # (N_E, 1, 1, N)\n", - "print('V_grid shape:', V_grid.shape)\n" + "# Build the energy-dependent interaction; .block has shape (N_E, M, M)\n", + "assert solver.potential is not None\n", + "interaction = solver.potential(gaussian_potential, energy_dependent=True)\n", + "V_grid = interaction.block # (N_E, M, M) = (N_E, N, N) for single channel\n", + "print(\"V_grid shape:\", V_grid.shape)" ] }, { @@ -166,9 +153,9 @@ } ], "source": [ - "spectra = jax.vmap(solver.spectrum)(V_grid) # batched Spectrum (N_E, ...)\n", + "spectra = jax.vmap(solver.spectrum)(V_grid) # batched Spectrum (N_E, ...)\n", "phases_coarse = np.asarray(solver.phases_grid(spectra))[:, 0] # (N_E,) rad\n", - "print('phase shifts at coarse grid (deg):', np.degrees(phases_coarse).round(2))\n" + "print(\"phase shifts at coarse grid (deg):\", np.degrees(phases_coarse).round(2))" ] }, { @@ -192,7 +179,7 @@ "interp_phases = solver.interpolate_phases(jnp.asarray(phases_coarse[:, None])) # (N_E, 1)\n", "\n", "# Evaluate interpolant on a fine grid\n", - "phases_interp = np.asarray(interp_phases(energies_fine))[:, 0] # (N_FINE,)\n" + "phases_interp = np.asarray(interp_phases(energies_fine))[:, 0] # (N_FINE,)" ] }, { @@ -209,34 +196,28 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "d5a06392", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Max Padé interpolation error: 375.5338 degrees\n" - ] - } - ], + "outputs": [], "source": [ "solver_ref = lm.compile(\n", - " mesh=lm.MeshSpec('legendre', 'x', n=20, scale=10.0),\n", + " mesh=lm.MeshSpec(\"legendre\", \"x\", n=20, scale=10.0),\n", " channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=HBAR2_2MU),),\n", - " solvers=('spectrum', 'phases'),\n", + " solvers=(\"spectrum\", \"phases\"),\n", " energies=energies_fine,\n", ")\n", "\n", + "assert solver_ref.potential is not None\n", "phases_ref = np.empty(N_FINE)\n", "for idx, e in enumerate(np.asarray(energies_fine)):\n", - " V_e = lm.assemble_local(solver_ref.mesh, lambda r: gaussian_potential(r, float(e)))\n", - " spec_e = solver_ref.spectrum(V_e)\n", + " e_val = float(e)\n", + " interaction_e = solver_ref.potential(lambda r: gaussian_potential(r, e_val))\n", + " spec_e = solver_ref.spectrum(interaction_e)\n", " phases_ref[idx] = float(solver_ref.phases(spec_e)[idx, 0])\n", "\n", "max_err_deg = float(np.max(np.abs(np.degrees(phases_interp - phases_ref))))\n", - "print(f'Max Padé interpolation error: {max_err_deg:.4f} degrees')\n" + "print(f\"Max Padé interpolation error: {max_err_deg:.4f} degrees\")" ] }, { @@ -268,23 +249,23 @@ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.5))\n", "\n", "E_coarse = np.asarray(energies_coarse)\n", - "E_fine = np.asarray(energies_fine)\n", + "E_fine = np.asarray(energies_fine)\n", "\n", - "axes[0].plot(E_fine, np.degrees(phases_ref), label='reference (fine grid)', lw=2)\n", - "axes[0].plot(E_fine, np.degrees(phases_interp), '--', label='Padé interpolant', lw=1.8)\n", - "axes[0].scatter(E_coarse, np.degrees(phases_coarse), zorder=5, label='coarse knots', s=30)\n", - "axes[0].set_xlabel('Energy [MeV]')\n", - "axes[0].set_ylabel('Phase shift [deg]')\n", - "axes[0].set_title(r'Energy-dependent Gaussian: $\\ell=0$ phase shift')\n", + "axes[0].plot(E_fine, np.degrees(phases_ref), label=\"reference (fine grid)\", lw=2)\n", + "axes[0].plot(E_fine, np.degrees(phases_interp), \"--\", label=\"Padé interpolant\", lw=1.8)\n", + "axes[0].scatter(E_coarse, np.degrees(phases_coarse), zorder=5, label=\"coarse knots\", s=30)\n", + "axes[0].set_xlabel(\"Energy [MeV]\")\n", + "axes[0].set_ylabel(\"Phase shift [deg]\")\n", + "axes[0].set_title(r\"Energy-dependent Gaussian: $\\ell=0$ phase shift\")\n", "axes[0].legend()\n", "\n", "axes[1].plot(E_fine, np.degrees(np.abs(phases_interp - phases_ref)))\n", - "axes[1].set_xlabel('Energy [MeV]')\n", - "axes[1].set_ylabel('|error| [deg]')\n", - "axes[1].set_title('Padé interpolation error')\n", + "axes[1].set_xlabel(\"Energy [MeV]\")\n", + "axes[1].set_ylabel(\"|error| [deg]\")\n", + "axes[1].set_title(\"Padé interpolation error\")\n", "\n", "fig.tight_layout()\n", - "plt.show()\n" + "plt.show()" ] } ], @@ -309,4 +290,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/examples/fourier_demo.ipynb b/examples/fourier_demo.ipynb index 7412df3..d8d579f 100644 --- a/examples/fourier_demo.ipynb +++ b/examples/fourier_demo.ipynb @@ -63,7 +63,7 @@ " )\n", "\n", "\n", - "def laguerre_solver(l: int, *, n: int = 100, scale: float = 1.0/2) -> lm.Solver:\n", + "def laguerre_solver(l: int, *, n: int = 100, scale: float = 1.0 / 2) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"laguerre\", \"x\", n=n, scale=scale),\n", " channels=(lm.ChannelSpec(l=l, threshold=0.0, mass_factor=2.0),),\n", @@ -74,7 +74,7 @@ "\n", "\n", "def relative_error(numerical: np.ndarray, analytic: np.ndarray) -> float:\n", - " return float(np.linalg.norm(numerical - analytic) / np.linalg.norm(analytic))\n" + " return float(np.linalg.norm(numerical - analytic) / np.linalg.norm(analytic))" ] }, { @@ -167,7 +167,7 @@ " axes[row, 1].set_ylabel(r\"$\\tilde u(k)$\")\n", " axes[row, 1].legend()\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -234,7 +234,7 @@ " axes[row, 1].set_xlabel(\"k\")\n", " axes[row, 1].set_ylabel(r\"$\\tilde u(k)$\")\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -253,7 +253,7 @@ "outputs": [ { "data": { - "image/png": "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Nt54Y7zzzjuYMGECXnvtNfzXf/0XNt98czzyyCOYPXs2lixZgnnz5qV0XH311Vi9ejWOP/549OvXD0OGDEmuHXbYYRgzZgzmzp2Lp556CldddRWGDh2Kiy66KJG54IILcOaZZ+Kwww7Dsccei3/961/4/ve/jw996EP44x//WNgTyAsvvBAdHR047bTTsHz5cnz729/G5z//eTz++OOk+J/5zGew9dZb41vf+hY4514+PPDAA7jxxhsxc+ZMbLzxxj1ug8GAgICA3oaeeB9dsGAB1ltvPcyaNQvrrbceHnjgAZx11llYsWIFvvOd7wAA5s2bh2uvvRa33norLr/8cqy33nrYaaedsM8+++DLX/4yDj30UHzyk58EAOy8884AgGeffRYf/OAHsemmm+KMM87AwIEDceONN2LatGn4xS9+gUMPPTTlxwknnIBNNtkEZ511FlatWqX1991338VHPvIRvPLKKzj55JMxcuRIXHfddXjggQeUaTvqqKOw1157Ye7cuVi2bBkuvfRS/O53v8s15rj22mvx9ttv48QTT8Tq1atx6aWX4sMf/jCefvppDBs2TBuviLJbvnx5ZuPzjTfeGABw3333YcqUKfjABz6Ac845B++++y6+//3v44Mf/CCeeuop73EIdTyzbNky7LPPPgmRtMkmm+A3v/kNjjnmGKxYsSKzEfF5552HddZZB6eddhrWrFljXCGyevXqJN2rVq3C7373O1xzzTX43Oc+lyKFHnjgAUyZMgV77LEHzj77bHR0dODqq6/Ghz/8Yfzv//4v9t57bwDNlUY333wzZs6cie233x5vvvkmfvvb3+Kvf/0rdt99d6xduxaTJ0/GmjVrcNJJJ2H48OF47bXXcPvtt+Ott97C4MGDARTbHufNm4eTTjoJ6623Hv77v/8bADL1SdVO/vCHP+CRRx7B4YcfjlGjRuGll17C5ZdfjokTJ+Ivf/kL1l133ZSOk046CRtuuCHOPvtsvPTSS5g3bx5mzpyJn//85wCapM5HP/pRbLLJJjjjjDOwwQYb4KWXXsItt9wCANhuu+1w3XXX4dRTT8WoUaPw1a9+FUCTMH733XcxceJEvPjii5g5cybGjBmDm266CUceeSTeeustfOUrX0n5YuoPP/vZz2K77bbDhRdeiDvuuAPnn38+hgwZgiuuuAIf/vCHcdFFF+FnP/sZTjvtNOy111740Ic+RM7rgDYDDwgIKA1nn302B8D/9a9/8b/+9a985MiRfK+99uL//ve/E5nzzjuPDxw4kP/tb39LxT3jjDN4Z2cnf+WVVzjnnC9evJgD4IMGDeKvv/660s7RRx+dCj/00EP5RhttlPx+6aWXeGdnJ7/gggtSck8//TTv06dPKnzGjBl89OjR1jROmDCBT5gwIfn94IMPcgB8u+2242vWrEnCL730Ug6AP/3000Z9cVqOOOIIq20TAPCOjg7+7LPP5tITEBAQEFAfesN99J133smE/dd//Rdfd911+erVq5V5EeNf//oXB8DPPvvsjI6PfOQjfKeddkrpaDQafN999+Vbb711Enb11VdzAHy//fbj77//vtXfefPmcQD8xhtvTMJWrVrFt9pqKw6AP/jgg5xzzteuXcuHDh3Kd9xxR/7uu+8msrfffjsHwM8666wkTB5LxJDzMC7DAQMG8H/84x9J+OOPP84B8FNPPTUJi/MrhkvZqRDnk+oTY9ddd+VDhw7lb775ZhL2pz/9iXd0dPDp06dr06XzmXPzeEYu+2OOOYaPGDGCv/HGGym5ww8/nA8ePDipa/FY7QMf+ICy/qnsqD7Tpk3L1K+tt96aT548mTcajST8nXfe4WPGjOEHHnhgEjZ48GB+4oknam3+8Y9/5AD4TTfdpJUpoz3usMMOyrpoaieqPHz00Uc5AH7ttddmdEyaNCmVP6eeeirv7Ozkb731Fuec81tvvZUD4H/4wx+Mvo4ePZoffPDBqbC4ff70pz9NwtauXcvHjx/P11tvPb5ixQrOOa0/PP7445Ow999/n48aNYozxviFF16YhP/nP//hAwYM4DNmzDD6GtDeCK+PBQRUgGeeeQYTJkzAFltsgfvuuw8bbrhhcu2mm27C/vvvjw033BBvvPFG8pk0aRK6urrw8MMPp3R96lOfSpaLy/jSl76U+r3//vvjzTffTJYD33LLLWg0GjjssMNStoYPH46tt94aDz74YGFpPuqoo1JPnPbff38AwP/93/+R4stp8cGECRMKfdc6ICAgIKAe9OT76IABA5Lvb7/9Nt544w3sv//+eOedd/Dcc8856wOAf//733jggQdw2GGHJTrfeOMNvPnmm5g8eTJeeOGFzCtcxx13HDo7O62677zzTowYMQKf/vSnk7B1110Xxx9/fEruiSeewOuvv44TTjghtd/MwQcfjG233RZ33HGHV9oAYNq0adh0002T33vvvTfGjRuHO++8UxunqLK77LLLcO+996Y+ALBkyRIsWrQIRx55ZGq1xc4774wDDzzQ6JsNlPEM5xy/+MUvMHXqVHDOU2mcPHkyli9fnno1CwBmzJiRqn8mHHLIIUl6f/nLX2L27Nm466678LnPfS5Z0b1o0SK88MIL+NznPoc333wzsb9q1Sp85CMfwcMPP5y80rnBBhvg8ccfxz//+U+lvXgl0N1336094azKcW0MVTsR8/C9997Dm2++ia222gobbLBBJs8B4Pjjj0+9Jrj//vujq6sLL7/8MoDWvmG333473nvvPSf/7rzzTgwfPhxHHHFEEta3b1+cfPLJWLlyJR566KGUvKk/PPbYY5PvnZ2d2HPPPcE5xzHHHJOEb7DBBhg7dix5fB/QngivjwUEVICpU6di2LBhuPvuu7Heeuulrr3wwgv485//rO2Q440lY8gnXojYfPPNU7/jQfN//vMfDBo0CC+88AI459h6662V8fv27WtNCxUmXygwpZOKInQEBAQEBNSPnnwfffbZZ/HNb34TDzzwQGZPF3nvFCpefPFFcM5x5pln4swzz1TKvP766ylihXrPjPd0kve+GTt2bEZOFQ4A2267LX7729+S7Kmgyv9tttkGN954ozZOUWW39957KzeaNqV3u+22w9133+29MTGlbP71r3/hrbfewpVXXokrr7xSKWNqC11dXZl9bYYMGZI84Bs1ahQmTZqUXPvEJz6BjTbaCKeddhpuv/12TJ06FS+88AKAJtmkw/Lly7Hhhhvi29/+NmbMmIHNNtsMe+yxBw466CBMnz4dH/jABxLfZs2ahe9973v42c9+hv333x+f+MQnkj1ugOLK1AWqsnj33Xcxd+5cXH311XjttddS2x6o2rBtjDxhwgR86lOfwpw5c3DJJZdg4sSJmDZtGj73uc+hX79+Rv9efvllbL311pkNw7fbbrvkui09Oj8HDx6M/v37J69LiuFvvvmm0a+A9kYghQICKsCnPvUpXHPNNfjZz36G//qv/0pdazQaOPDAA3H66acr426zzTap36YnOronfPHNqdFogDGG3/zmN0pZeaCdBzZfbKA+uSpbR0BAQEBA/eip99G33noLEyZMwKBBg3Duuediyy23RP/+/fHUU0/h61//emqjbBfE8U477TRMnjxZKRMfax+jznsmY0w5PhA3286LKsdANsiEWgxdeillE5f5F77wBS0pE+83pdL76quvZgiCBx98ULkBeIyPfOQjAICHH34YU6dOTXz4zne+g1133VUZJ87nww47DPvvvz9uvfVW3HPPPfjOd76Diy66CLfccgumTJkCAPjud7+LI488Er/85S9xzz334OSTT8bcuXPx2GOPYdSoUbWUqaosTjrpJFx99dU45ZRTMH78eAwePBiMMRx++OHKNmzrZxhjuPnmm/HYY4/h17/+Ne6++24cffTR+O53v4vHHnus0HS59od5x/cB7YlACgUEVIDvfOc76NOnD0444QSsv/76+NznPpdc23LLLbFy5crU05eysOWWW4JzjjFjxmQGyQEBAQEBAe2KnnofXbhwId58803ccsstqU1aFy9eTIqvIxfi1RZ9+/YtPF9Gjx6NZ555BpzzlP3nn38+IxeHf/jDH05de/7555PrQHOlhOr1E3lVQ4x4RYqIv/3tb8aNnMseA4nplfHcc89h4403TlYJbbjhhnjrrbcycrr0UrDJJptg/fXXR1dXl1eZDx8+PHkVLsYuu+xijPP+++8DAFauXAmgmccAMGjQIJIPI0aMwAknnIATTjgBr7/+OnbffXdccMEFCSkEADvttBN22mknfPOb38QjjzyCD37wg5g/fz7OP//8UspU16ZMuPnmmzFjxozUKVyrV69WlrEL9tlnH+yzzz644IILcP311+Pzn/88brjhhtRrXTJGjx6NP//5z2g0GqnVQvGrqGK7CwiIEfYUCgioAIwxXHnllfj0pz+NGTNmpI6DPeyww/Doo4/i7rvvzsR76623khtuEfjkJz+Jzs5OzJkzJ8Poc87D0s+AgICAgLZET72Pxk/dRV1r167FD3/4Q1L8+FQjefI5dOhQTJw4EVdccQWWLFmSiSe/JuSCgw46CP/85z9x8803J2HvvPNO5pWlPffcE0OHDsX8+fNTx9X/5je/wV//+lccfPDBSdiWW26J5557LuXXn/70p8wx5jFuu+221J5Iv//97/H444+nyAQZZY+BRowYgV133RXXXHNNqjyeeeYZ3HPPPTjooIOSsC233BLLly/Hn//85yRsyZIluPXWW73td3Z24lOf+hR+8Ytf4Jlnnslct5V5//79MWnSpNRH3LtLhV//+tcAWuTRHnvsgS233BIXX3xxQhSpfOjq6sq8VjV06FCMHDkyqSsrVqzItN2ddtoJHR0diUwZZTpw4EBnMqezszNj//vf/773Srf//Oc/GX3xyiuxLalw0EEHYenSpclJZkCTvPv+97+P9dZbDxMmTPDyKaBnI6wUCgioCB0dHfjpT3+KadOm4bDDDsOdd96JD3/4w/ja176GX/3qV/j4xz+OI488EnvssQdWrVqFp59+GjfffDNeeumlzLu7vthyyy1x/vnnY/bs2XjppZcwbdo0rL/++li8eDFuvfVWHH/88TjttNMKsVUGXnrpJYwZMwYzZszAggUL6nYnICAgIKBC9MT76L777osNN9wQM2bMwMknnwzGGK677jqnV6233357/PznP8c222yDIUOGYMcdd8SOO+6Iyy67DPvttx922mknHHfccfjABz6AZcuW4dFHH8U//vEP/OlPf/LKg+OOOw4/+MEPMH36dDz55JMYMWIErrvuusyx23379sVFF12Eo446ChMmTMARRxyRHEm/xRZb4NRTT01kjz76aHzve9/D5MmTccwxx+D111/H/PnzscMOO2T2WQKar77tt99++PKXv4w1a9Zg3rx52GijjbSvEALVjIG+853vYMqUKRg/fjyOOeaY5Ej6wYMH45xzzknkDj/8cHz961/HoYceipNPPhnvvPMOLr/8cmyzzTbKjYmpuPDCC/Hggw9i3LhxOO6447D99tvj3//+N5566incd999+Pe//+2t+29/+xt++tOfAmiSgI899hiuueYabLXVVvjiF78IoNlGr7rqKkyZMgU77LADjjrqKGy66aZ47bXX8OCDD2LQoEH49a9/jbfffhujRo3Cpz/9aeyyyy5Yb731cN999+EPf/hDstrmgQcewMyZM/GZz3wG22yzDd5//31cd911CfkFlFOme+yxBy6//HKcf/752GqrrTB06NDMSjcZH//4x3Hddddh8ODB2H777fHoo4/ivvvuw0YbbeSazQCAa665Bj/84Q9x6KGHYsstt8Tbb7+NH/3oRxg0aFCKXFTh+OOPxxVXXIEjjzwSTz75JLbYYgvcfPPN+N3vfod58+Zh/fXX9/IpoGcjkEIBARWib9++uPnmmzFlyhQccsghuO+++zBu3Dg89NBD+Na3voWbbroJ1157LQYNGoRtttkGc+bMSTbTKwpnnHEGttlmG1xyySWYM2cOAGCzzTbDRz/6UXziE58o1FbRiJ86jRgxomZPAgICAgLqQE+7j2600Ua4/fbb8dWvfhXf/OY3seGGG+ILX/gCPvKRj2j3ApJx1VVX4aSTTsKpp56KtWvX4uyzz8aOO+6I7bffHk888QTmzJmDBQsW4M0338TQoUOx22674ayzznJOd4x1110X999/P0466SR8//vfx7rrrovPf/7zmDJlCj72sY+lZI888kisu+66uPDCC/H1r38dAwcOxKGHHoqLLrooOWEJaG6Ce+211+Kss87CrFmzsP322+O6667D9ddfj4ULF2Z8mD59Ojo6OjBv3jy8/vrr2HvvvfGDH/zAOj4oeww0adIk3HXXXTj77LNx1llnoW/fvpgwYQIuuuii1H49G220EW699VbMmjULp59+OsaMGYO5c+fihRdeyEUKDRs2DL///e9x7rnn4pZbbsEPf/hDbLTRRthhhx1w0UUX5UqbeNJaZ2cnRowYgWOPPRbnnXdeavPsiRMn4tFHH8V5552HH/zgB1i5ciWGDx+OcePGJfuBrbvuujjhhBNwzz33JCeIbbXVVvjhD3+IL3/5ywCaq48mT56MX//613jttdew7rrrYpdddsFvfvMb7LPPPom9osv0rLPOwssvv4xvf/vbePvttzFhwgQrKXTppZeis7MTP/vZz7B69Wp88IMfxH333UduwzImTJiA3//+97jhhhuwbNkyDB48GHvvvTd+9rOfWTcdHzBgABYuXIgzzjgD11xzDVasWIGxY8fi6quvxpFHHunlT0DPB+NhV6iAgIBugh/+8Ic4/fTT8fe//x3Dhg2r252AgICAgICAgICAgIBujbCnUEBAQLfBgw8+iJNPPjkQQgEBAQEBAQEBAQEBAQUgrBQKCAgICAgICAgICAgICAgI6IUIK4UCAgICAgICAgICAgICAgICeiFqJYUefvhhTJ06FSNHjgRjDLfddlvq+sqVKzFz5kyMGjUqOV1h/vz59TgbEBAQEBAQEFAy5s6di7322gvrr78+hg4dimnTpuH555+3xrvpppuw7bbbon///thpp51w5513pq5zznHWWWdhxIgRGDBgACZNmoQXXnihrGQEBAQEBAQEdBPUSgqtWrUKu+yyCy677DLl9VmzZuGuu+7CT3/6U/z1r3/FKaecgpkzZ+JX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jz4aALDnnntiypQpWLFihRaBNm3ahD/84Q8466yzvH52dXWhq6src3zChAltec9Vo13rkWqMtjiNtvgAHKd2YLTFBxidceI21dAZ9aIQwzAMwzBMO3Huuedi0aJFOOKII3DUUUfh2muvxdatW3HGGWcAAD7+8Y9j1113xWWXXQYAOOecczBnzhxcffXVWLBgAW6//Xb88Y9/xHe+8x0AgBACS5YswX/8x39g33331VvST5s2TQtPDMMwDMN0JiwKMQzDMAzDtBALFy7E3/72N1x44YVYv349DjnkECxfvlwvFP3SSy9Zb0aPOeYY3HrrrfjqV7+KL3/5y9h3331x991348ADD9RuvvCFL2Dr1q349Kc/jY0bN+LYY4/F8uXL0d3dPeLxYxiGYRimdWBRqIXp6urCRRdd5B2+3cq0q90A294s2PbmwLaPPO1qNzPyLF68OHe62KpVqzLHPvrRj+KjH/1orn9CCFxyySW45JJLBmXPaCy7HKfWZ7TFB+A4tQOjLT4Ax4mpjiDew41hGIZhGIZhGIZhGKbj4FWZGIZhGIZhGIZhGIZhOhAWhRiGYRiGYRiGYRiGYToQFoUYhmEYhmEYhmEYhmE6EBaFWozLLrsMRx55JMaNG4dJkybhpJNOwrPPPttsswbF5ZdfrrfBbQdeffVVnHbaaXjHO96Bnp4ezJo1C3/84x+bbVZNoijCBRdcgD333BM9PT3Ye++9cemll6IVlwv77W9/iw9/+MOYNm0ahBC4++67rfNEhAsvvBBTp05FT08P5s2bh7Vr1zbHWIdqtpfLZZx//vmYNWsWxo4di2nTpuHjH/84XnvtteYZLKmV5iaf+cxnIITAtddeO2L2VaMe25955hmccMIJmDBhAsaOHYsjjzwSL7300sgb61DL9i1btmDx4sXYbbfd0NPTgwMOOADLli1rjrFMx7J06VK8853vRHd3N2bPno1HHnmkqvsf/ehH2H///dHd3Y1Zs2bhvvvus863Qh3eSJy++93v4r3vfS922mkn7LTTTpg3b17G/Sc+8QkIIazP8ccfv72joWkkPjfddFPGVnd3uXbLo7lz52biJITAggULtJtm5lEjz1jFqlWrcNhhh6Grqwv77LMPbrrppoybRu/N4aTRON155534wAc+gF122QXjx4/H0UcfjV/+8peWm3//93/P5NH++++/HWNh02icVq1a5S1369evt9w1K58ajY/vHhFCYObMmdpNM/NosP3fdngmtQssCrUYDzzwAM4++2w8/PDDuP/++1Eul3Hcccdh69atzTatIf73f/8X3/72t3HQQQc125S6eOutt/Ce97wHxWIRv/jFL/D000/j6quvxk477dRs02pyxRVX4Prrr8e3vvUtPPPMM7jiiitw5ZVX4rrrrmu2aRm2bt2Kgw8+GEuXLvWev/LKK/HNb34Ty5Ytwx/+8AeMHTsW8+fPR19f3whbmqWa7du2bcOaNWtwwQUXYM2aNbjzzjvx7LPP4oQTTmiCpTa10lxx11134eGHH8a0adNGyLLa1LL9+eefx7HHHov9998fq1atwp/+9CdccMEFLbHFdi3bzz33XCxfvhw/+MEP8Mwzz2DJkiVYvHgx7r333hG2lOlUfvjDH+Lcc8/FRRddhDVr1uDggw/G/PnzsWHDBq/7hx56CKeccgo++clP4rHHHsNJJ52Ek046CU8++aR20+w6vNE4rVq1CqeccgpWrlyJ1atXY/fdd8dxxx2HV1991XJ3/PHH4/XXX9ef2267bSSi03B8AGD8+PGWrS+++KJ1vt3y6M4777Ti8+STTyIMw8xOe83Ko3qfsYp169ZhwYIFeN/73ofHH38cS5YswZlnnmmJKIPJ9+Gk0Tj99re/xQc+8AHcd999ePTRR/G+970PH/7wh/HYY49Z7mbOnGnl0e9///vtYb6XRuOkePbZZy2bJ02apM81M58ajc83vvENKx4vv/wydt5558x91Kw8Gkz/tx2eSW0FMS3Nhg0bCAA98MADzTalbjZv3kz77rsv3X///TRnzhw655xzmm1STc4//3w69thjm23GoFiwYAH98z//s3XsIx/5CJ166qlNsqg+ANBdd92lf8dxTFOmTKGvfe1r+tjGjRupq6uLbrvttiZYmI9ru49HHnmEANCLL744MkbVQZ7dr7zyCu2666705JNP0vTp0+maa64Zcdtq4bN94cKFdNpppzXHoAbw2T5z5ky65JJLrGOHHXYYfeUrXxlBy5hO5qijjqKzzz5b/46iiKZNm0aXXXaZ1/3HPvYxWrBggXVs9uzZ9C//8i9E1Bp1eKNxcqlUKjRu3Di6+eab9bFFixbRiSeeONym1kWj8fne975HEyZMyPVvNOTRNddcQ+PGjaMtW7boY83MI5N62gZf+MIXaObMmdaxhQsX0vz58/XvoabRcFJPnHwccMABdPHFF+vfF110ER188MHDZ9gQqCdOK1euJAD01ltv5bpplXwaTB7dddddJISgv/71r/pYK+VRPf3fdngmtRM8UqjFefvttwEAO++8c5MtqZ+zzz4bCxYswLx585ptSt3ce++9OOKII/DRj34UkyZNwqGHHorvfve7zTarLo455hisWLECf/nLXwAA//d//4ff//73+OAHP9hkyxpj3bp1WL9+vVVuJkyYgNmzZ2P16tVNtGxwvP322xBCYMcdd2y2KVWJ4xinn346zjvvPGsYcasTxzF+/vOfY7/99sP8+fMxadIkzJ49u66h+63AMcccg3vvvRevvvoqiAgrV67EX/7yFxx33HHNNo3pAAYGBvDoo49a9W0QBJg3b15ufbt69erMc33+/PnafbPr8MHEyWXbtm0ol8uZNteqVaswadIkzJgxA2eddRbefPPNYbXdx2Djs2XLFkyfPh277747TjzxRDz11FP63GjIoxtuuAEnn3wyxo4dax1vRh4Nhlr30XCkUbOJ4xibN2/O3Edr167FtGnTsNdee+HUU09tianetTjkkEMwdepUfOADH8CDDz6oj7d7Pt1www2YN28epk+fbh1vlTyqp//b6s+kdoNFoRYmjmMsWbIE73nPe3DggQc225y6uP3227FmzRpcdtllzTalIV544QVcf/312HffffHLX/4SZ511Fj772c/i5ptvbrZpNfniF7+Ik08+Gfvvvz+KxSIOPfRQLFmyBKeeemqzTWsINU978uTJ1vHJkydn5nC3On19fTj//PNxyimnYPz48c02pypXXHEFCoUCPvvZzzbblIbYsGEDtmzZgssvvxzHH388fvWrX+Gf/umf8JGPfAQPPPBAs82ryXXXXYcDDjgAu+22G0qlEo4//ngsXboU//AP/9AIFz4kAAAMP0lEQVRs05gO4O9//zuiKGqovl2/fn1V982uwwcTJ5fzzz8f06ZNszoRxx9/PL7//e9jxYoVuOKKK/DAAw/ggx/8IKIoGlb7XQYTnxkzZuDGG2/EPffcgx/84AeI4xjHHHMMXnnlFQDtn0ePPPIInnzySZx55pnW8Wbl0WDIu482bdqE3t7eYSnHzeaqq67Cli1b8LGPfUwfmz17Nm666SYsX74c119/PdatW4f3vve92Lx5cxMtzWfq1KlYtmwZfvKTn+AnP/kJdt99d8ydOxdr1qwBMDz1TbN47bXX8Itf/CJzH7VKHtXb/231Z1K7UWi2AUw+Z599Np588skRnXM7FF5++WWcc845uP/++1tiTY9GiOMYRxxxBP7rv/4LAHDooYfiySefxLJly7Bo0aImW1edO+64A7fccgtuvfVWzJw5U89RnzZtWsvbPhopl8v42Mc+BiLC9ddf32xzqvLoo4/iG9/4BtasWQMhRLPNaYg4jgEAJ554Ij73uc8BSN7oPfTQQ1i2bBnmzJnTTPNqct111+Hhhx/Gvffei+nTp+O3v/0tzj777EyHlGGYkeHyyy/H7bffjlWrVlltmJNPPll/nzVrFg466CDsvffeWLVqFd7//vc3w9Rcjj76aBx99NH69zHHHIN3vetd+Pa3v41LL720iZYNDzfccANmzZqFo446yjreTnk02rn11ltx8cUX45577rHW3zFHrx900EGYPXs2pk+fjjvuuAOf/OQnm2FqVWbMmIEZM2bo38cccwyef/55XHPNNfif//mfJlo2dG6++WbsuOOOOOmkk6zjrZJH7db/HS3wSKEWZfHixfjZz36GlStXYrfddmu2OXXx6KOPYsOGDTjssMNQKBRQKBTwwAMP4Jvf/CYKhUJLvrFRTJ06FQcccIB17F3veldbDG0977zz9GihWbNm4fTTT8fnPve5thutNWXKFADAG2+8YR1/44039LlWRwlCL774Iu6///6WHyX0u9/9Dhs2bMAee+yh79kXX3wRn//85/HOd76z2eZVZeLEiSgUCm153/b29uLLX/4yvv71r+PDH/4wDjroICxevBgLFy7EVVdd1WzzmA5g4sSJCMOwofp2ypQpVd03uw4fTJwUV111FS6//HL86le/qrlBxl577YWJEyfiueeeG7LN1RhKfBRq9LCytZ3zaOvWrbj99tvr6pyOVB4Nhrz7aPz48ejp6RmWfG8Wt99+O84880zccccdNV9u7Ljjjthvv/1aMo/yOOqoo7S97ZpPRIQbb7wRp59+OkqlUlW3zcijRvq/rf5MajdYFGoxiAiLFy/GXXfdhd/85jfYc889m21S3bz//e/HE088gccff1x/jjjiCJx66ql4/PHHEYZhs03M5T3veU9m68O//OUvmbm2rci2bdsQBPatHIahHknRLuy5556YMmUKVqxYoY9t2rQJf/jDH6w3n62KEoTWrl2LX//613jHO97RbJNqcvrpp+NPf/qTdc9OmzYN5513XmY72VajVCrhyCOPbMv7tlwuo1wuj4r7lmlPSqUSDj/8cKu+jeMYK1asyK1vjz76aMs9ANx///3afbPr8MHECUh2p7n00kuxfPlyHHHEETXDeeWVV/Dmm29i6tSpw2J3HoONj0kURXjiiSe0re2aR0Cy9XR/fz9OO+20muGMVB4Nhlr30XDkezO47bbbcMYZZ+C2227DggULarrfsmULnn/++ZbMozwef/xxbW+75tMDDzyA5557ri5xdSTzaDD931Z/JrUdTV3mmslw1lln0YQJE2jVqlX0+uuv68+2bduabdqgaJfdxx555BEqFAr0n//5n7R27Vq65ZZbaMyYMfSDH/yg2abVZNGiRbTrrrvSz372M1q3bh3deeedNHHiRPrCF77QbNMybN68mR577DF67LHHCAB9/etfp8cee0zv0HX55ZfTjjvuSPfccw/96U9/ohNPPJH23HNP6u3tbbLl1W0fGBigE044gXbbbTd6/PHHrXu3v7+/Ze320Uq7j9Wy/c4776RisUjf+c53aO3atXTddddRGIb0u9/9rsmW17Z9zpw5NHPmTFq5ciW98MIL9L3vfY+6u7vpv//7v5tsOdMp3H777dTV1UU33XQTPf300/TpT3+adtxxR1q/fj0REZ1++un0xS9+Ubt/8MEHqVAo0FVXXUXPPPMMXXTRRVQsFumJJ57Qbppdhzcap8svv5xKpRL9+Mc/turtzZs3E1FyH//bv/0brV69mtatW0e//vWv6bDDDqN9992X+vr6Wi4+F198Mf3yl7+k559/nh599FE6+eSTqbu7m5566ikrzu2UR4pjjz2WFi5cmDne7DyqVdd/8YtfpNNPP127f+GFF2jMmDF03nnn0TPPPENLly6lMAxp+fLl2k2tNGq1ON1yyy1UKBRo6dKl1n20ceNG7ebzn/88rVq1itatW0cPPvggzZs3jyZOnEgbNmxoyThdc801dPfdd9PatWvpiSeeoHPOOYeCIKBf//rX2k0z86nR+ChOO+00mj17ttfPZuZRPf3fdnwmtRMsCrUYALyf733ve802bVC0iyhERPTTn/6UDjzwQOrq6qL999+fvvOd7zTbpLrYtGkTnXPOObTHHntQd3c37bXXXvSVr3yl6WKED7XFp/tZtGgRESXbR15wwQU0efJk6urqove///307LPPNtdoSTXb161bl3vvrly5smXt9tFKolA9tt9www20zz77UHd3Nx188MF09913N89gg1q2v/766/SJT3yCpk2bRt3d3TRjxgy6+uqrKY7j5hrOdBTXXXcd7bHHHlQqleioo46ihx9+WJ+bM2dOpp644447aL/99qNSqUQzZ86kn//859b5VqjDG4nT9OnTvffpRRddRERE27Zto+OOO4522WUXKhaLNH36dPrUpz41Yp3zRuOzZMkS7Xby5Mn0j//4j7RmzRrLv3bLIyKiP//5zwSAfvWrX2X8anYe1arrFy1aRHPmzMlcc8ghh1CpVKK99trL28avlkbbm0bjNGfOnJrP6oULF9LUqVOpVCrRrrvuSgsXLqTnnnuuZeN0xRVX0N57703d3d20884709y5c+k3v/lNxt9m5dNgyt3GjRupp6cnt3/TzDyqp//brs+kdkEQETU4uIhhGIZhGIZhGIZhGIZpc3hNIYZhGIZhGIZhGIZhmA6ERSGGYRiGYRiGYRiGYZgOhEUhhmEYhmEYhmEYhmGYDoRFIYZhGIZhGIZhGIZhmA6ERSGGYRiGYRiGYRiGYZgOhEUhhmEYhmEYhmEYhmGYDoRFIYZhGIZhGIZhGIZhmA6ERSGGYRiGYRiGYRiGYZgOhEUhhmEYhmEYhmGY7cjcuXOxZMmSZpvBMAyTgUUhhmEYhmEYhmEYhmGYDoRFIYZhGmZgYKDZJjAMwzAMwzAMwzBDhEUhhmFqMnfuXCxevBhLlizBxIkTMX/+/GabxDAMwzAM07b8/Oc/x4QJE3DLLbc02xSGYTqcQrMNYBimPbj55ptx1lln4cEHH2y2KQzDMAzDMG3Lrbfeis985jO49dZb8aEPfajZ5jAM0+GwKMQwTF3su+++uPLKK5ttBsMwDMMwTNuydOlSfOUrX8FPf/pTzJkzp9nmMAzDsCjEMEx9HH744c02gWEYhmEYpm358Y9/jA0bNuDBBx/EkUce2WxzGIZhAPCaQgzD1MnYsWObbQLDMAzDMEzbcuihh2KXXXbBjTfeCCJqtjkMwzAAWBRiGIZhGIZhGIbZ7uy9995YuXIl7rnnHvzrv/5rs81hGIYBwNPHGIZhGIZhGIZhRoT99tsPK1euxNy5c1EoFHDttdc22ySGYTocFoUYhmEYhmEYhmFGiBkzZuA3v/kN5s6dizAMcfXVVzfbJIZhOhhBPKGVYRiGYRiGYRiGYRim4+A1hRiGYRiGYRiGYRiGYToQFoUYhmEYhmEYhmEYhmE6EBaFGIZhGIZhGIZhGIZhOhAWhRiGYRiGYRiGYRiGYToQFoUYhmEYhmEYhmEYhmE6EBaFGIZhGIZhGIZhGIZhOhAWhRiGYRiGYRiGYRiGYToQFoUYhmEYhmEYhmEYhmE6EBaFGIZhGIZhGIZhGIZhOhAWhRiGYRiGYRiGYRiGYToQFoUYhmEYhmEYhmEYhmE6EBaFGIZhGIZhGIZhGIZhOpD/D+Y088nbgKEUAAAAAElFTkSuQmCC", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABIEAAAG4CAYAAADSe/cDAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsvXm8XEWZPv7UvQlJWBIIkITIFllld1AgCgYRzEQGCaAILhBAGWUbiKjwHdkUDbiGUZZxdAigDAMoKKigyDYqoICouCD4A0FkUZSEBLLdrt8ffaq6lvet5ZzT3Tf3nufz6Xu7q+pdaq/3PVV1hJRSokGDBg0aNGjQoEGDBg0aNGjQoMGIxkC/FWjQoEGDBg0aNGjQoEGDBg0aNGjQfTROoAYNGjRo0KBBgwYNGjRo0KBBg1GAxgnUoEGDBg0aNGjQoEGDBg0aNGgwCtA4gRo0aNCgQYMGDRo0aNCgQYMGDUYBGidQgwYNGjRo0KBBgwYNGjRo0KDBKEDjBGrQoEGDBg0aNGjQoEGDBg0aNBgFaJxADRo0aNCgQYMGDRo0aNCgQYMGowCNE6hBgwYNGjRo0KBBgwYNGjRo0GAUoHECNWjQoEGDBg0aNGjQoEGDBg0ajAI0TqAGDbqMc889F0II/O1vf+u3KtmYN28ettxyy2i6fffdF/vuu2/X9WnQoEGDBqMHo2H+zMFVV12F7bffHmPHjsX6669fK++quPPOOyGEwJ133tk1GU888QSEEPjc5z4XTavazkiGEALnnntuv9VYI9CN/thvLF26FO9///sxbdo0CCFw6qmn9lulBmsQGidQgwYNRiWEEFi0aFG/1WjQoEGDBg2i+P3vf4958+Zhq622wn/913/hK1/5Cl5++WWce+65XXW8NGhj0aJFEEKQnzPOOKPf6nUVbn7XWWcd7LDDDjj//PPx8ssv91u9WnHJJZesMWvDT3/601i0aBE+9KEP4aqrrsL73ve+fqvUYA3CmH4r0KBBgzUfP/jBD/qtQoMGDRo0aDBiceedd6LVauGiiy7C1ltvDQD429/+hvPOOw8Amt24PcInPvEJzJgxwwrbaaed+qLLK6+8gjFjemPKHXDAATjqqKMAtHeg/N///R/OOuss/PKXv8R1113XEx16gUsuuQQbbbQR5s2b129Vorj99tux11574Zxzzum3Kg3WQDROoAYN1nCsXr0arVYLa621Vt906IXsZcuWYZ111qnEo9VqYeXKlRg/fnxNWjVo0KBBgzUVw2H+TMXzzz8PAD05BlbHfDtSMWfOHLzuda/rm3xzHVPnWmb58uVYa621MDBAHxLZdttt8d73vlf//uAHP4iVK1fiW9/6FpYvXz4q11X97ifPP/88dthhh9r4rUnjYYPqaI6DNWjQB/zpT3/C1ltvjZ122gnPPfccAODFF1/Eqaeeis022wzjxo3D1ltvjQsvvBCtVkvTmefhFy5ciK222grjxo3Db3/7W33+/bHHHsO8efOw/vrrY9KkSTjmmGPI7bpf//rXsfvuu2PChAmYPHkyjjjiCDz11FOl8uPeCaTuBrj22mvxqU99CptuuinGjx+Pt7zlLXjsscei/FRefvvb3+Ld7343NthgA+y9997ZegkhcNJJJ+Eb3/gGdtxxR4wbNw633HJLNp8GDRo0aDA8MNLmz29/+9s48MADMX36dIwbNw5bbbUVPvnJT2JoaEin2XLLLfXT/o033hhCCMybNw8bb7wxAOC8887TR3XMO2J+//vf4x3veAcmT56M8ePH43Wvex2+853vWPLVMae77roLJ5xwAqZMmYJNN900qPOf//xnzJ07F+ussw6mTJmC0047DStWrCDTXnfddbqsNtpoI7z3ve/F008/baXh7hUM3ePyxS9+EVtssQUmTJiAWbNm4eGHHw7qrFBn3VG4/fbbsc8++2CdddbB+uuvj4MPPhi/+93vrDRcvqh7jELrGOpOoKeffhrHHnsspk6dinHjxmHHHXfEf//3f1tp1Brtmmuuwcc//nG86lWvwtprr40lS5Zk5VXdRePuRrrvvvvwz//8z5g0aRLWXnttzJo1Cz/5yU+sNC+99BJOPfVUbLnllhg3bhymTJmCAw44AA8++KBO8+ijj+Kwww7DtGnTMH78eGy66aY44ogjsHjxYotXXXW65ZZb4je/+Q3uuusu3Z9Uuwz1kz/96U844YQTsN1222HChAnYcMMN8c53vhNPPPGExV/x+MlPfoL58+dj4403xjrrrINDDjkEf/3rX620999/P2bPno2NNtoIEyZMwIwZM3DssccC6NTf448/ju9+97taVyXv+eefx3HHHYepU6di/Pjx2HXXXXHFFVdY/FPGwz/84Q9473vfi0mTJmHjjTfGWWedBSklnnrqKRx88MGYOHEipk2bhs9//vPZZd2g/2h2AjVo0GP88Y9/xH777YfJkyfjhz/8ITbaaCO8/PLLmDVrFp5++mn867/+KzbffHP89Kc/xZlnnolnnnkGCxcutHhcfvnlWL58OY4//niMGzcOkydP1nGHH344ZsyYgQULFuDBBx/EV7/6VUyZMgUXXnihTvOpT30KZ511Fg4//HC8//3vx1//+ld86Utfwpve9Cb84he/qO1J4wUXXICBgQGcfvrpWLx4MT7zmc/gPe95D+67774k+ne+853YZptt8OlPfxpSylI63H777bj22mtx0kknYaONNhpxFwM2aNCgwWjBSJw/Fy1ahHXXXRfz58/Huuuui9tvvx1nn302lixZgs9+9rMAgIULF+LKK6/EDTfcgEsvvRTrrrsudt55Z+y111740Ic+hEMOOQSHHnooAGCXXXYBAPzmN7/BG9/4RrzqVa/CGWecgXXWWQfXXnst5s6di29+85s45JBDLD1OOOEEbLzxxjj77LOxbNkyVt9XXnkFb3nLW/Dkk0/ilFNOwfTp03HVVVfh9ttvJ/N2zDHH4PWvfz0WLFiA5557DhdddBF+8pOfVFprXHnllXjppZdw4oknYvny5bjooouw33774de//jWmTp3K0tVRd4sXL/YuKt9oo40AALfddhvmzJmDV7/61Tj33HPxyiuv4Etf+hLe+MY34sEHHyy9/khdxzz33HPYa6+9tONo4403xve//30cd9xxWLJkiXdx8Cc/+UmstdZaOP3007FixYrgDpDly5frfC9btgw/+clPcMUVV+Dd73635QS6/fbbMWfOHOy+++4455xzMDAwgMsvvxz77bcf/u///g977LEHgPZOouuvvx4nnXQSdthhB7zwwgv48Y9/jN/97nf4p3/6J6xcuRKzZ8/GihUrcPLJJ2PatGl4+umncfPNN+PFF1/EpEmTANTbHxcuXIiTTz4Z6667Lv793/8dALz2RPWTn//85/jpT3+KI444AptuuimeeOIJXHrppdh3333x29/+FmuvvbbF4+STT8YGG2yAc845B0888QQWLlyIk046Cf/7v/8LoO3Eeetb34qNN94YZ5xxBtZff3088cQT+Na3vgUAeM1rXoOrrroKp512GjbddFN8+MMfBtB2EL/yyivYd9998dhjj+Gkk07CjBkzcN1112HevHl48cUX8W//9m+WLqHx8F3vehde85rX4IILLsB3v/tdnH/++Zg8eTL+8z//E/vttx8uvPBCfOMb38Dpp5+O17/+9XjTm96UXNYNhgFkgwYNuopzzjlHApB//etf5e9+9zs5ffp0+frXv17+/e9/12k++clPynXWWUf+4Q9/sGjPOOMMOTg4KJ988kkppZSPP/64BCAnTpwon3/+eVLOsccea4UfcsghcsMNN9S/n3jiCTk4OCg/9alPWel+/etfyzFjxljhRx99tNxiiy2ieZw1a5acNWuW/n3HHXdIAPI1r3mNXLFihQ6/6KKLJAD561//OshP5eXII4+Myg4BgBwYGJC/+c1vKvFp0KBBgwa9x2iYP19++WUv7F//9V/l2muvLZcvX06WhcJf//pXCUCec845Ho+3vOUtcuedd7Z4tFot+YY3vEFus802Ouzyyy+XAOTee+8tV69eHdV34cKFEoC89tprddiyZcvk1ltvLQHIO+64Q0op5cqVK+WUKVPkTjvtJF955RWd9uabb5YA5Nlnn63D3DWEgluGqg4nTJgg//znP+vw++67TwKQp512mg5T5aWQU3cUVDlRH4XddttNTpkyRb7wwgs67Je//KUcGBiQRx11FJsvTmcpw+sYt+6PO+44uckmm8i//e1vVrojjjhCTpo0Sbc1tUZ79atfTbY/Sg71mTt3rte+ttlmGzl79mzZarV0+MsvvyxnzJghDzjgAB02adIkeeKJJ7Iyf/GLX0gA8rrrrmPTdKM/7rjjjmRbDPUTqgzvueceCUBeeeWVHo/999/fKp/TTjtNDg4OyhdffFFKKeUNN9wgAcif//znQV232GILeeCBB1phqn9+/etf12ErV66UM2fOlOuuu65csmSJlDJtPDz++ON12OrVq+Wmm24qhRDyggsu0OH/+Mc/5IQJE+TRRx8d1LXB8ENzHKxBgx7h4YcfxqxZs7DlllvitttuwwYbbKDjrrvuOuyzzz7YYIMN8Le//U1/9t9/fwwNDeHuu++2eB122GF6G7iLD37wg9bvffbZBy+88ILe5vutb30LrVYLhx9+uCVr2rRp2GabbXDHHXfUludjjjnGerK0zz77AAD+v//v/0uid/NSBrNmzar1zHSDBg0aNOgtRvL8OWHCBP39pZdewt/+9jfss88+ePnll/H73/8+mx8A/P3vf8ftt9+Oww8/XPP829/+hhdeeAGzZ8/Go48+6h3J+sAHPoDBwcEo7+9973vYZJNN8I53vEOHrb322jj++OOtdPfffz+ef/55nHDCCdZ9MQceeCC23357fPe73y2VNwCYO3cuXvWqV+nfe+yxB/bcc09873vfY2nqqruLL74YP/zhD60PADzzzDN46KGHMG/ePGs3xS677IIDDjggqFsMKesYKSW++c1v4qCDDoKU0srj7NmzsXjxYuuoFQAcffTRVvsL4eCDD9b5/fa3v40zzzwTt9xyC9797nfrndoPPfQQHn30Ubz73e/GCy+8oOUvW7YMb3nLW3D33XfrI5rrr78+7rvvPvzlL38h5amdPrfeeiv7BrJermcVqH5iluGqVavwwgsvYOutt8b666/vlTkAHH/88daxv3322QdDQ0P405/+BKBz79fNN9+MVatWZen3ve99D9OmTcORRx6pw8aOHYtTTjkFS5cuxV133WWlD42H73//+/X3wcFBvO51r4OUEscdd5wOX3/99bHddtslr+sbDB80x8EaNOgRDjroIEydOhW33nor1l13XSvu0Ucfxa9+9St2IFYXQiq4b6Ywsfnmm1u/1WL5H//4ByZOnIhHH30UUkpss802JP3YsWOjeUlFSJcUhPKZijp4NGjQoEGD/mEkz5+/+c1v8PGPfxy33367dyeLe/dJKh577DFIKXHWWWfhrLPOItM8//zzliMlda5UdzK5d9dst912XjoqHAC23357/PjHP06SR4Eq/2233RbXXnstS1NX3e2xxx7kxdCh/L7mNa/BrbfeWvoi4ZS6+etf/4oXX3wRX/nKV/CVr3yFTBPqC0NDQ969NJMnT9YP8jbddFPsv//+Ou7tb387NtxwQ5x++um4+eabcdBBB+HRRx8F0HYucVi8eDE22GADfOYzn8HRRx+NzTbbDLvvvjve9ra34aijjsKrX/1qrdv8+fPxhS98Ad/4xjewzz774O1vf7u+owaor05zQNXFK6+8ggULFuDyyy/H008/bV1fQPXh2Np41qxZOOyww3Deeefhi1/8Ivbdd1/MnTsX7373uzFu3Ligfn/605+wzTbbeBd8v+Y1r9Hxsfxwek6aNAnjx4/Xxx/N8BdeeCGoV4Phh8YJ1KBBj3DYYYfhiiuuwDe+8Q3867/+qxXXarVwwAEH4KMf/ShJu+2221q/Q09uuCd5alJqtVoQQuD73/8+mdZdYFdBTJcYUp9QdZtHgwYNGjToH0bq/Pniiy9i1qxZmDhxIj7xiU9gq622wvjx4/Hggw/iYx/7mHWxdQ4U3emnn47Zs2eTadRr5hX6OVcKIch1gXk5dlX0cu0Tg+tAU+Dym1I3qs7f+973sk4YdV8Uxfepp57yHAJ33HEHeWG3wlve8hYAwN13342DDjpI6/DZz34Wu+22G0mjyvnwww/HPvvsgxtuuAE/+MEP8NnPfhYXXnghvvWtb2HOnDkAgM9//vOYN28evv3tb+MHP/gBTjnlFCxYsAD33nsvNt10077UKVUXJ598Mi6//HKceuqpmDlzJiZNmgQhBI444giyD8fGGSEErr/+etx777246aabcOutt+LYY4/F5z//edx777215it3PKy6rm8wfNA4gRo06BE++9nPYsyYMTjhhBOw3nrr4d3vfreO22qrrbB06VLrKUu3sNVWW0FKiRkzZniL4wYNGjRo0GC4YaTOn3feeSdeeOEFfOtb37IuVX388ceT6DlngtpNMXbs2NrLZYsttsDDDz8MKaUl/5FHHvHSqfD99tvPinvkkUd0PNDeCUEdJ3F3LSioHScm/vCHPwQvXu722sfMr4vf//732GijjfQuoA022AAvvviil47Lbwo23nhjrLfeehgaGipV59OmTdNH2xR23XXXIM3q1asBAEuXLgXQLmMAmDhxYpIOm2yyCU444QSccMIJeP755/FP//RP+NSnPqWdQACw8847Y+edd8bHP/5x/PSnP8Ub3/hGXHbZZTj//PO7Uqdcnwrh+uuvx9FHH229JWv58uVkHedgr732wl577YVPfepTuPrqq/Ge97wH11xzjXVMy8UWW2yBX/3qV2i1WtZuIHW01Ox3DUY3mjuBGjToEYQQ+MpXvoJ3vOMdOProo63XtB5++OG45557cOutt3p0L774op5o68Chhx6KwcFBnHfeeZ7nXkrZbOls0KBBgwbDCiN1/lRP1U1eK1euxCWXXJJEr9465BqbU6ZMwb777ov//M//xDPPPOPRucd+cvC2t70Nf/nLX3D99dfrsJdfftk7gvS6170OU6ZMwWWXXWa9Pv773/8+fve73+HAAw/UYVtttRV+//vfW3r98pe/9F4rrnDjjTdadxr97Gc/w3333Wc5D1x0e+2zySabYLfddsMVV1xh1cfDDz+MH/zgB3jb296mw7baaissXrwYv/rVr3TYM888gxtuuKG0/MHBQRx22GH45je/iYcfftiLj9X5+PHjsf/++1sf8+4tCjfddBOAjrNo9913x1ZbbYXPfe5z2jFE6TA0NOQdk5oyZQqmT5+u28qSJUu8vrvzzjtjYGBAp+lGna6zzjrZzpvBwUFP/pe+9KXSO9n+8Y9/ePzUziqzL1F429vehmeffVa/aQxoO+u+9KUvYd1118WsWbNK6dRg5KHZCdSgQQ8xMDCAr3/965g7dy4OP/xwfO9738N+++2Hj3zkI/jOd76Df/mXf8G8efOw++67Y9myZfj1r3+N66+/Hk888YR3BrcsttpqK5x//vk488wz8cQTT2Du3LlYb7318Pjjj+OGG27A8ccfj9NPP70WWd3AE088gRkzZuDoo4/GokWL+q1OgwYNGjToAUbi/PmGN7wBG2ywAY4++miccsopEELgqquuyjoyvcMOO+B///d/se2222Ly5MnYaaedsNNOO+Hiiy/G3nvvjZ133hkf+MAH8OpXvxrPPfcc7rnnHvz5z3/GL3/5y1Jl8IEPfABf/vKXcdRRR+GBBx7AJptsgquuusp7DfbYsWNx4YUX4phjjsGsWbNw5JFH6lfEb7nlljjttNN02mOPPRZf+MIXMHv2bBx33HF4/vnncdlll2HHHXf07kkC2kfZ9t57b3zoQx/CihUrsHDhQmy44YbskUCgN2ufz372s5gzZw5mzpyJ4447Tr8iftKkSTj33HN1uiOOOAIf+9jHcMghh+CUU07Byy+/jEsvvRTbbrsteZFwKi644ALccccd2HPPPfGBD3wAO+ywA/7+97/jwQcfxG233Ya///3vpXn/4Q9/wNe//nUAbaffvffeiyuuuAJbb7013ve+9wFo99GvfvWrmDNnDnbccUccc8wxeNWrXoWnn34ad9xxByZOnIibbroJL730EjbddFO84x3vwK677op1110Xt912G37+85/r3TS33347TjrpJLzzne/Etttui9WrV+Oqq67Szi6gO3W6++6749JLL8X555+PrbfeGlOmTPF2srn4l3/5F1x11VWYNGkSdthhB9xzzz247bbbsOGGG+YWMwDgiiuuwCWXXIJDDjkEW221FV566SX813/9FyZOnGg5Eykcf/zx+M///E/MmzcPDzzwALbccktcf/31+MlPfoKFCxdivfXWK6VTg5GHxgnUoEGPMXbsWFx//fWYM2cODj74YNx2223Yc889cdddd+HTn/40rrvuOlx55ZWYOHEitt12W5x33nn6Ery6cMYZZ2DbbbfFF7/4RZx33nkAgM022wxvfetb8fa3v71WWXVDPV3aZJNN+qxJgwYNGjToJUba/Lnhhhvi5ptvxoc//GF8/OMfxwYbbID3vve9eMtb3sLe5ePiq1/9Kk4++WScdtppWLlyJc455xzstNNO2GGHHXD//ffjvPPOw6JFi/DCCy9gypQpeO1rX4uzzz47O98Ka6+9Nn70ox/h5JNPxpe+9CWsvfbaeM973oM5c+bgn//5n6208+bNw9prr40LLrgAH/vYx7DOOuvgkEMOwYUXXqjfgAS0L6298sorcfbZZ2P+/PnYYYcdcNVVV+Hqq6/GnXfe6elw1FFHYWBgAAsXLsTzzz+PPfbYA1/+8pej64Jur332339/3HLLLTjnnHNw9tlnY+zYsZg1axYuvPBC676dDTfcEDfccAPmz5+Pj370o5gxYwYWLFiARx99tJITaOrUqfjZz36GT3ziE/jWt76FSy65BBtuuCF23HFHXHjhhZXyZr4JbXBwEJtssgne//7345Of/KR12fW+++6Le+65B5/85Cfx5S9/GUuXLsW0adOw55576vu81l57bZxwwgn4wQ9+oN/wtfXWW+OSSy7Bhz70IQDt3UWzZ8/GTTfdhKeffhprr702dt11V3z/+9/HXnvtpeXVXadnn302/vSnP+Ezn/kMXnrpJcyaNSvqBLroooswODiIb3zjG1i+fDne+MY34rbbbkvuwy5mzZqFn/3sZ7jmmmvw3HPPYdKkSdhjjz3wjW98I3pJ+IQJE3DnnXfijDPOwBVXXIElS5Zgu+22w+WXX4558+aV0qfByISQzU1ODRo0WINwySWX4KMf/Sj++Mc/YurUqf1Wp0GDBg0aNGjQoEGDBg3WGDR3AjVo0GCNwh133IFTTjmlcQA1aNCgQYMGDRo0aNCgQSaanUANGjRo0KBBgwYNGjRo0KBBgwajAM1OoAYNGjRo0KBBgwYNGjRo0KBBg1GAvjqB7r77bhx00EGYPn06hBC48cYbrfilS5fipJNOwqabbqrfgHDZZZf1R9kGDRo0aNCgQYMuYcGCBXj961+P9dZbD1OmTMHcuXPxyCOPROmuu+46bL/99hg/fjx23nlnfO9737PipZQ4++yzsckmm2DChAnYf//98eijj3YrGw0aNGjQoEGDYY6+OoGWLVuGXXfdFRdffDEZP3/+fNxyyy34+te/jt/97nc49dRTcdJJJ+E73/lOjzVt0KBBgwYNGjToHu666y6ceOKJuPfee/HDH/4Qq1atwlvf+lYsW7aMpfnpT3+KI488Escddxx+8YtfYO7cuZg7dy4efvhhneYzn/kM/uM//gOXXXYZ7rvvPqyzzjqYPXs2li9f3otsNWjQoEGDBg2GGYbNnUBCCNxwww2YO3euDttpp53wrne9C2eddZYO23333TFnzhycf/75fdCyQYMGDRo0aNCg+/jrX/+KKVOm4K677sKb3vQmMs273vUuLFu2DDfffLMO22uvvbDbbrvhsssug5QS06dPx4c//GGcfvrpAIDFixdj6tSpWLRoEY444oie5KVBgwYNGjRoMHwwpt8KhPCGN7wB3/nOd3Dsscdi+vTpuPPOO/GHP/wBX/ziF1maFStWYMWKFfp3q9XC3//+d2y44YYQQvRC7QYNGjRo0CAIKSVeeuklTJ8+HQMDzfV8DXwsXrwYADB58mQ2zT333IP58+dbYbNnz9bH6x9//HE8++yz2H///XX8pEmTsOeee+Kee+4hnUDNOqpBgwYNGgx3NOuoahjWTqAvfelLOP7447HppptizJgxGBgYwH/913+xT8SA9pn68847r4daNmjQoEGDBuXw1FNPYdNNN+23Gg2GGVqtFk499VS88Y1vxE477cSme/bZZzF16lQrbOrUqXj22Wd1vArj0rho1lENGjRo0GBNQbOOKodh7wS699578Z3vfAdbbLEF7r77bpx44omYPn269VTLxJlnnmk9FVu8eDE233xzvPa/T8ALL0+BXDEIjG1hcNxqDAy2AAkMDQ2itWIQWDUADBWEgwAGJTC2BTEgAQHIFoChAWBIAKsFREtAtAAUB+qkADAASCHb9AWdhko7JCCkgBgC0BIQssMDQFuWaNPLAfW74KX4FTRCFgQtQLQA0RJOnMMTKHh2eGv+LiQg4PAz9NUk6n+RFKocUORB6a3kwykXAEIrV/BuFeEqP1ofQk0nXzqvIZkqb8ZvnSfZZtr57svV+VT8BSEbZrz0GAg4eTbkAYnyi/+m/E5ZuOXU0UFYDOL5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d9yBd73rXdhll12w4447YuHChfje977nhPnMZz6TKacDDzxwFFPhom6a1q9fH6x7mzZtcsKNp3IKPStKKcybN8+G6WY5ter/joe+qVchJFCP4f7778eyZcvw4IMP4t5778Xw8DBOOOEEbN26tdum1cJPf/pT/OM//iMOOeSQbptSCX/+85/xtre9Df39/fjnf/5n/OIXv8CVV16J6dOnd9u0UqxatQrXX389/uEf/gFPPvkkVq1ahcsvvxzXXnttt00LYuvWrTj00ENx3XXXBe9ffvnl+PznP4/Vq1fjJz/5CbbffnssXrwYb7zxxhhbmkWR7a+99hoeeeQRXHjhhXjkkUdwxx134KmnnsJJJ53UBUuzKMt3gzvvvBMPPvgg5syZM0aWlaPM9meeeQbHHnssDjzwQKxfvx6PP/44Lrzwwp44ArvM9nPPPRdr1qzBV77yFTz55JNYsWIFli9fjm9+85tjbKlgsuBrX/sazj33XFx88cV45JFHcOihh2Lx4sV48cUXg+F//OMf47TTTsOHPvQhPProo1i6dCmWLl2KJ554wobpdrtdN03r16/HaaedhnXr1mHDhg3YY489cMIJJ+D3v/+9E27JkiX44x//aD9f/epXxyI5AOqnCQB23HFHx97f/e53zv1ullPd9Nxxxx1OWp544gk0Go3MSXjdLKOq/arBxo0bceKJJ+Id73gHHnvsMaxYsQIf/vCHHdKklXLvJOqm6Qc/+AHe9a534bvf/S4efvhhvOMd78B73vMePProo064efPmOeX0ox/9aDTMD6Jumgyeeuopx+aZM2fae+OtnD73uc85aXnuueew8847Z56nbpVTK/7veOibehok6Gm8+OKLBIDuv//+bptSGa+++irtt99+dO+999Jxxx1H55xzTrdNKsX5559Pxx57bLfNaAknnngi/Zf/8l+ca3/1V39F73//+7tkUXUAoDvvvNP+juOYZs2aRX//939vr7388ss0ZcoU+upXv9oFC/Ph2x7CQw89RADod7/73dgYVRF5tj///PO022670RNPPEFz586lq6++esxtK0PI9lNOOYU+8IEPdMegGgjZPm/ePPrsZz/rXDv88MPpU5/61BhaJphMOProo2nZsmX2d7PZpDlz5tDKlSuD4d/3vvfRiSee6FxbsGAB/df/+l+JqDfa7bpp8jEyMkI77LAD3XzzzfbaGWecQSeffHKnTa2Mumm68cYbadq0abnyul1O7ZbR1VdfTTvssANt2bLFXut2GXFUGRN84hOfoHnz5jnXTjnlFFq8eLH93W4+dRJV0hTCQQcdRJdccon9ffHFF9Ohhx7aOcPaQJU0rVu3jgDQn//859ww472c7rzzTlJK0W9/+1t7rZfKqYr/Ox76pl6GzATqcbzyyisAgJ133rnLllTHsmXLcOKJJ2LRokXdNqUyvvnNb+LII4/Ee9/7XsycORNvfetb8cUvfrHbZlXCMcccg7Vr1+JXv/oVAOD//b//hx/96Ed497vf3WXL6mPjxo3YtGmTU3emTZuGBQsWYMOGDV20rDW88sorUEphp5126rYppYjjGKeffjrOO+88Z3pwryOOY3znO9/B/vvvj8WLF2PmzJlYsGBBpWn5vYBjjjkG3/zmN/H73/8eRIR169bhV7/6FU444YRumyaYgBgaGsLDDz/stLFRFGHRokW5beyGDRsy/fnixYtt+G63262kycdrr72G4eHhzFhr/fr1mDlzJg444ACcffbZeOmllzpqex5aTdOWLVswd+5c7LHHHjj55JPx85//3N7rZjl1ooy+9KUv4dRTT8X222/vXO9WGbWCsmepE/nUbcRxjFdffTXzLD399NOYM2cO9tlnH7z//e/vieXaZTjssMMwe/ZsvOtd78IDDzxgr0+EcvrSl76ERYsWYe7cuc71XimnKv5vr/dNvQ4hgXoYcRxjxYoVeNvb3oaDDz642+ZUwm233YZHHnkEK1eu7LYptfCb3/wG119/Pfbbbz9873vfw9lnn42/+Zu/wc0339xt00pxwQUX4NRTT8WBBx6I/v5+vPWtb8WKFSvw/ve/v9um1YZZb73rrrs613fdddfMWuxexxtvvIHzzz8fp512Gnbcccdum1OKVatWoa+vD3/zN3/TbVNq4cUXX8SWLVtw2WWXYcmSJbjnnnvwH//jf8Rf/dVf4f777++2eaW49tprcdBBB2H33XfHwMAAlixZguuuuw5/8Rd/0W3TBBMQf/rTn9BsNmu1sZs2bSoM3+12u5U0+Tj//PMxZ84cx1lYsmQJvvzlL2Pt2rVYtWoV7r//frz73e9Gs9nsqP0htJKmAw44ADfccAPuvvtufOUrX0EcxzjmmGPw/PPPA+huObVbRg899BCeeOIJfPjDH3aud7OMWkHes7R582a8/vrrHanL3cYVV1yBLVu24H3ve5+9tmDBAtx0001Ys2YNrr/+emzcuBFvf/vb8eqrr3bR0nzMnj0bq1evxje+8Q184xvfwB577IHjjz8ejzzyCIDOtDndxB/+8Af88z//c+Z56pVyqur/9nrf1Ovo67YBgnwsW7YMTzzxxJium20Hzz33HM455xzce++9PbEXRx3EcYwjjzwS/+t//S8AwFvf+lY88cQTWL16Nc4444wuW1eM22+/HbfccgtuvfVWzJs3z64znzNnTs/bPlExPDyM973vfSAiXH/99d02pxQPP/wwPve5z+GRRx6BUqrb5tRCHMcAgJNPPhkf+9jHACRv73784x9j9erVOO6447ppXimuvfZaPPjgg/jmN7+JuXPn4gc/+AGWLVuWcUgFAsHo4LLLLsNtt92G9evXO2OXU0891X6fP38+DjnkEOy7775Yv3493vnOd3bD1EIsXLgQCxcutL+POeYYvOUtb8E//uM/4tJLL+2iZe3jS1/6EubPn4+jjz7auT7eymii49Zbb8Ull1yCu+++29k/h89MP+SQQ7BgwQLMnTsXt99+Oz70oQ91w9RCHHDAATjggAPs72OOOQbPPPMMrr76avzf//t/u2hZZ3DzzTdjp512wtKlS53rvVJO483/Ha+QmUA9iuXLl+Pb3/421q1bh913373b5lTCww8/jBdffBGHH344+vr60NfXh/vvvx+f//zn0dfX17NvZoCE9T/ooIOca295y1vGxXTV8847z84Gmj9/Pk4//XR87GMfG3ezsQBg1qxZAIAXXnjBuf7CCy/Ye70OQwD97ne/w7333jsuZgH98Ic/xIsvvog999zTPru/+93v8PGPfxx77bVXt80rxIwZM9DX1zcun9/XX38df/u3f4urrroK73nPe3DIIYdg+fLlOOWUU3DFFVd02zzBBMSMGTPQaDRqtbGzZs0qDN/tdruVNBlcccUVuOyyy3DPPfeUHmSxzz77YMaMGfj1r3/dts1laCdNBmZmsLG3m+XUTnq2bt2K2267rZITOpZl1ArynqUdd9wRU6dO7Ui5dwu33XYbPvzhD+P2228vfYGx0047Yf/99+/Zcgrh6KOPtvaO53IiItxwww04/fTTMTAwUBi2G+VUx//t9b6p1yEkUI+BiLB8+XLceeeduO+++7D33nt326TKeOc734mf/exneOyxx+znyCOPxPvf/3489thjaDQa3TYxF29729syRxH+6le/yqyV7UW89tpriCL3UW40GnaGxHjC3nvvjVmzZmHt2rX22ubNm/GTn/zEecPZqzAE0NNPP43vf//7eNOb3tRtkyrh9NNPx+OPP+48u3PmzMF5552XOeq11zAwMICjjjpqXD6/w8PDGB4enjDPr6D3MTAwgCOOOMJpY+M4xtq1a3Pb2IULFzrhAeDee++14bvdbreSJiA5NebSSy/FmjVrcOSRR5bqef755/HSSy9h9uzZHbG7CK2miaPZbOJnP/uZtbeb5dROer7+9a9j27Zt+MAHPlCqZyzLqBWUPUudKPdu4Ktf/SrOOussfPWrX8WJJ55YGn7Lli145plneracQnjsscesveO1nIDkFK5f//rXlUjVsSynVvzfXu+beh5d3ZZakMHZZ59N06ZNo/Xr19Mf//hH+3nttde6bVpLGC+ngz300EPU19dH//N//k96+umn6ZZbbqHtttuOvvKVr3TbtFKcccYZtNtuu9G3v/1t2rhxI91xxx00Y8YM+sQnPtFt04J49dVX6dFHH6VHH32UANBVV11Fjz76qD1B67LLLqOddtqJ7r77bnr88cfp5JNPpr333ptef/31LltebPvQ0BCddNJJtPvuu9Njjz3mPL/btm3rtuml+e6jl04HK7P9jjvuoP7+fvrCF75ATz/9NF177bXUaDTohz/8YZctL7f9uOOOo3nz5tG6devoN7/5Dd144400ODhI//t//+8uWy6YqLjttttoypQpdNNNN9EvfvEL+uhHP0o77bQTbdq0iYiITj/9dLrgggts+AceeID6+vroiiuuoCeffJIuvvhi6u/vp5/97Gc2TLfb7bppuuyyy2hgYID+6Z/+yWmrX331VSJKntv/8T/+B23YsIE2btxI3//+9+nwww+n/fbbj954442eTNMll1xC3/ve9+iZZ56hhx9+mE499VQaHBykn//85066u1VOddNjcOyxx9Ipp5ySud4LZVTWvl9wwQV0+umn2/C/+c1vaLvttqPzzjuPnnzySbruuuuo0WjQmjVrbJiyfOq1NN1yyy3U19dH1113nfMsvfzyyzbMxz/+cVq/fj1t3LiRHnjgAVq0aBHNmDGDXnzxxZ5M09VXX0133XUXPf300/Szn/2MzjnnHIqiiL7//e/bMOOtnAw+8IEP0IIFC4Iyu1lOVfzf8dg39TKEBOoxAAh+brzxxm6b1hLGCwlERPStb32LDj74YJoyZQodeOCB9IUvfKHbJlXC5s2b6ZxzzqE999yTBgcHaZ999qFPfepTPUE8hGCO3vQ/Z5xxBhElRzpeeOGFtOuuu9KUKVPone98Jz311FPdNVqjyPaNGzfmPr/r1q3rtuml+e6jl0igKrZ/6Utfoje/+c00ODhIhx56KN11113dM5ihzPY//vGPdOaZZ9KcOXNocHCQDjjgALryyispjuPuGi6Y0Lj22mtpzz33pIGBATr66KPpwQcftPeOO+64TLtw++230/77708DAwM0b948+s53vuPc74V2u06a5s6dG3wuL774YiIieu211+iEE06gXXbZhfr7+2nu3Ln0kY98ZMwcvFbStGLFCht21113pf/wH/4DPfLII468bpdT3Xr3y1/+kgDQPffck5HVC2VU1r6fccYZdNxxx2XiHHbYYTQwMED77LNPcHxflE+jjbppOu6440r751NOOYVmz55NAwMDtNtuu9Epp5xCv/71r3s2TatWraJ9992XBgcHaeedd6bjjz+e7rvvvozc8VRORMnx6FOnTs31b7pZTlX83/HaN/UqFBFRzclDAoFAIBAIBAKBQCAQCASCcQbZE0ggEAgEAoFAIBAIBAKBYBJASCCBQCAQCAQCgUAgEAgEgkkAIYEEAoFAIBAIBAKBQCAQCCYBhAQSCAQCgUAgEAgEAoFAIJgEEBJIIBAIBAKBQCAQCAQCgWASQEgggUAgEAgEAoFAIBAIBIJJACGBBAKBQCAQCAQCgUAgEAgmAYQEEggEAoFAIBAIBAKBQCCYBBASSCAQCAQCgUAgEAhGCccffzxWrFjRbTMEAoEAgJBAAoFAIBAIBAKBQCAQCASTAkICCQSCljA0NNRtEwQCgUAgEAgEAoFAUANCAgkEgko4/vjjsXz5cqxYsQIzZszA4sWLu22SQCAQCAQCwbjDd77zHUybNg233HJLt00RCASTEH3dNkAgEIwf3HzzzTj77LPxwAMPdNsUgUAgEAgEgnGHW2+9FX/913+NW2+9FX/5l3/ZbXMEAsEkhJBAAoGgMvbbbz9cfvnl3TZDIBAIBAKBYNzhuuuuw6c+9Sl861vfwnHHHddtcwQCwSSFkEACgaAyjjjiiG6bIBAIBAKBQDDu8E//9E948cUX8cADD+Coo47qtjkCgWASQ/YEEggElbH99tt32wSBQCAQCASCcYe3vvWt2GWXXXDDDTeAiLptjkAgmMQQEkggEAgEAoFAIBAIRhH77rsv1q1bh7vvvhv//b//926bIxAIJjFkOZhAIBAIBAKBQCAQjDL2339/rFu3Dscffzz6+vpwzTXXdNskgUAwCSEkkEAgEAgEAoFAIBCMAQ444ADcd999OP7449FoNHDllVd22ySBQDDJoEgWpQoEAoFAIBAIBAKBQCAQTHjInkACgUAgEAgEAoFAIBAIBJMAQgIJBAKBQCAQCAQCgUAgEEwCCAkkEAgEAoFAIBAIBAKBQDAJICSQQCAQCAQCgUAgEAgEAsEkgJBAAoFAIBAIBAKBQCAQCASTAEICCQQCgUAgEAgEAoFAIBBMAggJJBAIBAKBQCAQCAQCgUAwCSAkkEAgEAgEAoFAIBAIBALBJICQQAKBQCAQCAQCgUAgEAgEkwBCAgkEAoFAIBAIBAKBQCAQTAIICSQQCAQCgUAgEAgEAoFAMAkgJJBAIBAIBAKBQCAQCAQCwSTA/wck2sAFqjEQzgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -273,7 +273,8 @@ " return jnp.exp(-0.4 * (r1 - r2) ** 2) * jnp.exp(-0.05 * (r1**2 + r2**2))\n", "\n", "\n", - "mesh_kernel = lm.assemble_nonlocal(kernel_solver.mesh, gaussian_nonlocal_kernel)[0, 0]\n", + "ri, rj = jnp.meshgrid(kernel_solver.mesh.radii, kernel_solver.mesh.radii, indexing=\"ij\")\n", + "mesh_kernel = gaussian_nonlocal_kernel(ri, rj)\n", "grid_kernel = np.asarray(kernel_solver.to_grid_matrix(mesh_kernel))\n", "momentum_kernel = np.asarray(kernel_solver.double_fourier_transform(mesh_kernel))\n", "grid_r = np.asarray(kernel_solver.transforms.grid_r)\n", @@ -301,7 +302,7 @@ "axes[1].set_xlabel(\"k\")\n", "axes[1].set_ylabel(\"k'\")\n", "fig.colorbar(image_k, ax=axes[1], shrink=0.85)\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -384,7 +385,7 @@ "axes[1].set_title(\"Hydrogen 1s in k-space\")\n", "axes[1].set_xlabel(\"k\")\n", "axes[1].set_ylabel(r\"$\\tilde u(k)$\")\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { diff --git a/examples/hydrogen_demo.ipynb b/examples/hydrogen_demo.ipynb index 1a7ae8e..366e91a 100644 --- a/examples/hydrogen_demo.ipynb +++ b/examples/hydrogen_demo.ipynb @@ -35,7 +35,7 @@ "\n", "import lax as lm\n", "\n", - "HBAR2_2MU = 0.5\n" + "HBAR2_2MU = 0.5" ] }, { @@ -62,8 +62,10 @@ "\n", "def radial_u_analytic(n: int, angular_momentum: int, radii: np.ndarray) -> np.ndarray:\n", " rho = 2.0 * radii / float(n)\n", - " prefactor = 2.0 / (n**2) * math.sqrt(\n", - " math.factorial(n - angular_momentum - 1) / math.factorial(n + angular_momentum)\n", + " prefactor = (\n", + " 2.0\n", + " / (n**2)\n", + " * math.sqrt(math.factorial(n - angular_momentum - 1) / math.factorial(n + angular_momentum))\n", " )\n", " radial = (\n", " prefactor\n", @@ -86,14 +88,16 @@ " raise ValueError(f\"No analytic momentum-space form for (n, l)=({n}, {angular_momentum}).\")\n", "\n", "\n", - "def normalized_and_aligned(numerical: np.ndarray, analytic: np.ndarray, grid: np.ndarray) -> tuple[np.ndarray, np.ndarray]:\n", + "def normalized_and_aligned(\n", + " numerical: np.ndarray, analytic: np.ndarray, grid: np.ndarray\n", + ") -> tuple[np.ndarray, np.ndarray]:\n", " numerical_norm = math.sqrt(float(np.trapezoid(np.abs(numerical) ** 2, grid)))\n", " analytic_norm = math.sqrt(float(np.trapezoid(np.abs(analytic) ** 2, grid)))\n", " numerical_normalized = numerical / numerical_norm\n", " analytic_normalized = analytic / analytic_norm\n", " overlap = float(np.trapezoid(numerical_normalized * analytic_normalized, grid))\n", " sign = -1.0 if overlap < 0.0 else 1.0\n", - " return sign * numerical_normalized, analytic_normalized\n" + " return sign * numerical_normalized, analytic_normalized" ] }, { @@ -132,7 +136,7 @@ "\n", "print(\"State numerical analytic abs error\")\n", "for label, numerical, analytic in energy_rows:\n", - " print(f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\")\n" + " print(f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\")" ] }, { @@ -195,7 +199,7 @@ "for axis in axes:\n", " axis.legend(fontsize=9)\n", "\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { diff --git a/examples/yamaguchi_demo.ipynb b/examples/yamaguchi_demo.ipynb index b6af80b..081c028 100644 --- a/examples/yamaguchi_demo.ipynb +++ b/examples/yamaguchi_demo.ipynb @@ -34,7 +34,7 @@ "\n", "HBAR2_2MU = lm.constants.hbar2_over_2mu(1.008665, 1.008665) # MeV·fm²\n", "ALPHA = 0.2316053\n", - "BETA = 1.3918324\n" + "BETA = 1.3918324" ] }, { @@ -66,7 +66,7 @@ " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"phases\"),\n", " energies=energies,\n", - " )\n" + " )" ] }, { @@ -110,7 +110,7 @@ "axes[1].set_xlabel(r\"$r$ [fm]\")\n", "axes[1].set_ylabel(\"MeV\")\n", "axes[1].legend()\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { @@ -134,14 +134,14 @@ "\n", "for angular_momentum in partial_waves:\n", " solver = yamaguchi_solver(angular_momentum, energies)\n", - " potential = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel)\n", + " potential = solver.potential(yamaguchi_kernel)\n", " spectrum = solver.spectrum(potential)\n", " principal_branch = np.asarray(solver.phases(spectrum)[:, 0]) * (180.0 / np.pi)\n", " phase_curves[angular_momentum] = unwrap_phase_shift_deg(principal_branch)\n", "\n", "analytic_s_wave = yamaguchi_s_wave_analytic_phase_deg(np.asarray(energies))\n", "max_s_wave_error = np.max(np.abs(phase_curves[0] - analytic_s_wave))\n", - "print(f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\")\n" + "print(f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\")" ] }, { @@ -173,12 +173,14 @@ "axes[0].legend()\n", "\n", "for angular_momentum in partial_waves:\n", - " axes[1].plot(np.asarray(energies), phase_curves[angular_momentum], label=fr\"$\\ell={angular_momentum}$\")\n", + " axes[1].plot(\n", + " np.asarray(energies), phase_curves[angular_momentum], label=rf\"$\\ell={angular_momentum}$\"\n", + " )\n", "axes[1].set_title(\"Several partial waves from the spectral solver\")\n", "axes[1].set_xlabel(\"Energy [MeV]\")\n", "axes[1].set_ylabel(\"Phase shift [deg]\")\n", "axes[1].legend()\n", - "fig.tight_layout()\n" + "fig.tight_layout()" ] }, { diff --git a/src/lax/__init__.py b/src/lax/__init__.py index a712178..b9bc791 100644 --- a/src/lax/__init__.py +++ b/src/lax/__init__.py @@ -19,7 +19,6 @@ import lax.spectral as spectral from lax.boundary._types import Solver from lax.compile import compile -from lax.operators.potential import assemble_local, assemble_nonlocal from lax.types import ChannelSpec, Interaction, MeshSpec from lax.wavefunction import make_wavefunction_source @@ -28,8 +27,6 @@ "Interaction", "MeshSpec", "Solver", - "assemble_local", - "assemble_nonlocal", "compile", "constants", "make_wavefunction_source", diff --git a/src/lax/boundary/_types.py b/src/lax/boundary/_types.py index 77eddcc..1d03412 100644 --- a/src/lax/boundary/_types.py +++ b/src/lax/boundary/_types.py @@ -767,6 +767,7 @@ class Solver: interaction_from_block: Callable | None = None interaction_from_array: Callable | None = None interaction_from_funcs: Callable | None = None + potential: Callable | None = None interpolate_rmatrix: InterpolatorBuilder | None = None interpolate_smatrix: InterpolatorBuilder | None = None interpolate_phases: InterpolatorBuilder | None = None diff --git a/src/lax/compile.py b/src/lax/compile.py index ecd58c7..5855ba0 100644 --- a/src/lax/compile.py +++ b/src/lax/compile.py @@ -18,7 +18,6 @@ from lax.boundary import compute_boundary_values from lax.boundary._types import ( BoundaryValues, - DirectGridObservable, DirectRMatrixKernel, DoubleFourierTransform, EigenpairAccessor, @@ -47,15 +46,14 @@ make_interaction_from_array, make_interaction_from_block, make_interaction_from_funcs, + make_potential_builder, ) from lax.solvers import ( - bind_direct_grid_observables, bind_grid_observables, bind_interpolators, bind_observables, make_direct_wavefunction_kernel, make_phases_direct_observable, - make_rmatrix_direct_grid_observable, make_rmatrix_direct_kernel, make_smatrix_direct_observable, make_spectrum_kernel, @@ -112,15 +110,13 @@ class _ObservableBundle: smatrix_grid: SpectrumGridObservable | None phases_grid: SpectrumGridObservable | None rmatrix_direct: DirectRMatrixKernel | None - rmatrix_direct_grid: DirectGridObservable | None - smatrix_direct_grid: DirectGridObservable | None - phases_direct_grid: DirectGridObservable | None smatrix_direct: SMatrixDirectObservable | None phases_direct: PhasesDirectObservable | None wavefunction_direct: WavefunctionDirectObservable | None interaction_from_block: object | None interaction_from_array: object | None interaction_from_funcs: object | None + potential: object | None interpolate_rmatrix: InterpolatorBuilder | None interpolate_smatrix: InterpolatorBuilder | None interpolate_phases: InterpolatorBuilder | None @@ -160,12 +156,9 @@ def compile( automatically whenever the requested solver path needs it. solvers Runtime entry points to expose on the returned :class:`~lax.Solver`. - The potential passed to ``solver.spectrum(V)`` or - ``solver.rmatrix_direct(V)`` must have shape ``(N_c, N_c, N)`` for a - local potential or ``(N_c, N_c, N, N)`` for a non-local kernel, where - ``N = mesh.n`` and ``N_c = len(channels)``. Use - :func:`lax.assemble_local` / :func:`lax.assemble_nonlocal` to build - these arrays. + The potential passed to ``solver.spectrum(V)`` or ``solver.rmatrix_direct(V)`` + must be an :class:`~lax.Interaction`. Build one with ``solver.potential(fn)`` + or the ``solver.interaction_from_{block,array,funcs}`` builders. energies Compile-time energy grid used for boundary-value-dependent observables and aligned-grid workflows. @@ -535,9 +528,6 @@ def _bind_solver_observables( ) rmatrix_direct_fn: DirectRMatrixKernel | None = None - rmatrix_direct_grid_fn: DirectGridObservable | None = None - smatrix_direct_grid_fn: DirectGridObservable | None = None - phases_direct_grid_fn: DirectGridObservable | None = None smatrix_direct_fn: SMatrixDirectObservable | None = None phases_direct_fn: PhasesDirectObservable | None = None wavefunction_direct_fn: WavefunctionDirectObservable | None = None @@ -548,6 +538,7 @@ def _bind_solver_observables( request.channels, energies, boundary, + mass_factor_grid, ) from lax.solvers.linear_solve import _DirectRMatrixKernel # noqa: PLC0415 @@ -560,19 +551,6 @@ def _bind_solver_observables( request.channels, energies, ) - if has_energy_grid: - rmatrix_direct_grid_fn = make_rmatrix_direct_grid_observable( - mesh, - operators, - request.channels, - energies, - boundary, - mass_factor_grid=mass_factor_grid, - ) - ( - smatrix_direct_grid_fn, - phases_direct_grid_fn, - ) = bind_direct_grid_observables(rmatrix_direct_grid_fn, boundary) interpolate_rmatrix_fn: InterpolatorBuilder | None = None interpolate_smatrix_fn: InterpolatorBuilder | None = None @@ -584,13 +562,10 @@ def _bind_solver_observables( interpolate_phases_fn, ) = bind_interpolators(energies) - interaction_from_block_fn = None - interaction_from_array_fn = None - interaction_from_funcs_fn = None - if has_energy_grid: - interaction_from_block_fn = make_interaction_from_block(mesh, request.channels, energies) - interaction_from_array_fn = make_interaction_from_array(mesh, request.channels, energies) - interaction_from_funcs_fn = make_interaction_from_funcs(mesh, request.channels, energies) + interaction_from_block_fn = make_interaction_from_block(mesh, request.channels, energies) + interaction_from_array_fn = make_interaction_from_array(mesh, request.channels, energies) + interaction_from_funcs_fn = make_interaction_from_funcs(mesh, request.channels, energies) + potential_fn = make_potential_builder(mesh, request.channels, energies) return _ObservableBundle( spectrum=spectrum_fn, @@ -604,15 +579,13 @@ def _bind_solver_observables( smatrix_grid=smatrix_grid_fn, phases_grid=phases_grid_fn, rmatrix_direct=rmatrix_direct_fn, - rmatrix_direct_grid=rmatrix_direct_grid_fn, - smatrix_direct_grid=smatrix_direct_grid_fn, - phases_direct_grid=phases_direct_grid_fn, smatrix_direct=smatrix_direct_fn, phases_direct=phases_direct_fn, wavefunction_direct=wavefunction_direct_fn, interaction_from_block=interaction_from_block_fn, interaction_from_array=interaction_from_array_fn, interaction_from_funcs=interaction_from_funcs_fn, + potential=potential_fn, interpolate_rmatrix=interpolate_rmatrix_fn, interpolate_smatrix=interpolate_smatrix_fn, interpolate_phases=interpolate_phases_fn, @@ -657,15 +630,13 @@ def _assemble_solver( smatrix_grid=observables.smatrix_grid, phases_grid=observables.phases_grid, rmatrix_direct=observables.rmatrix_direct, - rmatrix_direct_grid=observables.rmatrix_direct_grid, - smatrix_direct_grid=observables.smatrix_direct_grid, - phases_direct_grid=observables.phases_direct_grid, smatrix_direct=observables.smatrix_direct, phases_direct=observables.phases_direct, wavefunction_direct=observables.wavefunction_direct, interaction_from_block=observables.interaction_from_block, interaction_from_array=observables.interaction_from_array, interaction_from_funcs=observables.interaction_from_funcs, + potential=observables.potential, interpolate_rmatrix=observables.interpolate_rmatrix, interpolate_smatrix=observables.interpolate_smatrix, interpolate_phases=observables.interpolate_phases, diff --git a/src/lax/models/optical.py b/src/lax/models/optical.py index cd7d9ae..b3778a8 100644 --- a/src/lax/models/optical.py +++ b/src/lax/models/optical.py @@ -3,7 +3,7 @@ These utilities expose the general machinery behind the coupled optical examples in the benchmark suite. Users can define their own rotor-coupled models, derive the corresponding :class:`lax.types.ChannelSpec` objects, and build local potential -callbacks for :func:`lax.assemble_local`. +callbacks for :meth:`~lax.Solver.interaction_from_block`. """ from __future__ import annotations @@ -210,8 +210,7 @@ def make_rotor_coupled_optical_potential(model: RotorCoupledOpticalModel) -> Cou Returns ------- CoupledPotential - Callback with signature ``(radii, channel_index, coupled_index)`` suitable - for :func:`lax.assemble_local`. + Callback with signature ``(radii, channel_index, coupled_index)``. """ def potential(radii: jax.Array, channel_index: int, coupled_index: int) -> jax.Array: diff --git a/src/lax/operators/__init__.py b/src/lax/operators/__init__.py index bbd8ed2..a6f956f 100644 --- a/src/lax/operators/__init__.py +++ b/src/lax/operators/__init__.py @@ -5,11 +5,8 @@ make_interaction_from_block, make_interaction_from_funcs, ) -from lax.operators.potential import assemble_local, assemble_nonlocal __all__ = [ - "assemble_local", - "assemble_nonlocal", "make_interaction_from_array", "make_interaction_from_block", "make_interaction_from_funcs", diff --git a/src/lax/operators/interaction.py b/src/lax/operators/interaction.py index 0149b80..50b30b0 100644 --- a/src/lax/operators/interaction.py +++ b/src/lax/operators/interaction.py @@ -1,6 +1,8 @@ """Factories for building Interaction blocks from potential terms.""" + from __future__ import annotations +import inspect from dataclasses import dataclass import jax @@ -30,9 +32,7 @@ def __call__( M = self.N_c * self.N expected_shape = (self.N_E, M, M) if energy_dependent else (M, M) if block.shape != expected_shape: - raise ValueError( - f"Expected block shape {expected_shape}, got {block.shape}." - ) + raise ValueError(f"Expected block shape {expected_shape}, got {block.shape}.") return Interaction(block=block, energy_dependent=energy_dependent) @@ -48,8 +48,7 @@ class _InteractionFromArray: def _validate_A(self, A: jax.Array, label: str) -> None: if A.shape != (self.N_c, self.N_c): raise ValueError( - f"{label}: coupling matrix A must be ({self.N_c},{self.N_c}), " - f"got {A.shape}." + f"{label}: coupling matrix A must be ({self.N_c},{self.N_c}), got {A.shape}." ) if not jnp.allclose(A, A.T, atol=1e-12): raise ValueError(f"{label}: coupling matrix A must be symmetric.") @@ -103,7 +102,7 @@ def __call__( col_start = cp * N diag_blocks = jax.vmap(jnp.diag)(A[c, cp] * g) # (N_E, N, N) block = block.at[ - :, row_start:row_start + N, col_start:col_start + N + :, row_start : row_start + N, col_start : col_start + N ].add(diag_blocks) else: if g.ndim != 1 or g.shape != (N,): @@ -117,9 +116,9 @@ def __call__( continue row_start = c * N col_start = cp * N - block = block.at[ - row_start:row_start + N, col_start:col_start + N - ].add(jnp.diag(A[c, cp] * g)) + block = block.at[row_start : row_start + N, col_start : col_start + N].add( + jnp.diag(A[c, cp] * g) + ) for term_idx, (g, A) in enumerate(nonlocal_): g = jnp.asarray(g) @@ -139,7 +138,7 @@ def __call__( row_start = c * N col_start = cp * N block = block.at[ - :, row_start:row_start + N, col_start:col_start + N + :, row_start : row_start + N, col_start : col_start + N ].add(A[c, cp] * scaled) else: if g.ndim != 2 or g.shape != (N, N): @@ -154,9 +153,9 @@ def __call__( continue row_start = c * N col_start = cp * N - block = block.at[ - row_start:row_start + N, col_start:col_start + N - ].add(A[c, cp] * scaled) + block = block.at[row_start : row_start + N, col_start : col_start + N].add( + A[c, cp] * scaled + ) first_block = block[0] if energy_dependent else block if not jnp.allclose(first_block, first_block.T, atol=1e-10): @@ -171,8 +170,8 @@ class _InteractionFromFuncs: N: int N_E: int - radii: jax.Array # (N,) - energies: jax.Array # (N_E,) + radii: jax.Array # (N,) + energies: jax.Array # (N_E,) array_builder: _InteractionFromArray def __call__( @@ -268,8 +267,96 @@ def make_interaction_from_funcs( ) +@dataclass(frozen=True) +class _PotentialBuilder: + """Pickle-safe ``solver.potential(fn, coupling, energy_dependent)`` callable. + + Wraps ``_InteractionFromFuncs`` with arity-based local/nonlocal dispatch and + a sensible ``coupling`` default for single-channel problems. + """ + + n_c: int + funcs_builder: _InteractionFromFuncs + + def __call__( + self, + fn: object, + *, + coupling: np.ndarray | None = None, + energy_dependent: bool = False, + ) -> Interaction: + """Build an :class:`~lax.Interaction` from a potential function. + + Parameters + ---------- + fn + Potential function. Arity determines local vs nonlocal: + + * ``energy_dependent=False``: ``fn(r)`` → local, ``fn(r, r')`` → nonlocal + * ``energy_dependent=True``: ``fn(r, E)`` → local, ``fn(r, r', E)`` → nonlocal + + coupling + ``(N_c, N_c)`` symmetric coupling matrix. Defaults to ``[[1.0]]`` + when ``N_c == 1``. Required for multi-channel solvers. + energy_dependent + Whether ``fn`` takes an energy argument and the result should carry + a leading ``(N_E,)`` axis. + """ + if coupling is None: + if self.n_c != 1: + raise ValueError( + f"coupling is required for {self.n_c}-channel solvers; " + "pass coupling=np.array([[...]])." + ) + coupling = np.ones((1, 1), dtype=np.float64) + + if energy_dependent and self.funcs_builder.N_E == 0: + raise ValueError( + "energy_dependent=True requires an energy grid; " + "re-compile with energies=... to use energy-dependent potentials." + ) + + n_args = len(inspect.signature(fn).parameters) # type: ignore[arg-type] + if energy_dependent: + if n_args == 2: + return self.funcs_builder(local=[(fn, coupling)], energy_dependent=True) # type: ignore[list-item] + elif n_args == 3: + return self.funcs_builder(nonlocal_=[(fn, coupling)], energy_dependent=True) # type: ignore[list-item] + else: + raise ValueError( + f"For energy_dependent=True, fn must take 2 args fn(r, E) " + f"(local) or 3 args fn(r, r', E) (nonlocal); got {n_args}." + ) + else: + if n_args == 1: + return self.funcs_builder(local=[(fn, coupling)], energy_dependent=False) # type: ignore[list-item] + elif n_args == 2: + return self.funcs_builder(nonlocal_=[(fn, coupling)], energy_dependent=False) # type: ignore[list-item] + else: + raise ValueError( + f"fn must take 1 arg fn(r) (local) or 2 args fn(r, r') " + f"(nonlocal); got {n_args}." + ) + + +def make_potential_builder( + mesh: Mesh, + channels: tuple[ChannelSpec, ...], + energies: jax.Array, +) -> _PotentialBuilder: + """Return ``solver.potential`` — a simple callable that builds an Interaction from a function. + + The returned callable auto-detects local vs nonlocal from function arity and + defaults ``coupling`` to ``[[1.0]]`` for single-channel problems. See + :class:`_PotentialBuilder` for the full signature. + """ + funcs_builder = make_interaction_from_funcs(mesh, channels, energies) + return _PotentialBuilder(n_c=len(channels), funcs_builder=funcs_builder) + + __all__ = [ "make_interaction_from_array", "make_interaction_from_block", "make_interaction_from_funcs", + "make_potential_builder", ] diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index 9674cdc..7ad41e0 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -23,7 +23,7 @@ from .assembly import assemble_block_hamiltonian, build_Q if TYPE_CHECKING: - from lax.types import Interaction + pass def _build_q_prime( @@ -57,56 +57,104 @@ class _DirectRMatrixKernel: matrix_size: int mass_factor: float boundary: BoundaryValues | None + mass_factor_grid: jax.Array | None = None def __call__(self, potential: jax.Array) -> jax.Array: """Evaluate the direct R-matrix on the compile-time energy grid. - Accepts either a raw potential array ``(N_c, N_c, N)`` / ``(N_c, N_c, N, N)`` - or an :class:`~lax.Interaction` object. When an ``Interaction`` with - ``energy_dependent=True`` is passed the per-energy block is used. + Parameters + ---------- + potential + :class:`~lax.Interaction` object built by ``solver.potential()`` or + ``solver.interaction_from_{block,array,funcs}()``. Energy-dependent + interactions (``energy_dependent=True``) use the per-energy block path. + + :class:`~lax.Interaction` object built by ``solver.potential()`` or + ``solver.interaction_from_{block,array,funcs}()``. For propagated meshes, + local energy-independent Interactions are supported: the per-interval + ``(N_c, N_c, N)`` array is extracted from the block diagonals. """ from lax.types import Interaction # noqa: PLC0415 - if isinstance(potential, Interaction): - if potential.energy_dependent: - return cast( - jax.Array, - _RMATRIX_DIRECT_GRID_JIT( - potential.block, - self.mesh, - self.operators, - self.channels, - self.energies, - self.q, - self.q_prime, - self.channel_radius, - self.matrix_size, - self.mass_factor, - self.boundary, - None, - ), + # Propagated meshes use per-interval raw (N_c, N_c, N) arrays. + # Extract from Interaction.block by taking the diagonal of each sub-block. + if self.mesh.propagation is not None: + if not isinstance(potential, Interaction): + raise TypeError( + "rmatrix_direct() accepts only Interaction objects. " + "Use solver.potential(fn) or solver.interaction_from_block(block)." ) - else: - return cast( - jax.Array, - _RMATRIX_DIRECT_JIT( - potential.block, - self.mesh, - self.operators, - self.channels, - self.energies, - self.q_prime, - self.channel_radius, - self.matrix_size, - self.mass_factor, - self.boundary, - ), + if potential.energy_dependent: + raise TypeError( + "rmatrix_direct() does not support energy-dependent Interactions " + "on propagated meshes." ) + N_c = len(self.channels) + N = self.mesh.n + # Propagated path supports only local Interactions: sub-blocks must be diagonal. + for c in range(N_c): + for cp in range(N_c): + sub = np.asarray(potential.block[c * N : (c + 1) * N, cp * N : (cp + 1) * N]) + if np.any(sub != np.diag(np.diag(sub))): + raise ValueError( + "rmatrix_direct() on propagated meshes supports only local " + "Interactions. Non-local propagated direct solves are not supported." + ) + potential = jnp.stack( + [ + jnp.stack( + [ + jnp.diag(potential.block[c * N : (c + 1) * N, cp * N : (cp + 1) * N]) + for cp in range(N_c) + ] + ) + for c in range(N_c) + ] + ) + return cast( + jax.Array, + _RMATRIX_DIRECT_JIT( + potential, + self.mesh, + self.operators, + self.channels, + self.energies, + self.q_prime, + self.channel_radius, + self.matrix_size, + self.mass_factor, + self.boundary, + ), + ) + if not isinstance(potential, Interaction): + raise TypeError( + "rmatrix_direct() accepts only Interaction objects. " + "Use solver.potential() or solver.interaction_from_block/array/funcs to build one." + ) + + if potential.energy_dependent: + return cast( + jax.Array, + _RMATRIX_DIRECT_GRID_JIT( + potential.block, + self.mesh, + self.operators, + self.channels, + self.energies, + self.q, + self.q_prime, + self.channel_radius, + self.matrix_size, + self.mass_factor, + self.boundary, + self.mass_factor_grid, + ), + ) return cast( jax.Array, _RMATRIX_DIRECT_JIT( - potential, + potential.block, self.mesh, self.operators, self.channels, @@ -206,10 +254,8 @@ def __call__( Parameters ---------- potential - Assembled potential or :class:`~lax.Interaction`. Shape - ``(N_c, N_c, N)`` / ``(N_c, N_c, N, N)`` (energy-independent) or - ``(N_E, N_c, N_c, N)`` / ``(N_E, N_c, N_c, N, N)`` (energy-dependent). - Also accepts an ``Interaction`` object. + :class:`~lax.Interaction` object. For energy-dependent interactions + the block at ``energy_index`` is extracted automatically. source Mesh-space driving term, shape ``(N_c·N,)``. energy_index @@ -222,12 +268,12 @@ def __call__( """ from lax.types import Interaction # noqa: PLC0415 - if isinstance(potential, Interaction): - block = potential.block[energy_index] if potential.energy_dependent else potential.block - else: - # Raw array: pass as-is. For energy-dependent arrays the caller must - # slice to the desired energy before calling (potential[energy_index]). - block = potential + if not isinstance(potential, Interaction): + raise TypeError( + "wavefunction_direct() accepts only Interaction objects. " + "Use solver.potential() or solver.interaction_from_block/array/funcs to build one." + ) + block = potential.block[energy_index] if potential.energy_dependent else potential.block return cast( jax.Array, @@ -249,6 +295,7 @@ def make_rmatrix_direct_kernel( channels: tuple[ChannelSpec, ...], energies: jax.Array, boundary: BoundaryValues | None, + mass_factor_grid: jax.Array | None = None, ) -> DirectRMatrixKernel: """Build a JIT-compiled ``rmatrix_direct(V) → R`` kernel for the compile-time grid. @@ -272,6 +319,10 @@ def make_rmatrix_direct_kernel( boundary Compile-time boundary values for S-matrix matching, or ``None`` if only the R-matrix is needed. + mass_factor_grid + Optional per-energy (and optionally per-channel) ℏ²/2μ values in MeV·fm², + shape ``(N_E,)`` or ``(N_E, N_c)``. Applied in the energy-dependent + Interaction path only (``energy_dependent=True``). Returns ------- @@ -297,6 +348,7 @@ def make_rmatrix_direct_kernel( matrix_size=matrix_size, mass_factor=mass_factor, boundary=boundary, + mass_factor_grid=mass_factor_grid, ), ) diff --git a/src/lax/solvers/spectrum.py b/src/lax/solvers/spectrum.py index 5101077..0128934 100644 --- a/src/lax/solvers/spectrum.py +++ b/src/lax/solvers/spectrum.py @@ -37,13 +37,17 @@ def __call__( Parameters ---------- potential - Assembled potential array, shape ``(N_c, N_c, N)`` for local or - ``(N_c, N_c, N, N)`` for non-local. + :class:`~lax.Interaction` object built by ``solver.potential()`` or + ``solver.interaction_from_{block,array,funcs}()``. Must have + ``energy_dependent=False`` (one eigendecomposition per potential). + For energy-dependent workflows, vmap over per-energy blocks:: + + jax.vmap(solver.spectrum)(interaction_list) + mass_factor Optional energy-dependent ℏ²/2μ value in MeV·fm². When provided, - overrides ``ChannelSpec.mass_factor`` in the Hamiltonian assembly so - that ``threshold/μ(E)`` and ``V/μ(E)`` use the correct per-energy - value. Typical usage:: + overrides ``ChannelSpec.mass_factor`` in the Hamiltonian assembly. + Typical usage:: spectra = jax.vmap( lambda V, mu: solver.spectrum(V, mass_factor=mu) @@ -54,6 +58,15 @@ def __call__( Spectrum Eigendecomposition of the Bloch-augmented Hamiltonian. """ + from lax.types import Interaction # noqa: PLC0415 + + if isinstance(potential, Interaction): + if potential.energy_dependent: + raise TypeError( + "spectrum() does not accept energy-dependent Interactions directly. " + "Vmap over per-energy blocks: jax.vmap(solver.spectrum)(interaction.block)." + ) + potential = potential.block if self.method == "eigh": return cast( @@ -144,9 +157,7 @@ def _spectrum_eigh( ) -> Spectrum: """Return the Hermitian spectrum for one potential.""" - H_MeV = assemble_block_hamiltonian( - mesh, operators, channels, potential, mass_factor_override - ) + H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential, mass_factor_override) if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: m0 = mass_factor_override else: @@ -177,9 +188,7 @@ def _spectrum_eig( ) -> Spectrum: """Return the complex-symmetric spectrum for one potential.""" - H_MeV = assemble_block_hamiltonian( - mesh, operators, channels, potential, mass_factor_override - ) + H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential, mass_factor_override) if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: m0 = mass_factor_override else: diff --git a/src/lax/types.py b/src/lax/types.py index cffb1fd..bbf5986 100644 --- a/src/lax/types.py +++ b/src/lax/types.py @@ -6,7 +6,6 @@ from typing import Literal import jax -import jax.numpy as jnp type MeshFamily = Literal["legendre", "laguerre"] type Regularization = Literal[ @@ -105,6 +104,26 @@ class Interaction: block: jax.Array energy_dependent: bool = field(metadata={"static": True}) + def __add__(self, other: object) -> Interaction: + """Combine two Interaction blocks by summing their potential contributions. + + Energy-independent + energy-independent → energy-independent. + Any combination involving an energy-dependent term → energy-dependent, + broadcasting ``(M, M)`` to ``(1, M, M)`` before adding. + """ + if not isinstance(other, Interaction): + return NotImplemented + if not self.energy_dependent and not other.energy_dependent: + return Interaction(block=self.block + other.block, energy_dependent=False) + b1 = self.block if self.energy_dependent else self.block[None] + b2 = other.block if other.energy_dependent else other.block[None] + return Interaction(block=b1 + b2, energy_dependent=True) + + def __radd__(self, other: object) -> Interaction: + if other == 0: + return self + return NotImplemented + __all__ = [ "ChannelSpec", diff --git a/src/lax/wavefunction.py b/src/lax/wavefunction.py index f71eb61..fdcb0ff 100644 --- a/src/lax/wavefunction.py +++ b/src/lax/wavefunction.py @@ -67,7 +67,7 @@ def make_wavefunction_source( ... solvers=("spectrum", "wavefunction"), ... energies=energies, ... ) - >>> V = lax.assemble_nonlocal(solver.mesh, lambda r1, r2: jnp.zeros_like(r1)) + >>> V = solver.potential(lambda r1, r2: jnp.zeros_like(r1)) >>> spec = solver.spectrum(V) >>> src = lax.make_wavefunction_source(solver, channel_index=0, energy_index=5) >>> psi = solver.wavefunction(spec, energies[5], src) diff --git a/tests/benchmarks/test_alpha_pb_optical.py b/tests/benchmarks/test_alpha_pb_optical.py index fc73a09..c3330d3 100644 --- a/tests/benchmarks/test_alpha_pb_optical.py +++ b/tests/benchmarks/test_alpha_pb_optical.py @@ -111,8 +111,8 @@ def test_alpha_pb_optical_matches_published_appendix_a( """Published Descouvemont Example 1 collision-matrix values stay visible in the suite.""" solver = _complex_solver(reference, "linear_solve", ("rmatrix_direct",)) - potential = lm.assemble_local(solver.mesh, lambda r: _optical_potential(r, imag_depth=10.0)) - smatrix = _smatrix_from_direct_rmatrix(solver, potential)[:, 0, 0] + V = solver.potential(lambda r: _optical_potential(r, imag_depth=10.0)) + smatrix = _smatrix_from_direct_rmatrix(solver, V)[:, 0, 0] assert np.allclose(smatrix, reference.collision_matrix, atol=1.0e-4, rtol=1.0e-4) @@ -123,7 +123,7 @@ def test_alpha_pb_optical_eig_matches_appendix_a() -> None: reference = ALPHA_PB_REFERENCE_A14_N60_NS1 solver = _complex_solver(reference, "eig", ("spectrum", "smatrix")) - potential = lm.assemble_local(solver.mesh, lambda r: _optical_potential(r, imag_depth=10.0)) + potential = solver.potential(lambda r: _optical_potential(r, imag_depth=10.0)) assert solver.spectrum is not None assert solver.smatrix is not None @@ -139,8 +139,8 @@ def test_alpha_pb_optical_direct_matches_appendix_a() -> None: reference = ALPHA_PB_REFERENCE_A14_N60_NS1 solver = _complex_solver(reference, "linear_solve", ("rmatrix_direct",)) - potential = lm.assemble_local(solver.mesh, lambda r: _optical_potential(r, imag_depth=10.0)) - smatrix = _smatrix_from_direct_rmatrix(solver, potential)[:, 0, 0] + V = solver.potential(lambda r: _optical_potential(r, imag_depth=10.0)) + smatrix = _smatrix_from_direct_rmatrix(solver, V)[:, 0, 0] assert np.allclose(smatrix, reference.collision_matrix, atol=1.0e-4, rtol=1.0e-4) @@ -154,13 +154,15 @@ def test_alpha_pb_optical_method_paths_agree() -> None: real_direct_solver = _real_solver(reference, "linear_solve", ("rmatrix_direct",)) complex_solver = _complex_solver(reference, "eig", ("spectrum", "smatrix")) complex_direct_solver = _complex_solver(reference, "linear_solve", ("rmatrix_direct",)) - real_potential = lm.assemble_local( - real_spectrum_solver.mesh, - lambda r: jnp.real(_optical_potential(r, imag_depth=0.0)), + real_V_spectral = real_spectrum_solver.potential( + lambda r: jnp.real(_optical_potential(r, imag_depth=0.0)) ) - complex_potential = lm.assemble_local( - complex_solver.mesh, - lambda r: _optical_potential(r, imag_depth=10.0), + real_V_direct = real_direct_solver.potential( + lambda r: jnp.real(_optical_potential(r, imag_depth=0.0)) + ) + complex_V_spectral = complex_solver.potential(lambda r: _optical_potential(r, imag_depth=10.0)) + complex_V_direct = complex_direct_solver.potential( + lambda r: _optical_potential(r, imag_depth=10.0) ) assert real_spectrum_solver.spectrum is not None @@ -169,11 +171,13 @@ def test_alpha_pb_optical_method_paths_agree() -> None: assert complex_solver.smatrix is not None real_smatrix = np.asarray( - real_spectrum_solver.smatrix(real_spectrum_solver.spectrum(real_potential)) + real_spectrum_solver.smatrix(real_spectrum_solver.spectrum(real_V_spectral)) + ) + real_direct = _smatrix_from_direct_rmatrix(real_direct_solver, real_V_direct) + complex_smatrix = np.asarray( + complex_solver.smatrix(complex_solver.spectrum(complex_V_spectral)) ) - real_direct = _smatrix_from_direct_rmatrix(real_direct_solver, real_potential) - complex_smatrix = np.asarray(complex_solver.smatrix(complex_solver.spectrum(complex_potential))) - complex_direct = _smatrix_from_direct_rmatrix(complex_direct_solver, complex_potential) + complex_direct = _smatrix_from_direct_rmatrix(complex_direct_solver, complex_V_direct) assert np.allclose(real_smatrix, real_direct, atol=1.0e-10, rtol=1.0e-10) assert np.allclose(complex_smatrix, complex_direct, atol=1.0e-10, rtol=1.0e-10) diff --git a/tests/benchmarks/test_coupled_closed_channel.py b/tests/benchmarks/test_coupled_closed_channel.py index d362c9b..5e55d1a 100644 --- a/tests/benchmarks/test_coupled_closed_channel.py +++ b/tests/benchmarks/test_coupled_closed_channel.py @@ -73,7 +73,20 @@ def _open_channel_potential(radii: jax.Array) -> jax.Array: return _toy_potential(radii, 0, 0) -def _smatrix_from_direct_rmatrix(solver: lm.Solver, potential: jax.Array) -> np.ndarray: +def _to_interaction_2ch(solver: lm.Solver, fn) -> object: + """Build a 2-channel Interaction from a fn(radii, c, cp) potential.""" + A00 = np.array([[1.0, 0.0], [0.0, 0.0]]) + A01 = np.array([[0.0, 1.0], [1.0, 0.0]]) + A11 = np.array([[0.0, 0.0], [0.0, 1.0]]) + assert solver.potential is not None + return ( + solver.potential(lambda r: fn(r, 0, 0), coupling=A00) + + solver.potential(lambda r: fn(r, 0, 1), coupling=A01) + + solver.potential(lambda r: fn(r, 1, 1), coupling=A11) + ) + + +def _smatrix_from_direct_rmatrix(solver: lm.Solver, potential) -> np.ndarray: """Evaluate the physical S-matrix from the direct R-matrix kernel.""" assert solver.rmatrix_direct is not None @@ -118,14 +131,14 @@ def test_coupled_closed_channel_spectral_and_direct_paths_agree() -> None: spectral_solver = _coupled_solver("eigh", ("spectrum", "smatrix")) direct_solver = _coupled_solver("linear_solve", ("rmatrix_direct",)) - potential = lm.assemble_local(spectral_solver.mesh, _toy_potential, n_channels=2) - direct_potential = lm.assemble_local(direct_solver.mesh, _toy_potential, n_channels=2) + spectral_V = _to_interaction_2ch(spectral_solver, _toy_potential) + direct_V = _to_interaction_2ch(direct_solver, _toy_potential) assert spectral_solver.spectrum is not None assert spectral_solver.smatrix is not None - spectral_smatrix = np.asarray(spectral_solver.smatrix(spectral_solver.spectrum(potential))) - direct_smatrix = _smatrix_from_direct_rmatrix(direct_solver, direct_potential) + spectral_smatrix = np.asarray(spectral_solver.smatrix(spectral_solver.spectrum(spectral_V))) + direct_smatrix = _smatrix_from_direct_rmatrix(direct_solver, direct_V) below_threshold = ENERGIES < CHANNEL_THRESHOLD above_threshold = np.logical_not(below_threshold) @@ -143,20 +156,18 @@ def test_coupled_closed_channel_decoupled_limit_matches_single_channel() -> None coupled_solver = _coupled_solver("eigh", ("spectrum", "smatrix")) single_channel_solver = _single_channel_solver() - coupled_potential = lm.assemble_local(coupled_solver.mesh, _decoupled_potential, n_channels=2) - single_channel_potential = lm.assemble_local( - single_channel_solver.mesh, - _open_channel_potential, - ) + coupled_V = _to_interaction_2ch(coupled_solver, _decoupled_potential) + assert single_channel_solver.potential is not None + single_channel_V = single_channel_solver.potential(_open_channel_potential) assert coupled_solver.spectrum is not None assert coupled_solver.smatrix is not None assert single_channel_solver.spectrum is not None assert single_channel_solver.smatrix is not None - coupled_smatrix = np.asarray(coupled_solver.smatrix(coupled_solver.spectrum(coupled_potential))) + coupled_smatrix = np.asarray(coupled_solver.smatrix(coupled_solver.spectrum(coupled_V))) single_channel_smatrix = np.asarray( - single_channel_solver.smatrix(single_channel_solver.spectrum(single_channel_potential)) + single_channel_solver.smatrix(single_channel_solver.spectrum(single_channel_V)) ) assert np.allclose( diff --git a/tests/benchmarks/test_descouvemont_closed_channels.py b/tests/benchmarks/test_descouvemont_closed_channels.py index 62707ce..c47b744 100644 --- a/tests/benchmarks/test_descouvemont_closed_channels.py +++ b/tests/benchmarks/test_descouvemont_closed_channels.py @@ -1,6 +1,6 @@ from __future__ import annotations -import jax +import jax.numpy as jnp import numpy as np import pytest @@ -43,8 +43,23 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) +def _rotor_interaction(solver: lm.Solver, fn) -> object: + """Build an Interaction for the 8-channel α+12C rotor model from fn(r, c, cp).""" + n_c = len(channels_from_rotor_model(ALPHA_C12_ROTOR_MODEL)) + N = solver.mesh.n + M = n_c * N + r = solver.mesh.radii + block = jnp.zeros((M, M), dtype=jnp.complex128) + for c in range(n_c): + for cp in range(n_c): + g = fn(r, c, cp) + block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g)) + assert solver.interaction_from_block is not None + return solver.interaction_from_block(block, energy_dependent=False) + + def _smatrix_from_direct_rmatrix( - solver: lm.Solver, potential: jax.Array + solver: lm.Solver, potential ) -> tuple[np.ndarray, tuple[np.ndarray, ...]]: """Evaluate the physical open-channel S-matrices from the direct R-matrix kernel.""" @@ -93,12 +108,8 @@ def test_descouvemont_closed_channel_matches_published_first_column( potential = make_rotor_coupled_optical_potential(ALPHA_C12_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - assembled_potential = lm.assemble_local( - solver.mesh, - potential, - n_channels=len(channels_from_rotor_model(ALPHA_C12_ROTOR_MODEL)), - ) - smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, assembled_potential) + interaction = _rotor_interaction(solver, potential) + smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): open_count = open_channel_count(ALPHA_C12_ROTOR_MODEL, float(energy)) @@ -133,12 +144,8 @@ def test_descouvemont_closed_channel_demo_matches_full_precision_reference() -> reference = load_alpha_c12_single_interval_demo() potential = make_rotor_coupled_optical_potential(ALPHA_C12_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - assembled_potential = lm.assemble_local( - solver.mesh, - potential, - n_channels=len(channels_from_rotor_model(ALPHA_C12_ROTOR_MODEL)), - ) - smatrices, _ = _smatrix_from_direct_rmatrix(solver, assembled_potential) + interaction = _rotor_interaction(solver, potential) + smatrices, _ = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): open_count = open_channel_count(ALPHA_C12_ROTOR_MODEL, float(energy)) @@ -190,24 +197,14 @@ def test_descouvemont_closed_channel_reduced_spectral_and_direct_paths_agree() - V_is_complex=True, z1z2=(2, 6), ) - spectral_potential = lm.assemble_local( - spectral_solver.mesh, - potential, - n_channels=len(channels), - ) - direct_potential = lm.assemble_local( - direct_solver.mesh, - potential, - n_channels=len(channels), - ) + spectral_V = _rotor_interaction(spectral_solver, potential) + direct_V = _rotor_interaction(direct_solver, potential) assert spectral_solver.spectrum is not None assert spectral_solver.smatrix is not None - spectral_smatrices = np.asarray( - spectral_solver.smatrix(spectral_solver.spectrum(spectral_potential)) - ) - direct_smatrices, _ = _smatrix_from_direct_rmatrix(direct_solver, direct_potential) + spectral_smatrices = np.asarray(spectral_solver.smatrix(spectral_solver.spectrum(spectral_V))) + direct_smatrices, _ = _smatrix_from_direct_rmatrix(direct_solver, direct_V) for energy_index, energy in enumerate(energies): open_count = open_channel_count(ALPHA_C12_ROTOR_MODEL, float(energy)) assert np.allclose( diff --git a/tests/benchmarks/test_descouvemont_np.py b/tests/benchmarks/test_descouvemont_np.py index 7af5584..7a409de 100644 --- a/tests/benchmarks/test_descouvemont_np.py +++ b/tests/benchmarks/test_descouvemont_np.py @@ -31,6 +31,24 @@ def _solver(reference: NpJ1Reference, method: str, solvers: tuple[str, ...]) -> ) +def _np_interaction(solver: lm.Solver) -> object: + """Build the Reid n-p J=1 Interaction from its channel decomposition.""" + + A00 = np.array([[1.0, 0.0], [0.0, 0.0]]) + A01 = np.array([[0.0, 1.0], [1.0, 0.0]]) + A11 = np.array([[0.0, 0.0], [0.0, 1.0]]) + r = solver.mesh.radii + assert solver.interaction_from_array is not None + return solver.interaction_from_array( + local=[ + (reid_np_j1_potential(r, 0, 0), A00), + (reid_np_j1_potential(r, 0, 1), A01), + (reid_np_j1_potential(r, 1, 1), A11), + ], + energy_dependent=False, + ) + + def _smatrix_from_direct_rmatrix(solver: lm.Solver, potential: jax.Array) -> np.ndarray: """Evaluate the collision matrix from the direct R-matrix kernel.""" @@ -81,8 +99,8 @@ def _paper_observables_from_direct( """Return the published observables from the direct R-matrix path.""" solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - potential = lm.assemble_local(solver.mesh, reid_np_j1_potential, n_channels=2) - smatrices = _smatrix_from_direct_rmatrix(solver, potential) + V = _np_interaction(solver) + smatrices = _smatrix_from_direct_rmatrix(solver, V) return _paper_observables(smatrices) @@ -122,8 +140,8 @@ def test_descouvemont_np_spectral_and_direct_paths_agree() -> None: reference = load_np_j1_references()[0] spectral_solver = _solver(reference, "eigh", ("spectrum", "smatrix")) direct_solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - spectral_potential = lm.assemble_local(spectral_solver.mesh, reid_np_j1_potential, n_channels=2) - direct_potential = lm.assemble_local(direct_solver.mesh, reid_np_j1_potential, n_channels=2) + spectral_potential = _np_interaction(spectral_solver) + direct_V = _np_interaction(direct_solver) assert spectral_solver.spectrum is not None assert spectral_solver.smatrix is not None @@ -131,6 +149,6 @@ def test_descouvemont_np_spectral_and_direct_paths_agree() -> None: spectral_smatrices = np.asarray( spectral_solver.smatrix(spectral_solver.spectrum(spectral_potential)) ) - direct_smatrices = _smatrix_from_direct_rmatrix(direct_solver, direct_potential) + direct_smatrices = _smatrix_from_direct_rmatrix(direct_solver, direct_V) assert np.allclose(spectral_smatrices, direct_smatrices, atol=1.0e-10, rtol=1.0e-10) diff --git a/tests/benchmarks/test_descouvemont_o16_ca44.py b/tests/benchmarks/test_descouvemont_o16_ca44.py index 8081975..548dc21 100644 --- a/tests/benchmarks/test_descouvemont_o16_ca44.py +++ b/tests/benchmarks/test_descouvemont_o16_ca44.py @@ -1,6 +1,6 @@ from __future__ import annotations -import jax +import jax.numpy as jnp import numpy as np import pytest @@ -42,8 +42,23 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) +def _rotor_interaction(solver: lm.Solver, fn) -> object: + """Build an Interaction for the 4-channel O16+Ca44 rotor model from fn(r, c, cp).""" + n_c = len(channels_from_rotor_model(O16_CA44_ROTOR_MODEL)) + N = solver.mesh.n + M = n_c * N + r = solver.mesh.radii + block = jnp.zeros((M, M), dtype=jnp.complex128) + for c in range(n_c): + for cp in range(n_c): + g = fn(r, c, cp) + block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g)) + assert solver.interaction_from_block is not None + return solver.interaction_from_block(block, energy_dependent=False) + + def _smatrix_from_direct_rmatrix( - solver: lm.Solver, potential: jax.Array + solver: lm.Solver, potential ) -> tuple[np.ndarray, tuple[np.ndarray, ...]]: """Evaluate the physical open-channel S-matrices from the direct R-matrix kernel.""" @@ -90,12 +105,8 @@ def test_descouvemont_o16_ca44_matches_published_output(reference: CoupledColumn potential = make_rotor_coupled_optical_potential(O16_CA44_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - assembled_potential = lm.assemble_local( - solver.mesh, - potential, - n_channels=len(channels_from_rotor_model(O16_CA44_ROTOR_MODEL)), - ) - smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, assembled_potential) + interaction = _rotor_interaction(solver, potential) + smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): open_count = open_channel_count(O16_CA44_ROTOR_MODEL, float(energy)) diff --git a/tests/benchmarks/test_phase8_meshes.py b/tests/benchmarks/test_phase8_meshes.py index ebd55ca..5870f8a 100644 --- a/tests/benchmarks/test_phase8_meshes.py +++ b/tests/benchmarks/test_phase8_meshes.py @@ -23,7 +23,8 @@ def test_confined_hydrogen_ground_state_legendre_x_one_minus_x() -> None: ) assert solver.spectrum is not None - potential = lm.assemble_local(solver.mesh, lambda r: -1.0 / r) + assert solver.potential is not None + potential = solver.potential(lambda r: -1.0 / r) spectrum = solver.spectrum(potential) ground_state = float(np.asarray(spectrum.eigenvalues)[0]) * HBAR2_2MU @@ -44,7 +45,8 @@ def test_harmonic_oscillator_ground_state_modified_laguerre_x2() -> None: ) assert solver.spectrum is not None - potential = lm.assemble_local(solver.mesh, lambda r: 0.25 * r**2) + assert solver.potential is not None + potential = solver.potential(lambda r: 0.25 * r**2) spectrum = solver.spectrum(potential) ground_state = float(np.asarray(spectrum.eigenvalues)[0]) diff --git a/tests/benchmarks/test_yamaguchi.py b/tests/benchmarks/test_yamaguchi.py index 388c0f7..9984752 100644 --- a/tests/benchmarks/test_yamaguchi.py +++ b/tests/benchmarks/test_yamaguchi.py @@ -53,7 +53,7 @@ def _complex_yamaguchi_kernel(r1, r2, imag_strength): return _yamaguchi_kernel(r1, r2) * (1.0 + 1.0j * imag_strength) -def _phase_from_direct_rmatrix(solver, potential): +def _phase_from_direct_rmatrix(solver, interaction): """Evaluate phase shifts from `solver.rmatrix_direct` on the compile-time energy grid.""" import jax.numpy as jnp @@ -64,7 +64,7 @@ def _phase_from_direct_rmatrix(solver, potential): assert solver.rmatrix_direct is not None assert solver.boundary is not None - r_values = solver.rmatrix_direct(potential) + r_values = solver.rmatrix_direct(interaction) phases = [] for energy_index in range(r_values.shape[0]): boundary = BoundaryValues( @@ -99,7 +99,7 @@ def test_yamaguchi_phase_shifts(reference: YamaguchiReference) -> None: solvers=("spectrum", "phases"), energies=jnp.asarray(reference.energies), ) - potential = lm.assemble_nonlocal(solver.mesh, _yamaguchi_kernel) + potential = solver.potential(_yamaguchi_kernel) spectrum = solver.spectrum(potential) phases_deg = np.asarray(solver.phases(spectrum))[:, 0] * (180.0 / np.pi) @@ -125,8 +125,8 @@ def test_yamaguchi_phase_shifts_direct_rmatrix(reference: YamaguchiReference) -> energies=reference.energies, method="linear_solve", ) - potential = lm.assemble_nonlocal(solver.mesh, _yamaguchi_kernel) - phases_deg = np.asarray(_phase_from_direct_rmatrix(solver, potential))[:, 0] * (180.0 / np.pi) + V = solver.potential(_yamaguchi_kernel) + phases_deg = np.asarray(_phase_from_direct_rmatrix(solver, V))[:, 0] * (180.0 / np.pi) assert np.allclose(phases_deg, reference.phases_deg, atol=1.0e-2, rtol=0.0) @@ -149,10 +149,10 @@ def test_yamaguchi_direct_matches_spectral(reference: YamaguchiReference) -> Non solvers=("spectrum", "rmatrix", "phases", "rmatrix_direct"), energies=reference.energies, ) - potential = lm.assemble_nonlocal(solver.mesh, _yamaguchi_kernel) - spectrum = solver.spectrum(potential) + V = solver.potential(_yamaguchi_kernel) + spectrum = solver.spectrum(V) spectral_delta = np.asarray(solver.phases(spectrum))[:, 0] - direct_delta = np.asarray(_phase_from_direct_rmatrix(solver, potential))[:, 0] + direct_delta = np.asarray(_phase_from_direct_rmatrix(solver, V))[:, 0] assert np.allclose(direct_delta, spectral_delta, atol=1.0e-10, rtol=1.0e-10) @@ -172,7 +172,7 @@ def test_yamaguchi_large_radius_matches_baye_reference(a, n, E, ref_deg, tol): solvers=("spectrum", "phases"), energies=jnp.array([E]), ) - potential = lm.assemble_nonlocal(solver.mesh, _yamaguchi_kernel) + potential = solver.potential(_yamaguchi_kernel) delta = float(solver.phases(solver.spectrum(potential))[0, 0]) * (180.0 / np.pi) assert abs(delta - ref_deg) < tol, ( @@ -205,10 +205,9 @@ def test_complex_yamaguchi_eig_matches_real_limit(a, n, E): V_is_complex=True, method="eig", ) - real_potential = lm.assemble_nonlocal(real_solver.mesh, _yamaguchi_kernel) - complex_potential = lm.assemble_nonlocal( - complex_solver.mesh, - lambda r1, r2: _complex_yamaguchi_kernel(r1, r2, imag_strength), + real_potential = real_solver.potential(_yamaguchi_kernel) + complex_potential = complex_solver.potential( + lambda r1, r2: _complex_yamaguchi_kernel(r1, r2, imag_strength) ) real_phase = float(real_solver.phases(real_solver.spectrum(real_potential))[0, 0]) complex_phase = float(complex_solver.phases(complex_solver.spectrum(complex_potential))[0, 0]) diff --git a/tests/benchmarks/test_yamaguchi_fourier.py b/tests/benchmarks/test_yamaguchi_fourier.py index 40eec49..7369c80 100644 --- a/tests/benchmarks/test_yamaguchi_fourier.py +++ b/tests/benchmarks/test_yamaguchi_fourier.py @@ -32,7 +32,8 @@ def yamaguchi_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: solvers=("spectrum", "wavefunction"), momenta=jnp.linspace(0.1, 2.0, 20), ) - potential = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) + assert solver.potential is not None + potential = solver.potential(yamaguchi_kernel) assert solver.spectrum is not None assert solver.fourier is not None diff --git a/tests/unit/test_interaction_builders.py b/tests/unit/test_interaction_builders.py index cfec85c..eec1a76 100644 --- a/tests/unit/test_interaction_builders.py +++ b/tests/unit/test_interaction_builders.py @@ -1,4 +1,5 @@ """Tests for make_interaction_from_{block,array,funcs} builder factories.""" + from __future__ import annotations import jax.numpy as jnp @@ -6,7 +7,7 @@ import pytest import lax as lm -from lax.operators import assemble_local, assemble_nonlocal, make_interaction_from_array, make_interaction_from_block, make_interaction_from_funcs +from lax.operators.potential import assemble_local, assemble_nonlocal pytest.importorskip("jax") @@ -122,7 +123,9 @@ def test_interaction_from_array_nonlocal_matches_assemble_nonlocal() -> None: ) # assemble_nonlocal applies sqrt(w_i * w_j) * a scaling; the block should match - V_raw = assemble_nonlocal(solver.mesh, lambda r1, r2: jnp.asarray(np.exp(-0.5 * (np.asarray(r1) + np.asarray(r2))))) + V_raw = assemble_nonlocal( + solver.mesh, lambda r1, r2: jnp.asarray(np.exp(-0.5 * (np.asarray(r1) + np.asarray(r2)))) + ) expected = np.asarray(V_raw[0, 0]) # (N, N) assert np.allclose(np.asarray(interaction.block), expected, atol=1e-13) @@ -223,8 +226,8 @@ def local_fn(r: jnp.ndarray) -> jnp.ndarray: # --------------------------------------------------------------------------- -def test_rmatrix_direct_interaction_matches_raw_array() -> None: - """rmatrix_direct(Interaction) produces the same R-matrix as rmatrix_direct(raw_V).""" +def test_rmatrix_direct_interaction_round_trip() -> None: + """rmatrix_direct(Interaction) produces physically correct R-matrix values.""" alpha, beta = 0.2316053, 1.3918324 HBAR2_2MU = 41.472 @@ -240,15 +243,19 @@ def yamaguchi_kernel(r1: jnp.ndarray, r2: jnp.ndarray) -> jnp.ndarray: energies=jnp.asarray([0.1, 5.0]), ) - V_raw = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) # (1, 1, N, N) - assert solver.rmatrix_direct is not None - assert solver.interaction_from_block is not None + assert solver.potential is not None - # Build Interaction from the pre-assembled block - interaction = solver.interaction_from_block(V_raw[0, 0], energy_dependent=False) + # Build via solver.potential (canonical API) + V = solver.potential(yamaguchi_kernel) + r_from_potential = np.asarray(solver.rmatrix_direct(V)) - r_raw = np.asarray(solver.rmatrix_direct(V_raw)) - r_interaction = np.asarray(solver.rmatrix_direct(interaction)) + # Build via interaction_from_block (pre-assembled with Gauss scaling applied manually) + ri, rj = jnp.meshgrid(solver.mesh.radii, solver.mesh.radii, indexing="ij") + wi, wj = jnp.meshgrid(solver.mesh.weights, solver.mesh.weights, indexing="ij") + scaled_block = yamaguchi_kernel(ri, rj) * (jnp.sqrt(wi * wj) * solver.mesh.scale) + assert solver.interaction_from_block is not None + interaction = solver.interaction_from_block(scaled_block, energy_dependent=False) + r_from_block = np.asarray(solver.rmatrix_direct(interaction)) - assert np.allclose(r_raw, r_interaction, atol=1.0e-12, rtol=1.0e-12) + assert np.allclose(r_from_potential, r_from_block, atol=1.0e-12, rtol=1.0e-12) diff --git a/tests/unit/test_solver_direct.py b/tests/unit/test_solver_direct.py index 24d55ff..dd38f15 100644 --- a/tests/unit/test_solver_direct.py +++ b/tests/unit/test_solver_direct.py @@ -6,7 +6,6 @@ import pytest import lax as lm -from lax.meshes import build_mesh from lax.solvers import assemble_block_hamiltonian, build_Q, make_rmatrix_direct_kernel pytest.importorskip("jax") @@ -14,12 +13,9 @@ HBAR2_2MU = 41.472 -def _make_energy_dependent_potential(solver: lm.Solver, energy: jax.Array) -> jax.Array: - """Return a smooth energy-dependent local potential in MeV.""" - - radii = solver.mesh.radii - values = (-3.5 * jnp.exp(-((radii / 2.4) ** 2)) + 0.02 * energy) * HBAR2_2MU - return values[None, None, :] +def _energy_dep_V(r: jax.Array, E: float) -> jax.Array: + """Smooth energy-dependent local potential in MeV used across several tests.""" + return (-3.5 * jnp.exp(-((r / 2.4) ** 2)) + 0.02 * E) * HBAR2_2MU def test_make_rmatrix_direct_kernel_matches_manual_linear_solve() -> None: @@ -34,7 +30,10 @@ def test_make_rmatrix_direct_kernel_matches_manual_linear_solve() -> None: solvers=("rmatrix_direct",), energies=jnp.asarray([0.25, 0.75]), ) - potential = jnp.asarray([[[0.1, 0.2, 0.3, 0.4]]]) + g = jnp.asarray([0.1, 0.2, 0.3, 0.4]) + interaction = solver.interaction_from_array( + local=[(g, np.ones((1, 1)))], energy_dependent=False + ) kernel = make_rmatrix_direct_kernel( solver.mesh, @@ -43,12 +42,14 @@ def test_make_rmatrix_direct_kernel_matches_manual_linear_solve() -> None: solver.energies, None, ) - result = np.asarray(kernel(potential)) + result = np.asarray(kernel(interaction)) # Manual computation using MeV form: H_MeV = m_c*(T+L) + V; C = H_MeV − E·I; # R = Q'^T C^{-1} Q' / a where Q' = sqrt(m_c) · Q. + # assemble_block_hamiltonian with (1,1,4) raw array gives the same Hamiltonian. + potential_raw = jnp.asarray([[[0.1, 0.2, 0.3, 0.4]]]) hamiltonian = np.asarray( - assemble_block_hamiltonian(solver.mesh, solver.operators, solver.channels, potential) + assemble_block_hamiltonian(solver.mesh, solver.operators, solver.channels, potential_raw) ) q = np.asarray(build_Q(solver.mesh, solver.channels)) m_c = channels[0].mass_factor @@ -73,9 +74,13 @@ def test_compile_exposes_direct_rmatrix_kernel() -> None: ) assert solver.rmatrix_direct is not None - assert solver.rmatrix_direct_grid is not None - assert solver.smatrix_direct_grid is not None - assert solver.phases_direct_grid is not None + assert solver.smatrix_direct is not None + assert solver.phases_direct is not None + assert solver.potential is not None + # deprecated aligned-grid observables are no longer wired + assert solver.rmatrix_direct_grid is None + assert solver.smatrix_direct_grid is None + assert solver.phases_direct_grid is None assert solver.interpolate_rmatrix is not None assert solver.interpolate_smatrix is not None assert solver.interpolate_phases is not None @@ -162,8 +167,9 @@ def yamaguchi_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: solvers=("spectrum", "rmatrix", "rmatrix_direct"), energies=energies, ) - potential = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) - spectrum = solver.spectrum(potential) + + V = solver.potential(yamaguchi_kernel) + spectrum = solver.spectrum(V) assert solver.rmatrix is not None assert solver.rmatrix_direct is not None @@ -171,13 +177,13 @@ def yamaguchi_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: spectral = np.stack( [np.asarray(solver.rmatrix(spectrum, float(energy))) for energy in np.asarray(energies)] ) - direct = np.asarray(solver.rmatrix_direct(potential)) + direct = np.asarray(solver.rmatrix_direct(V)) assert np.allclose(direct, spectral, atol=1.0e-10, rtol=1.0e-10) def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: - """`rmatrix_direct_grid` matches a manual per-energy linear solve with varying `V(E)`.""" + """`rmatrix_direct(energy_dep_interaction)` matches a manual per-energy linear solve.""" energies = jnp.asarray([0.25, 0.75, 1.25]) solver = lm.compile( @@ -189,11 +195,10 @@ def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: method="linear_solve", energy_dependent=True, ) - potentials = jax.vmap(lambda energy: _make_energy_dependent_potential(solver, energy))(energies) - assert solver.rmatrix_direct_grid is not None + interaction = solver.potential(_energy_dep_V, energy_dependent=True) + result = np.asarray(solver.rmatrix_direct(interaction)) - result = np.asarray(solver.rmatrix_direct_grid(potentials)) expected = [] m_c = solver.channels[0].mass_factor q = np.asarray(build_Q(solver.mesh, solver.channels)) @@ -204,7 +209,7 @@ def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: solver.mesh, solver.operators, solver.channels, - potentials[index], + interaction.block[index], # (M, M) per-energy block ) ) # MeV form: C = H_MeV − E·I; R = Q'^T C^{-1} Q' / a. @@ -214,20 +219,32 @@ def test_direct_rmatrix_grid_matches_manual_per_energy_solve() -> None: assert np.allclose(result, np.stack(expected), atol=1.0e-10, rtol=1.0e-10) -def test_assemble_nonlocal_rejects_propagated_mesh() -> None: - """Propagated meshes reject non-local kernel assembly explicitly.""" +def test_rmatrix_direct_propagated_rejects_nonlocal_interaction() -> None: + """Propagated-mesh direct solves reject non-local Interactions with a clear ValueError.""" - mesh, _ = build_mesh("legendre", "x", n=4, scale=8.0, operators={"T+L"}, n_intervals=2) + propagated_solver = lm.compile( + mesh=lm.MeshSpec("legendre", "x", n=4, scale=8.0, extras={"n_intervals": 2}), + channels=(lm.ChannelSpec(l=0, threshold=0.0, mass_factor=2.0),), + operators=("T+L",), + solvers=("rmatrix_direct",), + energies=jnp.asarray([0.3, 0.9]), + method="linear_solve", + ) def nonlocal_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: return -2.0 * jnp.exp(-0.5 * (r1 + r2)) - with pytest.raises(ValueError, match="Non-local kernels"): - lm.assemble_nonlocal(mesh, nonlocal_kernel) + assert propagated_solver.potential is not None + assert propagated_solver.rmatrix_direct is not None + + nonlocal_interaction = propagated_solver.potential(nonlocal_kernel) + + with pytest.raises(ValueError, match="Non-local propagated"): + propagated_solver.rmatrix_direct(nonlocal_interaction) -def test_propagated_nonlocal_direct_rejects_inconsistent_request() -> None: - """Propagated direct solves reject non-local potentials instead of emulating them.""" +def test_propagated_nonlocal_direct_rejects_non_interaction() -> None: + """Propagated direct solves reject non-Interaction inputs with a clear TypeError.""" propagated_solver = lm.compile( mesh=lm.MeshSpec("legendre", "x", n=4, scale=8.0, extras={"n_intervals": 2}), @@ -238,16 +255,14 @@ def test_propagated_nonlocal_direct_rejects_inconsistent_request() -> None: method="linear_solve", ) - potential = jnp.ones((1, 1, 8, 8), dtype=jnp.float64) - assert propagated_solver.rmatrix_direct is not None - with pytest.raises(ValueError, match="Non-local propagated solves"): - propagated_solver.rmatrix_direct(potential) + with pytest.raises(TypeError, match="Interaction"): + propagated_solver.rmatrix_direct(jnp.ones((4, 4), dtype=jnp.float64)) def test_direct_grid_observables_match_spectral_grid_for_real_energy_dependent_potential() -> None: - """Direct aligned-grid `R/S/δ` agree with the spectral aligned-grid helpers.""" + """Direct `R/S/δ` from `rmatrix_direct(energy_dep)` agree with spectral aligned-grid helpers.""" energies = jnp.linspace(0.2, 2.0, 9) spectral_solver = lm.compile( @@ -272,24 +287,28 @@ def test_direct_grid_observables_match_spectral_grid_for_real_energy_dependent_p assert spectral_solver.rmatrix_grid is not None assert spectral_solver.smatrix_grid is not None assert spectral_solver.phases_grid is not None - assert direct_solver.rmatrix_direct_grid is not None - assert direct_solver.smatrix_direct_grid is not None - assert direct_solver.phases_direct_grid is not None - - spectral_potentials = jax.vmap( - lambda energy: _make_energy_dependent_potential(spectral_solver, energy) - )(energies) - direct_potentials = jax.vmap( - lambda energy: _make_energy_dependent_potential(direct_solver, energy) - )(energies) - spectra = jax.vmap(spectral_solver.spectrum)(spectral_potentials) + assert direct_solver.rmatrix_direct is not None + assert direct_solver.smatrix_direct is not None + assert direct_solver.phases_direct is not None + # deprecated aligned-grid observables are no longer wired + assert direct_solver.rmatrix_direct_grid is None + assert direct_solver.smatrix_direct_grid is None + assert direct_solver.phases_direct_grid is None + + spectral_interaction = spectral_solver.potential(_energy_dep_V, energy_dependent=True) + direct_interaction = direct_solver.potential(_energy_dep_V, energy_dependent=True) + + # Spectral path: vmap spectrum over the per-energy (M, M) block slices. + # Raw 2D blocks pass through the Interaction check in _SpectrumKernel.__call__. + spectra = jax.vmap(spectral_solver.spectrum)(spectral_interaction.block) spectral_r = np.asarray(spectral_solver.rmatrix_grid(spectra)) spectral_s = np.asarray(spectral_solver.smatrix_grid(spectra)) spectral_phases = np.asarray(spectral_solver.phases_grid(spectra)) - direct_r = np.asarray(direct_solver.rmatrix_direct_grid(direct_potentials)) - direct_s = np.asarray(direct_solver.smatrix_direct_grid(direct_potentials)) - direct_phases = np.asarray(direct_solver.phases_direct_grid(direct_potentials)) + + direct_r = np.asarray(direct_solver.rmatrix_direct(direct_interaction)) + direct_s = np.asarray(direct_solver.smatrix_direct(direct_interaction)) + direct_phases = np.asarray(direct_solver.phases_direct(direct_interaction)) assert np.allclose(direct_r, spectral_r, atol=1.0e-10, rtol=1.0e-10) assert np.allclose(direct_s, spectral_s, atol=1.0e-10, rtol=1.0e-10) @@ -326,13 +345,14 @@ def test_mass_factor_grid_broadcast_scalar_reproduces_uniform() -> None: mass_factor_grid=jnp.full((2,), m), # (N_E,) — broadcasts to (N_E, N_c) ) - potentials = jax.vmap(lambda e: _make_energy_dependent_potential(solver_uniform, e))(energies) + assert solver_uniform.rmatrix_direct_grid is None # deprecated + assert solver_grid.rmatrix_direct_grid is None # deprecated - assert solver_uniform.rmatrix_direct_grid is not None - assert solver_grid.rmatrix_direct_grid is not None + interaction_uniform = solver_uniform.potential(_energy_dep_V, energy_dependent=True) + interaction_grid = solver_grid.potential(_energy_dep_V, energy_dependent=True) - r_uniform = np.asarray(solver_uniform.rmatrix_direct_grid(potentials)) - r_grid = np.asarray(solver_grid.rmatrix_direct_grid(potentials)) + r_uniform = np.asarray(solver_uniform.rmatrix_direct(interaction_uniform)) + r_grid = np.asarray(solver_grid.rmatrix_direct(interaction_grid)) assert np.allclose(r_uniform, r_grid, atol=1.0e-12, rtol=1.0e-12) @@ -362,13 +382,14 @@ def test_mass_factor_grid_2d_reproduces_uniform() -> None: mass_factor_grid=jnp.full((2, 1), m), # explicit (N_E, N_c) shape ) - potentials = jax.vmap(lambda e: _make_energy_dependent_potential(solver_uniform, e))(energies) + assert solver_uniform.rmatrix_direct_grid is None # deprecated + assert solver_grid.rmatrix_direct_grid is None # deprecated - assert solver_uniform.rmatrix_direct_grid is not None - assert solver_grid.rmatrix_direct_grid is not None + interaction_uniform = solver_uniform.potential(_energy_dep_V, energy_dependent=True) + interaction_grid = solver_grid.potential(_energy_dep_V, energy_dependent=True) - r_uniform = np.asarray(solver_uniform.rmatrix_direct_grid(potentials)) - r_grid = np.asarray(solver_grid.rmatrix_direct_grid(potentials)) + r_uniform = np.asarray(solver_uniform.rmatrix_direct(interaction_uniform)) + r_grid = np.asarray(solver_grid.rmatrix_direct(interaction_grid)) assert np.allclose(r_uniform, r_grid, atol=1.0e-12, rtol=1.0e-12) @@ -437,32 +458,29 @@ def test_per_channel_mass_factor_grid_decoupled_matches_single_channel() -> None energy_dependent=True, ) - # Decoupled diagonal potential: channel 0 gets g0, channel 1 gets g1. - radii = two_ch.mesh.radii - g0 = -0.5 * jnp.exp(-(radii / 2.5) ** 2) * m0 - g1 = -0.3 * jnp.exp(-(radii / 3.0) ** 2) * m1 - zeros = jnp.zeros_like(g0) - - def two_ch_pot(_energy: jax.Array) -> jax.Array: - return jnp.array([[g0, zeros], [zeros, g1]]) # (2, 2, N) + assert two_ch.rmatrix_direct_grid is None # deprecated + assert ch0_solver.rmatrix_direct_grid is None # deprecated + assert ch1_solver.rmatrix_direct_grid is None # deprecated - def ch0_pot(_energy: jax.Array) -> jax.Array: - return jnp.array([[[*g0]]]) # (1, 1, N) + # Decoupled diagonal potentials (energy-independent in value, energy-dependent in API). + def V_ch0_fn(r: jax.Array, E: float) -> jax.Array: + return -0.5 * jnp.exp(-((r / 2.5) ** 2)) * m0 - def ch1_pot(_energy: jax.Array) -> jax.Array: - return jnp.array([[[*g1]]]) # (1, 1, N) + def V_ch1_fn(r: jax.Array, E: float) -> jax.Array: + return -0.3 * jnp.exp(-((r / 3.0) ** 2)) * m1 - two_pots = jax.vmap(two_ch_pot)(energies) - ch0_pots = jax.vmap(ch0_pot)(energies) - ch1_pots = jax.vmap(ch1_pot)(energies) + A0 = np.array([[1.0, 0.0], [0.0, 0.0]]) + A1 = np.array([[0.0, 0.0], [0.0, 1.0]]) - assert two_ch.rmatrix_direct_grid is not None - assert ch0_solver.rmatrix_direct_grid is not None - assert ch1_solver.rmatrix_direct_grid is not None + V_two = two_ch.potential(V_ch0_fn, coupling=A0, energy_dependent=True) + two_ch.potential( + V_ch1_fn, coupling=A1, energy_dependent=True + ) + V_ch0 = ch0_solver.potential(V_ch0_fn, energy_dependent=True) + V_ch1 = ch1_solver.potential(V_ch1_fn, energy_dependent=True) - r_two = np.asarray(two_ch.rmatrix_direct_grid(two_pots)) # (N_E, 2, 2) - r_ch0 = np.asarray(ch0_solver.rmatrix_direct_grid(ch0_pots)) # (N_E, 1, 1) - r_ch1 = np.asarray(ch1_solver.rmatrix_direct_grid(ch1_pots)) # (N_E, 1, 1) + r_two = np.asarray(two_ch.rmatrix_direct(V_two)) # (N_E, 2, 2) + r_ch0 = np.asarray(ch0_solver.rmatrix_direct(V_ch0)) # (N_E, 1, 1) + r_ch1 = np.asarray(ch1_solver.rmatrix_direct(V_ch1)) # (N_E, 1, 1) # Diagonal elements of decoupled two-channel solver must match single-channel results. assert np.allclose(r_two[:, 0, 0], r_ch0[:, 0, 0], atol=1.0e-10, rtol=1.0e-10) @@ -495,23 +513,19 @@ def yamaguchi_kernel(r1: jax.Array, r2: jax.Array) -> jax.Array: energies=energies, ) - V_raw = lm.assemble_nonlocal(solver.mesh, yamaguchi_kernel) # (1, 1, N, N) - spec = solver.spectrum(V_raw) - assert solver.wavefunction is not None assert solver.wavefunction_direct is not None - assert solver.interaction_from_block is not None + assert solver.potential is not None - # Build Interaction from the pre-assembled (M, M) nonlocal block. - # For N_c=1, M=N, so V_raw[0, 0] is already (M, M). - interaction = solver.interaction_from_block(V_raw[0, 0], energy_dependent=False) + V = solver.potential(yamaguchi_kernel) + spec = solver.spectrum(V) for energy_index in range(len(energies)): energy = float(energies[energy_index]) src = lm.make_wavefunction_source(solver, channel_index=0, energy_index=energy_index) psi_spec = np.asarray(solver.wavefunction(spec, energy, src)) - psi_dir = np.asarray(solver.wavefunction_direct(interaction, src, energy_index)) + psi_dir = np.asarray(solver.wavefunction_direct(V, src, energy_index)) assert np.allclose(psi_spec, psi_dir, atol=1.0e-10, rtol=1.0e-10), ( f"wavefunction_direct mismatch at energy_index={energy_index}" diff --git a/tests/unit/test_solver_pickle.py b/tests/unit/test_solver_pickle.py index ac38e72..c6a4be8 100644 --- a/tests/unit/test_solver_pickle.py +++ b/tests/unit/test_solver_pickle.py @@ -30,12 +30,11 @@ def test_compiled_solver_round_trips_through_pickle() -> None: energies=jnp.asarray([0.25, 0.5]), grid=jnp.linspace(0.5, 6.5, 7), momenta=jnp.linspace(0.1, 1.0, 6), + energy_dependent=True, ) restored = pickle.loads(pickle.dumps(solver)) - potential = jnp.asarray([[[0.2, 0.1, 0.0, -0.1]]]) source = jnp.asarray([1.0, 0.0, 0.0, 0.0]) - potentials_grid = jnp.stack((potential, potential + 0.05), axis=0) vector = jnp.asarray([0.3, -0.2, 0.1, 0.4]) matrix = jnp.asarray( [ @@ -47,6 +46,15 @@ def test_compiled_solver_round_trips_through_pickle() -> None: ) diagonal_operator = jnp.asarray([1.0, 1.5, 2.0, 2.5]) + # Build potentials using the Interaction API. + g1 = jnp.asarray([0.2, 0.1, 0.0, -0.1]) + g2 = jnp.asarray([0.25, 0.15, 0.05, -0.05]) + A = np.ones((1, 1)) + interaction = solver.interaction_from_array(local=[(g1, A)], energy_dependent=False) + interaction_grid = solver.interaction_from_array( + local=[(jnp.stack([g1, g2]), A)], energy_dependent=True + ) + for name in ( "spectrum", "rmatrix", @@ -58,9 +66,9 @@ def test_compiled_solver_round_trips_through_pickle() -> None: "smatrix_grid", "phases_grid", "rmatrix_direct", - "rmatrix_direct_grid", - "smatrix_direct_grid", - "phases_direct_grid", + "smatrix_direct", + "phases_direct", + "potential", "interpolate_rmatrix", "interpolate_smatrix", "interpolate_phases", @@ -73,6 +81,14 @@ def test_compiled_solver_round_trips_through_pickle() -> None: ): assert getattr(restored, name) is not None + # deprecated aligned-grid observables are no longer wired + assert solver.rmatrix_direct_grid is None + assert solver.smatrix_direct_grid is None + assert solver.phases_direct_grid is None + assert restored.rmatrix_direct_grid is None + assert restored.smatrix_direct_grid is None + assert restored.phases_direct_grid is None + assert solver.spectrum is not None assert solver.rmatrix is not None assert solver.smatrix is not None @@ -83,9 +99,8 @@ def test_compiled_solver_round_trips_through_pickle() -> None: assert solver.smatrix_grid is not None assert solver.phases_grid is not None assert solver.rmatrix_direct is not None - assert solver.rmatrix_direct_grid is not None - assert solver.smatrix_direct_grid is not None - assert solver.phases_direct_grid is not None + assert solver.smatrix_direct is not None + assert solver.phases_direct is not None assert solver.interpolate_rmatrix is not None assert solver.interpolate_smatrix is not None assert solver.interpolate_phases is not None @@ -96,10 +111,11 @@ def test_compiled_solver_round_trips_through_pickle() -> None: assert solver.double_fourier_transform is not None assert solver.integrate is not None - fresh_spectrum = solver.spectrum(potential) - restored_spectrum = restored.spectrum(potential) - fresh_spectra_grid = jax.vmap(solver.spectrum)(potentials_grid) - restored_spectra_grid = jax.vmap(restored.spectrum)(potentials_grid) + fresh_spectrum = solver.spectrum(interaction) + restored_spectrum = restored.spectrum(interaction) + # Vmap over the per-energy block slices (raw 2D arrays pass through spectrum's Interaction check). + fresh_spectra_grid = jax.vmap(solver.spectrum)(interaction_grid.block) + restored_spectra_grid = jax.vmap(restored.spectrum)(interaction_grid.block) assert np.allclose(np.asarray(restored.mesh.nodes), np.asarray(solver.mesh.nodes)) assert np.allclose(np.asarray(restored.mesh.weights), np.asarray(solver.mesh.weights)) @@ -150,20 +166,16 @@ def test_compiled_solver_round_trips_through_pickle() -> None: np.asarray(solver.phases_grid(fresh_spectra_grid)), ) assert np.allclose( - np.asarray(restored.rmatrix_direct(potential)), - np.asarray(solver.rmatrix_direct(potential)), - ) - assert np.allclose( - np.asarray(restored.rmatrix_direct_grid(potentials_grid)), - np.asarray(solver.rmatrix_direct_grid(potentials_grid)), + np.asarray(restored.rmatrix_direct(interaction)), + np.asarray(solver.rmatrix_direct(interaction)), ) assert np.allclose( - np.asarray(restored.smatrix_direct_grid(potentials_grid)), - np.asarray(solver.smatrix_direct_grid(potentials_grid)), + np.asarray(restored.smatrix_direct(interaction)), + np.asarray(solver.smatrix_direct(interaction)), ) assert np.allclose( - np.asarray(restored.phases_direct_grid(potentials_grid)), - np.asarray(solver.phases_direct_grid(potentials_grid)), + np.asarray(restored.phases_direct(interaction)), + np.asarray(solver.phases_direct(interaction)), ) restored_smatrix_grid = restored.smatrix_grid(restored_spectra_grid) fresh_smatrix_grid = solver.smatrix_grid(fresh_spectra_grid) diff --git a/tests/unit/test_solver_spectrum.py b/tests/unit/test_solver_spectrum.py index e6ec724..3c73081 100644 --- a/tests/unit/test_solver_spectrum.py +++ b/tests/unit/test_solver_spectrum.py @@ -8,6 +8,7 @@ from lax.boundary import BoundaryValues from lax.boundary._types import OperatorMatrices from lax.meshes.legendre import build_legendre_x +from lax.operators import make_interaction_from_array from lax.solvers import ( assemble_block_hamiltonian, bind_observables, @@ -220,8 +221,17 @@ def test_coupled_channel_rmatrix_matches_direct_solver() -> None: k=jnp.asarray([[1.0, 1.0]]), ), ) + array_builder = make_interaction_from_array(mesh, channels, jnp.asarray([0.25])) + interaction = array_builder( + local=[ + (potential[0, 0], np.array([[1.0, 0.0], [0.0, 0.0]])), + (potential[0, 1], np.array([[0.0, 1.0], [1.0, 0.0]])), + (potential[1, 1], np.array([[0.0, 0.0], [0.0, 1.0]])), + ], + energy_dependent=False, + ) direct = make_rmatrix_direct_kernel(mesh, operators, channels, jnp.asarray([0.25]), None)( - potential + interaction ) assert smatrix is not None diff --git a/tests/unit/test_spectral.py b/tests/unit/test_spectral.py index 2361055..3c04cf0 100644 --- a/tests/unit/test_spectral.py +++ b/tests/unit/test_spectral.py @@ -138,11 +138,20 @@ def test_smatrix_from_R_is_symmetric_and_unitary_for_real_two_channel_r() -> Non solvers=("spectrum", "rmatrix"), energies=energy, ) - potential = lm.assemble_local(solver.mesh, reid_np_j1_potential, n_channels=2) assert solver.spectrum is not None assert solver.rmatrix is not None assert solver.boundary is not None - + assert solver.interaction_from_array is not None + + r = solver.mesh.radii + potential = solver.interaction_from_array( + local=[ + (reid_np_j1_potential(r, 0, 0), np.array([[1.0, 0.0], [0.0, 0.0]])), + (reid_np_j1_potential(r, 0, 1), np.array([[0.0, 1.0], [1.0, 0.0]])), + (reid_np_j1_potential(r, 1, 1), np.array([[0.0, 0.0], [0.0, 1.0]])), + ], + energy_dependent=False, + ) spectrum = solver.spectrum(potential) R = solver.rmatrix(spectrum, float(energy[0])) boundary = BoundaryValues( From 7e0e618fefe18130537532a89a863575361850db Mon Sep 17 00:00:00 2001 From: beykyle Date: Wed, 10 Jun 2026 02:23:23 -0400 Subject: [PATCH 06/10] static analysis --- src/lax/boundary/_types.py | 10 +-- src/lax/compile.py | 15 ++-- src/lax/operators/interaction.py | 54 ++++++------ src/lax/operators/potential.py | 110 ------------------------ src/lax/solvers/assembly.py | 4 +- src/lax/solvers/linear_solve.py | 4 +- tests/benchmarks/test_yamaguchi.py | 2 +- tests/unit/test_interaction_builders.py | 23 ++--- 8 files changed, 57 insertions(+), 165 deletions(-) delete mode 100644 src/lax/operators/potential.py diff --git a/src/lax/boundary/_types.py b/src/lax/boundary/_types.py index 1d03412..908749c 100644 --- a/src/lax/boundary/_types.py +++ b/src/lax/boundary/_types.py @@ -4,7 +4,7 @@ from collections.abc import Callable from dataclasses import dataclass, field -from typing import TYPE_CHECKING, Protocol +from typing import TYPE_CHECKING, Any, Protocol import jax @@ -764,10 +764,10 @@ class Solver: smatrix_direct: SMatrixDirectObservable | None = None phases_direct: PhasesDirectObservable | None = None wavefunction_direct: WavefunctionDirectObservable | None = None - interaction_from_block: Callable | None = None - interaction_from_array: Callable | None = None - interaction_from_funcs: Callable | None = None - potential: Callable | None = None + interaction_from_block: Callable[..., Any] | None = None + interaction_from_array: Callable[..., Any] | None = None + interaction_from_funcs: Callable[..., Any] | None = None + potential: Callable[..., Any] | None = None interpolate_rmatrix: InterpolatorBuilder | None = None interpolate_smatrix: InterpolatorBuilder | None = None interpolate_phases: InterpolatorBuilder | None = None diff --git a/src/lax/compile.py b/src/lax/compile.py index 5855ba0..8781b02 100644 --- a/src/lax/compile.py +++ b/src/lax/compile.py @@ -8,8 +8,9 @@ from __future__ import annotations -from collections.abc import Iterable +from collections.abc import Callable, Iterable from dataclasses import dataclass +from typing import Any import jax import jax.numpy as jnp @@ -113,10 +114,10 @@ class _ObservableBundle: smatrix_direct: SMatrixDirectObservable | None phases_direct: PhasesDirectObservable | None wavefunction_direct: WavefunctionDirectObservable | None - interaction_from_block: object | None - interaction_from_array: object | None - interaction_from_funcs: object | None - potential: object | None + interaction_from_block: Callable[..., Any] | None + interaction_from_array: Callable[..., Any] | None + interaction_from_funcs: Callable[..., Any] | None + potential: Callable[..., Any] | None interpolate_rmatrix: InterpolatorBuilder | None interpolate_smatrix: InterpolatorBuilder | None interpolate_phases: InterpolatorBuilder | None @@ -540,7 +541,9 @@ def _bind_solver_observables( boundary, mass_factor_grid, ) - from lax.solvers.linear_solve import _DirectRMatrixKernel # noqa: PLC0415 + from lax.solvers.linear_solve import ( + _DirectRMatrixKernel, # noqa: PLC0415 # pyright: ignore[reportPrivateUsage] + ) if isinstance(rmatrix_direct_fn, _DirectRMatrixKernel): smatrix_direct_fn = make_smatrix_direct_observable(rmatrix_direct_fn, boundary) diff --git a/src/lax/operators/interaction.py b/src/lax/operators/interaction.py index 50b30b0..7ea429b 100644 --- a/src/lax/operators/interaction.py +++ b/src/lax/operators/interaction.py @@ -3,7 +3,9 @@ from __future__ import annotations import inspect +from collections.abc import Sequence from dataclasses import dataclass +from typing import Any import jax import jax.numpy as jnp @@ -55,8 +57,8 @@ def _validate_A(self, A: jax.Array, label: str) -> None: def __call__( self, - local: list[tuple[jax.Array, jax.Array]] = (), - nonlocal_: list[tuple[jax.Array, jax.Array]] = (), + local: Sequence[tuple[jax.Array, jax.Array]] = (), + nonlocal_: Sequence[tuple[jax.Array, jax.Array]] = (), energy_dependent: bool = False, ) -> Interaction: """Build Interaction from (form_factor, coupling_matrix) term lists. @@ -84,10 +86,10 @@ def __call__( else: block = jnp.zeros((M, M), dtype=dtype) - for term_idx, (g, A) in enumerate(local): - g = jnp.asarray(g) - A = jnp.asarray(A) - self._validate_A(A, f"local term {term_idx}") + for term_idx, (g_raw, a_raw) in enumerate(local): + g = jnp.asarray(g_raw) + a_mat = jnp.asarray(a_raw) + self._validate_A(a_mat, f"local term {term_idx}") if energy_dependent: if g.ndim != 2 or g.shape != (N_E, N): raise ValueError( @@ -96,11 +98,11 @@ def __call__( ) for c in range(N_c): for cp in range(N_c): - if A[c, cp] == 0: + if a_mat[c, cp] == 0: continue row_start = c * N col_start = cp * N - diag_blocks = jax.vmap(jnp.diag)(A[c, cp] * g) # (N_E, N, N) + diag_blocks = jax.vmap(jnp.diag)(a_mat[c, cp] * g) # (N_E, N, N) block = block.at[ :, row_start : row_start + N, col_start : col_start + N ].add(diag_blocks) @@ -112,18 +114,18 @@ def __call__( ) for c in range(N_c): for cp in range(N_c): - if A[c, cp] == 0: + if a_mat[c, cp] == 0: continue row_start = c * N col_start = cp * N block = block.at[row_start : row_start + N, col_start : col_start + N].add( - jnp.diag(A[c, cp] * g) + jnp.diag(a_mat[c, cp] * g) ) - for term_idx, (g, A) in enumerate(nonlocal_): - g = jnp.asarray(g) - A = jnp.asarray(A) - self._validate_A(A, f"nonlocal term {term_idx}") + for term_idx, (g_raw, a_raw) in enumerate(nonlocal_): + g = jnp.asarray(g_raw) + a_mat = jnp.asarray(a_raw) + self._validate_A(a_mat, f"nonlocal term {term_idx}") if energy_dependent: if g.ndim != 3 or g.shape != (N_E, N, N): raise ValueError( @@ -133,13 +135,13 @@ def __call__( scaled = g * self.gauss_scale[None, :, :] # (N_E, N, N) for c in range(N_c): for cp in range(N_c): - if A[c, cp] == 0: + if a_mat[c, cp] == 0: continue row_start = c * N col_start = cp * N block = block.at[ :, row_start : row_start + N, col_start : col_start + N - ].add(A[c, cp] * scaled) + ].add(a_mat[c, cp] * scaled) else: if g.ndim != 2 or g.shape != (N, N): raise ValueError( @@ -149,12 +151,12 @@ def __call__( scaled = g * self.gauss_scale # (N, N) for c in range(N_c): for cp in range(N_c): - if A[c, cp] == 0: + if a_mat[c, cp] == 0: continue row_start = c * N col_start = cp * N block = block.at[row_start : row_start + N, col_start : col_start + N].add( - A[c, cp] * scaled + a_mat[c, cp] * scaled ) first_block = block[0] if energy_dependent else block @@ -176,8 +178,8 @@ class _InteractionFromFuncs: def __call__( self, - local: list = (), - nonlocal_: list = (), + local: Sequence[tuple[Any, Any]] = (), + nonlocal_: Sequence[tuple[Any, Any]] = (), energy_dependent: bool = False, ) -> Interaction: """Build Interaction from callable (form_factor_fn, coupling_matrix) terms. @@ -193,25 +195,25 @@ def __call__( N_E = self.N_E ri, rj = jnp.meshgrid(r, r, indexing="ij") # (N, N) - local_arrays = [] - for g_fn, A in local: + local_arrays: list[Any] = [] + for g_fn, a_mat in local: if energy_dependent: g_arr = jnp.stack( [g_fn(r, float(self.energies[ie])) for ie in range(N_E)] ) # (N_E, N) else: g_arr = g_fn(r) # (N,) - local_arrays.append((g_arr, A)) + local_arrays.append((g_arr, a_mat)) - nonlocal_arrays = [] - for g_fn, A in nonlocal_: + nonlocal_arrays: list[Any] = [] + for g_fn, a_mat in nonlocal_: if energy_dependent: g_arr = jnp.stack( [g_fn(ri, rj, float(self.energies[ie])) for ie in range(N_E)] ) # (N_E, N, N) else: g_arr = g_fn(ri, rj) # (N, N) - nonlocal_arrays.append((g_arr, A)) + nonlocal_arrays.append((g_arr, a_mat)) return self.array_builder( local=local_arrays, diff --git a/src/lax/operators/potential.py b/src/lax/operators/potential.py deleted file mode 100644 index e177f12..0000000 --- a/src/lax/operators/potential.py +++ /dev/null @@ -1,110 +0,0 @@ -"""Potential assembly helpers.""" - -from __future__ import annotations - -from collections.abc import Callable - -import jax -import jax.numpy as jnp - -from lax.boundary._types import Mesh - - -def assemble_local( - mesh: Mesh, - potential_fn: Callable[..., jax.Array], - n_channels: int = 1, -) -> jax.Array: - """Assemble a local potential sampled on the mesh radii. - - Parameters - ---------- - mesh - Compiled mesh (``solver.mesh``). - potential_fn - For single-channel: ``potential_fn(radii) -> (N,)`` array of potential - values in MeV. For coupled-channel: ``potential_fn(radii, c, c') -> - (N,)`` array for the ``(c, c')`` block. - n_channels - Number of coupled channels ``N_c``. - - Returns - ------- - jax.Array - Shape ``(N_c, N_c, N)`` where ``N = mesh.n``. Pass directly to - ``solver.spectrum(V)`` or ``solver.rmatrix_direct(V)``. - """ - - radii = mesh.radii - if n_channels == 1: - values = potential_fn(radii) - return values[None, None, :] - - blocks: list[jax.Array] = [] - for channel_index in range(n_channels): - row: list[jax.Array] = [] - for coupled_index in range(n_channels): - row.append(potential_fn(radii, channel_index, coupled_index)) - blocks.append(jnp.stack(row)) - matrix: jax.Array = jnp.stack(blocks) - return matrix - - -def assemble_nonlocal( - mesh: Mesh, - kernel_fn: Callable[..., jax.Array], - n_channels: int = 1, -) -> jax.Array: - """Assemble a Gauss-scaled non-local potential on the mesh. - - Applies the Gauss-quadrature weight scaling ``(λ_i λ_j)^{1/2} · a`` - required by the Lagrange-mesh non-local matrix element formula - [Descouvemont eq. 26]. - - Parameters - ---------- - mesh - Compiled mesh (``solver.mesh``). - kernel_fn - For single-channel: ``kernel_fn(r_i, r_j) -> (N, N)`` kernel values in - MeV. For coupled-channel: ``kernel_fn(r_i, r_j, c, c') -> (N, N)`` - for the ``(c, c')`` block. - n_channels - Number of coupled channels ``N_c``. - - Returns - ------- - jax.Array - Shape ``(N_c, N_c, N, N)`` where ``N = mesh.n``. Pass directly to - ``solver.spectrum(V)`` or ``solver.rmatrix_direct(V)``. - """ - - if mesh.propagation is not None: - msg = ( - "Subinterval propagation is defined only for local potentials in the direct " - "linear-solve formulation. Non-local kernels are not mathematically " - "supported on propagated meshes." - ) - raise ValueError(msg) - - radii = mesh.radii - weights = mesh.weights - radius_i, radius_j = jnp.meshgrid(radii, radii, indexing="ij") - weight_i, weight_j = jnp.meshgrid(weights, weights, indexing="ij") - scale = jnp.sqrt(weight_i * weight_j) * mesh.scale - - if n_channels == 1: - kernel = kernel_fn(radius_i, radius_j) - return (kernel * scale)[None, None, :, :] - - blocks: list[jax.Array] = [] - for channel_index in range(n_channels): - row: list[jax.Array] = [] - for coupled_index in range(n_channels): - row.append(kernel_fn(radius_i, radius_j, channel_index, coupled_index) * scale) - blocks.append(jnp.stack(row)) - matrix: jax.Array = jnp.stack(blocks) - return matrix - - -__all__ = ["assemble_local", "assemble_nonlocal"] diff --git a/src/lax/solvers/assembly.py b/src/lax/solvers/assembly.py index 306dd52..78f679c 100644 --- a/src/lax/solvers/assembly.py +++ b/src/lax/solvers/assembly.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import cast + import jax import jax.numpy as jnp @@ -65,7 +67,7 @@ def assemble_block_hamiltonian( if jnp.ndim(mass_factor_override) == 0: m_c = mass_factor_override else: - m_c = mass_factor_override[channel_index] + m_c = cast(jax.Array, mass_factor_override)[channel_index] else: m_c = channels[channel_index].mass_factor angular_momentum = channels[channel_index].l diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index 7ad41e0..0320197 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -731,13 +731,13 @@ def _direct_smatrix_grid( ) -> jax.Array: """Match an (N_E, N_c, N_c) R-matrix grid to the S-matrix grid.""" - return cast(jax.Array, jax.vmap(smatrix_from_R)(r_grid, boundary)) + return jax.vmap(smatrix_from_R)(r_grid, boundary) def _direct_phases_grid(s_grid: jax.Array) -> jax.Array: """Extract phase shifts from an (N_E, N_c, N_c) S-matrix grid.""" - return cast(jax.Array, jax.vmap(phases_from_S)(s_grid)) + return jax.vmap(phases_from_S)(s_grid) _RMATRIX_DIRECT_JIT = jax.jit( diff --git a/tests/benchmarks/test_yamaguchi.py b/tests/benchmarks/test_yamaguchi.py index 9984752..950dec4 100644 --- a/tests/benchmarks/test_yamaguchi.py +++ b/tests/benchmarks/test_yamaguchi.py @@ -17,7 +17,7 @@ the prototype and the library both recover it at `a=15, N=20`. This test is the keystone benchmark: it exercises the full chain - assemble_nonlocal → spectrum → rmatrix → smatrix → phases. + solver.potential → spectrum → rmatrix → smatrix → phases. """ import numpy as np diff --git a/tests/unit/test_interaction_builders.py b/tests/unit/test_interaction_builders.py index eec1a76..d46e173 100644 --- a/tests/unit/test_interaction_builders.py +++ b/tests/unit/test_interaction_builders.py @@ -7,7 +7,6 @@ import pytest import lax as lm -from lax.operators.potential import assemble_local, assemble_nonlocal pytest.importorskip("jax") @@ -79,7 +78,7 @@ def test_interaction_from_block_rejects_wrong_shape() -> None: def test_interaction_from_array_local_matches_assemble_local() -> None: - """Local term builds the same (M, M) diagonal block as assemble_local.""" + """Local term builds the correct (M, M) diagonal block.""" solver = _make_mesh_channels() radii = np.asarray(solver.mesh.radii) @@ -93,13 +92,9 @@ def test_interaction_from_array_local_matches_assemble_local() -> None: energy_dependent=False, ) - # assemble_local returns (1, 1, N); the block should be diag(g) - V_raw = assemble_local(solver.mesh, lambda r: g) # (1, 1, N) + # Local term with A=[[1]] should produce diag(g) as the (M, M) block expected = np.diag(np.asarray(g)) - assert np.allclose(np.asarray(interaction.block), expected, atol=1e-13) - # Also verify it matches the V_raw diagonal - assert np.allclose(np.asarray(interaction.block), np.diag(np.asarray(V_raw[0, 0])), atol=1e-13) # --------------------------------------------------------------------------- @@ -108,10 +103,12 @@ def test_interaction_from_array_local_matches_assemble_local() -> None: def test_interaction_from_array_nonlocal_matches_assemble_nonlocal() -> None: - """Nonlocal term builds the same (M, M) block as assemble_nonlocal.""" + """Nonlocal term builds the correct Gauss-scaled (M, M) block.""" solver = _make_mesh_channels() radii = np.asarray(solver.mesh.radii) + weights = np.asarray(solver.mesh.weights) + a = float(solver.mesh.scale) ri, rj = np.meshgrid(radii, radii, indexing="ij") K = jnp.asarray(np.exp(-0.5 * (ri + rj))) # (N, N) kernel values @@ -122,12 +119,10 @@ def test_interaction_from_array_nonlocal_matches_assemble_nonlocal() -> None: energy_dependent=False, ) - # assemble_nonlocal applies sqrt(w_i * w_j) * a scaling; the block should match - V_raw = assemble_nonlocal( - solver.mesh, lambda r1, r2: jnp.asarray(np.exp(-0.5 * (np.asarray(r1) + np.asarray(r2)))) - ) - expected = np.asarray(V_raw[0, 0]) # (N, N) - + # Nonlocal term with A=[[1]] should produce K * sqrt(w_i * w_j) * a + wi, wj = np.meshgrid(weights, weights, indexing="ij") + gauss_scale = np.sqrt(wi * wj) * a + expected = np.asarray(K) * gauss_scale assert np.allclose(np.asarray(interaction.block), expected, atol=1e-13) From e6264577f57745214970f26a46e5a8f6ba66b8cc Mon Sep 17 00:00:00 2001 From: beykyle Date: Wed, 10 Jun 2026 02:26:18 -0400 Subject: [PATCH 07/10] remove depr functions from api --- docs/api.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index f3ee4cf..7b869d8 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -11,10 +11,6 @@ containing all JIT-compiled observables. .. autofunction:: compile -.. autofunction:: assemble_local - -.. autofunction:: assemble_nonlocal - .. autofunction:: make_wavefunction_source .. autoclass:: MeshSpec From 3149a5ac8ceedf2dfc6c1c8e28ef07dd4c76c8c6 Mon Sep 17 00:00:00 2001 From: beykyle Date: Thu, 11 Jun 2026 01:11:52 -0400 Subject: [PATCH 08/10] remove depr code paths --- examples/alpha_pb_demo.ipynb | 91 ++++-- .../descouvemont_closed_channels_demo.ipynb | 53 +--- examples/descouvemont_np_demo.ipynb | 15 +- examples/descouvemont_o16_ca44_demo.ipynb | 49 +-- examples/energy_dependent_demo.ipynb | 8 +- examples/fourier_demo.ipynb | 17 +- examples/hydrogen_demo.ipynb | 27 +- examples/yamaguchi_demo.ipynb | 20 +- src/lax/boundary/_types.py | 40 +-- src/lax/boundary/coulomb.py | 31 +- src/lax/compile.py | 20 +- src/lax/meshes/laguerre.py | 12 +- src/lax/meshes/legendre.py | 24 +- src/lax/models/__init__.py | 6 +- src/lax/models/optical.py | 77 +++-- src/lax/solvers/__init__.py | 2 - src/lax/solvers/assembly.py | 24 +- src/lax/solvers/linear_solve.py | 140 ++++----- src/lax/solvers/observables.py | 279 ++---------------- src/lax/solvers/spectrum.py | 34 +-- src/lax/spectral/matching.py | 14 +- src/lax/types.py | 10 +- tests/benchmarks/test_alpha_pb_optical.py | 3 +- .../test_descouvemont_closed_channels.py | 30 +- tests/benchmarks/test_descouvemont_np.py | 3 +- .../benchmarks/test_descouvemont_o16_ca44.py | 22 +- tests/benchmarks/test_hydrogen.py | 19 +- tests/property/test_unitarity.py | 1 + tests/unit/test_energy_dependent_flow.py | 15 +- tests/unit/test_solver_direct.py | 18 -- tests/unit/test_solver_pickle.py | 8 - tests/unit/test_solver_spectrum.py | 1 + tests/unit/test_spectral.py | 2 + 33 files changed, 393 insertions(+), 722 deletions(-) diff --git a/examples/alpha_pb_demo.ipynb b/examples/alpha_pb_demo.ipynb index 37351fd..9f0837a 100644 --- a/examples/alpha_pb_demo.ipynb +++ b/examples/alpha_pb_demo.ipynb @@ -52,7 +52,9 @@ " ],\n", " dtype=np.complex128,\n", ")\n", - "ALPHA_PB_MASS_FACTOR = lm.constants.hbar2_over_2mu(4.001506, 207.9767) # α + ²⁰⁸Pb MeV·fm²\n", + "ALPHA_PB_MASS_FACTOR = lm.constants.hbar2_over_2mu(\n", + " 4.001506, 207.9767\n", + ") # α + ²⁰⁸Pb MeV·fm²\n", "BENCHMARK_L = 20\n", "CHANNEL_RADIUS = 14.0\n", "\n", @@ -79,7 +81,11 @@ "def complex_solver(method: str, solvers: tuple[str, ...]) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", - " channels=(lm.ChannelSpec(l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),),\n", + " channels=(\n", + " lm.ChannelSpec(\n", + " l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", + " ),\n", + " ),\n", " operators=(\"T+L\",),\n", " solvers=solvers,\n", " energies=OPTICAL_ENERGIES,\n", @@ -92,7 +98,11 @@ "def real_solver(method: str, solvers: tuple[str, ...]) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", - " channels=(lm.ChannelSpec(l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),),\n", + " channels=(\n", + " lm.ChannelSpec(\n", + " l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", + " ),\n", + " ),\n", " operators=(\"T+L\",),\n", " solvers=solvers,\n", " energies=OPTICAL_ENERGIES,\n", @@ -101,7 +111,9 @@ " )\n", "\n", "\n", - "def smatrix_from_direct_rmatrix(solver: lm.Solver, potential: jnp.ndarray) -> np.ndarray:\n", + "def smatrix_from_direct_rmatrix(\n", + " solver: lm.Solver, potential: jnp.ndarray\n", + ") -> np.ndarray:\n", " assert solver.rmatrix_direct is not None\n", " assert solver.boundary is not None\n", " r_values = solver.rmatrix_direct(potential)\n", @@ -113,6 +125,7 @@ " H_plus_p=solver.boundary.H_plus_p[energy_index],\n", " H_minus_p=solver.boundary.H_minus_p[energy_index],\n", " is_open=solver.boundary.is_open[energy_index],\n", + " k=solver.boundary.k[energy_index],\n", " )\n", " smatrix = lm.spectral.smatrix_from_R(r_values[energy_index], boundary)\n", " smatrices.append(np.asarray(smatrix))\n", @@ -155,7 +168,9 @@ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.6))\n", "axes[0].plot(r_plot, np.asarray(nuclear_real), label=\"real nuclear\", linewidth=2.2)\n", "axes[0].plot(r_plot, np.asarray(coulomb), label=\"Coulomb\", linewidth=2.2)\n", - "axes[0].plot(r_plot, np.asarray(total.real), \"--\", label=\"total real part\", linewidth=2.0)\n", + "axes[0].plot(\n", + " r_plot, np.asarray(total.real), \"--\", label=\"total real part\", linewidth=2.0\n", + ")\n", "axes[0].set_title(r\"$\\alpha + {}^{208}\\mathrm{Pb}$ real potential pieces\")\n", "axes[0].set_xlabel(\"r [fm]\")\n", "axes[0].set_ylabel(\"MeV\")\n", @@ -196,7 +211,9 @@ "solver_complex_eig = complex_solver(\"eig\", (\"spectrum\", \"smatrix\"))\n", "solver_complex_direct = complex_solver(\"linear_solve\", (\"rmatrix_direct\",))\n", "\n", - "potential_real = solver_real.potential(lambda r: jnp.real(optical_potential(r, imag_depth=0.0)))\n", + "potential_real = solver_real.potential(\n", + " lambda r: jnp.real(optical_potential(r, imag_depth=0.0))\n", + ")\n", "potential_complex_eig = solver_complex_eig.potential(\n", " lambda r: optical_potential(r, imag_depth=10.0)\n", ")\n", @@ -204,7 +221,9 @@ " lambda r: optical_potential(r, imag_depth=10.0)\n", ")\n", "\n", - "smatrix_real = np.asarray(solver_real.smatrix(solver_real.spectrum(potential_real)))[:, 0, 0]\n", + "smatrix_real = np.asarray(solver_real.smatrix(solver_real.spectrum(potential_real)))[\n", + " :, 0, 0\n", + "]\n", "smatrix_complex_eig = np.asarray(\n", " solver_complex_eig.smatrix(solver_complex_eig.spectrum(potential_complex_eig))\n", ")[:, 0, 0]\n", @@ -226,8 +245,12 @@ " )\n", "\n", "print()\n", - "print(f\"max |eig - Appendix A| = {np.max(np.abs(smatrix_complex_eig - APPENDIX_A_S)):.3e}\")\n", - "print(f\"max |direct - Appendix A| = {np.max(np.abs(smatrix_complex_direct - APPENDIX_A_S)):.3e}\")\n", + "print(\n", + " f\"max |eig - Appendix A| = {np.max(np.abs(smatrix_complex_eig - APPENDIX_A_S)):.3e}\"\n", + ")\n", + "print(\n", + " f\"max |direct - Appendix A| = {np.max(np.abs(smatrix_complex_direct - APPENDIX_A_S)):.3e}\"\n", + ")\n", "print(\n", " f\"max |eig - direct| = {np.max(np.abs(smatrix_complex_eig - smatrix_complex_direct)):.3e}\"\n", ")" @@ -253,19 +276,43 @@ "source": [ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))\n", "\n", - "axes[0].plot(OPTICAL_ENERGIES, APPENDIX_A_S.real, \"o-\", label=\"Appendix A real\", linewidth=2.2)\n", - "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_eig.real, \"--\", label=\"eig real\", linewidth=2.0)\n", - "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_direct.real, \":\", label=\"direct real\", linewidth=2.0)\n", - "axes[0].plot(OPTICAL_ENERGIES, APPENDIX_A_S.imag, \"o-\", label=\"Appendix A imag\", linewidth=2.2)\n", - "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_eig.imag, \"--\", label=\"eig imag\", linewidth=2.0)\n", - "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_direct.imag, \":\", label=\"direct imag\", linewidth=2.0)\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES, APPENDIX_A_S.real, \"o-\", label=\"Appendix A real\", linewidth=2.2\n", + ")\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES, smatrix_complex_eig.real, \"--\", label=\"eig real\", linewidth=2.0\n", + ")\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES,\n", + " smatrix_complex_direct.real,\n", + " \":\",\n", + " label=\"direct real\",\n", + " linewidth=2.0,\n", + ")\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES, APPENDIX_A_S.imag, \"o-\", label=\"Appendix A imag\", linewidth=2.2\n", + ")\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES, smatrix_complex_eig.imag, \"--\", label=\"eig imag\", linewidth=2.0\n", + ")\n", + "axes[0].plot(\n", + " OPTICAL_ENERGIES,\n", + " smatrix_complex_direct.imag,\n", + " \":\",\n", + " label=\"direct imag\",\n", + " linewidth=2.0,\n", + ")\n", "axes[0].set_title(\"Complex optical benchmark vs Appendix A\")\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", "axes[0].set_ylabel(r\"$S_{20}(E)$\")\n", "axes[0].legend(ncol=2, fontsize=9)\n", "\n", "axes[1].plot(\n", - " OPTICAL_ENERGIES, np.abs(smatrix_real), marker=\"o\", label=\"real spectrum |S|\", linewidth=2.2\n", + " OPTICAL_ENERGIES,\n", + " np.abs(smatrix_real),\n", + " marker=\"o\",\n", + " label=\"real spectrum |S|\",\n", + " linewidth=2.2,\n", ")\n", "axes[1].plot(\n", " OPTICAL_ENERGIES,\n", @@ -338,7 +385,9 @@ " lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", " channels=(\n", - " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),\n", + " lm.ChannelSpec(\n", + " l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", + " ),\n", " ),\n", " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"smatrix\", \"phases\"),\n", @@ -368,8 +417,12 @@ "for solver, angular_momentum in zip(solvers, partial_waves):\n", " potential = solver.potential(lambda r: optical_potential(r, imag_depth=10.0))\n", " spectrum = solver.spectrum(potential)\n", - " phase_curves[angular_momentum] = np.asarray(solver.phases(spectrum)[:, 0]) * (180.0 / np.pi)\n", - " abs_s_curves[angular_momentum] = np.abs(np.asarray(solver.smatrix(spectrum)[:, 0, 0]))" + " phase_curves[angular_momentum] = np.asarray(solver.phases(spectrum)[:, 0]) * (\n", + " 180.0 / np.pi\n", + " )\n", + " abs_s_curves[angular_momentum] = np.abs(\n", + " np.asarray(solver.smatrix(spectrum)[:, 0, 0])\n", + " )" ] }, { diff --git a/examples/descouvemont_closed_channels_demo.ipynb b/examples/descouvemont_closed_channels_demo.ipynb index 225add3..ba320f0 100644 --- a/examples/descouvemont_closed_channels_demo.ipynb +++ b/examples/descouvemont_closed_channels_demo.ipynb @@ -12,28 +12,10 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "806658f9", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'index': 0, 'label': '0+, L=3', 'threshold_mev': 0.0},\n", - " {'index': 1, 'label': '2+, L=1', 'threshold_mev': 4.44},\n", - " {'index': 2, 'label': '2+, L=3', 'threshold_mev': 4.44},\n", - " {'index': 3, 'label': '2+, L=5', 'threshold_mev': 4.44},\n", - " {'index': 4, 'label': '4+, L=1', 'threshold_mev': 14.08},\n", - " {'index': 5, 'label': '4+, L=3', 'threshold_mev': 14.08},\n", - " {'index': 6, 'label': '4+, L=5', 'threshold_mev': 14.08},\n", - " {'index': 7, 'label': '4+, L=7', 'threshold_mev': 14.08}]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from __future__ import annotations\n", "\n", @@ -53,7 +35,9 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " msg = (\n", + " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " )\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -62,7 +46,6 @@ "\n", "model = lm.models.ALPHA_C12_ROTOR_MODEL\n", "channels = lm.models.channels_from_rotor_model(model)\n", - "potential_fn = lm.models.make_rotor_coupled_optical_potential(model)\n", "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "\n", "[\n", @@ -100,14 +83,13 @@ "outputs": [], "source": [ "def boundary_at_energy(boundary: BoundaryValues, energy_index: int) -> BoundaryValues:\n", - " k_values = None if boundary.k is None else boundary.k[energy_index]\n", " return BoundaryValues(\n", " H_plus=boundary.H_plus[energy_index],\n", " H_minus=boundary.H_minus[energy_index],\n", " H_plus_p=boundary.H_plus_p[energy_index],\n", " H_minus_p=boundary.H_minus_p[energy_index],\n", " is_open=boundary.is_open[energy_index],\n", - " k=k_values,\n", + " k=boundary.k[energy_index],\n", " )\n", "\n", "\n", @@ -128,26 +110,19 @@ " z1z2=(model.projectile_charge, model.target_charge),\n", ")\n", "\n", - "# Build the interaction block from the 3-arg potential function.\n", - "import jax.numpy as jnp\n", - "\n", - "n_c = len(channels)\n", - "N = solver.mesh.n\n", - "r = solver.mesh.radii\n", - "block = jnp.zeros((n_c * N, n_c * N), dtype=jnp.complex128)\n", - "for c in range(n_c):\n", - " for cp in range(n_c):\n", - " g = potential_fn(r, c, cp)\n", - " block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g))\n", - "interaction = solver.interaction_from_block(block, energy_dependent=False)\n", + "interaction = lm.models.interaction_from_rotor_model(model, solver)\n", "r_values = solver.rmatrix_direct(interaction)\n", "\n", "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", + " smatrix = np.asarray(\n", + " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", + " )\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", - " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", + " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(\n", + " smatrix, open_count\n", + " )\n", " rows.append(\n", " {\n", " \"energy_mev\": float(energy),\n", @@ -214,4 +189,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/examples/descouvemont_np_demo.ipynb b/examples/descouvemont_np_demo.ipynb index d9e3d5b..3831364 100644 --- a/examples/descouvemont_np_demo.ipynb +++ b/examples/descouvemont_np_demo.ipynb @@ -56,7 +56,9 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " msg = (\n", + " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " )\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -65,7 +67,9 @@ "\n", "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "channels = lm.models.reid_np_j1_channels()\n", - "mesh = lm.MeshSpec(\"legendre\", \"x\", n=int(reference[\"n_basis\"]), scale=float(reference[\"scale\"]))\n", + "mesh = lm.MeshSpec(\n", + " \"legendre\", \"x\", n=int(reference[\"n_basis\"]), scale=float(reference[\"scale\"])\n", + ")\n", "\n", "{\n", " \"energies_mev\": energies.tolist(),\n", @@ -121,7 +125,8 @@ "source": [ "sample_radii = np.asarray([0.5, 1.0, 2.0, 4.0, 6.0], dtype=np.float64)\n", "central, tensor, spin_orbit = [\n", - " np.asarray(values) for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", + " np.asarray(values)\n", + " for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", "]\n", "\n", "[\n", @@ -131,7 +136,9 @@ " \"tensor_mev\": float(v_t),\n", " \"spin_orbit_mev\": float(v_ls),\n", " }\n", - " for radius, v_c, v_t, v_ls in zip(sample_radii, central, tensor, spin_orbit, strict=True)\n", + " for radius, v_c, v_t, v_ls in zip(\n", + " sample_radii, central, tensor, spin_orbit, strict=True\n", + " )\n", "]" ] }, diff --git a/examples/descouvemont_o16_ca44_demo.ipynb b/examples/descouvemont_o16_ca44_demo.ipynb index 28893a8..e137dbc 100644 --- a/examples/descouvemont_o16_ca44_demo.ipynb +++ b/examples/descouvemont_o16_ca44_demo.ipynb @@ -12,24 +12,10 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "id": "acae54e37e7d407bbb7b55eff062a284", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'index': 0, 'label': '0+, L=30', 'threshold_mev': 0.0},\n", - " {'index': 1, 'label': '2+, L=28', 'threshold_mev': 1.156},\n", - " {'index': 2, 'label': '2+, L=30', 'threshold_mev': 1.156},\n", - " {'index': 3, 'label': '2+, L=32', 'threshold_mev': 1.156}]" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "from __future__ import annotations\n", "\n", @@ -49,7 +35,9 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " msg = (\n", + " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", + " )\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -58,7 +46,6 @@ "\n", "model = lm.models.O16_CA44_ROTOR_MODEL\n", "channels = lm.models.channels_from_rotor_model(model)\n", - "potential_fn = lm.models.make_rotor_coupled_optical_potential(model)\n", "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "\n", "[\n", @@ -96,14 +83,13 @@ "outputs": [], "source": [ "def boundary_at_energy(boundary: BoundaryValues, energy_index: int) -> BoundaryValues:\n", - " k_values = None if boundary.k is None else boundary.k[energy_index]\n", " return BoundaryValues(\n", " H_plus=boundary.H_plus[energy_index],\n", " H_minus=boundary.H_minus[energy_index],\n", " H_plus_p=boundary.H_plus_p[energy_index],\n", " H_minus_p=boundary.H_minus_p[energy_index],\n", " is_open=boundary.is_open[energy_index],\n", - " k=k_values,\n", + " k=boundary.k[energy_index],\n", " )\n", "\n", "\n", @@ -124,26 +110,19 @@ " z1z2=(model.projectile_charge, model.target_charge),\n", ")\n", "\n", - "# Build the interaction block from the 3-arg potential function.\n", - "import jax.numpy as jnp\n", - "\n", - "n_c = len(channels)\n", - "N = solver.mesh.n\n", - "r = solver.mesh.radii\n", - "block = jnp.zeros((n_c * N, n_c * N), dtype=jnp.complex128)\n", - "for c in range(n_c):\n", - " for cp in range(n_c):\n", - " g = potential_fn(r, c, cp)\n", - " block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g))\n", - "interaction = solver.interaction_from_block(block, energy_dependent=False)\n", + "interaction = lm.models.interaction_from_rotor_model(model, solver)\n", "r_values = solver.rmatrix_direct(interaction)\n", "\n", "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", + " smatrix = np.asarray(\n", + " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", + " )\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", - " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", + " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(\n", + " smatrix, open_count\n", + " )\n", " rows.append(\n", " {\n", " \"energy_mev\": float(energy),\n", @@ -192,4 +171,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/examples/energy_dependent_demo.ipynb b/examples/energy_dependent_demo.ipynb index 9df1e9f..9c36d02 100644 --- a/examples/energy_dependent_demo.ipynb +++ b/examples/energy_dependent_demo.ipynb @@ -176,7 +176,9 @@ "metadata": {}, "outputs": [], "source": [ - "interp_phases = solver.interpolate_phases(jnp.asarray(phases_coarse[:, None])) # (N_E, 1)\n", + "interp_phases = solver.interpolate_phases(\n", + " jnp.asarray(phases_coarse[:, None])\n", + ") # (N_E, 1)\n", "\n", "# Evaluate interpolant on a fine grid\n", "phases_interp = np.asarray(interp_phases(energies_fine))[:, 0] # (N_FINE,)" @@ -253,7 +255,9 @@ "\n", "axes[0].plot(E_fine, np.degrees(phases_ref), label=\"reference (fine grid)\", lw=2)\n", "axes[0].plot(E_fine, np.degrees(phases_interp), \"--\", label=\"Padé interpolant\", lw=1.8)\n", - "axes[0].scatter(E_coarse, np.degrees(phases_coarse), zorder=5, label=\"coarse knots\", s=30)\n", + "axes[0].scatter(\n", + " E_coarse, np.degrees(phases_coarse), zorder=5, label=\"coarse knots\", s=30\n", + ")\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", "axes[0].set_ylabel(\"Phase shift [deg]\")\n", "axes[0].set_title(r\"Energy-dependent Gaussian: $\\ell=0$ phase shift\")\n", diff --git a/examples/fourier_demo.ipynb b/examples/fourier_demo.ipynb index d8d579f..35d8ab4 100644 --- a/examples/fourier_demo.ipynb +++ b/examples/fourier_demo.ipynb @@ -130,7 +130,9 @@ " \"Gaussian x polynomial l=0\",\n", " 0,\n", " lambda r: r**2 * (3.0 / (2.0 * beta) - r**2) * np.exp(-beta * r**2),\n", - " lambda k: ((k**2) / (4.0 * beta**2)) * np.exp(-(k**2) / (4.0 * beta)) / (2.0 * beta) ** 1.5,\n", + " lambda k: ((k**2) / (4.0 * beta**2))\n", + " * np.exp(-(k**2) / (4.0 * beta))\n", + " / (2.0 * beta) ** 1.5,\n", " ),\n", " (\n", " \"Gaussian l=1\",\n", @@ -208,7 +210,10 @@ "source": [ "numerical_profiles = [\n", " (\"damped oscillation\", lambda r: r * np.exp(-0.35 * r) * np.cos(1.5 * r)),\n", - " (\"double bump\", lambda r: np.exp(-0.7 * (r - 2.0) ** 2) - 0.6 * np.exp(-0.4 * (r - 6.0) ** 2)),\n", + " (\n", + " \"double bump\",\n", + " lambda r: np.exp(-0.7 * (r - 2.0) ** 2) - 0.6 * np.exp(-0.4 * (r - 6.0) ** 2),\n", + " ),\n", "]\n", "\n", "numerical_solver = legendre_solver(0, n=40, scale=18.0)\n", @@ -217,14 +222,18 @@ "momenta = np.asarray(numerical_solver.transforms.momenta)\n", "\n", "for row, (name, profile) in enumerate(numerical_profiles):\n", - " coeffs = numerical_solver.from_grid_vector(lambda r: jnp.asarray(profile(np.asarray(r))))\n", + " coeffs = numerical_solver.from_grid_vector(\n", + " lambda r: jnp.asarray(profile(np.asarray(r)))\n", + " )\n", " reconstructed = np.asarray(numerical_solver.to_grid_vector(coeffs))\n", " transformed = np.asarray(numerical_solver.fourier(coeffs))\n", " expected = profile(grid_r)\n", " print(name)\n", " print(\" grid relative error =\", relative_error(reconstructed, expected))\n", " axes[row, 0].plot(grid_r, expected, label=\"input profile\", linewidth=2.0)\n", - " axes[row, 0].plot(grid_r, reconstructed, \"--\", label=\"mesh reconstruction\", linewidth=1.8)\n", + " axes[row, 0].plot(\n", + " grid_r, reconstructed, \"--\", label=\"mesh reconstruction\", linewidth=1.8\n", + " )\n", " axes[row, 0].set_title(f\"{name} in r-space\")\n", " axes[row, 0].set_xlabel(\"r\")\n", " axes[row, 0].set_ylabel(\"u(r)\")\n", diff --git a/examples/hydrogen_demo.ipynb b/examples/hydrogen_demo.ipynb index 366e91a..9340e28 100644 --- a/examples/hydrogen_demo.ipynb +++ b/examples/hydrogen_demo.ipynb @@ -48,15 +48,15 @@ "def hydrogen_solver(angular_momentum: int) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"laguerre\", \"x\", n=30, scale=2.0),\n", - " channels=(lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),),\n", + " channels=(\n", + " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),\n", + " ),\n", " operators=(\"T\", \"1/r\"),\n", " solvers=(\"spectrum\", \"wavefunction\"),\n", " grid=jnp.linspace(0.0, 40.0, 3000),\n", " momenta=jnp.linspace(0.0, 6.0, 500),\n", " )\n", "\n", - "\n", - "def hydrogen_potential(solver: lm.Solver) -> jnp.ndarray:\n", " return jnp.asarray((-1.0 / solver.mesh.radii)[None, None, :])\n", "\n", "\n", @@ -65,7 +65,10 @@ " prefactor = (\n", " 2.0\n", " / (n**2)\n", - " * math.sqrt(math.factorial(n - angular_momentum - 1) / math.factorial(n + angular_momentum))\n", + " * math.sqrt(\n", + " math.factorial(n - angular_momentum - 1)\n", + " / math.factorial(n + angular_momentum)\n", + " )\n", " )\n", " radial = (\n", " prefactor\n", @@ -76,7 +79,9 @@ " return radii * radial\n", "\n", "\n", - "def momentum_u_analytic(n: int, angular_momentum: int, momenta: np.ndarray) -> np.ndarray:\n", + "def momentum_u_analytic(\n", + " n: int, angular_momentum: int, momenta: np.ndarray\n", + ") -> np.ndarray:\n", " if n == 1 and angular_momentum == 0:\n", " return np.sqrt(2.0 / np.pi) * 2.0 / (1.0 + momenta**2)\n", " if n == 2 and angular_momentum == 0:\n", @@ -85,7 +90,9 @@ " if n == 2 and angular_momentum == 1:\n", " denominator = momenta**2 + 0.25\n", " return np.sqrt(2.0 / (6.0 * np.pi)) * momenta / (denominator**2)\n", - " raise ValueError(f\"No analytic momentum-space form for (n, l)=({n}, {angular_momentum}).\")\n", + " raise ValueError(\n", + " f\"No analytic momentum-space form for (n, l)=({n}, {angular_momentum}).\"\n", + " )\n", "\n", "\n", "def normalized_and_aligned(\n", @@ -123,8 +130,8 @@ "solver_s = hydrogen_solver(0)\n", "solver_p = hydrogen_solver(1)\n", "\n", - "spectrum_s = solver_s.spectrum(hydrogen_potential(solver_s))\n", - "spectrum_p = solver_p.spectrum(hydrogen_potential(solver_p))\n", + "spectrum_s = solver_s.spectrum(solver_s.potential(lambda r: -1.0 / r))\n", + "spectrum_p = solver_p.spectrum(solver_p.potential(lambda r: -1.0 / r))\n", "\n", "energy_rows = [\n", " (\"1s\", float(np.asarray(spectrum_s.eigenvalues)[0]) * HBAR2_2MU, -0.5),\n", @@ -136,7 +143,9 @@ "\n", "print(\"State numerical analytic abs error\")\n", "for label, numerical, analytic in energy_rows:\n", - " print(f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\")" + " print(\n", + " f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\"\n", + " )" ] }, { diff --git a/examples/yamaguchi_demo.ipynb b/examples/yamaguchi_demo.ipynb index 081c028..64d3582 100644 --- a/examples/yamaguchi_demo.ipynb +++ b/examples/yamaguchi_demo.ipynb @@ -62,7 +62,9 @@ "def yamaguchi_solver(angular_momentum: int, energies: jax.Array) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=20, scale=15.0),\n", - " channels=(lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),),\n", + " channels=(\n", + " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),\n", + " ),\n", " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"phases\"),\n", " energies=energies,\n", @@ -141,7 +143,9 @@ "\n", "analytic_s_wave = yamaguchi_s_wave_analytic_phase_deg(np.asarray(energies))\n", "max_s_wave_error = np.max(np.abs(phase_curves[0] - analytic_s_wave))\n", - "print(f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\")" + "print(\n", + " f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\"\n", + ")" ] }, { @@ -165,8 +169,12 @@ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))\n", "\n", "phase_curves[0] += 180\n", - "axes[0].plot(np.asarray(energies), analytic_s_wave, label=\"analytic s-wave\", linewidth=2.5)\n", - "axes[0].plot(np.asarray(energies), phase_curves[0], \"--\", label=\"spectral s-wave\", linewidth=2.0)\n", + "axes[0].plot(\n", + " np.asarray(energies), analytic_s_wave, label=\"analytic s-wave\", linewidth=2.5\n", + ")\n", + "axes[0].plot(\n", + " np.asarray(energies), phase_curves[0], \"--\", label=\"spectral s-wave\", linewidth=2.0\n", + ")\n", "axes[0].set_title(r\"Yamaguchi $\\ell=0$ phase shift\")\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", "axes[0].set_ylabel(\"Phase shift [deg]\")\n", @@ -174,7 +182,9 @@ "\n", "for angular_momentum in partial_waves:\n", " axes[1].plot(\n", - " np.asarray(energies), phase_curves[angular_momentum], label=rf\"$\\ell={angular_momentum}$\"\n", + " np.asarray(energies),\n", + " phase_curves[angular_momentum],\n", + " label=rf\"$\\ell={angular_momentum}$\",\n", " )\n", "axes[1].set_title(\"Several partial waves from the spectral solver\")\n", "axes[1].set_xlabel(\"Energy [MeV]\")\n", diff --git a/src/lax/boundary/_types.py b/src/lax/boundary/_types.py index 908749c..1e029d4 100644 --- a/src/lax/boundary/_types.py +++ b/src/lax/boundary/_types.py @@ -8,7 +8,7 @@ import jax -from lax.types import ChannelSpec, MeshFamily, Method, Regularization +from lax.types import ChannelSpec, Interaction, MeshFamily, Method, Regularization if TYPE_CHECKING: from lax.spectral.types import Spectrum @@ -21,24 +21,16 @@ class SpectrumKernel(Protocol): def __call__( self, - potential: jax.Array, - mass_factor: float | jax.Array | None = None, + potential: jax.Array | Interaction, ) -> Spectrum: """Return the spectral decomposition for one assembled potential. Parameters ---------- potential - Assembled potential array, shape ``(N_c, N_c, N)`` for local or - ``(N_c, N_c, N, N)`` for non-local. - mass_factor - Optional per-energy ℏ²/2μ in MeV·fm². When provided, overrides - ``ChannelSpec.mass_factor`` so the Hamiltonian uses ``V/μ(E)`` and - ``threshold/μ(E)`` at each energy. Typical usage:: - - spectra = jax.vmap( - lambda V, mu: solver.spectrum(V, mass_factor=mu) - )(V_grid, mu_grid) + Assembled potential: either a raw ``jax.Array`` of shape + ``(N_c, N_c, N)`` for local or ``(N_c, N_c, N, N)`` for non-local, + or an :class:`~lax.Interaction` (energy-independent only). Returns ------- @@ -186,7 +178,7 @@ def __call__(self, spectrum: Spectrum) -> tuple[jax.Array, jax.Array]: class DirectRMatrixKernel(Protocol): """Callable that computes the direct R-matrix via per-energy linear solves.""" - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate the direct R-matrix on the compile-time energy grid. Parameters @@ -207,7 +199,7 @@ def __call__(self, potential: jax.Array) -> jax.Array: class SMatrixDirectObservable(Protocol): """Callable that computes the direct S-matrix via per-energy linear solves.""" - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate the S-matrix on the compile-time energy grid. Parameters @@ -226,7 +218,7 @@ def __call__(self, potential: jax.Array) -> jax.Array: class PhasesDirectObservable(Protocol): """Callable that computes direct phase shifts via per-energy linear solves.""" - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate phase shifts on the compile-time energy grid. Parameters @@ -247,7 +239,7 @@ class WavefunctionDirectObservable(Protocol): def __call__( self, - potential: jax.Array, + potential: jax.Array | Interaction, source: jax.Array, energy_index: int, ) -> jax.Array: @@ -608,8 +600,7 @@ class BoundaryValues: Boolean mask: ``True`` for open channels (``E > E_threshold``), shape ``(N_E, N_c)``. k - Channel wave numbers ``k_c(E)`` in fm⁻¹, shape ``(N_E, N_c)``, - or ``None`` when not needed for matching. + Channel wave numbers ``k_c(E)`` in fm⁻¹, shape ``(N_E, N_c)``. """ H_plus: jax.Array @@ -617,7 +608,7 @@ class BoundaryValues: H_plus_p: jax.Array H_minus_p: jax.Array is_open: jax.Array - k: jax.Array | None = None + k: jax.Array @jax.tree_util.register_dataclass @@ -710,12 +701,6 @@ class Solver: rmatrix_direct ``(V) → R`` — per-energy linear-solve R-matrix on the compile-time grid. - rmatrix_direct_grid - ``(V_grid) → R`` — aligned-grid direct R for energy-dependent V. - smatrix_direct_grid - ``(V_grid) → S`` — aligned-grid direct S. - phases_direct_grid - ``(V_grid) → δ`` — aligned-grid direct phases. **Padé interpolation builders** (present whenever ``energies`` was supplied): @@ -758,9 +743,6 @@ class Solver: smatrix_grid: SpectrumGridObservable | None = None phases_grid: SpectrumGridObservable | None = None rmatrix_direct: DirectRMatrixKernel | None = None - rmatrix_direct_grid: DirectGridObservable | None = None - smatrix_direct_grid: DirectGridObservable | None = None - phases_direct_grid: DirectGridObservable | None = None smatrix_direct: SMatrixDirectObservable | None = None phases_direct: PhasesDirectObservable | None = None wavefunction_direct: WavefunctionDirectObservable | None = None diff --git a/src/lax/boundary/coulomb.py b/src/lax/boundary/coulomb.py index aa1619f..ea56fce 100644 --- a/src/lax/boundary/coulomb.py +++ b/src/lax/boundary/coulomb.py @@ -3,8 +3,8 @@ from __future__ import annotations from collections.abc import Callable +from typing import cast -import jax import jax.numpy as jnp import mpmath as mp import numpy as np @@ -128,12 +128,12 @@ def compute_boundary_values( ) return BoundaryValues( - H_plus=_to_jax_array(H_plus), - H_minus=_to_jax_array(H_minus), - H_plus_p=_to_jax_array(H_plus_p), - H_minus_p=_to_jax_array(H_minus_p), - is_open=_to_jax_array(is_open), - k=_to_jax_array(k_values), + H_plus=jnp.asarray(H_plus), + H_minus=jnp.asarray(H_minus), + H_plus_p=jnp.asarray(H_plus_p), + H_minus_p=jnp.asarray(H_minus_p), + is_open=jnp.asarray(is_open), + k=jnp.asarray(k_values), ) @@ -153,9 +153,10 @@ def _fill_open_channel( ) -> None: """Fill one open-channel boundary-value entry.""" - k = np.sqrt(relative_energy / channel.mass_factor) + mf = cast(float, channel.mass_factor) + k = np.sqrt(relative_energy / mf) rho = k * channel_radius - eta = _sommerfeld(z1z2, k, channel.mass_factor) if z1z2 is not None else 0.0 + eta = _sommerfeld(z1z2, k, mf) if z1z2 is not None else 0.0 def coulombf_at_rho(rho_value: float) -> object: return _mp_coulombf(channel.l, eta, rho_value) @@ -194,9 +195,10 @@ def _fill_closed_channel( ) -> None: """Fill one closed-channel boundary-value entry.""" - k = np.sqrt(-relative_energy / channel.mass_factor) + mf = cast(float, channel.mass_factor) + k = np.sqrt(-relative_energy / mf) rho = 2.0 * k * channel_radius - eta = _sommerfeld(z1z2, k, channel.mass_factor) if z1z2 is not None else 0.0 + eta = _sommerfeld(z1z2, k, mf) if z1z2 is not None else 0.0 def whitw_at_rho(rho_value: float) -> object: return _mp_whittaker_w(-eta, channel.l + 0.5, rho_value) @@ -294,11 +296,4 @@ def _neutral_open_channel_values(l: int, rho: float) -> tuple[complex, complex, return F, G, dF, dG -def _to_jax_array(values: np.ndarray) -> jax.Array: - """Convert compile-time NumPy arrays to runtime JAX arrays.""" - - array: jax.Array = jnp.asarray(values) - return array - - __all__ = ["compute_boundary_values"] diff --git a/src/lax/compile.py b/src/lax/compile.py index 8781b02..4a752df 100644 --- a/src/lax/compile.py +++ b/src/lax/compile.py @@ -198,8 +198,7 @@ def compile( 1. **Boundary values** — wave numbers and Sommerfeld parameters at each ``(energy, channel)`` pair use ``mass_factor_grid[ie, ic]``. - 2. **Aligned-grid observables** — ``rmatrix_direct_grid`` (and its - derived ``smatrix``/``phases`` variants) assemble the Hamiltonian + 2. **Aligned-grid direct observables** — the Hamiltonian is assembled with the per-energy per-channel mass factor at each grid point. Returns @@ -253,7 +252,7 @@ def compile( momenta=momenta, ) mass_factor_grid_jax = ( - _to_jax_array(mass_factor_grid_np) if mass_factor_grid_np is not None else None + jnp.asarray(mass_factor_grid_np) if mass_factor_grid_np is not None else None ) observables = _bind_solver_observables( request=request, @@ -389,7 +388,7 @@ def _prepare_boundary_data( # The solver always stores an energy array so downstream code can rely on a # uniform bundle shape even when no boundary-valued observables are exposed. empty_energies = np.zeros((0,), dtype=np.float64) - return None, _to_jax_array(empty_energies) + return None, jnp.asarray(empty_energies) energies_np = np.asarray(energies) boundary = compute_boundary_values( @@ -400,7 +399,7 @@ def _prepare_boundary_data( dps=dps, mass_factor_grid=mass_factor_grid, ) - return boundary, _to_jax_array(energies_np) + return boundary, jnp.asarray(energies_np) def _prepare_transforms( @@ -420,7 +419,7 @@ def _prepare_transforms( double_fourier_transform_fn: DoubleFourierTransform | None = None if grid is not None: - grid_array = _to_jax_array(np.asarray(grid)) + grid_array = jnp.asarray(np.asarray(grid)) basis_grid = compute_B_grid(mesh, grid_array) transforms = TransformMatrices( B_grid=basis_grid, @@ -435,7 +434,7 @@ def _prepare_transforms( ) = make_to_grid(mesh, basis_grid, grid_array) if momenta is not None: - momenta_array = _to_jax_array(np.asarray(momenta)) + momenta_array = jnp.asarray(np.asarray(momenta)) unique_angular_momenta = sorted({channel.l for channel in channels}) matrices_by_l = { angular_momentum: compute_F_momentum(mesh, momenta_array, angular_momentum) @@ -652,13 +651,6 @@ def _assemble_solver( ) -def _to_jax_array(values: np.ndarray) -> jax.Array: - """Convert compile-time NumPy data to an explicitly typed JAX array.""" - - array: jax.Array = jnp.asarray(values) - return array - - def _broadcast_mass_factor_grid( arr: np.ndarray, n_energies: int, diff --git a/src/lax/meshes/laguerre.py b/src/lax/meshes/laguerre.py index 5646b0f..94dfbe5 100644 --- a/src/lax/meshes/laguerre.py +++ b/src/lax/meshes/laguerre.py @@ -81,11 +81,7 @@ def build_laguerre_x( T=_to_jax_array(kinetic) if include_kinetic else None, TpL=_to_jax_array(kinetic) if include_kinetic else None, inv_r=_diagonal_operator(1.0 / radii) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (radii**2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (radii**2)), ) return mesh, operators_out @@ -155,11 +151,7 @@ def build_laguerre_modified_x2( T=_to_jax_array(kinetic) if include_kinetic else None, TpL=_to_jax_array(kinetic) if include_kinetic else None, inv_r=_diagonal_operator(1.0 / radii) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (radii**2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (radii**2)), ) return mesh, operators_out diff --git a/src/lax/meshes/legendre.py b/src/lax/meshes/legendre.py index a9c06e2..49e98cd 100644 --- a/src/lax/meshes/legendre.py +++ b/src/lax/meshes/legendre.py @@ -101,11 +101,7 @@ def build_legendre_x( TpL=_to_jax_array(TpL) if {"T+L", "TpL"} & operators else None, D=_to_jax_array(D) if {"D", "d/dr"} & operators else None, inv_r=_diagonal_operator(1.0 / radii) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (radii**2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (radii**2)), ) return mesh, operators_out @@ -182,11 +178,7 @@ def _build_legendre_x_propagated( ) operators_out = OperatorMatrices( inv_r=_diagonal_operator(1.0 / np.asarray(radii)) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (np.asarray(radii) ** 2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (np.asarray(radii) ** 2)), ) return mesh, operators_out @@ -267,11 +259,7 @@ def build_legendre_x_one_minus_x( T=_to_jax_array(kinetic) if include_kinetic else None, TpL=_to_jax_array(kinetic) if include_kinetic else None, inv_r=_diagonal_operator(1.0 / radii) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (radii**2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (radii**2)), ) return mesh, operators_out @@ -330,11 +318,7 @@ def build_legendre_x_three_halves( operators_out = OperatorMatrices( TpL=_to_jax_array(t_plus_l) if include_kinetic else None, inv_r=_diagonal_operator(1.0 / radii) if {"1/r", "inv_r"} & operators else None, - inv_r2=( - _diagonal_operator(1.0 / (radii**2)) - if {"1/r^2", "1/r²", "inv_r2"} & operators - else None - ), + inv_r2=_diagonal_operator(1.0 / (radii**2)), ) return mesh, operators_out diff --git a/src/lax/models/__init__.py b/src/lax/models/__init__.py index 2a8269b..304b38d 100644 --- a/src/lax/models/__init__.py +++ b/src/lax/models/__init__.py @@ -3,12 +3,11 @@ from __future__ import annotations from lax.models.optical import ( - CoupledPotential, RotorChannel, RotorCoupledOpticalModel, channels_from_rotor_model, first_column_amplitudes_and_phases, - make_rotor_coupled_optical_potential, + interaction_from_rotor_model, open_channel_count, rotor_coupled_optical_potential, rotor_coupling_coefficient, @@ -26,14 +25,13 @@ __all__ = [ "ALPHA_C12_ROTOR_MODEL", - "CoupledPotential", "NN_MASS_FACTOR", "O16_CA44_ROTOR_MODEL", "RotorChannel", "RotorCoupledOpticalModel", "channels_from_rotor_model", "first_column_amplitudes_and_phases", - "make_rotor_coupled_optical_potential", + "interaction_from_rotor_model", "open_channel_count", "reid_np_j1_channels", "reid_np_j1_potential", diff --git a/src/lax/models/optical.py b/src/lax/models/optical.py index b3778a8..d8482c4 100644 --- a/src/lax/models/optical.py +++ b/src/lax/models/optical.py @@ -2,14 +2,13 @@ These utilities expose the general machinery behind the coupled optical examples in the benchmark suite. Users can define their own rotor-coupled models, derive the -corresponding :class:`lax.types.ChannelSpec` objects, and build local potential -callbacks for :meth:`~lax.Solver.interaction_from_block`. +corresponding :class:`lax.types.ChannelSpec` objects, and build interactions via +:func:`interaction_from_rotor_model`. """ from __future__ import annotations import math -from collections.abc import Callable from dataclasses import dataclass import jax @@ -17,9 +16,8 @@ import numpy as np from lax._angular import wigner_3j, wigner_6j -from lax.types import ChannelSpec - -type CoupledPotential = Callable[[jax.Array, int, int], jax.Array] +from lax.boundary._types import Solver +from lax.types import ChannelSpec, Interaction @dataclass(frozen=True) @@ -199,29 +197,71 @@ def rotor_coupled_optical_potential( return result -def make_rotor_coupled_optical_potential(model: RotorCoupledOpticalModel) -> CoupledPotential: - """Bind a rotor model into a local-potential callback. +def interaction_from_rotor_model( + model: RotorCoupledOpticalModel, + solver: Solver, +) -> Interaction: + """Build an :class:`~lax.Interaction` for a rotor-coupled optical model. + + Decomposes the potential into three local terms via the §6.1 term-decomposition + pattern and assembles them through :meth:`~lax.Solver.interaction_from_funcs`: + + * Nuclear diagonal: ``-complex_depth · WS(r)`` on the diagonal channels. + * Coulomb diagonal: ``Coulomb(r)`` on the diagonal channels. + * Derivative coupling: ``-complex_depth · β · R_c · dWS/dr`` scaled by the + angular coupling matrix ``A[c, c'] = rotor_coupling_coefficient(c, c')``. Parameters ---------- model Rotor-coupled optical model definition. + solver + Compiled solver whose :meth:`~lax.Solver.interaction_from_funcs` entry + point is used to assemble the potential block. Returns ------- - CoupledPotential - Callback with signature ``(radii, channel_index, coupled_index)``. + Interaction + Energy-independent assembled potential block ready for ``solver.spectrum`` + or ``solver.rmatrix_direct``. """ - def potential(radii: jax.Array, channel_index: int, coupled_index: int) -> jax.Array: - return rotor_coupled_optical_potential( - model, - radii, - channel_index, - coupled_index, + n_c = len(model.channels) + complex_depth = complex(model.real_depth + 1j * model.imaginary_depth) + R = model.potential_radius + a = model.diffuseness + coupling_matrix = np.array( + [[rotor_coupling_coefficient(model, c, cp) for cp in range(n_c)] for c in range(n_c)], + dtype=np.float64, + ) + + def _nuclear(r: jax.Array) -> jax.Array: + return jnp.asarray(-complex_depth * woods_saxon_form_factor(r, R, a)) + + def _coulomb(r: jax.Array) -> jax.Array: + return uniform_sphere_coulomb_potential( + r, + model.coulomb_radius, + model.projectile_charge, + model.target_charge, ) - return potential + def _coupling(r: jax.Array) -> jax.Array: + return jnp.asarray( + -complex_depth + * model.deformation + * model.coupling_radius + * woods_saxon_derivative(r, R, a) + ) + + assert solver.interaction_from_funcs is not None + return solver.interaction_from_funcs( + local=[ + (_nuclear, np.eye(n_c)), + (_coulomb, np.eye(n_c)), + (_coupling, coupling_matrix), + ], + ) def woods_saxon_form_factor(radii: jax.Array, radius: float, diffuseness: float) -> jax.Array: @@ -392,12 +432,11 @@ def first_column_amplitudes_and_phases( __all__ = [ - "CoupledPotential", "RotorChannel", "RotorCoupledOpticalModel", "channels_from_rotor_model", "first_column_amplitudes_and_phases", - "make_rotor_coupled_optical_potential", + "interaction_from_rotor_model", "open_channel_count", "rotor_coupled_optical_potential", "rotor_coupling_coefficient", diff --git a/src/lax/solvers/__init__.py b/src/lax/solvers/__init__.py index 58ba657..0a917ee 100644 --- a/src/lax/solvers/__init__.py +++ b/src/lax/solvers/__init__.py @@ -9,7 +9,6 @@ make_smatrix_direct_observable, ) from lax.solvers.observables import ( - bind_direct_grid_observables, bind_grid_observables, bind_interpolators, bind_observables, @@ -18,7 +17,6 @@ __all__ = [ "assemble_block_hamiltonian", - "bind_direct_grid_observables", "bind_grid_observables", "bind_interpolators", "bind_observables", diff --git a/src/lax/solvers/assembly.py b/src/lax/solvers/assembly.py index 78f679c..13ba092 100644 --- a/src/lax/solvers/assembly.py +++ b/src/lax/solvers/assembly.py @@ -2,8 +2,6 @@ from __future__ import annotations -from typing import cast - import jax import jax.numpy as jnp @@ -16,7 +14,6 @@ def assemble_block_hamiltonian( operators: OperatorMatrices, channels: tuple[ChannelSpec, ...], potential: jax.Array, - mass_factor_override: float | jax.Array | None = None, ) -> jax.Array: """Assemble the Bloch-augmented block Hamiltonian in MeV units. @@ -37,15 +34,12 @@ def assemble_block_hamiltonian( Precomputed operator matrices; ``TpL`` must be present. channels Channel definitions (``l``, ``threshold``, ``mass_factor``). + For energy-dependent μ, pass channels whose ``mass_factor`` fields + carry the per-energy values (e.g. a vmapped slice of + ``mass_factor_grid``). potential Assembled potential in MeV. Shape ``(N_c, N_c, N)`` for local or ``(N_c, N_c, N, N)`` for non-local. - mass_factor_override - When not ``None``, overrides ``channel.mass_factor`` for the - kinetic scaling. Accepts either a scalar (uniform override for - all channels) or a JAX array of shape ``(N_c,)`` for per-channel - values. Supply a traced scalar when using an energy-dependent - μ(E) so it vmaps correctly. Returns ------- @@ -56,20 +50,12 @@ def assemble_block_hamiltonian( channel_count = len(channels) basis_size = mesh.n t_plus_l = _require_operator(operators.TpL, "TpL") - inv_r2 = operators.inv_r2 - if inv_r2 is None: - inv_r2 = _diagonal_from_vector(1.0 / (mesh.radii**2)) + inv_r2 = _require_operator(operators.inv_r2, "inv_r2") blocks: list[jax.Array] = [] for channel_index in range(channel_count): row_blocks: list[jax.Array] = [] - if mass_factor_override is not None: - if jnp.ndim(mass_factor_override) == 0: - m_c = mass_factor_override - else: - m_c = cast(jax.Array, mass_factor_override)[channel_index] - else: - m_c = channels[channel_index].mass_factor + m_c = channels[channel_index].mass_factor angular_momentum = channels[channel_index].l threshold = channels[channel_index].threshold for coupled_index in range(channel_count): diff --git a/src/lax/solvers/linear_solve.py b/src/lax/solvers/linear_solve.py index 0320197..4ceee54 100644 --- a/src/lax/solvers/linear_solve.py +++ b/src/lax/solvers/linear_solve.py @@ -18,7 +18,7 @@ PropagationMatrices, ) from lax.spectral.matching import phases_from_S, smatrix_from_R -from lax.types import ChannelSpec +from lax.types import ChannelSpec, Interaction from .assembly import assemble_block_hamiltonian, build_Q @@ -55,11 +55,11 @@ class _DirectRMatrixKernel: q_prime: jax.Array channel_radius: float matrix_size: int - mass_factor: float + mass_factor: float | jax.Array boundary: BoundaryValues | None - mass_factor_grid: jax.Array | None = None + mass_factor_grid: jax.Array - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate the direct R-matrix on the compile-time energy grid. Parameters @@ -69,12 +69,9 @@ def __call__(self, potential: jax.Array) -> jax.Array: ``solver.interaction_from_{block,array,funcs}()``. Energy-dependent interactions (``energy_dependent=True``) use the per-energy block path. - :class:`~lax.Interaction` object built by ``solver.potential()`` or - ``solver.interaction_from_{block,array,funcs}()``. For propagated meshes, - local energy-independent Interactions are supported: the per-interval - ``(N_c, N_c, N)`` array is extracted from the block diagonals. + For propagated meshes, local energy-independent Interactions are supported: + the per-interval ``(N_c, N_c, N)`` array is extracted from the block diagonals. """ - from lax.types import Interaction # noqa: PLC0415 # Propagated meshes use per-interval raw (N_c, N_c, N) arrays. # Extract from Interaction.block by taking the diagonal of each sub-block. @@ -143,7 +140,6 @@ def __call__(self, potential: jax.Array) -> jax.Array: self.channels, self.energies, self.q, - self.q_prime, self.channel_radius, self.matrix_size, self.mass_factor, @@ -177,14 +173,13 @@ class _DirectRMatrixGridObservable: channels: tuple[ChannelSpec, ...] energies: jax.Array q: jax.Array - q_prime: jax.Array channel_radius: float matrix_size: int - mass_factor: float + mass_factor: float | jax.Array boundary: BoundaryValues | None - mass_factor_grid: jax.Array | None = None + mass_factor_grid: jax.Array - def __call__(self, potentials: jax.Array) -> jax.Array: + def __call__(self, potentials: jax.Array | Interaction) -> jax.Array: """Evaluate `R(E_i; V_i)` across the compile-time energy grid.""" return cast( @@ -196,7 +191,6 @@ def __call__(self, potentials: jax.Array) -> jax.Array: self.channels, self.energies, self.q, - self.q_prime, self.channel_radius, self.matrix_size, self.mass_factor, @@ -213,7 +207,7 @@ class _SMatrixDirectObservable: rmatrix_direct: _DirectRMatrixKernel boundary: BoundaryValues - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate the S-matrix on the compile-time energy grid.""" r = self.rmatrix_direct(potential) @@ -226,7 +220,7 @@ class _PhasesDirectObservable: smatrix_direct: _SMatrixDirectObservable - def __call__(self, potential: jax.Array) -> jax.Array: + def __call__(self, potential: jax.Array | Interaction) -> jax.Array: """Evaluate phase shifts on the compile-time energy grid.""" s = self.smatrix_direct(potential) @@ -245,7 +239,7 @@ class _WavefunctionDirectKernel: def __call__( self, - potential: jax.Array, + potential: jax.Array | Interaction, source: jax.Array, energy_index: int, ) -> jax.Array: @@ -266,8 +260,6 @@ def __call__( jax.Array Wavefunction coefficient vector, shape ``(N_c·N,)``. """ - from lax.types import Interaction # noqa: PLC0415 - if not isinstance(potential, Interaction): raise TypeError( "wavefunction_direct() accepts only Interaction objects. " @@ -335,6 +327,16 @@ def make_rmatrix_direct_kernel( channel_radius = mesh.scale matrix_size = mesh.n * len(channels) mass_factor = channels[0].mass_factor # used by propagated path only + n_e = len(energies) + n_c = len(channels) + if mass_factor_grid is None: + _mfg: jax.Array = jnp.broadcast_to( + jnp.array([c.mass_factor for c in channels], dtype=float), (n_e, n_c) + ) + elif jnp.asarray(mass_factor_grid).ndim == 1: + _mfg = jnp.broadcast_to(jnp.asarray(mass_factor_grid)[:, None], (n_e, n_c)) + else: + _mfg = jnp.asarray(mass_factor_grid) return cast( DirectRMatrixKernel, _DirectRMatrixKernel( @@ -348,7 +350,7 @@ def make_rmatrix_direct_kernel( matrix_size=matrix_size, mass_factor=mass_factor, boundary=boundary, - mass_factor_grid=mass_factor_grid, + mass_factor_grid=_mfg, ), ) @@ -392,10 +394,19 @@ def make_rmatrix_direct_grid_observable( """ q = build_Q(mesh, channels) - q_prime = _build_q_prime(q, channels, mesh.n) channel_radius = mesh.scale matrix_size = mesh.n * len(channels) mass_factor = channels[0].mass_factor # used by propagated path only + n_e = len(energies) + n_c = len(channels) + if mass_factor_grid is None: + _mfg: jax.Array = jnp.broadcast_to( + jnp.array([c.mass_factor for c in channels], dtype=float), (n_e, n_c) + ) + elif jnp.asarray(mass_factor_grid).ndim == 1: + _mfg = jnp.broadcast_to(jnp.asarray(mass_factor_grid)[:, None], (n_e, n_c)) + else: + _mfg = jnp.asarray(mass_factor_grid) return cast( DirectGridObservable, _DirectRMatrixGridObservable( @@ -404,12 +415,11 @@ def make_rmatrix_direct_grid_observable( channels=channels, energies=energies, q=q, - q_prime=q_prime, channel_radius=channel_radius, matrix_size=matrix_size, mass_factor=mass_factor, boundary=boundary, - mass_factor_grid=mass_factor_grid, + mass_factor_grid=_mfg, ), ) @@ -466,7 +476,7 @@ def _rmatrix_direct( q_prime: jax.Array, channel_radius: float, matrix_size: int, - mass_factor: float, + mass_factor: float | jax.Array, boundary: BoundaryValues | None, ) -> jax.Array: """Return the direct R-matrix across the compile-time energy grid. @@ -568,12 +578,11 @@ def _rmatrix_direct_grid( channels: tuple[ChannelSpec, ...], energies: jax.Array, q: jax.Array, - q_prime: jax.Array, channel_radius: float, matrix_size: int, - mass_factor: float, + mass_factor: float | jax.Array, boundary: BoundaryValues | None, - mass_factor_grid: jax.Array | None = None, + mass_factor_grid: jax.Array, ) -> jax.Array: """Return aligned-grid ``R(E_i; V_i)`` samples for energy-dependent potentials. @@ -586,10 +595,12 @@ def _rmatrix_direct_grid( potentials Per-energy potentials in MeV. Local: ``(N_E, N_c, N_c, N)``; non-local: ``(N_E, N_c, N_c, N, N)``. - mesh, operators, channels, energies, q, q_prime, channel_radius, matrix_size, mass_factor, boundary - Compile-time cached data. ``q`` is the unscaled surface projector used - when ``mass_factor_grid`` overrides the per-channel values at JIT time. + mesh, operators, channels, energies, q, channel_radius, matrix_size, mass_factor, boundary + Compile-time cached data. ``q`` is the unscaled surface projector; ``mass_factor`` is used only on the propagated path. + mass_factor_grid + Dense ``(N_E, N_c)`` mass-factor array, always present (promoted at + compile time from scalar / ``(N_E,)`` / per-channel inputs). Returns ------- @@ -638,68 +649,27 @@ def propagated_one_energy( ) raise ValueError(msg) - def one_energy(potential: jax.Array, energy: jax.Array) -> jax.Array: - hamiltonian = assemble_block_hamiltonian( - mesh, - operators, - channels, - potential, - ) - # Hamiltonian is in MeV; C = H_MeV − E·I. - matrix = hamiltonian - energy * jnp.eye( - matrix_size, - dtype=hamiltonian.dtype, - ) - solved = cast( - jax.Array, - jnp.linalg.solve( - matrix, - q_prime, - ), - ) - return (q_prime.T @ solved) / channel_radius - - def one_energy_with_mu( + def one_energy( potential: jax.Array, energy: jax.Array, - mu_row: jax.Array, # (N_c,) per-channel mass factors + mu_row: jax.Array, # (N_c,) per-channel mass factors, vmapped from mass_factor_grid ) -> jax.Array: - hamiltonian = assemble_block_hamiltonian( - mesh, - operators, - channels, - potential, - mass_factor_override=mu_row, - ) - # Hamiltonian assembled with override μ is in MeV; C = H_MeV − E·I. - # Q' = diag(repeat(sqrt(mu_row), N))·Q — per-channel scaling. - matrix = hamiltonian - energy * jnp.eye( - matrix_size, - dtype=hamiltonian.dtype, + updated = tuple( + ChannelSpec(l=ch.l, threshold=ch.threshold, mass_factor=mu_row[i]) + for i, ch in enumerate(channels) ) + hamiltonian = assemble_block_hamiltonian(mesh, operators, updated, potential) + # Hamiltonian in MeV; C = H_MeV − E·I. + # Q' = diag(repeat(sqrt(mu_row), N))·Q — per-channel reduced-width scaling. + matrix = hamiltonian - energy * jnp.eye(matrix_size, dtype=hamiltonian.dtype) n = mesh.n scale = jnp.repeat(jnp.sqrt(mu_row), n) # (N_c·N,) q_prime_mu: jax.Array = scale[:, None] * q - solved = cast( - jax.Array, - jnp.linalg.solve( - matrix, - q_prime_mu, - ), - ) + solved = cast(jax.Array, jnp.linalg.solve(matrix, q_prime_mu)) return (q_prime_mu.T @ solved) / channel_radius - if mass_factor_grid is not None: - # mass_factor_grid is (N_E, N_c); vmap slices to (N_c,) per energy step. - return jax.vmap(one_energy_with_mu)( - potentials, - energies, - mass_factor_grid, - ) - return jax.vmap(one_energy)( - potentials, - energies, - ) + # mass_factor_grid is (N_E, N_c); vmap slices to (N_c,) per energy step. + return jax.vmap(one_energy)(potentials, energies, mass_factor_grid) def _wavefunction_direct( @@ -764,7 +734,7 @@ def _propagated_rmatrix_at_energy( h_plus: jax.Array, h_plus_p: jax.Array, is_open: jax.Array, - mass_factor: float, + mass_factor: float | jax.Array, ) -> jax.Array: """Return the propagated effective R-matrix at one energy. diff --git a/src/lax/solvers/observables.py b/src/lax/solvers/observables.py index fd786ed..30e1625 100644 --- a/src/lax/solvers/observables.py +++ b/src/lax/solvers/observables.py @@ -17,7 +17,6 @@ from lax.boundary._types import ( BoundaryValues, - DirectGridObservable, EigenpairAccessor, GreenFunctionObservable, InterpolatorBuilder, @@ -160,29 +159,18 @@ class _RMatrixGridObservable: energies: jax.Array channel_radius: float - mass_factor: float - mass_factor_grid: jax.Array | None = None + mass_factor_grid: jax.Array def __call__(self, spectra: Spectrum) -> jax.Array: """Evaluate `R(E_i; spec_i)` across the compile-time energy grid.""" - if self.mass_factor_grid is not None: - return cast( - jax.Array, - _RMATRIX_GRID_WITH_MU_JIT( - spectra, - self.energies, - self.channel_radius, - self.mass_factor_grid, - ), - ) return cast( jax.Array, _RMATRIX_GRID_JIT( spectra, self.energies, self.channel_radius, - self.mass_factor, + self.mass_factor_grid, ), ) @@ -194,23 +182,11 @@ class _SMatrixGridObservable: energies: jax.Array boundary: BoundaryValues channel_radius: float - mass_factor: float - mass_factor_grid: jax.Array | None = None + mass_factor_grid: jax.Array def __call__(self, spectra: Spectrum) -> jax.Array: """Evaluate `S(E_i; spec_i)` across the compile-time energy grid.""" - if self.mass_factor_grid is not None: - return cast( - jax.Array, - _SMATRIX_GRID_WITH_MU_JIT( - spectra, - self.energies, - self.boundary, - self.channel_radius, - self.mass_factor_grid, - ), - ) return cast( jax.Array, _SMATRIX_GRID_JIT( @@ -218,7 +194,7 @@ def __call__(self, spectra: Spectrum) -> jax.Array: self.energies, self.boundary, self.channel_radius, - self.mass_factor, + self.mass_factor_grid, ), ) @@ -230,23 +206,11 @@ class _PhasesGridObservable: energies: jax.Array boundary: BoundaryValues channel_radius: float - mass_factor: float - mass_factor_grid: jax.Array | None = None + mass_factor_grid: jax.Array def __call__(self, spectra: Spectrum) -> jax.Array: """Evaluate `δ(E_i; spec_i)` across the compile-time energy grid.""" - if self.mass_factor_grid is not None: - return cast( - jax.Array, - _PHASES_GRID_WITH_MU_JIT( - spectra, - self.energies, - self.boundary, - self.channel_radius, - self.mass_factor_grid, - ), - ) return cast( jax.Array, _PHASES_GRID_JIT( @@ -254,38 +218,11 @@ def __call__(self, spectra: Spectrum) -> jax.Array: self.energies, self.boundary, self.channel_radius, - self.mass_factor, + self.mass_factor_grid, ), ) -@dataclass(frozen=True) -class _DirectSMatrixGridObservable: - """Pickle-safe aligned-grid S-matrix observable for direct R-matrices.""" - - rmatrix_direct_grid: DirectGridObservable - boundary: BoundaryValues - - def __call__(self, potentials: jax.Array) -> jax.Array: - """Evaluate `S(E_i; V_i)` from aligned direct R-matrix samples.""" - - rmatrix_grid = self.rmatrix_direct_grid(potentials) - return cast(jax.Array, _DIRECT_SMATRIX_GRID_JIT(rmatrix_grid, self.boundary)) - - -@dataclass(frozen=True) -class _DirectPhasesGridObservable: - """Pickle-safe aligned-grid phase observable for direct R-matrices.""" - - smatrix_direct_grid: DirectGridObservable - - def __call__(self, potentials: jax.Array) -> jax.Array: - """Evaluate `δ(E_i; V_i)` from aligned direct S-matrix samples.""" - - smatrix_grid = self.smatrix_direct_grid(potentials) - return cast(jax.Array, _DIRECT_PHASES_GRID_JIT(smatrix_grid)) - - @dataclass(frozen=True) class _InterpolatorBuilder: """Pickle-safe Padé interpolation builder bound to one energy grid.""" @@ -387,53 +324,25 @@ def bind_grid_observables( channel_radius = mesh.scale mass_factor = _uniform_mass_factor(channels) + _mfg = ( + jnp.full(len(energies), mass_factor) + if mass_factor_grid is None + else jnp.asarray(mass_factor_grid) + ) rmatrix_grid = _RMatrixGridObservable( energies=energies, channel_radius=channel_radius, - mass_factor=mass_factor, - mass_factor_grid=mass_factor_grid, + mass_factor_grid=_mfg, ) smatrix_grid, phases_grid = _matching_grid_observables( energies=energies, boundary=boundary, channel_radius=channel_radius, - mass_factor=mass_factor, - mass_factor_grid=mass_factor_grid, + mass_factor_grid=_mfg, ) return rmatrix_grid, smatrix_grid, phases_grid -def bind_direct_grid_observables( - rmatrix_direct_grid: DirectGridObservable, - boundary: BoundaryValues | None, -) -> tuple[DirectGridObservable | None, DirectGridObservable | None]: - """Bind aligned-grid direct S-matrix and phase observables. - - Parameters - ---------- - rmatrix_direct_grid - Aligned-grid direct R-matrix observable. - boundary - Compile-time boundary values used to match the direct R-matrix onto the - physical S-matrix. - - Returns - ------- - tuple - Bound aligned-grid direct S-matrix and phase observables, or ``(None, None)`` - when no boundary data are available. - """ - - if boundary is None: - return None, None - smatrix_direct_grid = _DirectSMatrixGridObservable( - rmatrix_direct_grid=rmatrix_direct_grid, - boundary=boundary, - ) - phases_direct_grid = _DirectPhasesGridObservable(smatrix_direct_grid=smatrix_direct_grid) - return smatrix_direct_grid, phases_direct_grid - - def bind_interpolators( energies: jax.Array, ) -> tuple[InterpolatorBuilder, InterpolatorBuilder, InterpolatorBuilder]: @@ -480,8 +389,7 @@ def _matching_grid_observables( energies: jax.Array, boundary: BoundaryValues | None, channel_radius: float, - mass_factor: float, - mass_factor_grid: jax.Array | None = None, + mass_factor_grid: jax.Array, ) -> tuple[SpectrumGridObservable | None, SpectrumGridObservable | None]: """Create aligned-grid matching observables when boundary data are available.""" @@ -492,14 +400,12 @@ def _matching_grid_observables( energies=energies, boundary=boundary, channel_radius=channel_radius, - mass_factor=mass_factor, mass_factor_grid=mass_factor_grid, ), _PhasesGridObservable( energies=energies, boundary=boundary, channel_radius=channel_radius, - mass_factor=mass_factor, mass_factor_grid=mass_factor_grid, ), ) @@ -631,79 +537,12 @@ def _eigh(spectrum: Spectrum) -> tuple[jax.Array, jax.Array]: def _rmatrix_grid( - spectra: Spectrum, - energies: jax.Array, - channel_radius: float, - mass_factor: float, -) -> jax.Array: - """Return aligned-grid `R(E_i; spec_i)` samples.""" - - def one_energy(spectrum: Spectrum, energy: jax.Array) -> jax.Array: - return _rmatrix(spectrum, energy, channel_radius, mass_factor) - - return jax.vmap(one_energy)( - spectra, - energies, - ) - - -def _smatrix_grid( - spectra: Spectrum, - energies: jax.Array, - boundary: BoundaryValues, - channel_radius: float, - mass_factor: float, -) -> jax.Array: - """Return aligned-grid `S(E_i; spec_i)` samples.""" - - wave_numbers = _boundary_wave_numbers(boundary) - - def one_energy( - spectrum: Spectrum, - energy: jax.Array, - h_plus: jax.Array, - h_minus: jax.Array, - h_plus_p: jax.Array, - h_minus_p: jax.Array, - is_open: jax.Array, - k: jax.Array, - ) -> jax.Array: - r = _rmatrix(spectrum, energy, channel_radius, mass_factor) - return _match_one_energy(r, h_plus, h_minus, h_plus_p, h_minus_p, is_open, k) - - return jax.vmap(one_energy)( - spectra, - energies, - boundary.H_plus, - boundary.H_minus, - boundary.H_plus_p, - boundary.H_minus_p, - boundary.is_open, - wave_numbers, - ) - - -def _phases_grid( - spectra: Spectrum, - energies: jax.Array, - boundary: BoundaryValues, - channel_radius: float, - mass_factor: float, -) -> jax.Array: - """Return aligned-grid `δ(E_i; spec_i)` samples.""" - - return jax.vmap(phases_from_S)( - _smatrix_grid(spectra, energies, boundary, channel_radius, mass_factor) - ) - - -def _rmatrix_grid_with_mu( spectra: Spectrum, energies: jax.Array, channel_radius: float, mass_factor_grid: jax.Array, ) -> jax.Array: - """Return aligned-grid ``R(E_i; spec_i)`` samples with per-energy μ(E).""" + """Return aligned-grid ``R(E_i; spec_i)`` samples.""" def one_energy(spectrum: Spectrum, energy: jax.Array, mu: jax.Array) -> jax.Array: return _rmatrix(spectrum, energy, channel_radius, mu) @@ -711,14 +550,14 @@ def one_energy(spectrum: Spectrum, energy: jax.Array, mu: jax.Array) -> jax.Arra return jax.vmap(one_energy)(spectra, energies, mass_factor_grid) -def _smatrix_grid_with_mu( +def _smatrix_grid( spectra: Spectrum, energies: jax.Array, boundary: BoundaryValues, channel_radius: float, mass_factor_grid: jax.Array, ) -> jax.Array: - """Return aligned-grid ``S(E_i; spec_i)`` samples with per-energy μ(E).""" + """Return aligned-grid ``S(E_i; spec_i)`` samples.""" wave_numbers = _boundary_wave_numbers(boundary) @@ -749,53 +588,20 @@ def one_energy( ) -def _phases_grid_with_mu( +def _phases_grid( spectra: Spectrum, energies: jax.Array, boundary: BoundaryValues, channel_radius: float, mass_factor_grid: jax.Array, ) -> jax.Array: - """Return aligned-grid ``δ(E_i; spec_i)`` samples with per-energy μ(E).""" + """Return aligned-grid ``δ(E_i; spec_i)`` samples.""" return jax.vmap(phases_from_S)( - _smatrix_grid_with_mu(spectra, energies, boundary, channel_radius, mass_factor_grid) - ) - - -def _direct_smatrix_grid(rmatrix_grid: jax.Array, boundary: BoundaryValues) -> jax.Array: - """Return aligned-grid `S(E_i; V_i)` samples from direct R-matrices.""" - - wave_numbers = _boundary_wave_numbers(boundary) - - def one_energy( - rmatrix: jax.Array, - h_plus: jax.Array, - h_minus: jax.Array, - h_plus_p: jax.Array, - h_minus_p: jax.Array, - is_open: jax.Array, - k: jax.Array, - ) -> jax.Array: - return _match_one_energy(rmatrix, h_plus, h_minus, h_plus_p, h_minus_p, is_open, k) - - return jax.vmap(one_energy)( - rmatrix_grid, - boundary.H_plus, - boundary.H_minus, - boundary.H_plus_p, - boundary.H_minus_p, - boundary.is_open, - wave_numbers, + _smatrix_grid(spectra, energies, boundary, channel_radius, mass_factor_grid) ) -def _direct_phases_grid(smatrix_grid: jax.Array) -> jax.Array: - """Return aligned-grid `δ(E_i; V_i)` samples from direct S-matrices.""" - - return jax.vmap(phases_from_S)(smatrix_grid) - - _RMATRIX_JIT = jax.jit( _rmatrix, static_argnames=("channel_radius", "mass_factor"), @@ -819,30 +625,14 @@ def _direct_phases_grid(smatrix_grid: jax.Array) -> jax.Array: _EIGH_JIT = jax.jit(_eigh) _RMATRIX_GRID_JIT = jax.jit( _rmatrix_grid, - static_argnames=("channel_radius", "mass_factor"), + static_argnames=("channel_radius",), ) _SMATRIX_GRID_JIT = jax.jit( _smatrix_grid, - static_argnames=("channel_radius", "mass_factor"), + static_argnames=("channel_radius",), ) _PHASES_GRID_JIT = jax.jit( _phases_grid, - static_argnames=("channel_radius", "mass_factor"), -) -_DIRECT_SMATRIX_GRID_JIT = jax.jit(_direct_smatrix_grid) -_DIRECT_PHASES_GRID_JIT = jax.jit(_direct_phases_grid) -# μ(E)-aware aligned-grid kernels: mass_factor_grid is a traced JAX array in the vmap, -# so it is NOT in static_argnames. channel_radius remains static. -_RMATRIX_GRID_WITH_MU_JIT = jax.jit( - _rmatrix_grid_with_mu, - static_argnames=("channel_radius",), -) -_SMATRIX_GRID_WITH_MU_JIT = jax.jit( - _smatrix_grid_with_mu, - static_argnames=("channel_radius",), -) -_PHASES_GRID_WITH_MU_JIT = jax.jit( - _phases_grid_with_mu, static_argnames=("channel_radius",), ) @@ -877,7 +667,7 @@ def _match_rmatrix( h_plus_p: jax.Array, h_minus_p: jax.Array, is_open: jax.Array, - k: jax.Array | None, + k: jax.Array, ) -> jax.Array: """Convert one channel-space R-matrix into the physical S-matrix.""" @@ -915,7 +705,7 @@ def _project_open_channels( h_plus_p: jax.Array, h_minus_p: jax.Array, is_open: jax.Array, - k: jax.Array | None, + k: jax.Array, ) -> tuple[jax.Array, BoundaryValues]: """Project the decoupled R-matrix and boundary values onto the open-channel subspace. @@ -934,7 +724,7 @@ def _project_open_channels( is_open Boolean mask for open channels, shape ``(N_c,)``. k - Wave numbers in fm⁻¹, shape ``(N_c,)``, or ``None``. + Wave numbers in fm⁻¹, shape ``(N_c,)``. Returns ------- @@ -951,11 +741,8 @@ def _project_open_channels( dtype=closed_dtype, ) mask_complex = is_open.astype(closed_dtype) - if k is None: - k_values = None - else: - ones_k: jax.Array = jnp.ones_like(k, dtype=k.dtype) - k_values = k * is_open.astype(k.dtype) + ones_k * (1 - is_open.astype(k.dtype)) + ones_k: jax.Array = jnp.ones_like(k, dtype=k.dtype) + k_values = k * is_open.astype(k.dtype) + ones_k * (1 - is_open.astype(k.dtype)) boundary_slice = BoundaryValues( H_plus=h_plus * mask_complex + ones * (1.0 - mask_complex), @@ -986,14 +773,9 @@ def _closed_channel_bloch( def _boundary_wave_numbers(boundary: BoundaryValues) -> jax.Array: - """Return concrete wave numbers for matching, defaulting closed tests to one.""" + """Return wave numbers for matching.""" - if boundary.k is not None: - return boundary.k - return jnp.ones_like( - boundary.is_open, - dtype=jnp.float64, - ) + return boundary.k def _uniform_mass_factor(channels: tuple[ChannelSpec, ...]) -> float: @@ -1004,11 +786,10 @@ def _uniform_mass_factor(channels: tuple[ChannelSpec, ...]) -> float: if channel.mass_factor != mass_factor: msg = "The MVP solver path requires a uniform mass_factor across channels." raise ValueError(msg) - return mass_factor + return cast(float, mass_factor) __all__ = [ - "bind_direct_grid_observables", "bind_grid_observables", "bind_interpolators", "bind_observables", diff --git a/src/lax/solvers/spectrum.py b/src/lax/solvers/spectrum.py index 0128934..abb73b9 100644 --- a/src/lax/solvers/spectrum.py +++ b/src/lax/solvers/spectrum.py @@ -11,7 +11,7 @@ from lax.boundary._types import Mesh, OperatorMatrices, SpectrumKernel from lax.spectral.types import Spectrum -from lax.types import ChannelSpec, Method +from lax.types import ChannelSpec, Interaction, Method from .assembly import assemble_block_hamiltonian, build_Q @@ -29,8 +29,7 @@ class _SpectrumKernel: def __call__( self, - potential: jax.Array, - mass_factor: float | jax.Array | None = None, + potential: jax.Array | Interaction, ) -> Spectrum: """Return the spectral decomposition for one assembled potential. @@ -44,22 +43,11 @@ def __call__( jax.vmap(solver.spectrum)(interaction_list) - mass_factor - Optional energy-dependent ℏ²/2μ value in MeV·fm². When provided, - overrides ``ChannelSpec.mass_factor`` in the Hamiltonian assembly. - Typical usage:: - - spectra = jax.vmap( - lambda V, mu: solver.spectrum(V, mass_factor=mu) - )(V_grid, mu_grid) - Returns ------- Spectrum Eigendecomposition of the Bloch-augmented Hamiltonian. """ - from lax.types import Interaction # noqa: PLC0415 - if isinstance(potential, Interaction): if potential.energy_dependent: raise TypeError( @@ -78,7 +66,6 @@ def __call__( self.channels, self.q, self.keep_eigenvectors, - mass_factor, ), ) if self.method == "eig": @@ -91,7 +78,6 @@ def __call__( self.channels, self.q, self.keep_eigenvectors, - mass_factor, ), ) msg = f"Method {self.method!r} is not implemented in the MVP spectrum kernel." @@ -153,15 +139,11 @@ def _spectrum_eigh( channels: tuple[ChannelSpec, ...], q: jax.Array, keep_eigenvectors: bool, - mass_factor_override: float | jax.Array | None, ) -> Spectrum: """Return the Hermitian spectrum for one potential.""" - H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential, mass_factor_override) - if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: - m0 = mass_factor_override - else: - m0 = channels[0].mass_factor + H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential) + m0 = channels[0].mass_factor hamiltonian = H_MeV / m0 eigensystem = cast( tuple[jax.Array, jax.Array], @@ -184,15 +166,11 @@ def _spectrum_eig( channels: tuple[ChannelSpec, ...], q: jax.Array, keep_eigenvectors: bool, - mass_factor_override: float | jax.Array | None, ) -> Spectrum: """Return the complex-symmetric spectrum for one potential.""" - H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential, mass_factor_override) - if mass_factor_override is not None and jnp.ndim(mass_factor_override) == 0: - m0 = mass_factor_override - else: - m0 = channels[0].mass_factor + H_MeV = assemble_block_hamiltonian(mesh, operators, channels, potential) + m0 = channels[0].mass_factor hamiltonian = H_MeV / m0 eigenvalues, eigenvectors = _eig_via_callback(hamiltonian) bilinear_norm = jnp.sqrt(jnp.diag(eigenvectors.T @ eigenvectors)) diff --git a/src/lax/spectral/matching.py b/src/lax/spectral/matching.py index 47228cc..3aea817 100644 --- a/src/lax/spectral/matching.py +++ b/src/lax/spectral/matching.py @@ -63,10 +63,7 @@ def smatrix_from_R(R: jax.Array, boundary_at_energy: BoundaryValues) -> jax.Arra H_minus = jnp.diag(boundary_at_energy.H_minus) H_plus_p = jnp.diag(boundary_at_energy.H_plus_p) H_minus_p = jnp.diag(boundary_at_energy.H_minus_p) - if boundary_at_energy.k is None: - k = jnp.ones(R.shape[0], dtype=R.dtype) - else: - k = boundary_at_energy.k.astype(R.dtype) + k = boundary_at_energy.k.astype(R.dtype) sqrt_k = jnp.sqrt(k) K = jnp.diag(sqrt_k) Kinv = jnp.diag(1.0 / sqrt_k) @@ -239,7 +236,7 @@ def _project_open_channels( h_plus_p: jax.Array, h_minus_p: jax.Array, is_open: jax.Array, - k: jax.Array | None, + k: jax.Array, ) -> tuple[jax.Array, BoundaryValues]: """Project a full-channel system onto the open-channel matching problem.""" @@ -251,11 +248,8 @@ def _project_open_channels( dtype=closed_dtype, ) mask_complex = is_open.astype(closed_dtype) - if k is None: - k_values = None - else: - ones_k: jax.Array = jnp.ones_like(k, dtype=k.dtype) - k_values = k * is_open.astype(k.dtype) + ones_k * (1 - is_open.astype(k.dtype)) + ones_k: jax.Array = jnp.ones_like(k, dtype=k.dtype) + k_values = k * is_open.astype(k.dtype) + ones_k * (1 - is_open.astype(k.dtype)) boundary_slice = BoundaryValues( H_plus=h_plus * mask_complex + ones * (1.0 - mask_complex), diff --git a/src/lax/types.py b/src/lax/types.py index bbf5986..ed126a8 100644 --- a/src/lax/types.py +++ b/src/lax/types.py @@ -16,11 +16,6 @@ ] type Method = Literal["eigh", "eig", "linear_solve"] -# Backward-compatible aliases for internal signatures and existing sketches. -type MeshFamilyT = MeshFamily -type RegularizationT = Regularization -type MethodT = Method - def _empty_extras() -> dict[str, object]: """Return a typed empty mapping for mesh-specific extra options.""" @@ -83,7 +78,7 @@ class ChannelSpec: l: int threshold: float - mass_factor: float + mass_factor: float | jax.Array @jax.tree_util.register_dataclass @@ -129,10 +124,7 @@ def __radd__(self, other: object) -> Interaction: "ChannelSpec", "Interaction", "MeshFamily", - "MeshFamilyT", "MeshSpec", "Method", - "MethodT", "Regularization", - "RegularizationT", ] diff --git a/tests/benchmarks/test_alpha_pb_optical.py b/tests/benchmarks/test_alpha_pb_optical.py index c3330d3..26dc3e1 100644 --- a/tests/benchmarks/test_alpha_pb_optical.py +++ b/tests/benchmarks/test_alpha_pb_optical.py @@ -88,14 +88,13 @@ def _boundary_at_energy(solver: lm.Solver, energy_index: int) -> BoundaryValues: """Return the boundary-value slice for one compile-time energy.""" assert solver.boundary is not None - k_values = None if solver.boundary.k is None else solver.boundary.k[energy_index] return BoundaryValues( H_plus=solver.boundary.H_plus[energy_index], H_minus=solver.boundary.H_minus[energy_index], H_plus_p=solver.boundary.H_plus_p[energy_index], H_minus_p=solver.boundary.H_minus_p[energy_index], is_open=solver.boundary.is_open[energy_index], - k=k_values, + k=solver.boundary.k[energy_index], ) diff --git a/tests/benchmarks/test_descouvemont_closed_channels.py b/tests/benchmarks/test_descouvemont_closed_channels.py index c47b744..1e4d2a1 100644 --- a/tests/benchmarks/test_descouvemont_closed_channels.py +++ b/tests/benchmarks/test_descouvemont_closed_channels.py @@ -1,6 +1,5 @@ from __future__ import annotations -import jax.numpy as jnp import numpy as np import pytest @@ -10,7 +9,7 @@ ALPHA_C12_ROTOR_MODEL, channels_from_rotor_model, first_column_amplitudes_and_phases, - make_rotor_coupled_optical_potential, + interaction_from_rotor_model, open_channel_count, ) from tests.benchmarks._descouvemont_fixtures import ( @@ -43,19 +42,6 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) -def _rotor_interaction(solver: lm.Solver, fn) -> object: - """Build an Interaction for the 8-channel α+12C rotor model from fn(r, c, cp).""" - n_c = len(channels_from_rotor_model(ALPHA_C12_ROTOR_MODEL)) - N = solver.mesh.n - M = n_c * N - r = solver.mesh.radii - block = jnp.zeros((M, M), dtype=jnp.complex128) - for c in range(n_c): - for cp in range(n_c): - g = fn(r, c, cp) - block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g)) - assert solver.interaction_from_block is not None - return solver.interaction_from_block(block, energy_dependent=False) def _smatrix_from_direct_rmatrix( @@ -84,14 +70,13 @@ def _boundary_at_energy(solver: lm.Solver, energy_index: int) -> BoundaryValues: """Return the boundary-value slice for one compile-time energy.""" assert solver.boundary is not None - k_values = None if solver.boundary.k is None else solver.boundary.k[energy_index] return BoundaryValues( H_plus=solver.boundary.H_plus[energy_index], H_minus=solver.boundary.H_minus[energy_index], H_plus_p=solver.boundary.H_plus_p[energy_index], H_minus_p=solver.boundary.H_minus_p[energy_index], is_open=solver.boundary.is_open[energy_index], - k=k_values, + k=solver.boundary.k[energy_index], ) @@ -106,9 +91,8 @@ def test_descouvemont_closed_channel_matches_published_first_column( ) -> None: """Published Descouvemont Example 4 values remain visible in the suite.""" - potential = make_rotor_coupled_optical_potential(ALPHA_C12_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - interaction = _rotor_interaction(solver, potential) + interaction = interaction_from_rotor_model(ALPHA_C12_ROTOR_MODEL, solver) smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): @@ -142,9 +126,8 @@ def test_descouvemont_closed_channel_demo_matches_full_precision_reference() -> """The single-interval notebook regression stays locked to the checked-in full-precision output.""" reference = load_alpha_c12_single_interval_demo() - potential = make_rotor_coupled_optical_potential(ALPHA_C12_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - interaction = _rotor_interaction(solver, potential) + interaction = interaction_from_rotor_model(ALPHA_C12_ROTOR_MODEL, solver) smatrices, _ = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): @@ -176,7 +159,6 @@ def test_descouvemont_closed_channel_reduced_spectral_and_direct_paths_agree() - energies = np.asarray([4.0, 8.0], dtype=np.float64) channels = channels_from_rotor_model(ALPHA_C12_ROTOR_MODEL) - potential = make_rotor_coupled_optical_potential(ALPHA_C12_ROTOR_MODEL) spectral_solver = lm.compile( mesh=lm.MeshSpec("legendre", "x", n=20, scale=11.0), channels=channels, @@ -197,8 +179,8 @@ def test_descouvemont_closed_channel_reduced_spectral_and_direct_paths_agree() - V_is_complex=True, z1z2=(2, 6), ) - spectral_V = _rotor_interaction(spectral_solver, potential) - direct_V = _rotor_interaction(direct_solver, potential) + spectral_V = interaction_from_rotor_model(ALPHA_C12_ROTOR_MODEL, spectral_solver) + direct_V = interaction_from_rotor_model(ALPHA_C12_ROTOR_MODEL, direct_solver) assert spectral_solver.spectrum is not None assert spectral_solver.smatrix is not None diff --git a/tests/benchmarks/test_descouvemont_np.py b/tests/benchmarks/test_descouvemont_np.py index 7a409de..5c27b8d 100644 --- a/tests/benchmarks/test_descouvemont_np.py +++ b/tests/benchmarks/test_descouvemont_np.py @@ -69,14 +69,13 @@ def _boundary_at_energy(solver: lm.Solver, energy_index: int) -> BoundaryValues: """Return the boundary-value slice for one compile-time energy.""" assert solver.boundary is not None - k_values = None if solver.boundary.k is None else solver.boundary.k[energy_index] return BoundaryValues( H_plus=solver.boundary.H_plus[energy_index], H_minus=solver.boundary.H_minus[energy_index], H_plus_p=solver.boundary.H_plus_p[energy_index], H_minus_p=solver.boundary.H_minus_p[energy_index], is_open=solver.boundary.is_open[energy_index], - k=k_values, + k=solver.boundary.k[energy_index], ) diff --git a/tests/benchmarks/test_descouvemont_o16_ca44.py b/tests/benchmarks/test_descouvemont_o16_ca44.py index 548dc21..6156e42 100644 --- a/tests/benchmarks/test_descouvemont_o16_ca44.py +++ b/tests/benchmarks/test_descouvemont_o16_ca44.py @@ -1,6 +1,5 @@ from __future__ import annotations -import jax.numpy as jnp import numpy as np import pytest @@ -10,7 +9,7 @@ O16_CA44_ROTOR_MODEL, channels_from_rotor_model, first_column_amplitudes_and_phases, - make_rotor_coupled_optical_potential, + interaction_from_rotor_model, open_channel_count, ) from tests.benchmarks._descouvemont_fixtures import ( @@ -42,19 +41,6 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) -def _rotor_interaction(solver: lm.Solver, fn) -> object: - """Build an Interaction for the 4-channel O16+Ca44 rotor model from fn(r, c, cp).""" - n_c = len(channels_from_rotor_model(O16_CA44_ROTOR_MODEL)) - N = solver.mesh.n - M = n_c * N - r = solver.mesh.radii - block = jnp.zeros((M, M), dtype=jnp.complex128) - for c in range(n_c): - for cp in range(n_c): - g = fn(r, c, cp) - block = block.at[c * N : (c + 1) * N, cp * N : (cp + 1) * N].set(jnp.diag(g)) - assert solver.interaction_from_block is not None - return solver.interaction_from_block(block, energy_dependent=False) def _smatrix_from_direct_rmatrix( @@ -83,14 +69,13 @@ def _boundary_at_energy(solver: lm.Solver, energy_index: int) -> BoundaryValues: """Return the boundary-value slice for one compile-time energy.""" assert solver.boundary is not None - k_values = None if solver.boundary.k is None else solver.boundary.k[energy_index] return BoundaryValues( H_plus=solver.boundary.H_plus[energy_index], H_minus=solver.boundary.H_minus[energy_index], H_plus_p=solver.boundary.H_plus_p[energy_index], H_minus_p=solver.boundary.H_minus_p[energy_index], is_open=solver.boundary.is_open[energy_index], - k=k_values, + k=solver.boundary.k[energy_index], ) @@ -103,9 +88,8 @@ def _boundary_at_energy(solver: lm.Solver, energy_index: int) -> BoundaryValues: def test_descouvemont_o16_ca44_matches_published_output(reference: CoupledColumnReference) -> None: """Published Descouvemont Example 3 values remain visible in the suite.""" - potential = make_rotor_coupled_optical_potential(O16_CA44_ROTOR_MODEL) solver = _solver(reference, "linear_solve", ("rmatrix_direct",)) - interaction = _rotor_interaction(solver, potential) + interaction = interaction_from_rotor_model(O16_CA44_ROTOR_MODEL, solver) smatrices, projected_boundaries = _smatrix_from_direct_rmatrix(solver, interaction) for energy_index, energy in enumerate(reference.energies): diff --git a/tests/benchmarks/test_hydrogen.py b/tests/benchmarks/test_hydrogen.py index 168c627..e1ae463 100644 --- a/tests/benchmarks/test_hydrogen.py +++ b/tests/benchmarks/test_hydrogen.py @@ -39,10 +39,6 @@ def _hydrogen_solver( ) -def _hydrogen_potential(solver: Solver) -> jax.Array: - """Return the Coulomb potential for one compiled hydrogen solver.""" - - return jnp.asarray((-1.0 / solver.mesh.radii)[None, None, :]) def _hydrogen_radial_wavefunction(n: int, angular_momentum: int, radii: np.ndarray) -> np.ndarray: @@ -124,7 +120,8 @@ def test_hydrogen_ground_state_laguerre_x() -> None: solver = _hydrogen_solver(0) assert solver.spectrum is not None - spectrum = solver.spectrum(_hydrogen_potential(solver)) + assert solver.potential is not None + spectrum = solver.spectrum(solver.potential(lambda r: -1.0 / r)) ground_state = float(np.asarray(spectrum.eigenvalues)[0]) * solver.channels[0].mass_factor assert abs(ground_state + 0.5) < 1.0e-10 @@ -147,7 +144,8 @@ def test_hydrogen_bound_state_energies( solver = _hydrogen_solver(angular_momentum) assert solver.spectrum is not None - spectrum = solver.spectrum(_hydrogen_potential(solver)) + assert solver.potential is not None + spectrum = solver.spectrum(solver.potential(lambda r: -1.0 / r)) physical_energies = np.asarray(spectrum.eigenvalues) * solver.channels[0].mass_factor expected = np.asarray([-0.5 / (n**2) for n in principal_quantum_numbers], dtype=np.float64) @@ -181,7 +179,8 @@ def test_hydrogen_wavefunctions_match_analytic_radial_forms( assert solver.to_grid_vector is not None assert solver.transforms.grid_r is not None - spectrum = solver.spectrum(_hydrogen_potential(solver)) + assert solver.potential is not None + spectrum = solver.spectrum(solver.potential(lambda r: -1.0 / r)) assert spectrum.eigenvectors is not None eigenvector = np.asarray(spectrum.eigenvectors)[:, state_index] @@ -220,7 +219,8 @@ def test_hydrogen_wavefunctions_match_analytic_momentum_forms( assert solver.fourier is not None assert solver.transforms.momenta is not None - spectrum = solver.spectrum(_hydrogen_potential(solver)) + assert solver.potential is not None + spectrum = solver.spectrum(solver.potential(lambda r: -1.0 / r)) assert spectrum.eigenvectors is not None eigenvector = np.asarray(spectrum.eigenvectors)[:, state_index] @@ -257,7 +257,8 @@ def test_hydrogen_momentum_norm_matches_current_fourier_convention() -> None: assert solver.transforms.grid_r is not None assert solver.transforms.momenta is not None - spectrum = solver.spectrum(_hydrogen_potential(solver)) + assert solver.potential is not None + spectrum = solver.spectrum(solver.potential(lambda r: -1.0 / r)) assert spectrum.eigenvectors is not None eigenvector = jnp.asarray(np.asarray(spectrum.eigenvectors)[:, 0]) diff --git a/tests/property/test_unitarity.py b/tests/property/test_unitarity.py index 1200f46..f31dc28 100644 --- a/tests/property/test_unitarity.py +++ b/tests/property/test_unitarity.py @@ -77,6 +77,7 @@ def test_smatrix_agrees_with_per_energy_rmatrix_path(V: jax.Array) -> None: H_plus_p=_SOLVER.boundary.H_plus_p[i], H_minus_p=_SOLVER.boundary.H_minus_p[i], is_open=_SOLVER.boundary.is_open[i], + k=_SOLVER.boundary.k[i], ) S_from_R = np.asarray(smatrix_from_R(R, boundary_slice)) assert np.allclose(S_from_R, S_grid[i], atol=1e-10), ( diff --git a/tests/unit/test_energy_dependent_flow.py b/tests/unit/test_energy_dependent_flow.py index 2f7f203..3a96b36 100644 --- a/tests/unit/test_energy_dependent_flow.py +++ b/tests/unit/test_energy_dependent_flow.py @@ -213,10 +213,9 @@ def test_constant_mass_factor_grid_reproduces_scalar_result() -> None: scalar_spectra = jax.vmap(scalar_solver.spectrum)(potentials) scalar_phases = scalar_solver.phases_grid(scalar_spectra) - # Grid path: spectrum uses mass_factor=mu_i (constant, same value) - grid_spectra = jax.vmap(lambda V, mu: grid_solver.spectrum(V, mass_factor=mu))( - potentials, mu_grid - ) + # Grid path: mass factor is baked in at compile time; spectrum uses ChannelSpec.mass_factor + # (which equals mu_scalar), and phases_grid uses the constant mass_factor_grid boundary. + grid_spectra = jax.vmap(grid_solver.spectrum)(potentials) grid_phases = grid_solver.phases_grid(grid_spectra) assert np.allclose( @@ -262,11 +261,13 @@ def test_varying_mass_factor_grid_changes_phases() -> None: const_spectra = jax.vmap(const_solver.spectrum)(potentials) const_phases = const_solver.phases_grid(const_spectra) - mu_spectra = jax.vmap(lambda V, mu: mu_solver.spectrum(V, mass_factor=mu))(potentials, mu_grid) + # Mass factors are baked at compile time; spectrum always uses ChannelSpec.mass_factor. + # The energy-dependent mu enters through the compiled boundary values (k_c, η_c) in + # phases_grid, so mu_phases differ from const_phases even though the spectra agree. + mu_spectra = jax.vmap(mu_solver.spectrum)(potentials) mu_phases = mu_solver.phases_grid(mu_spectra) - # Phases must differ — the energy-dependent mu changes both the Hamiltonian - # (threshold/mu, V/mu terms) and the spectral denominator (E/mu). + # Phases must differ — the energy-dependent mu changes the boundary matching (k_c, η_c). assert not np.allclose(np.asarray(const_phases), np.asarray(mu_phases), atol=1e-6), ( "Varying mu(E) should produce different phases from constant mu" ) diff --git a/tests/unit/test_solver_direct.py b/tests/unit/test_solver_direct.py index dd38f15..e3c6203 100644 --- a/tests/unit/test_solver_direct.py +++ b/tests/unit/test_solver_direct.py @@ -77,10 +77,6 @@ def test_compile_exposes_direct_rmatrix_kernel() -> None: assert solver.smatrix_direct is not None assert solver.phases_direct is not None assert solver.potential is not None - # deprecated aligned-grid observables are no longer wired - assert solver.rmatrix_direct_grid is None - assert solver.smatrix_direct_grid is None - assert solver.phases_direct_grid is None assert solver.interpolate_rmatrix is not None assert solver.interpolate_smatrix is not None assert solver.interpolate_phases is not None @@ -291,10 +287,6 @@ def test_direct_grid_observables_match_spectral_grid_for_real_energy_dependent_p assert direct_solver.smatrix_direct is not None assert direct_solver.phases_direct is not None # deprecated aligned-grid observables are no longer wired - assert direct_solver.rmatrix_direct_grid is None - assert direct_solver.smatrix_direct_grid is None - assert direct_solver.phases_direct_grid is None - spectral_interaction = spectral_solver.potential(_energy_dep_V, energy_dependent=True) direct_interaction = direct_solver.potential(_energy_dep_V, energy_dependent=True) @@ -345,9 +337,6 @@ def test_mass_factor_grid_broadcast_scalar_reproduces_uniform() -> None: mass_factor_grid=jnp.full((2,), m), # (N_E,) — broadcasts to (N_E, N_c) ) - assert solver_uniform.rmatrix_direct_grid is None # deprecated - assert solver_grid.rmatrix_direct_grid is None # deprecated - interaction_uniform = solver_uniform.potential(_energy_dep_V, energy_dependent=True) interaction_grid = solver_grid.potential(_energy_dep_V, energy_dependent=True) @@ -382,9 +371,6 @@ def test_mass_factor_grid_2d_reproduces_uniform() -> None: mass_factor_grid=jnp.full((2, 1), m), # explicit (N_E, N_c) shape ) - assert solver_uniform.rmatrix_direct_grid is None # deprecated - assert solver_grid.rmatrix_direct_grid is None # deprecated - interaction_uniform = solver_uniform.potential(_energy_dep_V, energy_dependent=True) interaction_grid = solver_grid.potential(_energy_dep_V, energy_dependent=True) @@ -458,10 +444,6 @@ def test_per_channel_mass_factor_grid_decoupled_matches_single_channel() -> None energy_dependent=True, ) - assert two_ch.rmatrix_direct_grid is None # deprecated - assert ch0_solver.rmatrix_direct_grid is None # deprecated - assert ch1_solver.rmatrix_direct_grid is None # deprecated - # Decoupled diagonal potentials (energy-independent in value, energy-dependent in API). def V_ch0_fn(r: jax.Array, E: float) -> jax.Array: return -0.5 * jnp.exp(-((r / 2.5) ** 2)) * m0 diff --git a/tests/unit/test_solver_pickle.py b/tests/unit/test_solver_pickle.py index c6a4be8..db5ea98 100644 --- a/tests/unit/test_solver_pickle.py +++ b/tests/unit/test_solver_pickle.py @@ -81,14 +81,6 @@ def test_compiled_solver_round_trips_through_pickle() -> None: ): assert getattr(restored, name) is not None - # deprecated aligned-grid observables are no longer wired - assert solver.rmatrix_direct_grid is None - assert solver.smatrix_direct_grid is None - assert solver.phases_direct_grid is None - assert restored.rmatrix_direct_grid is None - assert restored.smatrix_direct_grid is None - assert restored.phases_direct_grid is None - assert solver.spectrum is not None assert solver.rmatrix is not None assert solver.smatrix is not None diff --git a/tests/unit/test_solver_spectrum.py b/tests/unit/test_solver_spectrum.py index 3c73081..1cd92f7 100644 --- a/tests/unit/test_solver_spectrum.py +++ b/tests/unit/test_solver_spectrum.py @@ -138,6 +138,7 @@ def test_bind_observables_matches_direct_spectral_helpers() -> None: H_plus_p=jnp.asarray([[0.25 + 0.15j]]), H_minus_p=jnp.asarray([[0.25 - 0.15j]]), is_open=jnp.asarray([[True]]), + k=jnp.ones((1, 1)), ) spectrum = make_spectrum_kernel(mesh, operators, channels, keep_eigenvectors=True)(potential) diff --git a/tests/unit/test_spectral.py b/tests/unit/test_spectral.py index 3c04cf0..b7d2a7d 100644 --- a/tests/unit/test_spectral.py +++ b/tests/unit/test_spectral.py @@ -119,6 +119,7 @@ def test_smatrix_from_R_is_unitary_for_real_r() -> None: H_plus_p=jnp.asarray([0.3 + 0.2j]), H_minus_p=jnp.asarray([0.3 - 0.2j]), is_open=jnp.asarray([True]), + k=jnp.ones(1), ) S = np.asarray(smatrix_from_R(R, boundary)) @@ -160,6 +161,7 @@ def test_smatrix_from_R_is_symmetric_and_unitary_for_real_two_channel_r() -> Non H_plus_p=solver.boundary.H_plus_p[0], H_minus_p=solver.boundary.H_minus_p[0], is_open=solver.boundary.is_open[0], + k=solver.boundary.k[0], ) S = np.asarray(smatrix_from_R(R, boundary)) From 253fb84de7a7ae6211d0f61e8f20beb5d1932999 Mon Sep 17 00:00:00 2001 From: beykyle Date: Thu, 11 Jun 2026 01:43:43 -0400 Subject: [PATCH 09/10] update reid interaction to use updated solver.potential api cleanly --- docs/api.rst | 2 +- examples/alpha_pb_demo.ipynb | 68 +++++-------------- .../descouvemont_closed_channels_demo.ipynb | 12 +--- examples/descouvemont_np_demo.ipynb | 42 +++++------- examples/descouvemont_o16_ca44_demo.ipynb | 12 +--- examples/energy_dependent_demo.ipynb | 8 +-- examples/fourier_demo.ipynb | 12 +--- examples/hydrogen_demo.ipynb | 21 ++---- examples/yamaguchi_demo.ipynb | 16 ++--- src/lax/models/__init__.py | 4 +- src/lax/models/reid.py | 64 +++++++++++------ .../benchmarks/test_coupled_closed_channel.py | 48 ++++++------- .../test_descouvemont_closed_channels.py | 2 - tests/benchmarks/test_descouvemont_np.py | 20 ++---- .../benchmarks/test_descouvemont_o16_ca44.py | 2 - tests/benchmarks/test_hydrogen.py | 2 - tests/unit/test_spectral.py | 15 +--- 17 files changed, 126 insertions(+), 224 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 7b869d8..23f6514 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -83,7 +83,7 @@ Reusable interaction models and preset system parameters. .. autofunction:: lax.models.reid_np_j1_channels -.. autofunction:: lax.models.reid_np_j1_potential +.. autofunction:: lax.models.interaction_from_reid_np_j1 .. autofunction:: lax.models.reid_soft_core_triplet_components diff --git a/examples/alpha_pb_demo.ipynb b/examples/alpha_pb_demo.ipynb index 9f0837a..b414145 100644 --- a/examples/alpha_pb_demo.ipynb +++ b/examples/alpha_pb_demo.ipynb @@ -52,9 +52,7 @@ " ],\n", " dtype=np.complex128,\n", ")\n", - "ALPHA_PB_MASS_FACTOR = lm.constants.hbar2_over_2mu(\n", - " 4.001506, 207.9767\n", - ") # α + ²⁰⁸Pb MeV·fm²\n", + "ALPHA_PB_MASS_FACTOR = lm.constants.hbar2_over_2mu(4.001506, 207.9767) # α + ²⁰⁸Pb MeV·fm²\n", "BENCHMARK_L = 20\n", "CHANNEL_RADIUS = 14.0\n", "\n", @@ -81,11 +79,7 @@ "def complex_solver(method: str, solvers: tuple[str, ...]) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", - " channels=(\n", - " lm.ChannelSpec(\n", - " l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", - " ),\n", - " ),\n", + " channels=(lm.ChannelSpec(l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),),\n", " operators=(\"T+L\",),\n", " solvers=solvers,\n", " energies=OPTICAL_ENERGIES,\n", @@ -98,11 +92,7 @@ "def real_solver(method: str, solvers: tuple[str, ...]) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", - " channels=(\n", - " lm.ChannelSpec(\n", - " l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", - " ),\n", - " ),\n", + " channels=(lm.ChannelSpec(l=BENCHMARK_L, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),),\n", " operators=(\"T+L\",),\n", " solvers=solvers,\n", " energies=OPTICAL_ENERGIES,\n", @@ -111,9 +101,7 @@ " )\n", "\n", "\n", - "def smatrix_from_direct_rmatrix(\n", - " solver: lm.Solver, potential: jnp.ndarray\n", - ") -> np.ndarray:\n", + "def smatrix_from_direct_rmatrix(solver: lm.Solver, potential: jnp.ndarray) -> np.ndarray:\n", " assert solver.rmatrix_direct is not None\n", " assert solver.boundary is not None\n", " r_values = solver.rmatrix_direct(potential)\n", @@ -168,9 +156,7 @@ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.6))\n", "axes[0].plot(r_plot, np.asarray(nuclear_real), label=\"real nuclear\", linewidth=2.2)\n", "axes[0].plot(r_plot, np.asarray(coulomb), label=\"Coulomb\", linewidth=2.2)\n", - "axes[0].plot(\n", - " r_plot, np.asarray(total.real), \"--\", label=\"total real part\", linewidth=2.0\n", - ")\n", + "axes[0].plot(r_plot, np.asarray(total.real), \"--\", label=\"total real part\", linewidth=2.0)\n", "axes[0].set_title(r\"$\\alpha + {}^{208}\\mathrm{Pb}$ real potential pieces\")\n", "axes[0].set_xlabel(\"r [fm]\")\n", "axes[0].set_ylabel(\"MeV\")\n", @@ -211,9 +197,7 @@ "solver_complex_eig = complex_solver(\"eig\", (\"spectrum\", \"smatrix\"))\n", "solver_complex_direct = complex_solver(\"linear_solve\", (\"rmatrix_direct\",))\n", "\n", - "potential_real = solver_real.potential(\n", - " lambda r: jnp.real(optical_potential(r, imag_depth=0.0))\n", - ")\n", + "potential_real = solver_real.potential(lambda r: jnp.real(optical_potential(r, imag_depth=0.0)))\n", "potential_complex_eig = solver_complex_eig.potential(\n", " lambda r: optical_potential(r, imag_depth=10.0)\n", ")\n", @@ -221,9 +205,7 @@ " lambda r: optical_potential(r, imag_depth=10.0)\n", ")\n", "\n", - "smatrix_real = np.asarray(solver_real.smatrix(solver_real.spectrum(potential_real)))[\n", - " :, 0, 0\n", - "]\n", + "smatrix_real = np.asarray(solver_real.smatrix(solver_real.spectrum(potential_real)))[:, 0, 0]\n", "smatrix_complex_eig = np.asarray(\n", " solver_complex_eig.smatrix(solver_complex_eig.spectrum(potential_complex_eig))\n", ")[:, 0, 0]\n", @@ -245,12 +227,8 @@ " )\n", "\n", "print()\n", - "print(\n", - " f\"max |eig - Appendix A| = {np.max(np.abs(smatrix_complex_eig - APPENDIX_A_S)):.3e}\"\n", - ")\n", - "print(\n", - " f\"max |direct - Appendix A| = {np.max(np.abs(smatrix_complex_direct - APPENDIX_A_S)):.3e}\"\n", - ")\n", + "print(f\"max |eig - Appendix A| = {np.max(np.abs(smatrix_complex_eig - APPENDIX_A_S)):.3e}\")\n", + "print(f\"max |direct - Appendix A| = {np.max(np.abs(smatrix_complex_direct - APPENDIX_A_S)):.3e}\")\n", "print(\n", " f\"max |eig - direct| = {np.max(np.abs(smatrix_complex_eig - smatrix_complex_direct)):.3e}\"\n", ")" @@ -276,12 +254,8 @@ "source": [ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))\n", "\n", - "axes[0].plot(\n", - " OPTICAL_ENERGIES, APPENDIX_A_S.real, \"o-\", label=\"Appendix A real\", linewidth=2.2\n", - ")\n", - "axes[0].plot(\n", - " OPTICAL_ENERGIES, smatrix_complex_eig.real, \"--\", label=\"eig real\", linewidth=2.0\n", - ")\n", + "axes[0].plot(OPTICAL_ENERGIES, APPENDIX_A_S.real, \"o-\", label=\"Appendix A real\", linewidth=2.2)\n", + "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_eig.real, \"--\", label=\"eig real\", linewidth=2.0)\n", "axes[0].plot(\n", " OPTICAL_ENERGIES,\n", " smatrix_complex_direct.real,\n", @@ -289,12 +263,8 @@ " label=\"direct real\",\n", " linewidth=2.0,\n", ")\n", - "axes[0].plot(\n", - " OPTICAL_ENERGIES, APPENDIX_A_S.imag, \"o-\", label=\"Appendix A imag\", linewidth=2.2\n", - ")\n", - "axes[0].plot(\n", - " OPTICAL_ENERGIES, smatrix_complex_eig.imag, \"--\", label=\"eig imag\", linewidth=2.0\n", - ")\n", + "axes[0].plot(OPTICAL_ENERGIES, APPENDIX_A_S.imag, \"o-\", label=\"Appendix A imag\", linewidth=2.2)\n", + "axes[0].plot(OPTICAL_ENERGIES, smatrix_complex_eig.imag, \"--\", label=\"eig imag\", linewidth=2.0)\n", "axes[0].plot(\n", " OPTICAL_ENERGIES,\n", " smatrix_complex_direct.imag,\n", @@ -385,9 +355,7 @@ " lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=60, scale=CHANNEL_RADIUS),\n", " channels=(\n", - " lm.ChannelSpec(\n", - " l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR\n", - " ),\n", + " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=ALPHA_PB_MASS_FACTOR),\n", " ),\n", " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"smatrix\", \"phases\"),\n", @@ -417,12 +385,8 @@ "for solver, angular_momentum in zip(solvers, partial_waves):\n", " potential = solver.potential(lambda r: optical_potential(r, imag_depth=10.0))\n", " spectrum = solver.spectrum(potential)\n", - " phase_curves[angular_momentum] = np.asarray(solver.phases(spectrum)[:, 0]) * (\n", - " 180.0 / np.pi\n", - " )\n", - " abs_s_curves[angular_momentum] = np.abs(\n", - " np.asarray(solver.smatrix(spectrum)[:, 0, 0])\n", - " )" + " phase_curves[angular_momentum] = np.asarray(solver.phases(spectrum)[:, 0]) * (180.0 / np.pi)\n", + " abs_s_curves[angular_momentum] = np.abs(np.asarray(solver.smatrix(spectrum)[:, 0, 0]))" ] }, { diff --git a/examples/descouvemont_closed_channels_demo.ipynb b/examples/descouvemont_closed_channels_demo.ipynb index ba320f0..182a878 100644 --- a/examples/descouvemont_closed_channels_demo.ipynb +++ b/examples/descouvemont_closed_channels_demo.ipynb @@ -35,9 +35,7 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = (\n", - " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", - " )\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -116,13 +114,9 @@ "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(\n", - " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", - " )\n", + " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", - " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(\n", - " smatrix, open_count\n", - " )\n", + " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", " rows.append(\n", " {\n", " \"energy_mev\": float(energy),\n", diff --git a/examples/descouvemont_np_demo.ipynb b/examples/descouvemont_np_demo.ipynb index 3831364..5221914 100644 --- a/examples/descouvemont_np_demo.ipynb +++ b/examples/descouvemont_np_demo.ipynb @@ -56,9 +56,7 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = (\n", - " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", - " )\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -67,9 +65,7 @@ "\n", "energies = np.asarray(reference[\"energies\"], dtype=np.float64)\n", "channels = lm.models.reid_np_j1_channels()\n", - "mesh = lm.MeshSpec(\n", - " \"legendre\", \"x\", n=int(reference[\"n_basis\"]), scale=float(reference[\"scale\"])\n", - ")\n", + "mesh = lm.MeshSpec(\"legendre\", \"x\", n=int(reference[\"n_basis\"]), scale=float(reference[\"scale\"]))\n", "\n", "{\n", " \"energies_mev\": energies.tolist(),\n", @@ -84,7 +80,17 @@ "cell_type": "markdown", "id": "9a63283cbaf04dbcab1f6479b197f3a8", "metadata": {}, - "source": "## The public interaction helpers\n\n`lax.models.reid_soft_core_triplet_components(...)` returns the three radial pieces of the Reid soft-core triplet interaction:\n\n- a central term,\n- a tensor term, which is what mixes the `S` and `D` waves,\n- and a spin-orbit term.\n\nThe public helper `lax.models.reid_np_j1_potential(...)` combines those pieces into the `2 × 2` local potential that `solver.interaction_from_array(...)` accepts as individual matrix-element callbacks." + "source": [ + "## The public interaction helpers\n", + "\n", + "`lax.models.reid_soft_core_triplet_components(...)` returns the three radial pieces of the Reid soft-core triplet interaction:\n", + "\n", + "- a central term,\n", + "- a tensor term, which is what mixes the `S` and `D` waves,\n", + "- and a spin-orbit term.\n", + "\n", + "The public builder `lax.models.interaction_from_reid_np_j1(solver)` assembles those pieces into the coupled potential as a sum of *(form factor x coupling matrix)* terms: the central term on the channel diagonal, the tensor term scaled by `[[0, 2*sqrt(2)], [2*sqrt(2), -2]]`, and the spin-orbit term scaled by `[[0, 0], [0, -3]]`." + ] }, { "cell_type": "code", @@ -125,8 +131,7 @@ "source": [ "sample_radii = np.asarray([0.5, 1.0, 2.0, 4.0, 6.0], dtype=np.float64)\n", "central, tensor, spin_orbit = [\n", - " np.asarray(values)\n", - " for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", + " np.asarray(values) for values in lm.models.reid_soft_core_triplet_components(sample_radii)\n", "]\n", "\n", "[\n", @@ -136,9 +141,7 @@ " \"tensor_mev\": float(v_t),\n", " \"spin_orbit_mev\": float(v_ls),\n", " }\n", - " for radius, v_c, v_t, v_ls in zip(\n", - " sample_radii, central, tensor, spin_orbit, strict=True\n", - " )\n", + " for radius, v_c, v_t, v_ls in zip(sample_radii, central, tensor, spin_orbit, strict=True)\n", "]" ] }, @@ -167,16 +170,7 @@ " energies=energies,\n", " method=\"eigh\",\n", ")\n", - "assert solver.interaction_from_array is not None\n", - "r = solver.mesh.radii\n", - "potential = solver.interaction_from_array(\n", - " local=[\n", - " (lm.models.reid_np_j1_potential(r, 0, 0), np.array([[1.0, 0.0], [0.0, 0.0]])),\n", - " (lm.models.reid_np_j1_potential(r, 0, 1), np.array([[0.0, 1.0], [1.0, 0.0]])),\n", - " (lm.models.reid_np_j1_potential(r, 1, 1), np.array([[0.0, 0.0], [0.0, 1.0]])),\n", - " ],\n", - " energy_dependent=False,\n", - ")\n", + "potential = lm.models.interaction_from_reid_np_j1(solver)\n", "spectrum = solver.spectrum(potential)\n", "smatrices = np.asarray(solver.smatrix(spectrum))\n", "\n", @@ -216,7 +210,7 @@ "\n", "- swap `mesh` to study convergence,\n", "- replace `energies` with a denser scan,\n", - "- or replace `lm.models.reid_np_j1_potential` with another `2 × 2` coupled interaction callback.\n", + "- or replace the Reid terms with your own *(form factor, coupling matrix)* pairs via `solver.interaction_from_funcs(...)`.\n", "\n", "The notebook structure stays the same: define channels, assemble a potential, compile the solver, then interpret the `S` matrix in whatever basis is most useful for your application.\n" ] @@ -243,4 +237,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/examples/descouvemont_o16_ca44_demo.ipynb b/examples/descouvemont_o16_ca44_demo.ipynb index e137dbc..177d262 100644 --- a/examples/descouvemont_o16_ca44_demo.ipynb +++ b/examples/descouvemont_o16_ca44_demo.ipynb @@ -35,9 +35,7 @@ " candidate = root / \"tests\" / \"benchmarks\" / \"data\"\n", " if candidate.is_dir():\n", " return candidate\n", - " msg = (\n", - " \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", - " )\n", + " msg = \"Could not locate tests/benchmarks/data from the current notebook environment.\"\n", " raise FileNotFoundError(msg)\n", "\n", "\n", @@ -116,13 +114,9 @@ "rows = []\n", "for energy_index, energy in enumerate(energies):\n", " boundary = boundary_at_energy(solver.boundary, energy_index)\n", - " smatrix = np.asarray(\n", - " lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary)\n", - " )\n", + " smatrix = np.asarray(lm.spectral.open_channel_smatrix_from_R(r_values[energy_index], boundary))\n", " open_count = lm.models.open_channel_count(model, float(energy))\n", - " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(\n", - " smatrix, open_count\n", - " )\n", + " amplitudes, phases = lm.models.first_column_amplitudes_and_phases(smatrix, open_count)\n", " rows.append(\n", " {\n", " \"energy_mev\": float(energy),\n", diff --git a/examples/energy_dependent_demo.ipynb b/examples/energy_dependent_demo.ipynb index 9c36d02..9df1e9f 100644 --- a/examples/energy_dependent_demo.ipynb +++ b/examples/energy_dependent_demo.ipynb @@ -176,9 +176,7 @@ "metadata": {}, "outputs": [], "source": [ - "interp_phases = solver.interpolate_phases(\n", - " jnp.asarray(phases_coarse[:, None])\n", - ") # (N_E, 1)\n", + "interp_phases = solver.interpolate_phases(jnp.asarray(phases_coarse[:, None])) # (N_E, 1)\n", "\n", "# Evaluate interpolant on a fine grid\n", "phases_interp = np.asarray(interp_phases(energies_fine))[:, 0] # (N_FINE,)" @@ -255,9 +253,7 @@ "\n", "axes[0].plot(E_fine, np.degrees(phases_ref), label=\"reference (fine grid)\", lw=2)\n", "axes[0].plot(E_fine, np.degrees(phases_interp), \"--\", label=\"Padé interpolant\", lw=1.8)\n", - "axes[0].scatter(\n", - " E_coarse, np.degrees(phases_coarse), zorder=5, label=\"coarse knots\", s=30\n", - ")\n", + "axes[0].scatter(E_coarse, np.degrees(phases_coarse), zorder=5, label=\"coarse knots\", s=30)\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", "axes[0].set_ylabel(\"Phase shift [deg]\")\n", "axes[0].set_title(r\"Energy-dependent Gaussian: $\\ell=0$ phase shift\")\n", diff --git a/examples/fourier_demo.ipynb b/examples/fourier_demo.ipynb index 35d8ab4..51ed3de 100644 --- a/examples/fourier_demo.ipynb +++ b/examples/fourier_demo.ipynb @@ -130,9 +130,7 @@ " \"Gaussian x polynomial l=0\",\n", " 0,\n", " lambda r: r**2 * (3.0 / (2.0 * beta) - r**2) * np.exp(-beta * r**2),\n", - " lambda k: ((k**2) / (4.0 * beta**2))\n", - " * np.exp(-(k**2) / (4.0 * beta))\n", - " / (2.0 * beta) ** 1.5,\n", + " lambda k: ((k**2) / (4.0 * beta**2)) * np.exp(-(k**2) / (4.0 * beta)) / (2.0 * beta) ** 1.5,\n", " ),\n", " (\n", " \"Gaussian l=1\",\n", @@ -222,18 +220,14 @@ "momenta = np.asarray(numerical_solver.transforms.momenta)\n", "\n", "for row, (name, profile) in enumerate(numerical_profiles):\n", - " coeffs = numerical_solver.from_grid_vector(\n", - " lambda r: jnp.asarray(profile(np.asarray(r)))\n", - " )\n", + " coeffs = numerical_solver.from_grid_vector(lambda r: jnp.asarray(profile(np.asarray(r))))\n", " reconstructed = np.asarray(numerical_solver.to_grid_vector(coeffs))\n", " transformed = np.asarray(numerical_solver.fourier(coeffs))\n", " expected = profile(grid_r)\n", " print(name)\n", " print(\" grid relative error =\", relative_error(reconstructed, expected))\n", " axes[row, 0].plot(grid_r, expected, label=\"input profile\", linewidth=2.0)\n", - " axes[row, 0].plot(\n", - " grid_r, reconstructed, \"--\", label=\"mesh reconstruction\", linewidth=1.8\n", - " )\n", + " axes[row, 0].plot(grid_r, reconstructed, \"--\", label=\"mesh reconstruction\", linewidth=1.8)\n", " axes[row, 0].set_title(f\"{name} in r-space\")\n", " axes[row, 0].set_xlabel(\"r\")\n", " axes[row, 0].set_ylabel(\"u(r)\")\n", diff --git a/examples/hydrogen_demo.ipynb b/examples/hydrogen_demo.ipynb index 9340e28..b9e5818 100644 --- a/examples/hydrogen_demo.ipynb +++ b/examples/hydrogen_demo.ipynb @@ -48,9 +48,7 @@ "def hydrogen_solver(angular_momentum: int) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"laguerre\", \"x\", n=30, scale=2.0),\n", - " channels=(\n", - " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),\n", - " ),\n", + " channels=(lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),),\n", " operators=(\"T\", \"1/r\"),\n", " solvers=(\"spectrum\", \"wavefunction\"),\n", " grid=jnp.linspace(0.0, 40.0, 3000),\n", @@ -65,10 +63,7 @@ " prefactor = (\n", " 2.0\n", " / (n**2)\n", - " * math.sqrt(\n", - " math.factorial(n - angular_momentum - 1)\n", - " / math.factorial(n + angular_momentum)\n", - " )\n", + " * math.sqrt(math.factorial(n - angular_momentum - 1) / math.factorial(n + angular_momentum))\n", " )\n", " radial = (\n", " prefactor\n", @@ -79,9 +74,7 @@ " return radii * radial\n", "\n", "\n", - "def momentum_u_analytic(\n", - " n: int, angular_momentum: int, momenta: np.ndarray\n", - ") -> np.ndarray:\n", + "def momentum_u_analytic(n: int, angular_momentum: int, momenta: np.ndarray) -> np.ndarray:\n", " if n == 1 and angular_momentum == 0:\n", " return np.sqrt(2.0 / np.pi) * 2.0 / (1.0 + momenta**2)\n", " if n == 2 and angular_momentum == 0:\n", @@ -90,9 +83,7 @@ " if n == 2 and angular_momentum == 1:\n", " denominator = momenta**2 + 0.25\n", " return np.sqrt(2.0 / (6.0 * np.pi)) * momenta / (denominator**2)\n", - " raise ValueError(\n", - " f\"No analytic momentum-space form for (n, l)=({n}, {angular_momentum}).\"\n", - " )\n", + " raise ValueError(f\"No analytic momentum-space form for (n, l)=({n}, {angular_momentum}).\")\n", "\n", "\n", "def normalized_and_aligned(\n", @@ -143,9 +134,7 @@ "\n", "print(\"State numerical analytic abs error\")\n", "for label, numerical, analytic in energy_rows:\n", - " print(\n", - " f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\"\n", - " )" + " print(f\"{label:>3} {numerical: .10f} {analytic: .10f} {abs(numerical - analytic):.3e}\")" ] }, { diff --git a/examples/yamaguchi_demo.ipynb b/examples/yamaguchi_demo.ipynb index 64d3582..68a7ea0 100644 --- a/examples/yamaguchi_demo.ipynb +++ b/examples/yamaguchi_demo.ipynb @@ -62,9 +62,7 @@ "def yamaguchi_solver(angular_momentum: int, energies: jax.Array) -> lm.Solver:\n", " return lm.compile(\n", " mesh=lm.MeshSpec(\"legendre\", \"x\", n=20, scale=15.0),\n", - " channels=(\n", - " lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),\n", - " ),\n", + " channels=(lm.ChannelSpec(l=angular_momentum, threshold=0.0, mass_factor=HBAR2_2MU),),\n", " operators=(\"T+L\",),\n", " solvers=(\"spectrum\", \"phases\"),\n", " energies=energies,\n", @@ -143,9 +141,7 @@ "\n", "analytic_s_wave = yamaguchi_s_wave_analytic_phase_deg(np.asarray(energies))\n", "max_s_wave_error = np.max(np.abs(phase_curves[0] - analytic_s_wave))\n", - "print(\n", - " f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\"\n", - ")" + "print(f\"Maximum |δ_mesh - δ_analytic| for l=0 on this grid: {max_s_wave_error:.3e} degrees\")" ] }, { @@ -169,12 +165,8 @@ "fig, axes = plt.subplots(1, 2, figsize=(13, 4.8))\n", "\n", "phase_curves[0] += 180\n", - "axes[0].plot(\n", - " np.asarray(energies), analytic_s_wave, label=\"analytic s-wave\", linewidth=2.5\n", - ")\n", - "axes[0].plot(\n", - " np.asarray(energies), phase_curves[0], \"--\", label=\"spectral s-wave\", linewidth=2.0\n", - ")\n", + "axes[0].plot(np.asarray(energies), analytic_s_wave, label=\"analytic s-wave\", linewidth=2.5)\n", + "axes[0].plot(np.asarray(energies), phase_curves[0], \"--\", label=\"spectral s-wave\", linewidth=2.0)\n", "axes[0].set_title(r\"Yamaguchi $\\ell=0$ phase shift\")\n", "axes[0].set_xlabel(\"Energy [MeV]\")\n", "axes[0].set_ylabel(\"Phase shift [deg]\")\n", diff --git a/src/lax/models/__init__.py b/src/lax/models/__init__.py index 304b38d..f6662ab 100644 --- a/src/lax/models/__init__.py +++ b/src/lax/models/__init__.py @@ -18,8 +18,8 @@ from lax.models.presets import ALPHA_C12_ROTOR_MODEL, O16_CA44_ROTOR_MODEL from lax.models.reid import ( NN_MASS_FACTOR, + interaction_from_reid_np_j1, reid_np_j1_channels, - reid_np_j1_potential, reid_soft_core_triplet_components, ) @@ -31,10 +31,10 @@ "RotorCoupledOpticalModel", "channels_from_rotor_model", "first_column_amplitudes_and_phases", + "interaction_from_reid_np_j1", "interaction_from_rotor_model", "open_channel_count", "reid_np_j1_channels", - "reid_np_j1_potential", "reid_soft_core_triplet_components", "rotor_coupled_optical_potential", "rotor_coupling_coefficient", diff --git a/src/lax/models/reid.py b/src/lax/models/reid.py index b999dd3..e28ae2e 100644 --- a/src/lax/models/reid.py +++ b/src/lax/models/reid.py @@ -6,9 +6,11 @@ import jax import jax.numpy as jnp +import numpy as np +from lax.boundary._types import Solver from lax.constants import hbar2_over_2mu -from lax.types import ChannelSpec +from lax.types import ChannelSpec, Interaction NN_MASS_FACTOR: Final[float] = hbar2_over_2mu(1.008665, 1.008665) @@ -63,39 +65,57 @@ def reid_soft_core_triplet_components( return v_central, v_tensor, v_spin_orbit -def reid_np_j1_potential( - radii: jax.Array, - channel_index: int, - coupled_index: int, -) -> jax.Array: - """Return the coupled Reid soft-core ``n-p`` potential in MeV. +def interaction_from_reid_np_j1(solver: Solver) -> Interaction: + """Build an :class:`~lax.Interaction` for the coupled Reid soft-core ``n-p`` model. + + Decomposes the ``J=1`` triplet potential into its three physical terms via the + §6.1 term-decomposition pattern and assembles them through + :meth:`~lax.Solver.interaction_from_funcs`: + + * Central: ``v_central(r)`` on the diagonal channels. + * Tensor: ``v_tensor(r)`` scaled by ``[[0, 2√2], [2√2, -2]]``. + * Spin-orbit: ``v_spin_orbit(r)`` scaled by ``[[0, 0], [0, -3]]``. Parameters ---------- - radii - Radial grid in fm. - channel_index - Bra-channel index. ``0`` selects ``^3S_1`` and ``1`` selects ``^3D_1``. - coupled_index - Ket-channel index. ``0`` selects ``^3S_1`` and ``1`` selects ``^3D_1``. + solver + Compiled two-channel solver (see :func:`reid_np_j1_channels`) whose + :meth:`~lax.Solver.interaction_from_funcs` entry point is used to assemble + the potential block. Returns ------- - jax.Array - One matrix element of the coupled local potential in MeV. + Interaction + Energy-independent assembled potential block ready for ``solver.spectrum`` + or ``solver.rmatrix_direct``. """ - v_central, v_tensor, v_spin_orbit = reid_soft_core_triplet_components(radii) - if channel_index == coupled_index == 0: - return v_central - if channel_index == coupled_index == 1: - return v_central - 2.0 * v_tensor - 3.0 * v_spin_orbit - return 2.0 * jnp.sqrt(2.0) * v_tensor + tensor_coupling = 2.0 * np.sqrt(2.0) + A_tensor = np.array([[0.0, tensor_coupling], [tensor_coupling, -2.0]]) + A_spin_orbit = np.array([[0.0, 0.0], [0.0, -3.0]]) + + def _central(r: jax.Array) -> jax.Array: + return reid_soft_core_triplet_components(r)[0] + + def _tensor(r: jax.Array) -> jax.Array: + return reid_soft_core_triplet_components(r)[1] + + def _spin_orbit(r: jax.Array) -> jax.Array: + return reid_soft_core_triplet_components(r)[2] + + assert solver.interaction_from_funcs is not None + return solver.interaction_from_funcs( + local=[ + (_central, np.eye(2)), + (_tensor, A_tensor), + (_spin_orbit, A_spin_orbit), + ], + ) __all__ = [ "NN_MASS_FACTOR", + "interaction_from_reid_np_j1", "reid_np_j1_channels", - "reid_np_j1_potential", "reid_soft_core_triplet_components", ] diff --git a/tests/benchmarks/test_coupled_closed_channel.py b/tests/benchmarks/test_coupled_closed_channel.py index 5e55d1a..21a030b 100644 --- a/tests/benchmarks/test_coupled_closed_channel.py +++ b/tests/benchmarks/test_coupled_closed_channel.py @@ -45,45 +45,37 @@ def _single_channel_solver() -> lm.Solver: ) -def _toy_potential(radii: jax.Array, channel_index: int, coupled_index: int) -> jax.Array: - """Return a smooth two-channel local potential in MeV.""" +def _diagonal_open(radii: jax.Array) -> jax.Array: + """Return the open-channel diagonal potential in MeV.""" - diagonal_open = -6.0 * jnp.exp(-((radii / 2.1) ** 2)) - diagonal_closed = -4.5 * jnp.exp(-((radii / 2.6) ** 2)) - coupling = -1.25 * jnp.exp(-((radii / 2.3) ** 2)) + return -6.0 * jnp.exp(-((radii / 2.1) ** 2)) - if channel_index == coupled_index == 0: - return diagonal_open - if channel_index == coupled_index == 1: - return diagonal_closed - return coupling +def _diagonal_closed(radii: jax.Array) -> jax.Array: + """Return the closed-channel diagonal potential in MeV.""" -def _decoupled_potential(radii: jax.Array, channel_index: int, coupled_index: int) -> jax.Array: - """Return the same toy model with the inter-channel coupling removed.""" + return -4.5 * jnp.exp(-((radii / 2.6) ** 2)) - if channel_index != coupled_index: - return jnp.zeros_like(radii) - return _toy_potential(radii, channel_index, coupled_index) +def _channel_coupling(radii: jax.Array) -> jax.Array: + """Return the inter-channel coupling potential in MeV.""" -def _open_channel_potential(radii: jax.Array) -> jax.Array: - """Return the open-channel diagonal potential used in the decoupled limit.""" + return -1.25 * jnp.exp(-((radii / 2.3) ** 2)) - return _toy_potential(radii, 0, 0) +def _toy_interaction(solver: lm.Solver, *, coupled: bool) -> object: + """Build the 2-channel toy Interaction, optionally without the channel coupling.""" -def _to_interaction_2ch(solver: lm.Solver, fn) -> object: - """Build a 2-channel Interaction from a fn(radii, c, cp) potential.""" A00 = np.array([[1.0, 0.0], [0.0, 0.0]]) A01 = np.array([[0.0, 1.0], [1.0, 0.0]]) A11 = np.array([[0.0, 0.0], [0.0, 1.0]]) assert solver.potential is not None - return ( - solver.potential(lambda r: fn(r, 0, 0), coupling=A00) - + solver.potential(lambda r: fn(r, 0, 1), coupling=A01) - + solver.potential(lambda r: fn(r, 1, 1), coupling=A11) + interaction = solver.potential(_diagonal_open, coupling=A00) + solver.potential( + _diagonal_closed, coupling=A11 ) + if coupled: + interaction = interaction + solver.potential(_channel_coupling, coupling=A01) + return interaction def _smatrix_from_direct_rmatrix(solver: lm.Solver, potential) -> np.ndarray: @@ -131,8 +123,8 @@ def test_coupled_closed_channel_spectral_and_direct_paths_agree() -> None: spectral_solver = _coupled_solver("eigh", ("spectrum", "smatrix")) direct_solver = _coupled_solver("linear_solve", ("rmatrix_direct",)) - spectral_V = _to_interaction_2ch(spectral_solver, _toy_potential) - direct_V = _to_interaction_2ch(direct_solver, _toy_potential) + spectral_V = _toy_interaction(spectral_solver, coupled=True) + direct_V = _toy_interaction(direct_solver, coupled=True) assert spectral_solver.spectrum is not None assert spectral_solver.smatrix is not None @@ -156,9 +148,9 @@ def test_coupled_closed_channel_decoupled_limit_matches_single_channel() -> None coupled_solver = _coupled_solver("eigh", ("spectrum", "smatrix")) single_channel_solver = _single_channel_solver() - coupled_V = _to_interaction_2ch(coupled_solver, _decoupled_potential) + coupled_V = _toy_interaction(coupled_solver, coupled=False) assert single_channel_solver.potential is not None - single_channel_V = single_channel_solver.potential(_open_channel_potential) + single_channel_V = single_channel_solver.potential(_diagonal_open) assert coupled_solver.spectrum is not None assert coupled_solver.smatrix is not None diff --git a/tests/benchmarks/test_descouvemont_closed_channels.py b/tests/benchmarks/test_descouvemont_closed_channels.py index 1e4d2a1..fd8113e 100644 --- a/tests/benchmarks/test_descouvemont_closed_channels.py +++ b/tests/benchmarks/test_descouvemont_closed_channels.py @@ -42,8 +42,6 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) - - def _smatrix_from_direct_rmatrix( solver: lm.Solver, potential ) -> tuple[np.ndarray, tuple[np.ndarray, ...]]: diff --git a/tests/benchmarks/test_descouvemont_np.py b/tests/benchmarks/test_descouvemont_np.py index 5c27b8d..be558e7 100644 --- a/tests/benchmarks/test_descouvemont_np.py +++ b/tests/benchmarks/test_descouvemont_np.py @@ -6,7 +6,7 @@ import lax as lm from lax.boundary import BoundaryValues -from lax.models import reid_np_j1_channels, reid_np_j1_potential +from lax.models import interaction_from_reid_np_j1, reid_np_j1_channels from tests.benchmarks._descouvemont_fixtures import NpJ1Reference, load_np_j1_references pytest.importorskip("jax") @@ -32,21 +32,9 @@ def _solver(reference: NpJ1Reference, method: str, solvers: tuple[str, ...]) -> def _np_interaction(solver: lm.Solver) -> object: - """Build the Reid n-p J=1 Interaction from its channel decomposition.""" - - A00 = np.array([[1.0, 0.0], [0.0, 0.0]]) - A01 = np.array([[0.0, 1.0], [1.0, 0.0]]) - A11 = np.array([[0.0, 0.0], [0.0, 1.0]]) - r = solver.mesh.radii - assert solver.interaction_from_array is not None - return solver.interaction_from_array( - local=[ - (reid_np_j1_potential(r, 0, 0), A00), - (reid_np_j1_potential(r, 0, 1), A01), - (reid_np_j1_potential(r, 1, 1), A11), - ], - energy_dependent=False, - ) + """Build the Reid n-p J=1 Interaction from its term decomposition.""" + + return interaction_from_reid_np_j1(solver) def _smatrix_from_direct_rmatrix(solver: lm.Solver, potential: jax.Array) -> np.ndarray: diff --git a/tests/benchmarks/test_descouvemont_o16_ca44.py b/tests/benchmarks/test_descouvemont_o16_ca44.py index 6156e42..d388250 100644 --- a/tests/benchmarks/test_descouvemont_o16_ca44.py +++ b/tests/benchmarks/test_descouvemont_o16_ca44.py @@ -41,8 +41,6 @@ def _solver(reference: CoupledColumnReference, method: str, solvers: tuple[str, ) - - def _smatrix_from_direct_rmatrix( solver: lm.Solver, potential ) -> tuple[np.ndarray, tuple[np.ndarray, ...]]: diff --git a/tests/benchmarks/test_hydrogen.py b/tests/benchmarks/test_hydrogen.py index e1ae463..48ca944 100644 --- a/tests/benchmarks/test_hydrogen.py +++ b/tests/benchmarks/test_hydrogen.py @@ -39,8 +39,6 @@ def _hydrogen_solver( ) - - def _hydrogen_radial_wavefunction(n: int, angular_momentum: int, radii: np.ndarray) -> np.ndarray: """Return the normalized internal hydrogen radial wavefunction `u_{nl}(r)`.""" diff --git a/tests/unit/test_spectral.py b/tests/unit/test_spectral.py index b7d2a7d..75288a9 100644 --- a/tests/unit/test_spectral.py +++ b/tests/unit/test_spectral.py @@ -6,7 +6,7 @@ import lax as lm from lax.boundary._types import BoundaryValues -from lax.models import reid_np_j1_channels, reid_np_j1_potential +from lax.models import interaction_from_reid_np_j1, reid_np_j1_channels from lax.spectral import ( Spectrum, coupled_channel_parameters_from_S, @@ -142,17 +142,8 @@ def test_smatrix_from_R_is_symmetric_and_unitary_for_real_two_channel_r() -> Non assert solver.spectrum is not None assert solver.rmatrix is not None assert solver.boundary is not None - assert solver.interaction_from_array is not None - - r = solver.mesh.radii - potential = solver.interaction_from_array( - local=[ - (reid_np_j1_potential(r, 0, 0), np.array([[1.0, 0.0], [0.0, 0.0]])), - (reid_np_j1_potential(r, 0, 1), np.array([[0.0, 1.0], [1.0, 0.0]])), - (reid_np_j1_potential(r, 1, 1), np.array([[0.0, 0.0], [0.0, 1.0]])), - ], - energy_dependent=False, - ) + + potential = interaction_from_reid_np_j1(solver) spectrum = solver.spectrum(potential) R = solver.rmatrix(spectrum, float(energy[0])) boundary = BoundaryValues( From d68baa77428eb62356fbadfca4ba5aac2a87c1a1 Mon Sep 17 00:00:00 2001 From: beykyle Date: Thu, 11 Jun 2026 01:58:53 -0400 Subject: [PATCH 10/10] update docs --- docs/api.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 23f6514..0ca262e 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -67,7 +67,9 @@ Reusable interaction models and preset system parameters. .. autofunction:: lax.models.channels_from_rotor_model -.. autofunction:: lax.models.make_rotor_coupled_optical_potential +.. autofunction:: lax.models.rotor_coupled_optical_potential + +.. autofunction:: lax.models.interaction_from_rotor_model .. autofunction:: lax.models.open_channel_count