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.

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-310-x86_64-linux-gnu.so +0 -0
  37. lightweaver/DefaultIterSchemes/SimdImpl_AVX512.cpython-310-x86_64-linux-gnu.so +0 -0
  38. lightweaver/DefaultIterSchemes/SimdImpl_SSE2.cpython-310-x86_64-linux-gnu.so +0 -0
  39. lightweaver/LwCompiled.cpython-310-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
@@ -0,0 +1,605 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import TYPE_CHECKING, Any, List, Optional, Sequence
3
+
4
+ import astropy.units as u
5
+ import numpy as np
6
+
7
+ import lightweaver.constants as Const
8
+ from .atomic_table import PeriodicTable
9
+ from .barklem import Barklem
10
+
11
+ if TYPE_CHECKING:
12
+ from .atmosphere import Atmosphere
13
+ from .atomic_model import AtomicLine
14
+ from .atomic_set import SpeciesStateTable
15
+
16
+ @dataclass
17
+ class LineBroadeningResult:
18
+ '''
19
+ Result expected from instances of `LineBroadening.broaden`.
20
+ '''
21
+ natural: np.ndarray
22
+ Qelast: np.ndarray
23
+ other: Optional[List] = None
24
+
25
+
26
+ @dataclass
27
+ class LineBroadener:
28
+ '''
29
+ Base class for broadening implementations. To be used if your broadener
30
+ does something special and can't just return an array.
31
+ '''
32
+ def __repr__(self):
33
+ raise NotImplementedError
34
+
35
+ def setup(self, line: 'AtomicLine'):
36
+ pass
37
+
38
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> Any:
39
+ raise NotImplementedError
40
+
41
+ @dataclass
42
+ class StandardLineBroadener(LineBroadener):
43
+ '''
44
+ Standard base class for broadening implementations. Unless you need to do
45
+ something weird, inherit from this one.
46
+ '''
47
+ def __repr__(self):
48
+ raise NotImplementedError
49
+
50
+ def setup(self, line: 'AtomicLine'):
51
+ pass
52
+
53
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
54
+ raise NotImplementedError
55
+
56
+
57
+ @dataclass
58
+ class LineBroadening:
59
+ '''
60
+ Standard component of AtomicLine to compute the broadening parameters in
61
+ a flexible way.
62
+
63
+ For most Voigt-like situations, this should be usable without
64
+ modifications, but this class can be inherited from to make substantial
65
+ modifications.
66
+
67
+ Parameters
68
+ ----------
69
+ natural : list of StandardLineBroadener
70
+ List of broadening terms that are not elastic collisions (separated for PRD).
71
+ elastic : list of StandardLineBroadener
72
+ List of elastic broadening terms.
73
+ other : list of LineBroadener, optional
74
+ List of other broadening terms, not used by the VoigtLine by default,
75
+ but existing to provide _options_ (default: None)
76
+ '''
77
+ natural: List[StandardLineBroadener]
78
+ elastic: List[StandardLineBroadener]
79
+ other: Optional[List[LineBroadener]] = None
80
+
81
+ def __repr__(self):
82
+ otherStr = '' if self.other is None else ', other=%s' % repr(self.other)
83
+ s = 'LineBroadening(natural=%s, elastic=%s%s)' % (repr(self.natural),
84
+ repr(self.elastic), otherStr)
85
+ return s
86
+
87
+ def __post_init__(self):
88
+ if len(self.natural) == 0 and len(self.elastic) == 0:
89
+ raise ValueError('No standard broadening terms provided to LineBroadening')
90
+
91
+ def setup(self, line: 'AtomicLine'):
92
+ b: LineBroadener
93
+ for b in self.natural:
94
+ b.setup(line)
95
+
96
+ for b in self.elastic:
97
+ b.setup(line)
98
+
99
+ if self.other is not None:
100
+ for b in self.other:
101
+ b.setup(line)
102
+
103
+ @staticmethod
104
+ def sum_broadening_list(broadeners: List[StandardLineBroadener], atmos: 'Atmosphere',
105
+ eqPops: 'SpeciesStateTable') -> Optional[np.ndarray]:
106
+ '''
107
+ Sums a list of StandardLineBroadeners.
108
+ '''
109
+ if len(broadeners) == 0:
110
+ return None
111
+
112
+ result = broadeners[0].broaden(atmos, eqPops)
113
+ for b in broadeners[1:]:
114
+ result += b.broaden(atmos, eqPops)
115
+ return result
116
+
117
+ @staticmethod
118
+ def compute_other_broadening(broadeners: Optional[List[LineBroadener]],
119
+ atmos: 'Atmosphere',
120
+ eqPops: 'SpeciesStateTable') -> Optional[List]:
121
+ '''
122
+ Returns a list of the computed broadening terms.
123
+ '''
124
+
125
+ if broadeners is None:
126
+ return None
127
+ if len(broadeners) == 0:
128
+ return None
129
+
130
+ result = [b.broaden(atmos, eqPops) for b in broadeners]
131
+ return result
132
+
133
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> LineBroadeningResult:
134
+ '''
135
+ Computes the broadening, this function is called by the AtomicLine object.
136
+ '''
137
+ natural = self.sum_broadening_list(self.natural, atmos, eqPops)
138
+ Qelast = self.sum_broadening_list(self.elastic, atmos, eqPops)
139
+
140
+ others = self.compute_other_broadening(self.other, atmos, eqPops)
141
+
142
+ if natural is None:
143
+ if Qelast is None:
144
+ raise ValueError(f'Insufficient information provided to {self}')
145
+ natural = np.zeros_like(Qelast) # type: ignore
146
+ elif Qelast is None:
147
+ Qelast = np.zeros_like(natural)
148
+
149
+ return LineBroadeningResult(natural=natural,
150
+ Qelast=Qelast, other=others)
151
+
152
+
153
+ @dataclass(eq=False)
154
+ class VdwApprox(StandardLineBroadener):
155
+ '''
156
+ Base class for van der Waals approximation using a list of coefficients
157
+ (vals).
158
+ '''
159
+ vals: Sequence[float]
160
+ line: 'AtomicLine' = field(init=False)
161
+
162
+ def setup(self, line: 'AtomicLine'):
163
+ self.line = line
164
+
165
+ def __repr__(self):
166
+ s = '%s(vals=%s)' % (type(self).__name__, repr(self.vals))
167
+ return s
168
+
169
+ def __eq__(self, other):
170
+ if type(self) is not type(other):
171
+ return False
172
+
173
+ if self.vals != other.vals:
174
+ return False
175
+
176
+ try:
177
+ if self.line != other.line:
178
+ return False
179
+ except AttributeError:
180
+ pass
181
+
182
+ return True
183
+
184
+
185
+ @dataclass(eq=False, repr=False)
186
+ class VdwUnsold(VdwApprox):
187
+ '''
188
+ Implementation of the Unsold method for van der Waals broadening.
189
+ '''
190
+ def setup(self, line: 'AtomicLine'):
191
+ self.line = line
192
+ if len(self.vals) != 2:
193
+ raise ValueError('VdwUnsold expects 2 coefficients (%s)' % repr(line))
194
+
195
+ Z = line.jLevel.stage + 1
196
+ cont = line.overlyingContinuumLevel
197
+
198
+ deltaR = (Const.ERydberg / (cont.E_SI - line.jLevel.E_SI))**2 \
199
+ - (Const.ERydberg / (cont.E_SI - line.iLevel.E_SI))**2
200
+ fourPiEps0 = 4.0 * np.pi * Const.Epsilon0
201
+ self.C625 = (2.5 * Const.QElectron**2 / fourPiEps0 * Const.ABarH / fourPiEps0 \
202
+ * 2 * np.pi * (Z * Const.RBohr)**2 / Const.HPlanck * deltaR)**0.4
203
+
204
+ element = line.atom.element
205
+
206
+ self.vRel35He = (8.0 * Const.KBoltzmann / (np.pi*Const.Amu * element.mass)\
207
+ * (1.0 + element.mass / PeriodicTable[2].mass))**0.3
208
+ self.vRel35H = (8.0 * Const.KBoltzmann / (np.pi*Const.Amu * element.mass)\
209
+ * (1.0 + element.mass / PeriodicTable[1].mass))**0.3
210
+
211
+
212
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
213
+ '''
214
+ The function that is called by LineBroadening.
215
+
216
+ Parameters
217
+ ----------
218
+ atmos : Atmosphere
219
+ The atmosphere in which to compute the broadening.
220
+ eqPops : SpeciesStateTable
221
+ The populations to use for computing the broadening.
222
+
223
+ Returns
224
+ -------
225
+ broad : np.ndarray
226
+ An array detailing the broadening at each location in the
227
+ atmosphere [Nspace].
228
+ '''
229
+ heAbund = eqPops.abundance[PeriodicTable[2]]
230
+ cross = 8.08 * (self.vals[0] * self.vRel35H \
231
+ + self.vals[1] * heAbund * self.vRel35He) * self.C625
232
+ nHGround = eqPops['H'][0, :]
233
+ broad = cross * atmos.temperature**0.3 * nHGround
234
+ return broad
235
+
236
+
237
+ @dataclass(eq=False, repr=False)
238
+ class VdwBarklem(VdwApprox):
239
+ '''
240
+ Implementation of the Barklem method for van der Waals broadening.
241
+ '''
242
+ def setup(self, line: 'AtomicLine'):
243
+ self.line = line
244
+ if len(self.vals) != 2:
245
+ raise ValueError('VdwBarklem expects 2 coefficients (%s)' % (repr(line)))
246
+ newVals = Barklem.get_active_cross_section(line.atom, line, self.vals)
247
+
248
+ self.barklemVals = newVals
249
+
250
+ Z = line.jLevel.stage + 1
251
+ cont = line.overlyingContinuumLevel
252
+
253
+ deltaR = (Const.ERydberg / (cont.E_SI - line.jLevel.E_SI))**2 \
254
+ - (Const.ERydberg / (cont.E_SI - line.iLevel.E_SI))**2
255
+ fourPiEps0 = 4.0 * np.pi * Const.Epsilon0
256
+ self.C625 = (2.5 * Const.QElectron**2 / fourPiEps0 * Const.ABarH / fourPiEps0 \
257
+ * 2 * np.pi * (Z * Const.RBohr)**2 / Const.HPlanck * deltaR)**0.4
258
+
259
+ element = line.atom.element
260
+
261
+ self.vRel35He = (8.0 * Const.KBoltzmann / (np.pi*Const.Amu * element.mass)\
262
+ * (1.0 + element.mass / PeriodicTable[2].mass))**0.3
263
+
264
+
265
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
266
+ '''
267
+ The function that is called by LineBroadening.
268
+
269
+ Parameters
270
+ ----------
271
+ atmos : Atmosphere
272
+ The atmosphere in which to compute the broadening.
273
+ eqPops : SpeciesStateTable
274
+ The populations to use for computing the broadening.
275
+
276
+ Returns
277
+ -------
278
+ broad : np.ndarray
279
+ An array detailing the broadening at each location in the
280
+ atmosphere [Nspace].
281
+ '''
282
+ heAbund = eqPops.abundance[PeriodicTable[2]]
283
+ nHGround = eqPops['H'][0, :]
284
+ cross = 8.08 * self.barklemVals[2] * heAbund * self.vRel35He * self.C625
285
+
286
+ broad = self.barklemVals[0] * atmos.temperature**(0.5*(1.0-self.barklemVals[1])) \
287
+ + cross * atmos.temperature**0.3
288
+ broad *= nHGround
289
+ return broad
290
+
291
+
292
+ @dataclass(eq=False)
293
+ class RadiativeBroadening(StandardLineBroadener):
294
+ '''
295
+ Simple constant radiative broadening with coefficient gamma.
296
+ '''
297
+ gamma: float
298
+ line: 'AtomicLine' = field(init=False)
299
+
300
+ def setup(self, line: 'AtomicLine'):
301
+ self.line = line
302
+
303
+ def __repr__(self):
304
+ s = '%s(gamma=%g)' % (type(self).__name__, self.gamma)
305
+ return s
306
+
307
+ def __eq__(self, other):
308
+ if type(self) is not type(other):
309
+ return False
310
+
311
+ if self.gamma != other.gamma:
312
+ return False
313
+
314
+ try:
315
+ if self.line != other.line:
316
+ return False
317
+ except AttributeError:
318
+ pass
319
+
320
+ return True
321
+
322
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
323
+ '''
324
+ The function that is called by LineBroadening.
325
+
326
+ Parameters
327
+ ----------
328
+ atmos : Atmosphere
329
+ The atmosphere in which to compute the broadening.
330
+ eqPops : SpeciesStateTable
331
+ The populations to use for computing the broadening.
332
+
333
+ Returns
334
+ -------
335
+ broad : np.ndarray
336
+ An array detailing the broadening at each location in the
337
+ atmosphere [Nspace].
338
+ '''
339
+ return np.ones_like(atmos.temperature) * self.gamma
340
+
341
+ @dataclass
342
+ class QuadraticStarkBroadening(StandardLineBroadener):
343
+ '''
344
+ Lindholm theory result for Quadratic Stark broadening by electrons and
345
+ singly ionised particles.
346
+ Follows HM2014 pp. 238-239, uses C4 from Traving 1960 via RH.
347
+ '''
348
+ coeff: float
349
+ line: 'AtomicLine' = field(init=False)
350
+
351
+ def __repr__(self):
352
+ s = '%s(coeff=%g)' % (type(self).__name__, self.coeff)
353
+ return s
354
+
355
+ def __eq__(self, other):
356
+ if type(self) is not type(other):
357
+ return False
358
+
359
+ if self.coeff != other.coeff:
360
+ return False
361
+
362
+ try:
363
+ if self.line != other.line:
364
+ return False
365
+ except AttributeError:
366
+ pass
367
+
368
+ return True
369
+
370
+ def setup(self, line: 'AtomicLine'):
371
+ self.line = line
372
+ weight = line.atom.element.mass
373
+ C = 8.0 * Const.KBoltzmann / (np.pi * Const.Amu * weight)
374
+ Cm = (1.0 + weight / (Const.MElectron / Const.Amu))**(1.0/6.0)
375
+ # NOTE(cmo): 28.0 is average atomic weight
376
+ Cm += (1.0 + weight / (28.0))**(1.0/6.0)
377
+ self.C = C
378
+ self.Cm = Cm
379
+
380
+ Z = line.iLevel.stage + 1
381
+ cont = line.overlyingContinuumLevel
382
+
383
+ E_Ryd = Const.ERydberg / (1.0 + Const.MElectron / (weight * Const.Amu))
384
+ neff_l = Z * np.sqrt(E_Ryd / (cont.E_SI - line.iLevel.E_SI))
385
+ neff_u = Z * np.sqrt(E_Ryd / (cont.E_SI - line.jLevel.E_SI))
386
+
387
+ C4 = Const.QElectron**2 / (4.0 * np.pi * Const.Epsilon0) \
388
+ * Const.RBohr \
389
+ * (2.0 * np.pi * Const.RBohr**2 / Const.HPlanck) / (18.0 * Z**4) \
390
+ * ((neff_u * (5.0 * neff_u**2 + 1.0))**2 \
391
+ - (neff_l * (5.0 * neff_l**2 + 1.0))**2)
392
+ self.cStark23 = 11.37 * (self.coeff * C4)**(2.0/3.0)
393
+
394
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
395
+ '''
396
+ The function that is called by LineBroadening.
397
+
398
+ Parameters
399
+ ----------
400
+ atmos : Atmosphere
401
+ The atmosphere in which to compute the broadening.
402
+ eqPops : SpeciesStateTable
403
+ The populations to use for computing the broadening.
404
+
405
+ Returns
406
+ -------
407
+ broad : np.ndarray
408
+ An array detailing the broadening at each location in the
409
+ atmosphere [Nspace].
410
+ '''
411
+ vRel = (self.C * atmos.temperature)**(1.0/6.0) * self.Cm
412
+ stark = self.cStark23 * vRel * atmos.ne
413
+ return stark
414
+
415
+ @dataclass
416
+ class MultiplicativeStarkBroadening(StandardLineBroadener):
417
+ '''
418
+ Simple expression for multiplicative Stark broadening, assumes that this
419
+ can be expresed as a constant * ne.
420
+ '''
421
+ coeff: float
422
+
423
+ def __repr__(self):
424
+ s = '%s(coeff=%g)' % (type(self).__name__, self.coeff)
425
+ return s
426
+
427
+ def __eq__(self, other):
428
+ if type(self) is not type(other):
429
+ return False
430
+
431
+ if self.coeff != other.coeff:
432
+ return False
433
+
434
+ return True
435
+
436
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
437
+ '''
438
+ The function that is called by LineBroadening.
439
+
440
+ Parameters
441
+ ----------
442
+ atmos : Atmosphere
443
+ The atmosphere in which to compute the broadening.
444
+ eqPops : SpeciesStateTable
445
+ The populations to use for computing the broadening.
446
+
447
+ Returns
448
+ -------
449
+ broad : np.ndarray
450
+ An array detailing the broadening at each location in the
451
+ atmosphere [Nspace].
452
+ '''
453
+ return self.coeff * atmos.ne # type: ignore
454
+
455
+ @dataclass
456
+ class HydrogenLinearStarkBroadening(StandardLineBroadener):
457
+ '''
458
+ Linear Stark broadening for the case of Hydrogen from Sutton 1978 (like
459
+ RH).
460
+
461
+ `reproduceOldRHBug` allows for reproducing an issue in older versions of RH
462
+ where the broadening effects was a factor os ~2pi too small as it had not
463
+ been converted to angular frequency.
464
+ '''
465
+ line: 'AtomicLine' = field(init=False)
466
+ reproduceOldRHBug: bool = False
467
+
468
+ def __repr__(self):
469
+ s = f'{type(self).__name__}(reproduceOldRHBug={self.reproduceOldRHBug})'
470
+ return s
471
+
472
+ def __eq__(self, other):
473
+ if type(self) is not type(other):
474
+ return False
475
+
476
+ try:
477
+ if self.line != other.line:
478
+ return False
479
+ except AttributeError:
480
+ pass
481
+
482
+ return True
483
+
484
+ def setup(self, line: 'AtomicLine'):
485
+ self.line = line
486
+
487
+ if line.atom.element.Z != 1:
488
+ raise ValueError('HydrogenicLinearStarkBroadening applied to non-Hydrogen line')
489
+
490
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
491
+ '''
492
+ The function that is called by LineBroadening.
493
+
494
+ Parameters
495
+ ----------
496
+ atmos : Atmosphere
497
+ The atmosphere in which to compute the broadening.
498
+ eqPops : SpeciesStateTable
499
+ The populations to use for computing the broadening.
500
+
501
+ Returns
502
+ -------
503
+ broad : np.ndarray
504
+ An array detailing the broadening at each location in the
505
+ atmosphere [Nspace].
506
+ '''
507
+ nUpper = int(np.round(np.sqrt(0.5*self.line.jLevel.g)))
508
+ nLower = int(np.round(np.sqrt(0.5*self.line.iLevel.g)))
509
+
510
+ a1 = 0.642 if nUpper - nLower == 1 else 1.0
511
+ C = a1 * 0.6 * (nUpper**2 - nLower**2)
512
+ if not self.reproduceOldRHBug:
513
+ C *= 4.0 * np.pi * 0.425
514
+ GStark = C * u.Unit('m-2').to('cm-2') * atmos.ne**(2.0/3.0)
515
+ return GStark
516
+
517
+ @dataclass(eq=False)
518
+ class ScaledExponentBroadening(StandardLineBroadener):
519
+ '''
520
+ Broadening implementation following the CRTAF ScaledExponents recipe.
521
+ scaling * T**a * n_H(0)**b * n_e**c
522
+
523
+ scaling : float
524
+ Scalar multiplication term
525
+ temperatureExp : float
526
+ Temperature exponent
527
+ hydrogenExp : float
528
+ Neutral (ground-state) hydrogen density exponent
529
+ electronExp : float
530
+ Electron density exponent
531
+ '''
532
+ scaling: float
533
+ temperatureExp: float
534
+ hydrogenExp: float
535
+ electronExp: float
536
+ line: 'AtomicLine' = field(init=False)
537
+
538
+ def setup(self, line: 'AtomicLine'):
539
+ self.line = line
540
+
541
+ def __repr__(self):
542
+ s = '%s(scaling=%g, temperatureExp=%g, hydrogenExp=%g, electronExp=%g)' % (type(self).__name__,
543
+ self.scaling, self.temperatureExp, self.hydrogenExp, self.electronExp)
544
+ return s
545
+
546
+ def __eq__(self, other):
547
+ if type(self) is not type(other):
548
+ return False
549
+
550
+ if self.scaling != other.scaling:
551
+ return False
552
+ if self.temperatureExp != other.temperatureExp:
553
+ return False
554
+ if self.hydrogenExp != other.hydrogenExp:
555
+ return False
556
+ if self.electronExp != other.electronExp:
557
+ return False
558
+
559
+ try:
560
+ if self.line != other.line:
561
+ return False
562
+ except AttributeError:
563
+ pass
564
+
565
+ return True
566
+
567
+ def broaden(self, atmos: 'Atmosphere', eqPops: 'SpeciesStateTable') -> np.ndarray:
568
+ '''
569
+ The function that is called by LineBroadening.
570
+
571
+ Parameters
572
+ ----------
573
+ atmos : Atmosphere
574
+ The atmosphere in which to compute the broadening.
575
+ eqPops : SpeciesStateTable
576
+ The populations to use for computing the broadening.
577
+
578
+ Returns
579
+ -------
580
+ broad : np.ndarray
581
+ An array detailing the broadening at each location in the
582
+ atmosphere [Nspace].
583
+ '''
584
+ result = np.ones_like(atmos.temperature)
585
+
586
+ if self.temperatureExp > 0.0:
587
+ if self.temperatureExp == 1.0:
588
+ result *= atmos.temperature
589
+ else:
590
+ result *= atmos.temperature**self.temperatureExp
591
+
592
+ if self.hydrogenExp > 0.0:
593
+ nHGround = eqPops['H'][0, :]
594
+ if self.hydrogenExp == 1.0:
595
+ result *= nHGround
596
+ else:
597
+ result *= nHGround**self.hydrogenExp
598
+
599
+ if self.electronExp > 0.0:
600
+ if self.electronExp == 1.0:
601
+ result *= atmos.ne
602
+ else:
603
+ result *= atmos.ne**self.electronExp
604
+
605
+ return self.scaling * result