Standard solar models
The Sun entry points – osc_prob_{2,3,4,5}nu_sun[_nsi|_liv] and
osc_prob_sun() – describe the Sun by an exponential fit to its
electron density unless told otherwise. density_profile puts a published standard
solar model in its place, from tables that ship with the package.
Added in version 1.1.1.
|
Model |
Tabulated range [\(R_\odot\)] |
Reference |
|---|---|---|---|
|
Bahcall, Pinsonneault & Basu |
0.0065 – 0.949 |
[BPB01] |
|
Bahcall & Pinsonneault |
0.0065 – 0.947 |
[BP04] |
|
Bahcall, Serenelli & Basu, GS98 composition |
0.0016 – 0.983 |
[BSB05] |
|
Bahcall, Serenelli & Basu, AGS05 composition |
0.0016 – 0.983 |
[BSB05] |
|
Vinyoles et al., GS98 composition |
0.0005 – 1 |
[VSV+17] |
|
Vinyoles et al., AGSS09met composition |
0.0005 – 1 |
[VSV+17] |
|
Herrera & Serenelli, one per solar composition |
0 – 1 |
[HS23] |
Names are matched without regard to case, and 'exp' is the default.
import magnus.globaldefs as gd
from magnus import oscprob
R_sun = gd.SUN_RADIUS*gd.UNIT_KM
for profile in ('exp', 'BP04', 'B16-GS98', 'B23-AAG21'):
P_ee = oscprob.osc_prob_3nu_sun(energy=10*gd.UNIT_MEV, L=R_sun, L0=0.0,
nu_i=gd.NUE, nu_f=gd.NUE, average=True,
density_profile=profile)
print('%-10s <P_ee> = %.4f' % (profile, P_ee))
exp <P_ee> = 0.2971
BP04 <P_ee> = 0.3185
B16-GS98 <P_ee> = 0.3189
B23-AAG21 <P_ee> = 0.3192
From the command line, magnus prob --environment sun takes the same names through
--density-profile (see Command-Line Calculator). Notebook 13
compares all twelve on the averaged observable: they agree to \(2.4\times10^{-3}\),
and the exponential fit is off by 0.1.
What is tabulated, and what is computed from it
Each table holds three columns of the authors’ file, copied as written: the radius, the mass density \(\rho\) and the hydrogen mass fraction \(X\). The electron density is
with \(m_N\) the mean nucleon mass: hydrogen brings one electron per nucleon, and
everything heavier one per two. This is the formula notebooks 13 and 28 use; inside the
table, 'BS05-AGS-OP' gives notebook 28’s profile bit for bit. \(n_e\) is
interpolated linearly in its logarithm.
For the wrappers with sterile states, the neutral-current term needs the
neutron-to-proton ratio, \(n_n/n_p = (1 - X)/(1 + X)\). With a solar model and
ratio_number_neutrons_to_protons left at its default, None, the wrappers take it
from the same table, radius by radius; a value or a callable passed explicitly is used
instead. The exponential fit carries no composition, and keeps the 1.0 it always had.
osc_prob_sun() passes only the electron density to H_func; a
Hamiltonian with sterile states that wants the composition can take it from
magnus.solarmodels.neutron_to_proton_ratio_profile().
Outside the table
Only the B23 tables start at the centre, and the older ones stop short of the surface. Below the first row, the density holds its first value, since the core is flat. Past the last row, it continues along the logarithmic slope of the last tabulated interval, so that it keeps falling rather than stopping at a constant or dropping to zero. That is a continuation, not a model of the outer Sun: continued from 0.95 \(R_\odot\), BP2000 and BP04 reach about \(1.6\times10^{-3}\) g cm-3 at the surface, where B16 and B23, which are tabulated there, give about \(1.7\times10^{-7}\).
stop_at_table_edge=True refuses the continuation. A baseline that ends past the last
row returns NaN, with a SolarModelRangeWarning naming the edge,
and the others are computed as usual:
import warnings
import numpy as np
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter('always')
P_ee = oscprob.osc_prob_3nu_sun(energy=10*gd.UNIT_MEV,
L=np.array([0.5, 0.9, 1.0])*R_sun, L0=0.0,
nu_i=gd.NUE, nu_f=gd.NUE, average=True,
density_profile='BP04', stop_at_table_edge=True)
print(P_ee)
print(caught[0].category.__name__)
[0.32657468 0.31861298 nan]
SolarModelRangeWarning
A path that starts past the last row has nothing inside the table to compute, and is
refused with a ValueError; so is stop_at_table_edge with the exponential fit, which
has no last row. magnus.solarmodels.table_edge() gives the edge in the units of
L.
Coherent probabilities through a table
The interpolated profile has a kink at every row, and the Bahcall tables, printed to four
significant figures, step through the flat core. The phase-averaged probability
(average=True) does not notice: on all twelve models at 1, 5, 10 and 20 MeV, from the
centre to 0.9 \(R_\odot\), it raised no warning.
A coherent probability over most of the Sun can notice. The hybrid engine may then fail
to certify it and hand it to the slab ladder, which runs out of slabs and says so with
ToleranceNotAchievedWarning. On the same grid, 4 of the 48
coherent calls did (BP04 and BS05-OP at 10 and 20 MeV). The answers were still within the
default tolerance. On eleven cases, those four among them, every default answer was within
\(10^{-3}\) of a reference converged to \(10^{-9}\), and the ones that warned were
the closest, within \(3\times10^{-5}\). The warning is the package saying it could not
verify that.
For a coherent probability that is verified, put t_breakpoints at the rows, so that
no slab straddles a kink, and start the slab ladder fine enough to resolve the
oscillation:
from magnus import solarmodels
rows = solarmodels.load_solar_model('BS05-AGS-OP')['r_over_r_sun']*R_sun
P_ee = oscprob.osc_prob_3nu_sun(energy=10*gd.UNIT_MEV, L=0.95*R_sun, L0=0.0,
nu_i=gd.NUE, nu_f=gd.NUE,
density_profile='BS05-AGS-OP', strategy='magnus',
t_breakpoints=rows, n_slabs=200_000,
max_n_slabs=10_000_000)
print('P_ee = %.9f' % P_ee)
P_ee = 0.333876132
On the same eleven cases this came within \(4\times10^{-9}\) of the reference, with no
ToleranceNotAchievedWarning. Two still raised
MagnusConvergenceWarning, which reports a slab width rather than an
error (see Accuracy and diagnostics). The measurements are in
docs/dev/adversarial_batteries/solar_model_engines.py and solar_model_coherent.py.
Provenance
magnus.solarmodels.solar_model_info() gives each model’s reference, the source it was
taken from, the date, the SHA-256 of the original file, and its terms of use. Each table,
in magnus/data/solar_models/, carries the same in its header, above the authors’
original header. The Bahcall tables come from the IAS archive, whose terms ask only for a
note on how they are used; the B16 tables from the Internet Archive’s copy of the authors’
page, which is no longer online; and the B23 tables from their Zenodo release, under
CC-BY-4.0. If you use a model, cite its paper.
tools/build_solar_model_tables.py rebuilds the tables from the original files, and with
--check verifies that the committed ones are exactly what those files give. It refuses
any original whose hash has changed.