Skip to content

GIModel API ​

Every exported name of GIModel, grouped by topic. The Manual pages explain how the pieces fit together.

Parameter types and loading ​

The model inputs: see Inputs and parameters.

GIModel.load_parameters_and_quark_masses Function
julia
load_parameters_and_quark_masses(path) -> (GIParameters, QuarkMassTable)

Read model parameters and constituent masses from one TOML file. Destructure the returned tuple as params, mq.

Example

julia
using GIModel
path = default_parameters_path()
params, mq = load_parameters_and_quark_masses(path)
meson = Meson(mq, :c, :b)

Related

source
GIModel.load_parameters Function
julia
load_parameters(path) -> GIParameters

Read a solver-parameter TOML file (data/parameters.provisional.toml layout: [potential] with a central method name, [relativistic_smearing], [relativistic_factors], [fine_structure], optional [annihilation]). All listed sections and their fields are required; unknown/inactive keys are errors. The optional annihilation section must be complete when supplied; when omitted, the documented AnnihilationAmplitudes() defaults apply. Programmatic constructors remain available for diagnostic configurations. The historical Table II Lambda_MeV is reference-only: the runtime uses the published fixed Gaussian coupling profile rather than refitting it from Lambda. Use load_parameters_and_quark_masses to also get the [masses] table. The file describes the model only; pick the radial method with a RadialSolver at the call site.

Example

julia
using GIModel
path = default_parameters_path()
params = load_parameters(path)
meson = Meson(:c, :c, ConstituentMasses(1.628, 1.628))

Related

GIParameters, Meson, compute_spectrum. The bundled path above is independent of the notebook's working directory; replace path with your own TOML file for a parameter scan.

source
GIModel.load_quark_masses Function
julia
load_quark_masses(path) -> QuarkMassTable

Read the [masses] block of a parameter TOML file, converting MeV to GeV. The light-average mass supplies all three keys "u", "d", and "q".

Example

julia
using GIModel
path = default_parameters_path()
mq = load_quark_masses(path)
Meson(mq, :c, :b)

Related

QuarkMassTable, Meson, load_parameters_and_quark_masses.

source
GIModel.default_parameters_path Function
julia
default_parameters_path() -> String

Path to the Godfrey–Isgur parameter set shipped with GIModel: the Table II masses and potential parameters with the Appendix A switches. The path does not depend on the working directory.

Example

julia
using GIModel
params, mq = load_parameters_and_quark_masses(default_parameters_path())

Related

load_parameters_and_quark_masses reads both parts; load_parameters and load_quark_masses read one each.

source
GIModel.GIParameters Type
julia
GIParameters

Model parameters grouped by aspect, one field per TOML section:

  • potential::ConfinementPotential — b, c constants.

  • central::CentralPotentialMethod — which central-potential construction runs.

  • smearing::RelativisticSmearing — (A9) σ₀ and s.

  • factors::RelativisticFactors — ε factors and sandwich/kernel switches.

  • fine_structure::FineStructure — spin-orbit/tensor master switch and scales.

  • annihilation::AnnihilationAmplitudes — Table III constants.

Construct via load_parameters (TOML), or use the copy constructor GIParameters(params; potential = ConfinementPotential(params.potential; b = 0.20)). Construction from scratch requires all six keyword fields explicitly; no simplified model or fitted constants are silently supplied.

This is the model, and nothing more: every field is a number the paper quotes. How the resulting Schrödinger equation gets solved is a separate choice, carried by the RadialSolver you pass to channel_solution or compute_spectrum.

Next steps

Inspect groups such as params.potential and params.fine_structure, or use propertynames(params) to list them. Supply params alongside a Meson to compute_spectrum; the meson supplies constituent masses separately. The returned MixedSpectrum provides .states for inspecting results.

Related

load_parameters_and_quark_masses loads both inputs from one file. spectrum_levels selects which levels to compute; spectrum_state retrieves a computed level.

source
GIModel.ConfinementPotential Type
julia
ConfinementPotential(; b, c)

Linear-plus-constant confinement from Table II: slope b in GeV² and offset c in GeV (the TOML stores c_MeV). The Coulomb part comes from the running coupling, not from these constants.

source
GIModel.RelativisticSmearing Type
julia
RelativisticSmearing(; sigma0, s)

Appendix A (A9) universal smearing width inputs: sigma0 in GeV and the dimensionless s, combined per quark-mass pair by contact_smearing_sigma.

source
GIModel.RelativisticFactors Type
julia
RelativisticFactors(; epsilon_c=0, epsilon_t=0, epsilon_so_vector=0, epsilon_so_scalar=0,
                     contact_momentum_sandwich=false,
                     fine_structure_momentum_sandwich=false,
                     fine_structure_smeared_kernels=false)

Post-(A14) relativistic ε factors and the switches choosing how they are applied: contact_momentum_sandwich wraps the smeared contact operator in the GI Hermitian momentum-factor sandwich; fine_structure_momentum_sandwich does the same for first-order spin-orbit/tensor expectations; fine_structure_smeared_kernels uses derivatives of the closed-form smeared G̃/S̃ for those radial kernels instead of the pointwise running-coupling forms.

source
GIModel.FineStructure Type
julia
FineStructure(; enabled=true)

Master switch for the Appendix-A spin-orbit and tensor operators. Their strengths are fixed by Eqs. (A15)-(A16); there are no fitted bridge factors.

source
GIModel.AnnihilationAmplitudes Type
julia
AnnihilationAmplitudes(; p1_A_np=0.5, p1_m_eta=0.548, p2_A_np=0.55, p2_M0=1.17,
                        s1_A=2.5, a_3p2=-0.8)

Table III pseudoscalar/vector/tensor annihilation constants: Eq. (18a) P1 (p1_A_np, p1_m_eta in GeV), Eq. (18b) P2 (p2_A_np, zero at p2_M0 GeV), and the Eq. (16) channel amplitudes A(^3S_1) = s1_A, A(^3P_2) = a_3p2.

source
GIModel.QuarkMassTable Type
julia
QuarkMassTable

Flavor-keyed constituent masses in GeV. This is an alias for Dict{String,Float64}, with keys "u", "d", "q" (light average), "s", "c", and "b". A manually created table only needs the flavors you use.

Example

julia
using GIModel
path = default_parameters_path()
mq = load_quark_masses(path)
mq["c"]                           # charm constituent mass in GeV

Or create a table and pass it to Meson:

julia
custom = QuarkMassTable("c" => 1.628, "b" => 4.977)
Meson(custom, :c, :b)

Related

source

Central potential methods ​

How the spin-independent potential is built.

GIModel.CentralPotentialMethod Type
julia
CentralPotentialMethod

Which construction evaluates the spin-independent central potential. One of PointwiseCentral, Coulomb1DSmearing, AppendixASmearing3D, AppendixADerivativeG, AppendixAClosedForm, AppendixAMomentumSandwich. Selected by the central key of the [potential] TOML section; the methods are mutually exclusive by construction (no precedence rules).

source
GIModel.AppendixAMomentumSandwich Type
julia
AppendixAMomentumSandwich

Active reproduction path: closed-form G̃, S̃ plus the nonlocal Coulomb momentum sandwich A(p) G̃ A(p), A(p) = sqrt(1 + p²/(E₁E₂)), on the FD basis.

source
GIModel.AppendixAClosedForm Type
julia
AppendixAClosedForm

Closed-form Gaussian smearing of GI G(r) and S(r) via the checked (A12)–(A14) τ_k and smeared-linear formulas. Diagonal only: omits the central Coulomb momentum sandwich G' = A(p) G̃ A(p).

source
GIModel.PointwiseCentral Type
julia
PointwiseCentral

Raw diagnostic baseline: V = b r - 4α_s/(3r) + c evaluated pointwise on the FD mesh (Eqs. (11)–(13) orientation).

source
GIModel.Coulomb1DSmearing Type
julia
Coulomb1DSmearing

Research comparator: 1D Gaussian renormalization of G(r) on the radial grid only; S(r) = br + c kept pointwise. Same σ as contact (A9); not (A12)–(A13).

source
GIModel.AppendixASmearing3D Type
julia
AppendixASmearing3D

Experimental (A7)–(A8)-style 3D Gaussian smearing of pointwise G and S with the contact-hyperfine σ (A9). Can wipe the small-r Coulomb well on a radial grid; kept as a comparator, not the active reproduction path.

source
GIModel.AppendixADerivativeG Type
julia
AppendixADerivativeG

Research comparator: first derivative-expansion term for the Gaussian-smeared Coulomb G(r) (G + ∇²G/(4σ²)), with S(r) pointwise.

source
GIModel.central_potential_method Function
julia
central_potential_method(name::AbstractString) -> CentralPotentialMethod

Resolve the central key of the [potential] TOML section to its CentralPotentialMethod singleton; throws ArgumentError for unknown names.

source
GIModel.CentralPotentialPath Type
julia
CentralPotentialPath(name, paper_refs, notes)

Human-readable description of the spin-independent central construction in effect, as returned by central_potential_path: the method name, the paper equations it implements (paper_refs) and short notes.

source
GIModel.central_potential_path Function

Return a short description of which Appendix A construction is in effect for params.

source
GIModel.central_potential_values Function
julia
central_potential_values(params, m1, m2, r; method = params.central)
central_potential_values(params, masses::ConstituentMasses, r; kwargs...)

Diagonal central potential V(r) (GeV) on the mesh r for the given constituent masses, evaluated through the CentralPotentialMethod method. Pass method explicitly to compare constructions on identical inputs (as the Appendix-A audit scripts do). Note AppendixAMomentumSandwich returns the same closed-form diagonal as AppendixAClosedForm; the nonlocal sandwich part lives in the Hamiltonian builder, not in these pointwise values.

source

Quarks and mesons ​

GIModel.Meson Type
julia
Meson(quark_masses, flavor1, flavor2)
Meson(flavor1, flavor2, constituent_masses)

A channel with constituent masses. Flavors are :u, :d, :s, :c, :b, or :q (light average; :n is an alias). The antiquark flavor is unadorned: :c, :u means charm–antiup.

Supply a QuarkMassTable or explicit ConstituentMasses. Unknown or missing table flavors throw ArgumentError.

Example

julia
using GIModel
mq = QuarkMassTable("c" => 1.628, "b" => 4.977)
meson = Meson(mq, :c, :b)

Read flavors through meson.flavor1 and meson.flavor2; masses through meson.constituent_masses.m1_GeV and .m2_GeV.

julia
reduced_mass(meson)  # reduced mass in GeV
flavor_label(meson)  # channel label, e.g. "cb"
is_equal_flavor(meson)
propertynames(meson)

For bound-state masses, supply params from load_parameters:

julia
spec = compute_spectrum(params, meson; levels=spectrum_levels(1))
state = spectrum_state(spec, "1^1P_1")
state.mass_GeV

Related

source
GIModel.ConstituentMasses Type
julia
ConstituentMasses(m1_GeV, m2_GeV)

Constituent quark masses in GeV for a meson sector / spin-independent radial channel.

Components promote together and preserve the resulting real values exactly. Cache normalization belongs to RadialChannelKey, not to physics input.

Masses enter spin-dependent operators, smearing widths, and kinetic factors.

Example

julia
using GIModel
masses = ConstituentMasses(1.628, 4.977)
reduced_mass(masses)
Meson(:c, :b, masses)

Related

GIParameters stores interaction parameters and model switches. Constituent masses are supplied separately through Meson, so the same interaction parameters can be used for different meson channels. QuarkMassTable provides masses by flavor; reduced_mass computes the two-body reduced mass.

source
GIModel.reduced_mass Function
julia
reduced_mass(masses::ConstituentMasses)

Reduced mass    in GeV (same units as the constituents).

source
julia
reduced_mass(meson::Meson)

Return m1 * m2 / (m1 + m2) in GeV from the Meson's constituent masses. This is a two-body input quantity, not the predicted bound-state mass.

Related

source
GIModel.flavor_label Function
julia
flavor_label(meson::Meson) -> String

Return the compact flavor-pair label, e.g. "cb" for a charm–antibottom Meson. Read meson.flavor1 and meson.flavor2 for individual symbols.

Related

source
GIModel.is_equal_flavor Function
julia
is_equal_flavor(meson) -> Bool

true for self-conjugate flavor content (c cbar, q qbar, …). Gates the same-J antisymmetric spin-orbit mixing, which vanishes for equal masses. Different flavors with manually equal masses still return false.

Related

source
GIModel.AbstractQuark Type
julia
AbstractQuark

A constituent quark: a mass plus whatever flavor identity the model can resolve. In the GI model the medium (b, c, σ₀, s, α_s(Q²)) is flavor-blind and the mass is the only dynamical input — quarks of equal mass give bit-identical spectra regardless of name. Flavor identity therefore does exactly two jobs: it carries electric charge, and it supplies the name whose equality gates self-conjugate behavior (is_equal_flavor).

The three concrete types record which distinctions are physical here:

typemasscharge
LightQuarkm_u = m_dundefined — the model has no isospin breaking
StrangeQuarkm_s-1//3
HeavyQuarkfree dial+2//3 / -1//3 from the type tag

Every subtype has a mass_GeV::Float64 field; use mass_GeV to read it generically and flavor_symbol for the label a Meson stores.

source
GIModel.LightQuark Type
julia
LightQuark(mass_GeV)

An up/down constituent quark. The GI parameter set assigns u and d the same mass (m_ud_avg), so the model cannot resolve them: nothing in the dynamics branches on up-vs-down.

Consequently charge is deliberately not defined for LightQuark — calling it raises MethodError rather than returning a wrong number. A light quark has no charge of its own here: charge belongs to the meson's flavor wavefunction, which distinguishes states the constituent masses cannot (π⁺ = u d̄ carries charge while π⁰ = (u ū − d d̄)/√2 does not, at identical mass). Callers that need light-quark charges supply them per meson row.

source
GIModel.StrangeQuark Type
julia
StrangeQuark(mass_GeV)

The strange constituent quark. It gets its own type because it is the model's SU(3)-breaking axis: m_s ≠ m_ud splits the strange sectors, and the nonstrange/strange (ns/ss) distinction drives the isoscalar annihilation basis. Unlike LightQuark it has no mass-degenerate isospin partner, so its charge is unambiguous: -1//3.

source
GIModel.HeavyQuark Type
julia
HeavyQuark{T}(mass_GeV, name)

A heavy constituent quark, where T is the weak-isospin class — :up for charm/top (+2//3) or :down for bottom (-1//3). Two charge classes genuinely exist among the heavy flavors, so the tag is what distinguishes them; the name (:c, :b, :t, …) is bookkeeping and is dynamically inert.

mass_GeV is a free external dial: heavy quarks decouple from the light sector (changing m_c leaves the ρ bit-identical), so it can be varied without retuning the medium. Heavy-light observables then organize into heavy-quark symmetry — Λ̄ = M̄ − m_Q and ΔM_hf · m_Q both flatten as m_Q grows.

julia
HeavyQuark{:up}(1.628, :c)     # charm
HeavyQuark{:down}(4.977, :b)   # bottom

Warning

The FD radial grid and the fixed harmonic-oscillator β grid are tuned for masses up to bottomonium; quarkonium much heavier than m_b becomes too compact to resolve on the defaults.

source
GIModel.charge Function
julia
charge(q::AbstractQuark) -> Rational{Int}

Electric charge in units of e. Defined for StrangeQuark (-1//3) and HeavyQuark (+2//3 for :up, -1//3 for :down).

Not defined for LightQuark — see its docstring; the model cannot resolve u from d, so a light quark has no charge of its own and the call raises MethodError instead of guessing.

source
GIModel.flavor_symbol Function
julia
flavor_symbol(q::AbstractQuark) -> Symbol

The flavor label a Meson stores for this quark: :q for light (the isospin-averaged stand-in), :s for strange, and the given name for heavy. Equality of these symbols is what is_equal_flavor tests.

source
GIModel.mass_GeV Function
julia
mass_GeV(q::AbstractQuark) -> Float64

Constituent mass in GeV — the only dynamical input the GI medium responds to.

source

Levels and quantum numbers ​

GIModel.BasisState Type
julia
BasisState(n, L_label, multiplicity, J; label="", flavors=nothing)

Quantum labels for a requested level or mixing component: radial n ≥ 1, orbital L_label ("S", "P", …), spin multiplicity = 2S + 1, and total J. Multiplicity is 1 for singlets or 3 for triplets; it selects spin interactions and mixing partners.

spectrum_levels leaves flavors = nothing for reuse across mesons. Solvers attach (flavor1, flavor2) to a copy. This distinguishes nonstrange and strange components in compute_isoscalar_spectrum.

Example

julia
using GIModel
singlet = BasisState(1, "P", 1, 1)  # 1^1P_1, S = 0
triplet = BasisState(1, "P", 3, 1)  # 1^3P_1, S = 1
strange = BasisState(1, "P", 3, 1; flavors=(:s, :s))

Related

compute_spectrum, spectrum_state, MixingBlock, physical_components.

source
GIModel.spectrum_levels Function
julia
spectrum_levels(nmax; L_labels=("S", "P", "D")) -> Vector{BasisState}

Enumerate the multiplets for n in 1:nmax and each orbital letter: the spin singlet (J = L) and the spin triplets (J = 1 for S waves, J in L-1:L+1 otherwise). Use as the levels argument of compute_spectrum; hand-built BasisState vectors work the same way for custom selections. Entries have flavors = nothing: the same selection can be used for any Meson. Solved states carry explicit channel flavors.

Example

julia
using GIModel
levels = spectrum_levels(2; L_labels=("S", "P"))
levels[1].multiplicity, levels[1].flavors
source
GIModel.FineStructureMultiplet Type
julia
FineStructureMultiplet(L_label, multiplicity, J)

Spectroscopic spin/orbital labels shared by spin-dependent corrections:

The comparison layer (GIPaper) adds an overload for its reference-catalog rows.

source
GIModel.orbital_angular_momentum Function

Return the orbital angular momentum encoded by a spectroscopic letter.

source
GIModel.orbital_label Function

Return the spectroscopic orbital letter for angular momentum L.

source

Spectrum stages and states ​

See Computing a spectrum.

GIModel.compute_spectrum Function
julia
compute_spectrum(params, meson; levels=spectrum_levels(2), ...) -> MixedSpectrum

Run the physical production stages: fixed_spectrum → add_intra_meson_mixing. The independent central_spectrum diagnostic is not evaluated. Returns a MixedSpectrum containing MixedState entries, including levels that did not mix.

Example

julia
using GIModel
path = default_parameters_path()
params, mq = load_parameters_and_quark_masses(path)
meson = Meson(mq, :c, :b)

Compute the spectrum, then inspect one level:

julia
spec = compute_spectrum(params, meson; levels=spectrum_levels(1))
state = spectrum_state(spec, "1^1P_1")
state.mass_GeV
physical_components(spec, state)

Related

load_parameters_and_quark_masses, Meson, spectrum_levels, RadialSolver, SpinTerms, spectrum_state, physical_components.

source
GIModel.fixed_spectrum Function
julia
fixed_spectrum(params, meson; levels=spectrum_levels(2), solver, terms)

Assemble and diagonalize the complete fixed (L,S,J) Hamiltonian for every requested sector and cache its native waves. This is the production entry point before cross-sector mixing. It does not call central_spectrum.

The reported central/contact/spin-orbit/tensor values are contributions in the same solved eigenstate and therefore sum to its fixed-sector eigenvalue. With a switch off, that operator family is absent from both the Hamiltonian and the decomposition.

source
GIModel.add_intra_meson_mixing Function
julia
add_intra_meson_mixing(spec::CorrectedSpectrum; terms=SpinTerms()) -> MixedSpectrum

Stage 3: apply intra-meson same-J antisymmetric spin-orbit mixing (unequal flavor only) and triplet tensor L = J∓1 mixing on the corrected masses. Mixing needs the fine-structure operators, so it only acts when stage 2 actually applied them (any state with a convention other than "disabled"); otherwise every state passes through with empty mixings.

Mixed eigenvalues are assigned order-preservingly: ascending mixed mass to ascending unmixed diagonal. Each state's StateMixing records the full block so other orderings can be reconstructed downstream.

source
GIModel.central_spectrum Function
julia
central_spectrum(params, meson; levels=spectrum_levels(2), ...) -> CentralSpectrum

Stage 1: solve the spin-independent radial problem once per distinct orbital in levels and return the central eigenvalues as CentralStates together with the filled SectorComputation.

nlevels_per_channel bounds the radial levels kept per channel; a level with n beyond it throws ArgumentError.

Every wave in the returned spectrum comes from solver.

source
GIModel.Spectrum Type
julia
Spectrum{S}

Staged model spectrum over one or more flavor channels, the states (in the request order), and the underlying SectorComputation. Ordinary spectra contain one channel; the final isoscalar spectrum contains the nonstrange and strange channels whose native solves participate in flavor mixing. nonstrange_isoscalar records when the light flavor channel has the coherent (uū+dd̄)/√2 interpretation; ordinary spectra leave this false. The stage is the element type S of states:

compute_spectrum composes the fixed-sector solve and spectroscopic mixing. The GIParameters that produced the spectrum live in computation.params; use parameters to retrieve them.

source
GIModel.MixedSpectrum Type
julia
MixedSpectrum

Spectrum with spectroscopic and/or flavor mixing applied: Spectrum{MixedState}. Obtain one with compute_spectrum or compute_isoscalar_spectrum.

Properties

  • spec.states: MixedState entries in request order.

  • spec.channels: the Meson channels represented in the spectrum.

  • spec.computation: parameters and cached radial solutions; use parameters.

Mixing belongs to individual states: use spec.states[i].mixings, not spec.mixings or spec.mixing. Each entry is a StateMixing.

Example

Given spec from compute_spectrum:

julia
[(s.label, s.mass_GeV) for s in spec.states]
state = spectrum_state(spec, first(spec.states).basis)
state.mixings
physical_components(spec, state)

Related

source
GIModel.CorrectedSpectrum Type

Spectrum with spin-dependent shifts attached: Spectrum{CorrectedState}.

source
GIModel.CentralSpectrum Type

Spectrum after the central solve: Spectrum{CentralState}.

source
GIModel.MixedState Type
julia
MixedState

One level of a MixedSpectrum, obtained with spectrum_state or spec.states[i].

  • state.mass_GeV: final mass.

  • state.corrected: pre-mixing CorrectedState.

  • state.mixings: StateMixing records; empty for unmixed levels.

  • state.basis: assigned quantum numbers and flavors.

Quantum labels and energy contributions are also accessible directly, e.g. state.n, state.L, state.J, and state.contact_shift_GeV. Use propertynames(state) for the full list. fine_structure_mass_convention reflects mixing; state.corrected retains the pre-mixing convention.

Example

Given spec from compute_spectrum, including P levels:

julia
state = spectrum_state(spec, "1^1P_1")
state.mass_GeV
state.corrected.mass_GeV  # before mixing
state.mixings

For its wavefunction, use physical_components(spec, state): each component has a signed coefficient and a radial wave. radial_wave(spec, state.corrected) returns only the assigned precursor wave.

Related

source
GIModel.CorrectedState Type
julia
CorrectedState

One eigenstate of the complete fixed-sector Hamiltonian. central_GeV is the central-Hamiltonian contribution in this spin-distorted eigenstate, not the eigenvalue of a separate central-only solve. Together with the contact, vector/Thomas spin-orbit, and tensor contributions it sums to mass_GeV. The spectroscopic identity reuses BasisState; no central-state holder is embedded in the production state.

Next steps

Read state.mass_GeV for the fixed-sector mass and state.basis for the quantum numbers. propertynames(state) lists the energy contributions, including state.contact_shift_GeV and state.tensor_shift_GeV. Use radial_wave(spec, state) with the parent spectrum to obtain its radial wave. Apply add_intra_meson_mixing to the whole CorrectedSpectrum to obtain a MixedSpectrum.

Related

source
GIModel.CentralState Type
julia
CentralState

One level after the spin-independent central solve only: the quantum labels and the central eigenvalue central_GeV. Element type of CentralSpectrum; no spin-dependent data exists at this stage.

Next steps

Read state.central_GeV for the central eigenvalue and state.basis for its quantum numbers. With its parent spectrum spec, use radial_wave(spec, state) to obtain the wavefunction. For masses including spin interactions and mixing, run compute_spectrum with the same parameters and meson.

Related

source
GIModel.spectrum_state Function
julia
spectrum_state(spectrum, n, L_label, multiplicity, J)
spectrum_state(spectrum, level::BasisState)
spectrum_state(spectrum, label::AbstractString)

Look up one state by quantum numbers at any stage; throws ArgumentError when absent. The return type is the spectrum's state type.

The string form takes the state's own label ("1^3S_1"), which is the handle every state carries and every report prints. If several flavor channels share the quantum numbers or label, use a BasisState with explicit flavors; an ambiguous lookup throws ArgumentError.

Example

Given spec from compute_spectrum:

julia
state = spectrum_state(spec, "1^1P_1")
state.mass_GeV
physical_components(spec, state)

Related

MixedState, MixedSpectrum, radial_wave, physical_components.

source
GIModel.parameters Function
julia
parameters(spec::Spectrum) -> GIParameters

The parameters used to build spec (single copy, stored with the cached radial solves in SectorComputation).

source

Mixing records and blocks ​

GIModel.StateMixing Type
julia
StateMixing

Provenance of one mixing transformation applied to a MixedState: the shared MixingResult, the eigenstate column selected for this member, and its pre-mixing mass. Derived properties expose mechanism, block_label, partner_labels, components, partner_masses_GeV, and the largest offdiag_GeV in the shared block without storing copies of the block eigensystem or undefined pairwise angles for a multi-level block.

source
GIModel.MixingMechanism Type
julia
MixingMechanism

Marker supertype for post-fixed-sector mixing mechanisms. These objects name which mass-matrix contribution is being applied to model states; they are not radial solver paths. The same bookkeeping covers intra-channel spin mixing and cross-channel flavor annihilation.

source
GIModel.AntisymmetricSpinOrbit Type

Open-flavor unequal-mass ^1L_J/^3L_J antisymmetric spin-orbit mixing.

source
GIModel.TensorMixing Type

Triplet same-J, different-L tensor mixing, e.g. ^3S_1/^3D_1.

source
GIModel.IsoscalarAnnihilation Type

Self-conjugate isoscalar flavor/radial annihilation mixing.

source
GIModel.MixingBlock Type
julia
MixingBlock(name, basis, matrix; mechanism="", source="", notes="")

Hermitian mass matrix over pure BasisState entries. The matrix is in GeV and may be any size; small 2x2 same-J spin-orbit blocks and larger tensor/flavor/radial mixing blocks use the same representation.

source
GIModel.MixingResult Type
julia
MixingResult(block, masses, vectors[, pole_matrices])

Solution of a MixingBlock. Columns of vectors are components in block.basis, ordered by ascending masses. pole_matrices is empty for an ordinary Hermitian eigensystem. It contains one effective matrix per pole only for the mass-dependent Eq. (18b) fixed-point problem.

source
GIModel.diagonalize_mixing_block Function
julia
diagonalize_mixing_block(block; phase_anchor=:assigned)

Diagonalize a mixing block. By default each column has positive overlap with its assigned basis state, using ascending unmixed masses for the assignment, as in the spectrum and annihilation solvers. A zero overlap falls back to the largest component. An integer phase_anchor explicitly selects a common anchor row for callers that need that convention.

source
GIModel.same_j_mixing Function
julia
same_j_mixing(singlet_mass, triplet_mass, offdiag)

Diagonalize the (^1L_L, ^3L_L) same-J mass matrix. The returned angle uses the Fig. 9 convention low = cos(theta) * singlet + sin(theta) * triplet.

source
GIModel.spin_orbit_mixing_components Function
julia
spin_orbit_mixing_components(params, masses, L_label, radial; ...)

Antisymmetric spin-orbit matrix element for the same-J basis |n ^1L_L> / |n ^3L_L>. The angular convention is <^1L_L| L·(S1-S2) |^3L_L> = sqrt(L(L+1)); the sign of the reported mixing angle is therefore tied to the basis ordering used in same_j_mixing.

source
GIModel.tensor_mixing_components Function
julia
tensor_mixing_components(params, masses, radial_left, radial_right, J;
                         enabled = true) -> NamedTuple

Tensor off-diagonal element between   (radial_left) and   (radial_right). Returns (I_tk, angular, total): the radial tensor-kernel overlap, the angular factor tensor_triplet_offdiag_sameJ, and total = I_tk * angular / (12 m1 m2) in GeV. The kernel is the smeared or running-coupling Coulomb tensor kernel, sandwiched with the momentum factors when the parameters enable it. All components are zero when enabled is false or J = 0.

source

Annihilation mixing ​

See Isoscalar flavor mixing.

GIModel.compute_isoscalar_spectrum Function
julia
compute_isoscalar_spectrum(params, nn_meson, ss_meson; ...)

End-to-end model-level isoscalar calculation: solve both native flavor channels through fixed-sector and spectroscopic mixing, then call add_isoscalar_annihilation. No paper reference rows are accepted. The default is FiniteDifferenceSolver, matching compute_spectrum. Pass solver = OscillatorSolver() explicitly to use the paper’s oscillator method.

Returns a MixedSpectrum with both Meson channels. Use spectrum_state with a flavor-qualified BasisState when quantum numbers are shared across channels, and physical_components to inspect the physical state's flavor and radial composition.

Related

compute_spectrum solves one meson channel; MixedState describes mass and mixing properties.

source
GIModel.add_isoscalar_annihilation Function
julia
add_isoscalar_annihilation(params, nn, ss;
    pseudoscalar=nothing, pseudoscalar_targets=nothing, amplitudes=Dict())

Combine solved nonstrange and strange self-conjugate spectra and apply the requested Eq. (16)-Eq. (18) flavor-annihilation blocks. The returned MixedSpectrum owns both flavor channels, final masses, and the shared MixingResults used by physical_components.

Nothing is selected from reference data: eigenstates are assigned by ascending model mass to ascending pre-annihilation model mass. pseudoscalar must be an explicit PaperP1Annihilation, PaperP2Annihilation, or calibrated control; the latter also requires explicit pseudoscalar_targets. amplitudes maps (L_label, multiplicity, J) to the general Eq. (16) amplitude and is applied to every radial level present in both flavor channels.

source
julia
add_isoscalar_annihilation(params, spectra;
    pseudoscalar=nothing, pseudoscalar_basis=BasisState[], amplitudes=Dict())

Combine any number of distinct self-conjugate flavor spectra. An explicit flavor-qualified pseudoscalar_basis selects the radial/flavor entries of a literal P1 or P2 block (including heavy components). General Eq. (16) blocks mix the available flavors separately at each radial level (or only those in annihilation_radial_levels, when supplied) for the requested (L, multiplicity, J) amplitudes. All compositions and native waves belong to the returned spectrum; inputs are not modified.

source
GIModel.PaperP1Annihilation Type

Paper Eq. (18a) pseudoscalar annihilation model.

source
GIModel.PaperP2Annihilation Type

Paper Eq. (18b) mass-dependent pseudoscalar annihilation model.

source
GIModel.CalibratedP1Annihilation Type

Calibrated rank-one control matching the digitized GI Fig. 5/Table III masses.

source
GIModel.MomentumIntegralSmearing Type

Numerical evaluation of the Eq. (17) momentum integral.

source
GIModel.isoscalar_annihilation_block Function
julia
isoscalar_annihilation_block(params, nn, ss, level; amplitude_A)

General Eq. (16) two-flavor annihilation block for one channel across the nn and ss Spectrums (basis order [nn, ss]). Wraps isoscalar_general_annihilation_solution; the caller supplies the channel amplitude A(^{2S+1}L_J).

source
GIModel.pseudoscalar_annihilation_block Function
julia
pseudoscalar_annihilation_block(model, params, nn, ss; targets=nothing)

^1S_0 isoscalar annihilation block over the [1 nn̄, 1 ss̄, 2 nn̄, 2 ss̄] basis built from two Spectrums. Dispatches on the PseudoscalarAnnihilationModel: CalibratedP1Annihilation requires explicit targets (four masses to calibrate the rank-one block to — digitized paper values live in the comparison layer, not here); PaperP1Annihilation/PaperP2Annihilation use the Eq. (18a,b) formulas with the cached waves.

source
GIModel.annihilation_basis_input Function
julia
annihilation_basis_input(spec::Spectrum, level::BasisState)

One flavor-channel entry for an annihilation mixing block: the state's pre-annihilation model mass as the diagonal, and the signed projection of its physical radial components into the requested (L,S,J) annihilation channel. Each wave is phase-fixed to the GI convention Φ(0) > 0 (see fix_annihilation_phase!), with the compensating sign retained in its coefficient. The eigensolver hands back arbitrary column signs, and without the convention the S_L factor flips between quark masses and radial levels, randomizing the off-diagonal block elements.

The wave comes from the spectrum's own solver, like every other observable.

Historical note, because the alternative looks principled and is not. This used to take a wave_basis keyword defaulting to :ho, so annihilation read a separately-cached oscillator wave no matter which solver produced the spectrum. The stated reason was that the oscillator basis gave a ~3x larger wavefunction-at-origin for light quarks and Table III was built on that basis. The real cause was a normalization bug: finite differences then returned Euclidean eigenvectors (sum u^2 = 1) against the oscillator path's physical ones (int u^2 dr = 1), a ratio of 1/sqrt(h) = 3.17 on the Table III audit's own 220-point mesh. That bug is fixed (see physically_normalized_waves), and the two solvers now agree on the smeared origin factor to 0.1%, so there is nothing left for a second basis to correct.

source
GIModel.pseudoscalar_annihilation_basis_input Function
julia
pseudoscalar_annihilation_basis_input(basis, constituent_mass_GeV, diagonal_GeV,
                                      radial; isoscalar_coherent)
pseudoscalar_annihilation_basis_input(basis, constituent_mass_GeV, diagonal_GeV,
                                      radial_components; isoscalar_coherent)

One flavor channel of an annihilation mixing block: its basis label, the constituent quark mass, the pre-annihilation model mass on the diagonal, and either a single radial wave or signed (coefficient, wave) components. isoscalar_coherent states whether the channel is the coherent   combination, which carries a amplitude factor. annihilation_basis_input builds these from a spectrum.

source
GIModel.fix_annihilation_phase Function
julia
fix_annihilation_phase(w::RadialWave) -> RadialWave

Return w with the GI annihilation phase convention Φ(0) > 0, fixed by the sign of ∫ r u(r) dr; the input wave is not modified. This is the wave-level counterpart of fix_annihilation_phase! and is what annihilation_basis_input applies to each radial component.

source
GIModel.fix_annihilation_phase! Function
julia
fix_annihilation_phase!(vecs, r)

Enforce the GI annihilation phase convention on radial eigenvector columns: the momentum-space wave at the origin, Φ(0) ∝ ∫ r u(r) dr, is positive for every level. For nodeless ground states this coincides with u(r_min) > 0; for radially excited states the outer lobe dominates the integral, so the sign alternates relative to the small-r convention. Table III amplitude signs follow this convention: with it, all four literal-P1 pseudoscalar eigenvectors match the published sign structure, while the small-r convention flips the 2 ns/2 ss couplings and doubles the amplitude RMS.

source
GIModel.isoscalar_pseudoscalar_annihilation_solution Function
julia
isoscalar_pseudoscalar_annihilation_solution(diagonal; targets)

Build the calibrated rank-one ^1S_0 isoscalar annihilation block over the [1 n nbar, 1 s sbar, 2 n nbar, 2 s sbar] basis, targeting the four masses in targets (GeV). The digitized GI Fig. 5 values live in the GIPaper comparison package — this function only performs the calibration. It deliberately labels the operation as an annihilation block rather than changing contact hyperfine or central potential parameters.

source
GIModel.isoscalar_general_annihilation_solution Function
julia
isoscalar_general_annihilation_solution(params, basis; amplitude_A, L, multiplicity, J, smearing)

General non-pseudoscalar Eq. (16) annihilation block in the channel ^{2S+1}L_J. The matrix element from q_i q̄_i → q_j q̄_j is

4π(2L+1) A(^{2S+1}L_J) [α_s(M_j²)α_s(M_i²)/π²]^{n/2} S_L(Ψ_j)S_L(Ψ_i)/(m_i m_j)

with n = 2 for C = + and n = 3 for C = − (C = (−1)^{L+S}) and the Eq. (17) smearing S_L. Each input retains its solver-native radial wave; momentum_wave dispatches on that representation. Select an HO solver in the calling spectrum calculation when reproducing the paper algorithm.

source
GIModel.isoscalar_general_s1_solution Function
julia
isoscalar_general_s1_solution(params, basis; smearing)

^3S_1 special case of isoscalar_general_annihilation_solution with the Table III amplitude A(^3S_1) from the parameters (three-gluon bracket, C = −).

source

Solver types ​

See Solvers and convergence.

GIModel.RadialSolver Type
julia
RadialSolver

Which method solves the radial Schrödinger equation, and how finely — the discretization, never the physics content. Two implementations, and the choice of implementation lives here, not in GIParameters: the parameters are the model, the solver is how you solve it.

Accepted by channel_solution, central_spectrum and compute_spectrum, so one object describes a whole calculation. The complete fixed-sector production path requires the relativistic FD kinetic term; kinetic=:nonrelativistic is intentionally limited to central diagnostics:

julia
compute_spectrum(params, meson; solver = FiniteDifferenceSolver(ngrid = 900))
compute_spectrum(params, meson; solver = OscillatorSolver(nbasis = 32))

Changing a solver setting should never change a physical answer, and the two implementations should agree on every quantity. Where they do not, one of them is under-resolved — that disagreement is a measurement, not a convention.

RadialSolver(; kwargs...) builds the default implementation, so RadialSolver(ngrid = 900) still means what it always did.

source
GIModel.OscillatorSolver Type
julia
OscillatorSolver(; nbasis=24, max_nbasis=80, basis_step=8,
    energy_tolerance_GeV=1e-4, beta_grid=0.25:0.10:2.35,
    beta_tolerance_GeV=2e-3, converge=true, nlevels_per_channel=6)

Solve by expansion in harmonic-oscillator radial functions — Godfrey & Isgur's own method, Eq. (A17). The Hamiltonian is a finite nbasis × nbasis matrix, and the oscillator scale β is a variational parameter scanned over beta_grid.

There is no mesh on this path. p² has closed-form oscillator matrix elements (ho_p2_matrix). Non-polynomial momentum factors and smeared coordinate potentials are independently integrated by Gauss–Laguerre quadrature (ho_operator_matrix); sandwiches retain a larger intermediate basis before projection. Accuracy of the solved wave is set by the basis/beta refinement controls below. Plotting or export code may explicitly sample the returned OscillatorWave; sampling settings are not solver state.

Fields:

  • nbasis, max_nbasis, basis_step — initial, maximum, and increment of the oscillator expansion. With converge=true, every requested eigenvalue must change by less than energy_tolerance_GeV on two successive refinements. converge=false performs one explicitly unchecked fixed-size solve for convergence studies. nbasis must be at least the number of eigenlevels requested by a solve.

  • beta_grid — the β candidates, in GeV. One β is chosen per sector, the one minimizing the highest requested level, following the paper's convention. The best grid cell is refined to beta_tolerance_GeV; an endpoint optimum fails because the declared bracket does not contain the variational minimum. A one-element grid explicitly fixes beta and therefore has no bracket to rail.

  • energy_tolerance_GeV — maximum basis-refinement change over all requested eigenvalues. The default is 0.1 MeV.

  • nlevels_per_channel — radial levels kept per orbital channel.

source
GIModel.FiniteDifferenceSolver Type
julia
FiniteDifferenceSolver(; ngrid=450, rmax=24.0, kinetic=:relativistic,
                         eigensolver=:full, nlevels_per_channel=6)

Solve on a uniform radial mesh. Here the mesh is the method: every operator is a matrix on it, so ngrid and rmax set the accuracy of the answer. The defaults are fast and accurate to a fraction of an MeV for most states. (ngrid, rmax) = (2400, 32.0) is a precision setting for cross-checks over the q/s/c/b sectors. Finite differences are an independent comparator, not part of the paper's oscillator algorithm.

Fields:

  • ngrid, rmax — the ngrid interior points rᵢ = i rmax/(ngrid+1), with Dirichlet boundaries at 0 and rmax. Heavy quarkonium is compact and needs points, not reach; light mesons need reach. Too coarse and the spin-dependent shifts degrade long before the eigenvalues visibly do — see MIN_POINTS_ACROSS_STATE.

  • kinetic — :relativistic (the model's √(p²+m²) kinetic term) or :nonrelativistic (p²/2μ, a comparator).

  • eigensolver — :full (dense eigen) or :krylov.

  • nlevels_per_channel — maximum radial levels kept per requested channel (central L diagnostic or physical fixed (L,S,J) sector).

kinetic and eigensolver are deliberately absent from OscillatorSolver, which has neither choice to make.

source
GIModel.SpinTerms Type
julia
SpinTerms(; contact_hyperfine=true, fine_structure=true,
            same_j_spin_orbit=true, tensor=true)

Which spin-dependent terms enter the mass, one switch per paper equation. Unlike RadialSolver, turning one off is meant to change the answer — that is how you read off what a term contributes:

julia
compute_spectrum(params, meson; terms = SpinTerms(tensor = false))
  • contact_hyperfine — the smeared spin-spin contact term (stage 2). This is the whole 1^1S_0 / 1^3S_1 splitting.

  • fine_structure — spin-orbit (vector + Thomas) and tensor shifts (stage 2). Gated additionally by params.fine_structure.enabled, so a parameter file that disables fine structure wins over a true here.

  • same_j_spin_orbit — the same-J antisymmetric spin-orbit mixing (stage 3); vanishes identically for equal constituent masses.

  • tensor — same-J tensor mixing (stage 3).

source
GIModel.OscillatorConvergence Type
julia
OscillatorConvergence

Numerical certificate attached to an HO ChannelRadialSolution. status is :converged for an adaptive solve or :unchecked when the caller explicitly requested OscillatorSolver(converge=false). energy_delta_GeV is the largest requested-eigenvalue change on the final basis refinement; max_wave_overlap_defect is max(1-|<u_N|u_previous>|) over those levels. The latter is recorded for wave-sensitive follow-up audits but is not used as an energy-convergence substitute.

source
GIModel.numerics_provenance Function
julia
numerics_provenance(solvers...) -> String

One Markdown line naming the radial solver(s) a report's numbers came from, for the report header.

A residual report is a measurement, and a measurement without its instrument settings cannot be checked or reproduced. mean_abs = 6.0 MeV says nothing about whether that was a 450- or 900-point mesh, or the oscillator expansion at nbasis = 24 — and those are exactly the knobs a reader would want to rule out before believing a residual is physics.

Pass every solver that produced numbers in the report; comparison reports pass both.

source
GIModel.channel_solution Function
julia
channel_solution(params, masses, L; solver, nlevels) -> ChannelRadialSolution

Solve the radial equation for one orbital channel. Together with resummed_channel_solution this is where all the numerics in the model live; everything downstream consumes the returned native RadialWaves.

The solver picks the method — FiniteDifferenceSolver or OscillatorSolver — and both return the same physical quantity in the same convention. The result retains native radial-wave objects; callers that need plotted or exported samples must request them explicitly with sample_wave.

source
GIModel.fixed_channel_solution Function
julia
fixed_channel_solution(params, masses, multiplet; solver, terms, nlevels)

Diagonalize the complete radial Hamiltonian for one fixed (L,S,J) sector: central + contact hyperfine + symmetric spin-orbit + diagonal tensor. HO and FD return the same ChannelRadialSolution contract with native waves.

source
GIModel.ChannelRadialSolution Type
julia
ChannelRadialSolution(eigenvalues_GeV, waves)
ChannelRadialSolution(eigenvalues_GeV, mesh_eigenvectors, r)

Output of one channel_solution call, stored in SectorComputation.channel_cache:

  • eigenvalues_GeV: lowest radial eigenvalues in GeV;

  • waves: one native RadialWave per eigenvalue (MeshWave for FD, OscillatorWave for native HO);

  • convergence: the OscillatorConvergence certificate for HO, or nothing for a method without an automatic certificate.

Use radial_wave(solution, n) to retrieve it. The three-argument constructor is a convenience for numerical methods that naturally produce a matrix of mesh samples; the matrix and grid are immediately folded into MeshWave objects and are not retained separately.

source
GIModel.RadialChannelKey Type
julia
RadialChannelKey(masses, L_label[, multiplicity, J])

Dict key for a radial channel: ConstituentMasses, orbital label, and optionally spin multiplicity/J. (multiplicity,J) == (0,0) identifies a central spin-independent channel; physical fixed sectors use their actual values. The key normalizes masses to 12 significant digits so numerically identical channels collapse to one cache entry without rounding the physics values in ConstituentMasses.

The three-argument form builds ConstituentMasses(m1_GeV, m2_GeV) for convenience.

source
GIModel.SectorComputation Type
julia
SectorComputation(params, solver, channel_cache)

Container filled by one spectrum calculation: its native radial solves plus how they were produced. A production fixed_spectrum stores fixed (L,S,J) keys; an independent central_spectrum stores central L keys. The two calculations are not combined implicitly.

  • params: GIParameters used to build each central Hamiltonian.

  • solver: the RadialSolver that produced them and is reused for every fixed-sector solve.

  • channel_cache: map RadialChannelKey → ChannelRadialSolution.

Spectrum keeps this alive so later stages and two-meson flavor mixing can reuse the relevant solved states.

source
GIModel.solve_sector Function
julia
solve_sector(params, equal_mass_GeV; …)

Equal-mass diagnostic sweep over every orbital letter in L_SYMBOLS, using equal_mass_GeV for both constituents (same reduced dynamics as charmonium/bottomonium with that mass).

source
GIModel.resummed_channel_solution Function
julia
resummed_channel_solution(params, masses, L, V; solver, nlevels)
    -> ChannelRadialSolution

Finite-difference diagnostic that diagonalizes the central Hamiltonian plus a dense operator V on the solver's uniform mesh. Native HO callers use fixed_channel_solution; a bare mesh matrix is not an HO operator.

The returned wave has physical normalization ∫u² dr = 1.

source
GIModel.contact_hyperfine_nonperturbative_states Function
julia
contact_hyperfine_nonperturbative_states(params, masses, L, multiplicity, r, nlevels)
    -> ChannelRadialSolution

Like contact_hyperfine_nonperturbative_levels but retains the native radial waves of the fixed-L Hamiltonian with the contact-hyperfine operator added non-perturbatively. The singlet/triplet split of these waves is what makes the ^1S_0 (e.g. pi) more compact than the ^3S_1 (e.g. rho) and drives the Eq. (20)/(21) realistic-factor ratios. All orbital partial waves use the same fixed-sector solve. Invalid spins or meshes throw instead of returning an empty result that could trigger a silent fallback.

source

Wave representations and operations ​

See Wavefunctions.

GIModel.RadialWave Type
julia
abstract type RadialWave

One radial eigenlevel, however it was computed. Consumers ask a RadialWave for operations and never touch its representation:

operationmeaning
radial_expect(w, f)integral of u^2 f(r) dr
radial_overlap(wx, wy, f)integral of u_x u_y f(r) dr
radial_derivative_overlap(wx, wy, f)integral of (du_x/dr) u_y f(r) dr
momentum_wave(w, L)the momentum-space wave Phi(p)
momentum_expect(mw, g)integral of p^2
wave_mean_squares(w, L)both mean-square radius and momentum
wave_norm(w)integral of u^2 dr, guaranteed 1

Two implementations, in separate files, that never refer to each other:

  • MeshWave — samples on a uniform mesh. This is the finite-difference solver's native form.

  • OscillatorWave — the analytic oscillator representation (β + expansion coefficients). It implements an operation only when that operation has a closed form; anything not yet derived has no method and fails loudly rather than quietly discretizing.

Related

Obtain a wave with radial_wave for an unmixed level or physical_components for a mixed state. For plotting, a MeshWave already exposes .r (GeV⁻¹) and .u (the reduced radial wave); use sample_wave to sample an OscillatorWave on a plotting grid.

source
GIModel.OscillatorWave Type
julia
OscillatorWave(L, beta, coefficients)

A normalized radial wave expanded in harmonic-oscillator basis functions. coefficients[n+1] multiplies ho_reduced_radial(n, L, beta, r); L is the orbital angular momentum and beta is a momentum scale in GeV. No spatial or momentum mesh is stored.

A GIModel oscillator-basis solve determines the coefficients by diagonalizing the model Hamiltonian. In that case this type represents a calculated model wave, subject to basis convergence. Manually supplying [1.0] instead assumes a single oscillator shape with a chosen width. The constructor normalizes the supplied coefficients. Prefer radial_wave to retrieve a solved wave.

Example

julia
using GIModel
assumed_wave = OscillatorWave(0, 0.5, [1.0]) # Assumed S-wave, not a GI solve.
@assert wave_norm(assumed_wave) ≈ 1

Related

radial_wave, RadialWave, sample_wave.

source
GIModel.MeshWave Type
julia
MeshWave(u, r, h)
MeshWave(u, r)

Reduced radial wavefunction on a uniform interior grid: samples uᵢ and radii rᵢ with spacing h (for length(r) ≥ 2, the two-argument form sets h = r[2] - r[1]).

This bundles the data fine_structure_components, contact_hyperfine_shift, and physical_u_norm rely on. It is one radial eigenlevel on the mesh — not the full multi-level output of channel_solution.

For a cached ChannelRadialSolution, use radial_wave to retrieve the stored native representation. Sample an OscillatorWave only for an explicit plot/export grid with sample_wave(wave, r).

The explicit h argument must agree with the uniform spacing implied by r (guardrail).

source
GIModel.radial_wave Function

Return one native radial eigenlevel from a channel solution.

source
julia
radial_wave(spec, state) -> RadialWave
radial_wave(spec, label) -> RadialWave

The native radial wavefunction behind an unmixed level of spec. For a spin-resolved spectrum this is the eigenvector of the complete fixed-sector Hamiltonian, not the central precursor.

This is the hand-off from the spectrum to every wavefunction-level observable: annihilation and leptonic widths, two-photon amplitudes, charge radii and the radiative transition moments all take a RadialWave. The solve is already cached on the spectrum, so this is a lookup, not a recomputation.

For a MixedState with nonempty mixings, this method throws ArgumentError: use physical_components to obtain all signed components. radial_wave(spec, state.corrected) retrieves only the assigned pre-mixing basis wave, not the physical superposition.

Example

Given spec from compute_spectrum:

julia
state = spectrum_state(spec, "1^1S_0")
wave = radial_wave(spec, state)  # this level is unmixed in this example
wave_norm(wave)

Related

RadialWave, sample_wave, wave_norm, physical_components, spectrum_state.

Throws ArgumentError when the orbital was not in levels or when n exceeds the levels kept per channel.

source
GIModel.physical_components Function
julia
physical_components(spec, state_or_label)

Resolve a physical state's fully flattened spectroscopic/flavor composition. Each returned named tuple contains the pure basis identity, its signed coefficient, and that component's native radial wave. Unmixed states return one unit component. Sequential spin and flavor transformations are composed from their shared StateMixing eigensystems, and paths ending at the same native basis state are combined.

Example

Given spec from compute_spectrum:

julia
components = physical_components(spec, "1^1P_1")
[(c.basis.flavors, c.basis.label, c.coefficient) for c in components]
[wave_norm(c.wave) for c in components]
sum(abs2(c.coefficient) for c in components)  # approximately 1

Coefficients are signed amplitudes; squaring them gives component weights. Keep their signs when computing interference-sensitive observables.

Related

MixedState, spectrum_state, radial_wave, RadialWave, sample_wave, physical_state_amplitude.

source
GIModel.physical_state_amplitude Function
julia
physical_state_amplitude(kernel, spec, state_or_label)

Coherently apply a linear amplitude kernel(component) to every signed native component of one physical state. This is the observable-side counterpart of physical_components: consumers do not need to read a mixing matrix or reconstruct a parallel flavor/radial coefficient vector.

kernel receives one named tuple with basis, coefficient, and wave fields. Its return value must exclude the mixing coefficient; this function multiplies by that coefficient exactly once.

source
GIModel.physical_transition_amplitude Function
julia
physical_transition_amplitude(kernel, spec, left, right)

Coherently apply a bilinear transition kernel(left_component, right_component) between two physical states. The signed coefficients of both states are composed automatically. The kernel owns the observable's selection rules: it should return zero for flavor, spin, or angular components that the operator does not connect.

source
GIModel.sample_wave Function
julia
sample_wave(w::RadialWave, r) -> MeshWave

Sample a radial wave on a uniform radial grid r in GeV⁻¹ for plotting or export. Supply at least two points and enough radial extent to contain the wave. The returned samples are normalized on this finite grid, so this is a plotting representation, not an independent convergence check.

An OscillatorWave is evaluated from its expansion. A MeshWave is linearly interpolated between its mesh points, with u(0) = 0 and u = 0 beyond its outer boundary, so the same plotting code works for either solver.

Example

julia
using GIModel
wave = OscillatorWave(0, 0.5, [1.0])
sampled = sample_wave(wave, range(0.0, 15.0; length=301))
sampled.r, sampled.u  # plot radius against the reduced radial wave u(r)

A MeshWave also exposes its own mesh directly as .r and .u.

Related

RadialWave, OscillatorWave, radial_wave, physical_components, wave_norm.

source
GIModel.wave_norm Function
julia
wave_norm(w::RadialWave) -> Float64

The physical norm integral u^2 dr. Guaranteed to be 1 for any wave produced by a solve; exposed so the invariant can be asserted rather than assumed.

Related

RadialWave, radial_wave, physical_components. Use the wave returned for each component, e.g. wave_norm(component.wave).

source
GIModel.radial_expect Function
julia
radial_expect(w::RadialWave, f) -> Float64

integral u^2 f(r) dr with u normalized. f is called as f(r).

source
GIModel.radial_overlap Function
julia
radial_overlap(wx::RadialWave, wy::RadialWave, f) -> Float64

integral u_x u_y f(r) dr, each wave normalized. Both must share a mesh.

source
GIModel.radial_derivative_overlap Function
julia
radial_derivative_overlap(wx::RadialWave, wy::RadialWave, f)

Evaluate

with both reduced radial waves physically normalized. The derivative acts on the first argument. This is a generic wave operation: transition operators combine it with their own angular and u/r terms rather than inspecting a wave representation.

The mesh method uses the solver's Dirichlet endpoints u(0)=u(r_max+h)=0 and a centered difference on every interior point. Complex-valued kernels are supported.

source
GIModel.wave_mean_squares Function
julia
wave_mean_squares(wave, L; momentum_kwargs...) -> (r2, p2)
wave_mean_squares(wave::OscillatorWave; momentum_kwargs...) -> (r2, p2)

Return the mean-square relative radius r2 = <r^2> in GeV^-2 and mean-square relative momentum p2 = <p^2> in GeV^2 for one radial wave. The calculation composes the representation-independent radial_expect, momentum_wave, and momentum_expect operations.

L is required for a MeshWave, whose sampled reduced radial function does not itself store the orbital label. An OscillatorWave already stores L, so the one-argument form is available. Keywords such as pmax and npoints are forwarded to the numerical momentum transform of a mesh wave.

Example

julia
moments = wave_mean_squares(wave, 0)
moments.r2
moments.p2
source
GIModel.MomentumWave Type
julia
abstract type MomentumWave

A radial wave in momentum space. Separate from RadialWave because the two spaces are different objects — except in the oscillator basis, where the Fourier–Bessel transform maps the family onto itself (scale β → 1/β), so an oscillator wave transformed is still an oscillator wave. A mesh wave transformed is samples on a different grid, hence MeshMomentumWave.

source
GIModel.OscillatorMomentumWave Type

Exact momentum-space view of a native OscillatorWave. Call phi(p) to evaluate the radial Phi_L(p) at a nonnegative momentum in GeV; its normalization is integral p^2 abs2(Phi_L(p)) dp = 1. For example, momentum_wave(OscillatorWave(0, 0.5, [1.0]))(0.3) evaluates an assumed Gaussian wave directly, without a sampled transform.

source
GIModel.MeshMomentumWave Type

A normalized momentum-space radial wave Φ_L(p) sampled on a p-grid.

source
GIModel.momentum_wave Function
julia
momentum_wave(w::RadialWave, L; pmax=30.0, npoints=1501) -> MeshMomentumWave

The momentum-space radial wave Phi(p), normalized so integral p^2 Phi^2 dp = 1. For a MeshWave this is a numerical spherical-Bessel transform.

source
GIModel.momentum_expect Function
julia
momentum_expect(mw::MeshMomentumWave, g) -> Float64

integral p^2 Phi(p)^2 g(p) dp. g is called as g(p); g = p -> sqrt(m^2+p^2) gives the mean relativistic quark energy.

source
GIModel.momentum_overlap Function

integral p^2 Phi_x(p) Phi_y(p) g(p) dp, with both waves normalized.

source
GIModel.momentum_functional Function
julia
momentum_functional(mw::MomentumWave, K) -> Float64

integral p^2 Phi(p) K(p) dp — linear in Phi, unlike momentum_expect which is quadratic. K is supplied by the physics that needs it, not by the wave: the annihilation amplitude S_L uses K(p) = (m/E) (p/E)^L, which is why the mass belongs to the kernel and not to the wave interface.

source
GIModel.mock_momentum_wave Function
julia
mock_momentum_wave(radial, L; pmax=30.0, npoints=1501) -> MeshMomentumWave

Spherical-Bessel transform of the reduced radial wave to momentum space, Φ_L(p) = √(2/π) ∫ dr r u(r) j_L(pr), sampled on npoints momenta up to pmax (GeV) and normalized so that ∫ p² Φ² dp = 1.

source

Potentials and spin operators ​

Building blocks of the Hamiltonian, mainly for diagnostics and tests.

GIModel.alpha_s_q Function
julia
alpha_s_q(Q) -> Float64

The Godfrey–Isgur running coupling    (Eq. 12), Q in GeV — three fixed Gaussians with no quark-mass or flavor dependence at all: there is no threshold, so the historical Lambda_MeV reference value is not a runtime input. This is the precise sense in which the model's medium is flavor-blind; quark mass enters the model only through contact_smearing_sigma and the relativistic weight.

source
GIModel.alpha_s_r Function
julia
alpha_s_r(r) -> Float64

The coordinate-space running coupling   , the Coulomb-kernel representation of alpha_s_q. Used by the static potential   .

source
GIModel.contact_smearing_sigma Function
julia
contact_smearing_sigma(params, m1, m2) -> Float64
contact_smearing_sigma(params, masses::ConstituentMasses) -> Float64

The Appendix A (A9) universal smearing width    in GeV,

julia
σ² = σ₀² (1/2 + 1/2 [4 m₁m₂/(m₁+m₂)²]⁴) + s² (2 m₁m₂/(m₁+m₂))²

built from the Table II inputs σ₀ and s. It specifies the mass dependence of the smearing; the interaction also carries explicit mass denominators and relativistic momentum factors. The potential parameters (b, c) and alpha_s_q are flavor independent.

source
GIModel.spin_dot Function
julia
spin_dot(multiplicity)
spin_dot(multiplet::FineStructureMultiplet)

⟨S₁·S₂⟩ for a q q̄ pair with total-spin multiplicity 2S+1: -3/4 for the singlet (multiplicity = 1), +1/4 for the triplet (3).

source
GIModel.LdotS Function
julia
LdotS(L, S, J) -> Float64

Eigenvalue of   in a state of total angular momentum J:      .

source
GIModel.tensor_triplet_LJ Function
julia
tensor_triplet_LJ(L, J, S) -> Float64

Diagonal angular factor of the tensor operator in a spin-triplet state:    for   , for   and   for   . Zero for singlets and S waves.

source
GIModel.tensor_triplet_offdiag_sameJ Function
julia
tensor_triplet_offdiag_sameJ(J, S) -> Float64

Off-diagonal angular factor of between the triplets   and  :  . Zero for singlets and  . See tensor_mixing_components.

source
GIModel.fine_structure_split Function

Convenience: same as fine_structure_split(params, ConstituentMasses(m1, m2), ...).

source
GIModel.fine_structure_components Function

Convenience: same as fine_structure_components(params, ConstituentMasses(m1, m2), ...).

source
GIModel.fine_structure_radial_kernels Function
julia
fine_structure_radial_kernels(params, masses, r)

Return the six local radial kernels appearing in Appendix A15-A16 before their momentum-dependent factors are applied. The fields are vector_11, vector_22, vector_12, scalar_11, scalar_22, and tensor_12.

These are the coordinate-space middle operators in the GI sandwiches B(p²) K(r) B(p²), not complete potentials: spin-angular coefficients and the explicit mass denominators in A15-A16 are deliberately not folded in. Broadcast this scalar method over a radial grid when plotting a profile.

source
GIModel.fine_structure_grid_operator Function

Summed FD spin-orbit plus tensor operator; see fine_structure_grid_matrices.

source
GIModel.radial_cross_expect_udr Function
julia
radial_cross_expect_udr(u_left, u_right, r, h, f) -> Float64

Mesh cross matrix element     on a uniform grid of spacing h, with both reduced waves first normalized to  . The kernel receives the radius and the grid index. This is the off-diagonal counterpart of radial_expect_udr; wave objects should use radial_overlap instead.

source
GIModel.ho_p2_matrix Function
julia
ho_p2_matrix(L, β, nbasis) -> SymTridiagonal

Exact matrix elements of p² in the 3D harmonic-oscillator basis — the first ingredient of Eq. (A17), with no mesh anywhere.

The oscillator Hamiltonian H = p²/2μ + ½μω²r² is diagonal with eigenvalue (2n+L+3/2)ω, and r² is tridiagonal with known elements, so

julia
p² = 2μH − β⁴r²,    β² = μω

is tridiagonal too:

julia
⟨n|p²|n⟩   = β² (2n + L + 3/2)
⟨n|p²|n+1⟩ = β² √((n+1)(n + L + 3/2))

Verified against the mesh projection it replaced: the difference falls from 4.3e-3 at (ngrid, rmax) = (450, 24) to 7.4e-5 at (8000, 56), i.e. it is the mesh's error and not this formula's.

For non-polynomial momentum factors, do not take a matrix function of this finite matrix: f(P_N p² P_N) is not P_N f(p²) P_N. The production Hamiltonian projects the continuum momentum function by independent Gauss–Laguerre quadrature. Momentum sandwiches also retain an auxiliary intermediate basis, since applying a momentum factor can take a wave outside its original variational space. The energy basis is still refined by OscillatorSolver.

source
GIModel.ho_r2_matrix Function
julia
ho_r2_matrix(L, β, nbasis) -> SymTridiagonal

Exact matrix elements of r² in the 3D harmonic-oscillator basis — the position-space companion of ho_p2_matrix:

julia
⟨n|r²|n⟩   =  (2n + L + 3/2) / β²
⟨n|r²|n+1⟩ = -√((n+1)(n + L + 3/2)) / β²

The two together are self-validating without any mesh, reference data or model input: since H = p²/2μ + ½μω²r² is diagonal with eigenvalue (2n+L+3/2)ω and β² = μω, the combination

julia
p²/2μ + (β⁴/2μ) r²

must come out exactly diagonal. Any error in either operator's magnitude, sign or power of β breaks that cancellation, so the reconstruction tests both and their relative normalization at once. See the ho_r2_matrix / ho_p2_matrix testset.

source
GIModel.ho_operator_matrix Function
julia
ho_operator_matrix(L, β, nbasis, g; rtol=1e-12, nq=64, nq_max=4096) -> Symmetric

Matrix elements ⟨a|g(r)|b⟩ = ∫₀^∞ u_a(r) g(r) u_b(r) dr in the 3D oscillator basis — the position-space half of Eq. (A17), with no spatial mesh.

This is generalized Gauss–Laguerre quadrature in Golub–Welsch (DVR) form, and the Jacobi matrix it needs is already ho_r2_matrix: for weight x^(L+1/2) e^{-x} with x = (βr)² the recurrence coefficients are exactly ⟨n|r²|n⟩β² and ⟨n|r²|n+1⟩β². So

julia
β² r²  =  Z diag(xᵢ) Zᵀ ,      rᵢ = √xᵢ / β
⟨a|g|b⟩ = Σᵢ Z[a,i] g(rᵢ) Z[b,i]

Why this form and not weights-times-polynomials. Not because the huge×tiny product loses digits — it does not. At 120 Gauss–Hermite nodes the outer node reaches Laguerre argument ≈218, where L₁₂^{1/2} ≈ 1.7e19 against a weight of ≈1e-95, but floating-point multiplication preserves relative accuracy and the summands of the rule are all comparable in size (the scaled weight wᵢ·e^{tᵢ²} stays between 0.29 and 0.74 across every node at 60), so there is no cancellation for the digits to be lost to. Given correct weights, the two-factor form holds 1.3e-15 on g = 1 and 3e-13 on g = r² out to 200 nodes. Compensated summation is not needed and would not be the fix.

The actual hazard is narrower and lives entirely in the weights. Golub–Welsch delivers them as μ₀·v₁², the square of an eigenvector's first component. Once the true weight is small enough that v₁ reaches the eigensolver's noise floor, LAPACK returns it as exactly zero — first zeros around a true weight of 1e-36, then 4 of 60 weights, 34 of 120, 88 of 200 — each one silently deleting a whole node from the rule. Ordinary Gauss–Hermite users never notice, because their integrand is negligible where those nodes sit; here it carries e^{+tᵢ²} in the polynomial factor, so a deleted node costs a full-size contribution: the g = r² error jumps from 3.3e-12 at 44 nodes to 2.0e-5 at 60.

The DVR form is immune because it never asks for that number. The eigenvector entries are the product √wᵢ p_n(xᵢ); neither extreme ever exists. Any future rule that takes √wᵢ from an eigensolver inherits the trap.

Two exact self-checks, needing no reference data:

  • g = 1 returns the identity (Z is orthogonal), to ~5e-15.

  • g = r² returns ho_r2_matrix — spectral reconstruction of the very Jacobi matrix that generated the rule — to ~1e-13.

nq (the quadrature size, distinct from nbasis) doubles until the result stops moving by rtol. The default 1e-10 is well below what central-potential eigenvalues need (~1e-6 GeV) and is reached throughout HO_BETA_GRID for the smooth Appendix-A central kernels. The very narrow Gaussian contact/tensor kernels at deliberately diffuse endpoint bases use a separately certified 1e-8: after the A15 mass prefactor their remaining matrix uncertainty is below the 0.1 MeV spectrum gate. Verified against QuadGK on the Appendix-A smeared potential: agreement 2.8e-16 to 1.2e-13.

source

Internal names referenced above ​

These functions are not exported. They appear here because exported docstrings refer to them.

GIModel.contact_hyperfine_shift Function

First-order local contact approximation, for any L. This explicit diagnostic uses the historical (1 + epsilon_c) coefficient; production callers use contact_hyperfine_shift_active to select the configured prescription.

For the reduced radial wavefunction u(r), with ∫|u|² dr = 1, a radial smeared contact kernel K(r) has expectation ∫ |u(r)|² K(r) dr for every L. There is no extra 4π factor. Solving and reporting use the same native matrix.

Uses only FineStructureMultiplet.L_label and .multiplicity; .J is unused (same multiplet object as fine-structure).

source

Convenience: same as contact_hyperfine_shift(params, ConstituentMasses(m1, m2), ...).

source
GIModel.fine_structure_grid_matrices Function
julia
fine_structure_grid_matrices(params, masses, J, r, h; L = 1, multiplicity = 3)

Triplet ³L_J spin-orbit and tensor potentials as dense operators on the uniform radial mesh r, term-by-term identical to Appendix A15-A16. The returned fields match ho_fine_structure_matrices: spin_orbit_vector, spin_orbit_thomas, spin_orbit, tensor, and total.

Requires the smeared momentum-sandwich prescription; throws otherwise.

source
GIModel.ho_fine_structure_matrices Function
julia
ho_fine_structure_matrices(params, masses, L, multiplicity, J, beta, nbasis)

Native HO matrices for the vector spin-orbit, scalar/Thomas spin-orbit, and tensor terms of one fixed (L,S,J) sector. Each radial kernel is enclosed by its own continuum-projected momentum factor; no sampled grid operator is used.

source
GIModel.orthonormalize_physical_basis Function
julia
orthonormalize_physical_basis(U, h) -> Matrix

Orthonormalize mesh-sampled basis columns under the physical inner product integral f g dr = h * sum(f_i g_i), with the phase of the input preserved.

The phase fix is not cosmetic. LAPACK's QR assigns each column whatever sign its algorithm produces, and those signs vary with nbasis, β and the mesh (at β = 0.65, nbasis = 24 they flipped at n = 10 and n = 18 — isolated, so not a convention). That is invisible while everything is numerical, because a column sign flip is a unitary transformation and leaves every eigenvalue and observable alone. It becomes fatal the moment a closed-form matrix element is used, since analytic formulas are written in ho_reduced_radial's convention: mixing the two put the oscillator charmonium 1S 9.4 MeV below the finite-difference answer, which a variational calculation in a finite basis cannot do.

Same lesson as fix_annihilation_phase!, which exists because eigenvector signs are arbitrary and the Table III amplitudes depend on them. A basis that will ever meet an analytic expression needs a stated phase.

source
GIModel.convergence Function
julia
convergence(solution::ChannelRadialSolution)
convergence(spectrum, state_or_label)

Return a radial solution's HO energy-convergence certificate (nothing for FD), or a vector of (basis, certificate) records for every component of a spectrum state. Mixed states can depend on several independently solved channels; no single certificate covers the entire mixed state or a decay observable. Certificates describe the original radial energy solves.

Example

julia
using GIModel
params, mq = load_parameters_and_quark_masses(default_parameters_path())
spec = compute_spectrum(params, Meson(mq, :c, :c);
    levels=[BasisState(1,"S",1,0)], solver=OscillatorSolver())
convergence(spec, "1^1S_0")[1].certificate.status

Related

OscillatorConvergence, physical_components, compute_spectrum.

source