lightweaver 0.15.0__cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lightweaver might be problematic. Click here for more details.
- lightweaver/Data/AbundancesAsplund09.pickle +0 -0
- lightweaver/Data/AtomicMassesNames.pickle +0 -0
- lightweaver/Data/Barklem_dfdata.dat +41 -0
- lightweaver/Data/Barklem_pddata.dat +40 -0
- lightweaver/Data/Barklem_spdata.dat +46 -0
- lightweaver/Data/DefaultMolecules/C2.molecule +27 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-A.asc +46409 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-A_12.asc +28322 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-B.asc +4272 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-B_12.asc +2583 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-C.asc +20916 -0
- lightweaver/Data/DefaultMolecules/CH/CH_X-C_12.asc +13106 -0
- lightweaver/Data/DefaultMolecules/CH.molecule +35 -0
- lightweaver/Data/DefaultMolecules/CN.molecule +30 -0
- lightweaver/Data/DefaultMolecules/CO/vmax=3_Jmax=49_dv=1_26 +296 -0
- lightweaver/Data/DefaultMolecules/CO/vmax=9_Jmax=120_dv=1_26 +2162 -0
- lightweaver/Data/DefaultMolecules/CO.molecule +30 -0
- lightweaver/Data/DefaultMolecules/CO_NLTE.molecule +29 -0
- lightweaver/Data/DefaultMolecules/CaH.molecule +29 -0
- lightweaver/Data/DefaultMolecules/H2+.molecule +27 -0
- lightweaver/Data/DefaultMolecules/H2.molecule +27 -0
- lightweaver/Data/DefaultMolecules/H2O.molecule +27 -0
- lightweaver/Data/DefaultMolecules/HF.molecule +29 -0
- lightweaver/Data/DefaultMolecules/LiH.molecule +27 -0
- lightweaver/Data/DefaultMolecules/MgH.molecule +34 -0
- lightweaver/Data/DefaultMolecules/N2.molecule +28 -0
- lightweaver/Data/DefaultMolecules/NH.molecule +27 -0
- lightweaver/Data/DefaultMolecules/NO.molecule +27 -0
- lightweaver/Data/DefaultMolecules/O2.molecule +27 -0
- lightweaver/Data/DefaultMolecules/OH.molecule +27 -0
- lightweaver/Data/DefaultMolecules/SiO.molecule +26 -0
- lightweaver/Data/DefaultMolecules/TiO.molecule +30 -0
- lightweaver/Data/Quadratures.pickle +0 -0
- lightweaver/Data/pf_Kurucz.input +0 -0
- lightweaver/DefaultIterSchemes/.placeholder +0 -0
- lightweaver/DefaultIterSchemes/SimdImpl_AVX2FMA.cpython-310-x86_64-linux-gnu.so +0 -0
- lightweaver/DefaultIterSchemes/SimdImpl_AVX512.cpython-310-x86_64-linux-gnu.so +0 -0
- lightweaver/DefaultIterSchemes/SimdImpl_SSE2.cpython-310-x86_64-linux-gnu.so +0 -0
- lightweaver/LwCompiled.cpython-310-x86_64-linux-gnu.so +0 -0
- lightweaver/__init__.py +33 -0
- lightweaver/atmosphere.py +1640 -0
- lightweaver/atomic_model.py +852 -0
- lightweaver/atomic_set.py +1286 -0
- lightweaver/atomic_table.py +653 -0
- lightweaver/barklem.py +151 -0
- lightweaver/benchmark.py +113 -0
- lightweaver/broadening.py +605 -0
- lightweaver/collisional_rates.py +337 -0
- lightweaver/config.py +106 -0
- lightweaver/constants.py +22 -0
- lightweaver/crtaf.py +197 -0
- lightweaver/fal.py +440 -0
- lightweaver/iterate_ctx.py +241 -0
- lightweaver/iteration_update.py +134 -0
- lightweaver/libenkiTS.so +0 -0
- lightweaver/molecule.py +225 -0
- lightweaver/multi.py +113 -0
- lightweaver/nr_update.py +106 -0
- lightweaver/rh_atoms.py +19743 -0
- lightweaver/simd_management.py +42 -0
- lightweaver/utils.py +504 -0
- lightweaver/version.py +34 -0
- lightweaver/wittmann.py +1375 -0
- lightweaver/zeeman.py +157 -0
- lightweaver-0.15.0.dist-info/METADATA +81 -0
- lightweaver-0.15.0.dist-info/RECORD +69 -0
- lightweaver-0.15.0.dist-info/WHEEL +6 -0
- lightweaver-0.15.0.dist-info/licenses/LICENSE +21 -0
- lightweaver-0.15.0.dist-info/top_level.txt +1 -0
lightweaver/barklem.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Sequence, Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from scipy.interpolate import RectBivariateSpline
|
|
5
|
+
from scipy.special import gamma
|
|
6
|
+
|
|
7
|
+
import lightweaver.constants as Const
|
|
8
|
+
from .atomic_table import PeriodicTable
|
|
9
|
+
from .utils import get_data_path
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .atomic_model import AtomicLine, AtomicModel
|
|
13
|
+
|
|
14
|
+
DeltaNeff = 0.1
|
|
15
|
+
|
|
16
|
+
class BarklemTable:
|
|
17
|
+
'''
|
|
18
|
+
Storage for each table of Barklem data for Van der Waals approximation.
|
|
19
|
+
'''
|
|
20
|
+
def __init__(self, path: str, neff0: Tuple[float, float]):
|
|
21
|
+
data = np.genfromtxt(path, comments='c')
|
|
22
|
+
shape = data.shape
|
|
23
|
+
self.cross = data[:shape[0]//2]
|
|
24
|
+
self.alpha = data[shape[0]//2:]
|
|
25
|
+
|
|
26
|
+
self.neff1 = neff0[0] + np.arange(shape[0]//2) * DeltaNeff
|
|
27
|
+
self.neff2 = neff0[1] + np.arange(shape[1]) * DeltaNeff
|
|
28
|
+
|
|
29
|
+
class BarklemCrossSectionError(Exception):
|
|
30
|
+
'''
|
|
31
|
+
Raised if the Barklem cross-section cannot be applied to the atom in
|
|
32
|
+
question.
|
|
33
|
+
'''
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
class Barklem:
|
|
37
|
+
'''
|
|
38
|
+
Storage for all three Barklem cross-section cases and application via the
|
|
39
|
+
`get_active_cross_section` function.
|
|
40
|
+
'''
|
|
41
|
+
barklem_sp = BarklemTable(get_data_path() + 'Barklem_spdata.dat', (1.0, 1.3))
|
|
42
|
+
barklem_pd = BarklemTable(get_data_path() + 'Barklem_pddata.dat', (1.3, 2.3))
|
|
43
|
+
barklem_df = BarklemTable(get_data_path() + 'Barklem_dfdata.dat', (2.3, 3.3))
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def get_active_cross_section(cls, atom: 'AtomicModel',
|
|
47
|
+
line: 'AtomicLine',
|
|
48
|
+
vals: Sequence[float]) -> Sequence[float]:
|
|
49
|
+
'''
|
|
50
|
+
Returns the cross section data for use in the Van der Waals collisional
|
|
51
|
+
broadening routines.
|
|
52
|
+
See:
|
|
53
|
+
|
|
54
|
+
- Anstee & O'Mara 1995, MNRAS 276, 859-866
|
|
55
|
+
|
|
56
|
+
- Barklem & O'Mara 1998, MNRAS 300, 863-871
|
|
57
|
+
|
|
58
|
+
- Unsold:
|
|
59
|
+
|
|
60
|
+
- Traving 1960, "Uber die Theorie der Druckverbreiterung
|
|
61
|
+
von Spektrallinien", p 91-97
|
|
62
|
+
|
|
63
|
+
- Mihalas 1978, p. 282ff, and Table 9-1/
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
result : list of 3 float
|
|
68
|
+
Barklem cross-section, Barklem alpha, Helium contribution
|
|
69
|
+
following Unsold (always 1.0)
|
|
70
|
+
'''
|
|
71
|
+
i = line.i
|
|
72
|
+
j = line.j
|
|
73
|
+
|
|
74
|
+
SOrbit = 0
|
|
75
|
+
POrbit = 1
|
|
76
|
+
DOrbit = 2
|
|
77
|
+
FOrbit = 3
|
|
78
|
+
|
|
79
|
+
result = [vals[0], vals[1], 0.0]
|
|
80
|
+
|
|
81
|
+
# Follows original RH version. Interpolate tables if sigma < 20.0, otherwise
|
|
82
|
+
# assume the provided values are the coefficients
|
|
83
|
+
if vals[0] < 20.0:
|
|
84
|
+
if atom.levels[i].stage > 0:
|
|
85
|
+
raise BarklemCrossSectionError('Atom is not neutral.')
|
|
86
|
+
|
|
87
|
+
# Find principal quantum numbers
|
|
88
|
+
# try:
|
|
89
|
+
# lowerNum = determinate(atom.levels[i])
|
|
90
|
+
# upperNum = determinate(atom.levels[j])
|
|
91
|
+
# except CompositeLevelError:
|
|
92
|
+
# raise BarklemCrossSectionError()
|
|
93
|
+
lowerNum = atom.levels[i].L
|
|
94
|
+
upperNum = atom.levels[j].L
|
|
95
|
+
if lowerNum is None or upperNum is None:
|
|
96
|
+
raise BarklemCrossSectionError('L not provided for levels.')
|
|
97
|
+
|
|
98
|
+
nums = (lowerNum, upperNum)
|
|
99
|
+
|
|
100
|
+
# Check is a Barklem case applies
|
|
101
|
+
if nums == (SOrbit, POrbit) or nums == (POrbit, SOrbit):
|
|
102
|
+
table = cls.barklem_sp
|
|
103
|
+
elif nums == (POrbit, DOrbit) or nums == (DOrbit, POrbit):
|
|
104
|
+
table = cls.barklem_pd
|
|
105
|
+
elif nums == (DOrbit, FOrbit) or nums == (FOrbit, DOrbit):
|
|
106
|
+
table = cls.barklem_df
|
|
107
|
+
else:
|
|
108
|
+
raise BarklemCrossSectionError('Not a valid shell combination.')
|
|
109
|
+
|
|
110
|
+
Z = atom.levels[j].stage + 1
|
|
111
|
+
# Find index of continuum level
|
|
112
|
+
ic = j + 1
|
|
113
|
+
while atom.levels[ic].stage < atom.levels[j].stage + 1:
|
|
114
|
+
ic += 1
|
|
115
|
+
|
|
116
|
+
deltaEi = (atom.levels[ic].E - atom.levels[i].E) * Const.HC_CM
|
|
117
|
+
deltaEj = (atom.levels[ic].E - atom.levels[j].E) * Const.HC_CM
|
|
118
|
+
E_Rydberg = Const.ERydberg / (1.0 + Const.MElectron
|
|
119
|
+
/ (atom.element.mass * Const.Amu))
|
|
120
|
+
|
|
121
|
+
neff1 = Z * np.sqrt(E_Rydberg / deltaEi)
|
|
122
|
+
neff2 = Z * np.sqrt(E_Rydberg / deltaEj)
|
|
123
|
+
|
|
124
|
+
if nums[0] > nums[1]:
|
|
125
|
+
neff1, neff2 = neff2, neff1
|
|
126
|
+
|
|
127
|
+
if not (table.neff1[0] <= neff1 <= table.neff1[-1]):
|
|
128
|
+
raise BarklemCrossSectionError('neff1 outside table.')
|
|
129
|
+
if not (table.neff2[0] <= neff2 <= table.neff2[-1]):
|
|
130
|
+
raise BarklemCrossSectionError('neff2 outside table.')
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
result[0] = float(RectBivariateSpline(table.neff1, table.neff2,
|
|
134
|
+
table.cross)(neff1, neff2))
|
|
135
|
+
result[1] = float(RectBivariateSpline(table.neff1, table.neff2,
|
|
136
|
+
table.alpha)(neff1, neff2))
|
|
137
|
+
|
|
138
|
+
reducedMass = Const.Amu / (1.0 / PeriodicTable[1].mass + 1.0 / atom.element.mass)
|
|
139
|
+
meanVel = np.sqrt(8.0 * Const.KBoltzmann / (np.pi * reducedMass))
|
|
140
|
+
sigma = result[0]
|
|
141
|
+
alpha = result[1]
|
|
142
|
+
crossSection = sigma * Const.RBohr**2 * (meanVel / 1.0e4)**(-alpha)
|
|
143
|
+
|
|
144
|
+
# NOTE(cmo): This is w/N/T^(0.5*(1.0-alpha)) (eq 3 without temperature contrib, multiplied by 2 for half-width)
|
|
145
|
+
result[0] = 2.0 * ((4.0 / np.pi)**(alpha / 2.0)
|
|
146
|
+
* gamma(2.0 - alpha / 2.0) * meanVel * crossSection)
|
|
147
|
+
|
|
148
|
+
# Use Unsold for Helium contribution
|
|
149
|
+
result[2] = 1.0
|
|
150
|
+
|
|
151
|
+
return result
|
lightweaver/benchmark.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
from weno4 import weno4
|
|
6
|
+
|
|
7
|
+
from lightweaver.config import update_config_file
|
|
8
|
+
from .atmosphere import Atmosphere, ScaleType
|
|
9
|
+
from .atomic_set import RadiativeSet
|
|
10
|
+
from .config import params as rcParams
|
|
11
|
+
from .config import get_home_config_path, update_config_file
|
|
12
|
+
from .fal import Falc82
|
|
13
|
+
from .rh_atoms import CaII_atom, H_6_atom
|
|
14
|
+
from .simd_management import get_available_simd_suffixes
|
|
15
|
+
from .LwCompiled import LwContext
|
|
16
|
+
|
|
17
|
+
__all__ = ['benchmark']
|
|
18
|
+
|
|
19
|
+
def configure_context(Nspace=500, fsIterScheme=None):
|
|
20
|
+
'''
|
|
21
|
+
Configure a FALC context (with more or fewer depth points), 1 thread and a
|
|
22
|
+
particular iteration scheme. For use in benchmarking.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
Nspace : int, optional
|
|
27
|
+
Number of spatial points to interpolate the atmosphere to. (Default: 500)
|
|
28
|
+
fsIterScheme : str, optional
|
|
29
|
+
The fsIterScheme to use in the Context. (Default: None, i.e. read from
|
|
30
|
+
the user's config)
|
|
31
|
+
'''
|
|
32
|
+
fal = Falc82()
|
|
33
|
+
interp = lambda x: weno4(np.linspace(0,1,Nspace), np.linspace(0,1,fal.Nspace), x)
|
|
34
|
+
|
|
35
|
+
atmos = Atmosphere.make_1d(ScaleType.Geometric, interp(fal.height),
|
|
36
|
+
temperature=interp(fal.temperature), vlos=interp(fal.vlos),\
|
|
37
|
+
vturb=interp(fal.vturb), ne=interp(fal.ne),
|
|
38
|
+
nHTot=interp(fal.nHTot))
|
|
39
|
+
atmos.quadrature(5)
|
|
40
|
+
aSet = RadiativeSet([H_6_atom(), CaII_atom()])
|
|
41
|
+
aSet.set_active('H', 'Ca')
|
|
42
|
+
eqPops = aSet.compute_eq_pops(atmos)
|
|
43
|
+
spect = aSet.compute_wavelength_grid()
|
|
44
|
+
ctx = LwContext(atmos, spect, eqPops, fsIterScheme=fsIterScheme)
|
|
45
|
+
return ctx
|
|
46
|
+
|
|
47
|
+
def benchmark(Niter=50, Nrep=3, verbose=True, writeConfig=True, warmUp=True):
|
|
48
|
+
'''
|
|
49
|
+
Benchmark the various SIMD implementations for Lightweaver's formal solver
|
|
50
|
+
and iteration functions.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
Niter : int, optional
|
|
55
|
+
The number of iterations to use for each scheme. (Default: 50)
|
|
56
|
+
Nrep : int, optional
|
|
57
|
+
The number of repetitions to average for each scheme. (Default: 3)
|
|
58
|
+
verbose : bool, optional
|
|
59
|
+
Whether to print information as the function runs. (Default: True)
|
|
60
|
+
writeConfig : bool, optional
|
|
61
|
+
Whether to writ the optimal method to the user's config file. (Default:
|
|
62
|
+
True)
|
|
63
|
+
warmUp : bool, optional
|
|
64
|
+
Whether to run a Context first (discarded) to ensure that all numba jit
|
|
65
|
+
code is jitted and warm. (Default: True)
|
|
66
|
+
'''
|
|
67
|
+
timer = time.perf_counter
|
|
68
|
+
|
|
69
|
+
if verbose:
|
|
70
|
+
print('This will take a couple of minutes...')
|
|
71
|
+
|
|
72
|
+
suffixes = get_available_simd_suffixes()
|
|
73
|
+
suffixes = ['scalar'] + suffixes
|
|
74
|
+
methods = [f'mali_full_precond_{suffix}' for suffix in suffixes]
|
|
75
|
+
|
|
76
|
+
if warmUp:
|
|
77
|
+
ctx = configure_context(fsIterScheme=methods[0])
|
|
78
|
+
for _ in range(max(Niter // 5, 10)):
|
|
79
|
+
ctx.formal_sol_gamma_matrices(printUpdate=False)
|
|
80
|
+
|
|
81
|
+
timings = [0.0] * len(suffixes)
|
|
82
|
+
it = tqdm(methods * Nrep) if verbose else methods * Nrep
|
|
83
|
+
for idx, method in enumerate(it):
|
|
84
|
+
ctx = configure_context(fsIterScheme=method)
|
|
85
|
+
start = timer()
|
|
86
|
+
for _ in range(Niter):
|
|
87
|
+
ctx.formal_sol_gamma_matrices(printUpdate=False)
|
|
88
|
+
end = timer()
|
|
89
|
+
duration = (end - start)
|
|
90
|
+
timings[idx % len(methods)] += duration
|
|
91
|
+
|
|
92
|
+
timings = [t / Nrep for t in timings]
|
|
93
|
+
if verbose:
|
|
94
|
+
for idx, method in enumerate(methods):
|
|
95
|
+
print(f'Timing for method "{method}": {timings[idx]:.3f} s '
|
|
96
|
+
f'({Niter} iterations, {Nrep} repetitions)')
|
|
97
|
+
|
|
98
|
+
if writeConfig:
|
|
99
|
+
minTiming = min(timings)
|
|
100
|
+
minIdx = timings.index(minTiming)
|
|
101
|
+
if verbose:
|
|
102
|
+
print(f'Selecting method: {methods[minIdx]}')
|
|
103
|
+
|
|
104
|
+
impl = suffixes[minIdx]
|
|
105
|
+
rcParams['SimdImpl'] = impl
|
|
106
|
+
|
|
107
|
+
path = get_home_config_path()
|
|
108
|
+
if verbose:
|
|
109
|
+
print(f'Writing config to \'{path}\'...')
|
|
110
|
+
update_config_file(path)
|
|
111
|
+
|
|
112
|
+
if verbose:
|
|
113
|
+
print('Benchmark complete.')
|