lightweaver 0.15.0__cp312-cp312-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.

Files changed (69) hide show
  1. lightweaver/Data/AbundancesAsplund09.pickle +0 -0
  2. lightweaver/Data/AtomicMassesNames.pickle +0 -0
  3. lightweaver/Data/Barklem_dfdata.dat +41 -0
  4. lightweaver/Data/Barklem_pddata.dat +40 -0
  5. lightweaver/Data/Barklem_spdata.dat +46 -0
  6. lightweaver/Data/DefaultMolecules/C2.molecule +27 -0
  7. lightweaver/Data/DefaultMolecules/CH/CH_X-A.asc +46409 -0
  8. lightweaver/Data/DefaultMolecules/CH/CH_X-A_12.asc +28322 -0
  9. lightweaver/Data/DefaultMolecules/CH/CH_X-B.asc +4272 -0
  10. lightweaver/Data/DefaultMolecules/CH/CH_X-B_12.asc +2583 -0
  11. lightweaver/Data/DefaultMolecules/CH/CH_X-C.asc +20916 -0
  12. lightweaver/Data/DefaultMolecules/CH/CH_X-C_12.asc +13106 -0
  13. lightweaver/Data/DefaultMolecules/CH.molecule +35 -0
  14. lightweaver/Data/DefaultMolecules/CN.molecule +30 -0
  15. lightweaver/Data/DefaultMolecules/CO/vmax=3_Jmax=49_dv=1_26 +296 -0
  16. lightweaver/Data/DefaultMolecules/CO/vmax=9_Jmax=120_dv=1_26 +2162 -0
  17. lightweaver/Data/DefaultMolecules/CO.molecule +30 -0
  18. lightweaver/Data/DefaultMolecules/CO_NLTE.molecule +29 -0
  19. lightweaver/Data/DefaultMolecules/CaH.molecule +29 -0
  20. lightweaver/Data/DefaultMolecules/H2+.molecule +27 -0
  21. lightweaver/Data/DefaultMolecules/H2.molecule +27 -0
  22. lightweaver/Data/DefaultMolecules/H2O.molecule +27 -0
  23. lightweaver/Data/DefaultMolecules/HF.molecule +29 -0
  24. lightweaver/Data/DefaultMolecules/LiH.molecule +27 -0
  25. lightweaver/Data/DefaultMolecules/MgH.molecule +34 -0
  26. lightweaver/Data/DefaultMolecules/N2.molecule +28 -0
  27. lightweaver/Data/DefaultMolecules/NH.molecule +27 -0
  28. lightweaver/Data/DefaultMolecules/NO.molecule +27 -0
  29. lightweaver/Data/DefaultMolecules/O2.molecule +27 -0
  30. lightweaver/Data/DefaultMolecules/OH.molecule +27 -0
  31. lightweaver/Data/DefaultMolecules/SiO.molecule +26 -0
  32. lightweaver/Data/DefaultMolecules/TiO.molecule +30 -0
  33. lightweaver/Data/Quadratures.pickle +0 -0
  34. lightweaver/Data/pf_Kurucz.input +0 -0
  35. lightweaver/DefaultIterSchemes/.placeholder +0 -0
  36. lightweaver/DefaultIterSchemes/SimdImpl_AVX2FMA.cpython-312-x86_64-linux-gnu.so +0 -0
  37. lightweaver/DefaultIterSchemes/SimdImpl_AVX512.cpython-312-x86_64-linux-gnu.so +0 -0
  38. lightweaver/DefaultIterSchemes/SimdImpl_SSE2.cpython-312-x86_64-linux-gnu.so +0 -0
  39. lightweaver/LwCompiled.cpython-312-x86_64-linux-gnu.so +0 -0
  40. lightweaver/__init__.py +33 -0
  41. lightweaver/atmosphere.py +1640 -0
  42. lightweaver/atomic_model.py +852 -0
  43. lightweaver/atomic_set.py +1286 -0
  44. lightweaver/atomic_table.py +653 -0
  45. lightweaver/barklem.py +151 -0
  46. lightweaver/benchmark.py +113 -0
  47. lightweaver/broadening.py +605 -0
  48. lightweaver/collisional_rates.py +337 -0
  49. lightweaver/config.py +106 -0
  50. lightweaver/constants.py +22 -0
  51. lightweaver/crtaf.py +197 -0
  52. lightweaver/fal.py +440 -0
  53. lightweaver/iterate_ctx.py +241 -0
  54. lightweaver/iteration_update.py +134 -0
  55. lightweaver/libenkiTS.so +0 -0
  56. lightweaver/molecule.py +225 -0
  57. lightweaver/multi.py +113 -0
  58. lightweaver/nr_update.py +106 -0
  59. lightweaver/rh_atoms.py +19743 -0
  60. lightweaver/simd_management.py +42 -0
  61. lightweaver/utils.py +504 -0
  62. lightweaver/version.py +34 -0
  63. lightweaver/wittmann.py +1375 -0
  64. lightweaver/zeeman.py +157 -0
  65. lightweaver-0.15.0.dist-info/METADATA +81 -0
  66. lightweaver-0.15.0.dist-info/RECORD +69 -0
  67. lightweaver-0.15.0.dist-info/WHEEL +6 -0
  68. lightweaver-0.15.0.dist-info/licenses/LICENSE +21 -0
  69. 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
@@ -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.')