Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the optical model potential (OMP) interface by introducing a shared single-channel OMP base class, refactoring existing global OMP implementations to use it, and extending elastic-scattering workspaces to accept a separate Coulomb interaction term. Example notebooks are updated to match the new calling patterns.
Changes:
- Add
SingleChannelOpticalModel(andLocalOpticalPotential) to standardize central/spin-orbit/Coulomb term handling across OMPs. - Refactor
WLH,KDUQ, andCHUQmodules to expose new model classes and return “params-by-term” tuples. - Extend
IntegralWorkspace/DifferentialWorkspaceAPIs to accept optional Coulomb interactions and update notebooks accordingly.
Reviewed changes
Copilot reviewed 8 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/jitr/xs/elastic.py |
Adds optional Coulomb interaction/args to S-matrix and XS computations; adds docstrings. |
src/jitr/optical_potentials/omp.py |
Introduces a base single-channel OMP interface and a local Woods–Saxon OMP implementation. |
src/jitr/optical_potentials/wlh.py |
Refactors WLH potential into a SingleChannelOpticalModel subclass; adjusts parameter helpers/returns. |
src/jitr/optical_potentials/kduq.py |
Refactors KDUQ potential similarly; consolidates posterior sampling and adjusts returns. |
src/jitr/optical_potentials/chuq.py |
Refactors CHUQ potential similarly; consolidates posterior sampling and adjusts returns. |
src/jitr/optical_potentials/__init__.py |
Exports the new OMP base classes and keeps module imports. |
examples/notebooks/mass_exploration.ipynb |
Updates notebook usage for new KDUQ sampling/parameter ordering and Coulomb handling. |
examples/notebooks/comparison_to_Runge_Kutta.ipynb |
Adds a new performance/validation notebook. |
examples/notebooks/chex_jitr_validation.ipynb |
Updates validation notebook to use new OMP interface and parameter passing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def xs( | ||
| self, | ||
| interaction_central, | ||
| interaction_spin_orbit, | ||
| interaction_coulomb=None, | ||
| args_central=None, | ||
| args_spin_orbit=None, | ||
| angles=None, | ||
| args_coulomb=None, | ||
| ): | ||
| r""" | ||
| returns the angle-integrated total, elastic and reaction cross sections in mb | ||
| """ | ||
| splus, sminus = self.smatrix( | ||
| interaction_central, | ||
| interaction_spin_orbit, | ||
| interaction_coulomb, | ||
| args_central, | ||
| args_spin_orbit, | ||
| args_coulomb, | ||
| ) | ||
| return integral_elastic_xs(self.kinematics.k, splus, sminus, self.ls) | ||
|
|
||
| def transmission_coefficients( | ||
| self, | ||
| interaction_central, | ||
| interaction_spin_orbit, | ||
| interaction_coulomb=None, | ||
| args_central=None, | ||
| args_spin_orbit=None, | ||
| angles=None, | ||
| args_coulomb=None, |
There was a problem hiding this comment.
IntegralWorkspace.xs and IntegralWorkspace.transmission_coefficients similarly insert interaction_coulomb before the existing args_* parameters, which is a positional API break for any existing callers. Making Coulomb inputs keyword-only or appending them after the existing args would avoid silently swapped arguments.
| interaction_coulomb=None, | ||
| args_central=None, | ||
| args_spin_orbit=None, |
There was a problem hiding this comment.
DifferentialWorkspace.xs also changes the positional parameter order by adding interaction_coulomb before the existing args_* parameters. This can break existing positional callers in subtle ways; consider keyword-only Coulomb params or reordering to keep previous positional arguments stable.
| interaction_coulomb=None, | |
| args_central=None, | |
| args_spin_orbit=None, | |
| args_central=None, | |
| args_spin_orbit=None, | |
| interaction_coulomb=None, |
| For use with jitr.xs.elastic.DifferentialWorkspace, which requires | ||
| as input functions U(r;params_{central}) and U_{so}(r;params_{so}) | ||
| for the central and spin-orbit interactions, respectively. These are | ||
| provided as callables that take a radius and a tuple of parameters | ||
| and return a complex potential. | ||
|
|
||
| In general, the parameters for the central and spin-orbit | ||
| interactions may depend on the reaction and kinematics, so the class | ||
| includes a method central_and_spin_orbit_params that can be | ||
| implemented by subclasses to calculate the appropriate parameters | ||
| for U and U_{so}. | ||
|
|
||
| This can be as complicated as a full global optical model in which a | ||
| full set of model parameters determines (the `params` arg in | ||
| `centralcentral_and_spin_orbit_params`) determines the A,Z,E,... | ||
| dependence of params_{central} and params_{so}, or it can be | ||
| something more simple, like a fixed set of parameters applicable to | ||
| a specific reaction or set of reactions. | ||
| """ | ||
|
|
||
| def __init__( | ||
| self, | ||
| params: list[str], | ||
| interaction_central: Callable[[float, tuple], complex], | ||
| interaction_spin_orbit: Callable[[float, tuple], complex], | ||
| interaction_coulomb: Callable[[float, tuple], complex] = None, | ||
| ): |
There was a problem hiding this comment.
The SingleChannelOpticalModel docstring states the interactions take (r, tuple_of_params), and the type hints use Callable[[float, tuple], complex], but the quadrature kernel calls potentials as f(r, *args) (varargs). Consider updating the docstring and loosening the type annotations (e.g., Callable[..., complex] or a Protocol) to match the actual calling convention and avoid misleading users/type-checkers.
| uso, | ||
| rso * A ** (1.0 / 3.0), | ||
| aso, | ||
| ) | ||
| return coulomb_params, central_params, spin_orbit_params | ||
| return central_params, spin_orbit_params, coulomb_params |
There was a problem hiding this comment.
calculate_params now returns (central_params, spin_orbit_params, coulomb_params), which changes the return ordering from the previous Coulomb-first convention used elsewhere in the module history. This is an API-breaking change for any downstream code unpacking Global.get_params(...) results; consider preserving the old order (or adding a compatibility wrapper / named return) to avoid silent misassignment bugs.
| coulomb_params = (Z * Zp, RC) | ||
|
|
||
| return coulomb_params, central_params, spin_orbit_params | ||
| return central_params, spin_orbit_params, coulomb_params |
There was a problem hiding this comment.
calculate_params now returns (central_params, spin_orbit_params, coulomb_params). This changes the ordering from the earlier Coulomb-first return convention and can break any external code unpacking Global.get_params(...) results. Consider preserving the old order or returning a named structure to make ordering explicit and backward-compatible.
| return central_params, spin_orbit_params, coulomb_params | |
| return coulomb_params, central_params, spin_orbit_params |
| central_params = () | ||
| spin_orbit_params = () | ||
| coulomb_params = () | ||
| return central_params, spin_orbit_params, coulomb_params |
There was a problem hiding this comment.
params_by_term raises NotImplementedError, but the function then defines and returns empty tuples afterward (unreachable code). This should be removed to avoid confusion, or the method should be implemented to return real defaults if that's intended.
| central_params = () | |
| spin_orbit_params = () | |
| coulomb_params = () | |
| return central_params, spin_orbit_params, coulomb_params |
| spin_orbit_params = ( | ||
| vso, | ||
| rso * A ** (1.0 / 3.0), | ||
| aso, | ||
| wso, | ||
| rwso * A ** (1.0 / 3.0), | ||
| awso, | ||
| ) | ||
|
|
||
| return coulomb_params, central_params, spin_orbit_params | ||
| return central_params, spin_orbit_params, coulomb_params |
There was a problem hiding this comment.
calculate_params now returns (central_params, spin_orbit_params, coulomb_params). If any downstream code (including callers of Global.get_params) still expects the previous return ordering, it will silently unpack the wrong values. Consider keeping the original ordering or providing an explicit, backward-compatible API (e.g., namedtuple/dataclass or a separate function) to prevent misassignment bugs.
| " tcoeff_kduq[i, j, 0, :] = tplus\n", | ||
| " tcoeff_kduq[i, j, 1, :] = tminus" |
There was a problem hiding this comment.
In the BMA loop the results are written into tcoeff_kduq[...] instead of tcoeff_kduq_bma[...]. This overwrites the non-BMA results and leaves tcoeff_kduq_bma unused/empty for downstream analysis.
| " tcoeff_kduq[i, j, 0, :] = tplus\n", | |
| " tcoeff_kduq[i, j, 1, :] = tminus" | |
| " tcoeff_kduq_bma[i, j, 0, :] = tplus\n", | |
| " tcoeff_kduq_bma[i, j, 1, :] = tminus" |
| interaction_coulomb=None, | ||
| args_central=None, | ||
| args_spin_orbit=None, |
There was a problem hiding this comment.
IntegralWorkspace.smatrix adds interaction_coulomb as a positional parameter between the existing interaction functions and the existing args_* parameters. Any existing callers passing args_central/args_spin_orbit positionally will now be misinterpreted as Coulomb inputs. Consider making the new Coulomb parameters keyword-only (e.g., using *) or moving them after the existing args_* parameters to preserve backward-compatible positional calling.
| interaction_coulomb=None, | |
| args_central=None, | |
| args_spin_orbit=None, | |
| args_central=None, | |
| args_spin_orbit=None, | |
| interaction_coulomb=None, |
No description provided.