qscat.model¶
Everything tied to a specific molecule: the ResonanceModel protocol that
qscat.core depends on, the shared neutral and ionic potential forms, the
potential factory’s flexible form (FlexibleDiatomicModel, with SmoothR
sigmoid or long-range-correct TailR coefficient functions, embedding the
published models exactly via from_diatomic), and the molecule registry —
O2 being the first entry that is a fit rather than a published parameter
set. Adding a molecule is a registry entry plus validation, never solver code.
Structural type: anything with this shape is a model qscat.core can drive, regardless of functional form. |
|
The shared Morse + sigmoid + Gaussian-in-r resonance-model form, implementing ResonanceModel. |
|
The H2+ Morse + sigma-capture + Coulomb-tail resonance-model form, implementing ResonanceModel. |
|
EMO neutral curve + Gaussian well with lam(R), alpha(R) + optional shell. |
|
f(R) = f_inf + f_0 / (1 + exp(f_1 (R - R_f))) * (1 + sum_i coeffs[i] y_p(R)^(i+1)). |
|
f(R) = f_inf + (1 - y_q(R)) * sum_k coeffs[k] y_p(R)^k. |
|
Embed a published DiatomicResonanceModel exactly (to round-off). |
|
|
The shared Morse + sigmoid + Gaussian-in-r resonance-model form, implementing ResonanceModel. |
|
The shared Morse + sigmoid + Gaussian-in-r resonance-model form, implementing ResonanceModel. |
|
The shared Morse + sigmoid + Gaussian-in-r resonance-model form, implementing ResonanceModel. |
|
The H2+ Morse + sigma-capture + Coulomb-tail resonance-model form, implementing ResonanceModel. |
|
EMO neutral curve + Gaussian well with lam(R), alpha(R) + optional shell. |
|
EMO neutral curve + Gaussian well with lam(R), alpha(R) + optional shell. |
|
EMO neutral curve + Gaussian well with lam(R), alpha(R) + optional shell. |
The model layer: the ResonanceModel protocol, the shared diatomic resonance-model form, the H2+ ionic resonance-model form, and the per-molecule parameter registry.
- Public API:
ResonanceModel – the structural protocol qscat.core’s solvers depend on (never a concrete class below).
DiatomicResonanceModel – the shared Morse + sigmoid + Gaussian-in-r form (N2/NO/F2 differ only in parameters).
IonicResonanceModel – the H2+ Morse + sigma-capture + Coulomb-tail form.
FlexibleDiatomicModel (+ SmoothR/TailR) – the potential factory’s fitted form: EMO neutral + Gaussian well with lam(R), alpha(R) and an optional shell; embeds the DiatomicResonanceModel`s exactly (`from_diatomic) – see docs/physics/potential-factory.md.
N2, NO, F2, H2P, O2 – the registry instances (O2 is the first FITTED model, not a published parameter set), plus O2_SO12 / O2_SO32, its two spin-orbit components (statistical factor 1/3 each).
Adding a molecule means adding a registry entry (parameters) plus its validation – never solver code, which lives model-free in qscat.core. See docs/physics/qscat-core-scattering.md.
- class qscat.model.DiatomicResonanceModel(mu, ell, D0, alpha0, R0, lambda_inf, lambda_1, R_lambda, lambda_c, R_c, alpha_c, charge=0)[source]¶
The shared Morse + sigmoid + Gaussian-in-r resonance-model form, implementing ResonanceModel. Carries no grid state – purely the potential-surface parameters; qscat.model.library holds the per-molecule instances.
- Parameters:
- v0(R)[source]¶
Neutral Morse potential (Hartree). Minimum -D0 at R0.
R is converted to complex128, never a real dtype: it may be complex (ECS-rotated tail points), and coercing to real would silently discard Im(R) and corrupt the analytic continuation the exterior-complex-scaling method relies on.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- lam(R)[source]¶
Sigmoid interaction strength; lam(R_c) == lambda_c.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- v_int(r, R)[source]¶
Electron-molecule interaction potential (Hartree).
r is converted to complex128, never a real dtype: it may be complex (ECS-rotated tail points), and coercing to real would silently discard Im(r) and corrupt the analytic continuation the exterior-complex-scaling method relies on.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- surface(r, R)[source]¶
The full surface v0(R) + ell(ell+1)/(2 r^2) + v_int(r, R).
Must not coerce to a real dtype: r/R are complex on the ECS tails.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- hamiltonian(tgrid)[source]¶
H_2D on tgrid (axis 0 = electronic r, axis 1 = nuclear R).
- Parameters:
tgrid (TensorGrid)
- Return type:
csr_matrix
- interaction_diag(tgrid)[source]¶
V_int evaluated on the tensor grid, flattened (C order).
- Parameters:
tgrid (TensorGrid)
- Return type:
NDArray[complex128]
- class qscat.model.FlexibleDiatomicModel(mu, ell, D_e, R_e, betas, p, lam, alpha, shell, alpha_b, r_b, charge=0)[source]¶
EMO neutral curve + Gaussian well with lam(R), alpha(R) + optional shell.
- Parameters:
- beta_R(R)[source]¶
EMO exponent beta(R) = sum_i betas[i] y_p(R)^i, a polynomial in Le Roy’s y_p.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- v0(R)[source]¶
EMO: D_e [ (1 - exp(-beta(R)(R - R_e)))^2 - 1 ], minimum -D_e at R_e, 0 at infinity.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- lam_R(R)[source]¶
Well depth lam(R) of the interaction (SmoothR or TailR).
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- alpha_R(R)[source]¶
Well width parameter alpha(R) of the interaction.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- shell_R(R)[source]¶
Repulsive-shell amplitude at R; zero everywhere when there is no shell.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- v_int(r, R)[source]¶
Electron–molecule interaction -lam(R) e^{-alpha(R) r^2} plus the optional shell shell(R) e^{-alpha_b (r - r_b)^2} (the ResonanceModel contract).
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- surface(r, R)[source]¶
Full 2-D potential v0(R) + l(l+1)/(2 r^2) + v_int(r, R).
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- hamiltonian(tgrid)[source]¶
Sparse 2-D Hamiltonian on tgrid (electron mass 1, nuclear mass mu).
- Parameters:
tgrid (TensorGrid)
- Return type:
csr_matrix
- interaction_diag(tgrid)[source]¶
v_int sampled on tgrid’s nodes, in the grid’s flattened order.
- Parameters:
tgrid (TensorGrid)
- Return type:
NDArray[complex128]
- class qscat.model.IonicResonanceModel(mu, ell, charge, V0, R0, alpha, a1, a2, a3, a4, max_nuclear_ecs_angle_deg=22.5)[source]¶
The H2+ Morse + sigma-capture + Coulomb-tail resonance-model form, implementing ResonanceModel. Carries no grid state – purely the potential-surface parameters; qscat.model.library holds the H2+ instance (H2P).
- Parameters:
- v0(R)[source]¶
Ion-core Morse potential (Hartree). Minimum -V0 at R0.
R is converted to complex128, never a real dtype: it may be complex (ECS-rotated tail points), and coercing to real would silently discard Im(R) and corrupt the analytic continuation the exterior-complex-scaling method relies on.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- v_int(r, R)[source]¶
Sigma-capture electron-molecule interaction potential (Hartree).
v_int(r,R) = -a1 * (1 - tanh Q(R)) * S(R) * (exp(-r^2/3) / r), Q(R) = (a2 - R - a3 R^4) / 7, S(R) = tanh(R/a4)^4.
r/R are converted to complex128, never a real dtype: they may be complex (ECS-rotated tail points), and coercing to real would silently discard Im(r)/Im(R) and corrupt the analytic continuation the exterior-complex-scaling method relies on.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- surface(r, R)[source]¶
The full surface v0(R) + v_int(r, R) + ell(ell+1)/(2 r^2) + charge/r – the charge/r term is the electron-core Coulomb tail (charge=-1 for H2+, the -1/r attraction).
Must not coerce to a real dtype: r/R are complex on the ECS tails.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- hamiltonian(tgrid)[source]¶
H_2D on tgrid (axis 0 = electronic r, axis 1 = nuclear R).
- Parameters:
tgrid (TensorGrid)
- Return type:
csr_matrix
- interaction_diag(tgrid)[source]¶
V_int evaluated on the tensor grid, flattened (C order).
- Parameters:
tgrid (TensorGrid)
- Return type:
NDArray[complex128]
- class qscat.model.ResonanceModel(*args, **kwargs)[source]¶
Structural type: anything with this shape is a model qscat.core can drive, regardless of functional form.
mu/ell/charge are per-molecule constants (nuclear reduced mass, fixed partial wave, Coulomb charge of the residual channel – 0 for a neutral target, -1 for a cation like H2+). v0/v_int/surface are the potential-energy surface, evaluated pointwise (scalars or broadcastable arrays; r/R may be COMPLEX on an exterior-complex-scaling tail, and an implementation must not coerce them to a real dtype). hamiltonian/interaction_diag assemble those surfaces onto a qscat.dvr.TensorGrid: the sparse H_2D and the flattened diag(V_int) a time-dependent free-reference subtracts off H_2D.
mu/ell are declared as READ-ONLY properties (not plain mutable attributes) so that a frozen dataclass like DiatomicResonanceModel – whose fields are read-only by construction – satisfies this protocol structurally under mypy. A plain mu: float annotation here would require a SETTABLE attribute (mypy’s default for Protocol attributes), which a frozen dataclass field can never be; qscat.core.driven’s model: ResonanceModel parameter is the first real static consumer of this protocol (earlier code only used isinstance at runtime, which does not distinguish read-only from settable), so the mismatch stayed latent until a solver first took model: ResonanceModel statically.
- property charge: int¶
The Coulomb charge z for the channel functions; 0 for neutral targets, -1 for a singly-charged cation like H2+.
- v0(R)[source]¶
Neutral molecule’s own potential (Hartree); a CHANNEL potential – survives as r -> infinity.
- Parameters:
R (ArrayLike)
- Return type:
NDArray[complex128]
- v_int(r, R)[source]¶
V_int(r, R) = -lambda(R) exp(-alpha_c r^2) – the perturbation ALONE, excluding v0(R) and the centrifugal term.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- surface(r, R)[source]¶
The full surface v0(R) + ell(ell+1)/(2 r^2) + v_int(r, R) that goes into hamiltonian.
- Parameters:
r (ArrayLike)
R (ArrayLike)
- Return type:
NDArray[complex128]
- hamiltonian(tgrid)[source]¶
H_2D on tgrid (axis 0 electronic r, axis 1 nuclear R), sparse CSR, complex symmetric (never Hermitian) whenever an axis has an ECS tail.
- Parameters:
tgrid (TensorGrid)
- Return type:
csr_matrix
- interaction_diag(tgrid)[source]¶
V_int evaluated on tgrid, flattened (C order) – what a time-dependent free-reference subtracts off hamiltonian(tgrid).
- Parameters:
tgrid (TensorGrid)
- Return type:
NDArray[complex128]
- class qscat.model.SmoothR(f_inf, f_0, f_1, R_f, coeffs=(), R_e=2.0, p=3)[source]¶
f(R) = f_inf + f_0 / (1 + exp(f_1 (R - R_f))) * (1 + sum_i coeffs[i] y_p(R)^(i+1)).
With coeffs == () this is exactly Houfek’s sigmoid lambda_inf + lambda_0 / (1 + exp(lambda_1 (R - R_lambda))).
- class qscat.model.TailR(f_inf, coeffs, R_e=2.0, p=3, q=4)[source]¶
f(R) = f_inf + (1 - y_q(R)) * sum_k coeffs[k] y_p(R)^k.
The long-range-correct alternative to SmoothR: every term carries the factor 1 - y_q(R) ~ 2 (R_e/R)^q as R -> inf, so f(inf) == f_inf EXACTLY and the approach is the power law R^-q – with q = 4 the ion–atom polarisation form the anion curve must follow (the polarisation_tail of target.py). Inside, P(y_p) is a plain polynomial in Le Roy’s bounded variable y_p in (-1, 1), so the fit is linear in coeffs and well conditioned – no sigmoid inflection to run off to large R, which is how the SmoothR form held -EA at one node and missed it by 0.2 eV beyond (measured on O2). SmoothR stays for the published models, whose lam(R) IS a sigmoid.
- qscat.model.from_diatomic(model)[source]¶
Embed a published DiatomicResonanceModel exactly (to round-off).
- Parameters:
model (DiatomicResonanceModel)
- Return type: