From b5866254e86f81cae2b9dfa6cface41730b25daf Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 28 Jun 2024 00:37:53 +0200 Subject: [PATCH 01/11] Add donor_metastable attribute to core BeamCXPEC (#411). Replace receiver ion density with the total ion density in BeamCXPEC (#441). --- cherab/core/atomic/rates.pxd | 2 ++ cherab/core/atomic/rates.pyx | 7 ++++++- cherab/core/model/beam/charge_exchange.pxd | 2 +- cherab/core/model/beam/charge_exchange.pyx | 14 +++++++------- cherab/core/tests/test_beamcxline.py | 2 +- cherab/openadas/rates/cx.pxd | 1 - cherab/openadas/rates/cx.pyx | 4 ++-- 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/cherab/core/atomic/rates.pxd b/cherab/core/atomic/rates.pxd index 1f844122..ac8d69ce 100644 --- a/cherab/core/atomic/rates.pxd +++ b/cherab/core/atomic/rates.pxd @@ -51,6 +51,8 @@ cdef class ThermalCXPEC(_PECRate): cdef class BeamCXPEC: + cdef readonly int donor_metastable + cpdef double evaluate(self, double energy, double temperature, double density, double z_effective, double b_field) except? -1e999 diff --git a/cherab/core/atomic/rates.pyx b/cherab/core/atomic/rates.pyx index f3a653db..52510e4b 100644 --- a/cherab/core/atomic/rates.pyx +++ b/cherab/core/atomic/rates.pyx @@ -144,8 +144,13 @@ cdef class BeamCXPEC: transition :math:`n\rightarrow n'` of ion :math:`Z^{(\alpha+1)+}` with electron donor :math:`H^0` in metastable state :math:`m_{i}`. Equivalent to :math:`q^{eff}_{n\rightarrow n'}` in `adf12 _`. + + :param donor_metastable: The metastable state of the donor species for which the rate data applies. """ + def __init__(self, int donor_metastable): + self.donor_metastable = donor_metastable + def __call__(self, double energy, double temperature, double density, double z_effective, double b_field): """Evaluates the Beam CX rate at the given plasma conditions. @@ -158,7 +163,7 @@ cdef class BeamCXPEC: :param float energy: Interaction energy in eV/amu. :param float temperature: Receiver ion temperature in eV. - :param float density: Receiver ion density in m^-3 + :param float density: Plasma total ion density in m^-3 :param float z_effective: Plasma Z-effective. :param float b_field: Magnetic field magnitude in Tesla. :return: The effective rate diff --git a/cherab/core/model/beam/charge_exchange.pxd b/cherab/core/model/beam/charge_exchange.pxd index cd0b48db..46e22891 100644 --- a/cherab/core/model/beam/charge_exchange.pxd +++ b/cherab/core/model/beam/charge_exchange.pxd @@ -36,7 +36,7 @@ cdef class BeamCXLine(BeamModel): object _lineshape_class, _lineshape_args, _lineshape_kwargs cdef double _composite_cx_rate(self, double x, double y, double z, double interaction_energy, - Vector3D donor_velocity, double receiver_temperature, double receiver_density) except? -1e999 + Vector3D donor_velocity, double receiver_temperature) except? -1e999 cdef double _beam_population(self, double x, double y, double z, Vector3D beam_velocity, list population_data) except? -1e999 diff --git a/cherab/core/model/beam/charge_exchange.pyx b/cherab/core/model/beam/charge_exchange.pyx index 295d5f5f..12650ddb 100644 --- a/cherab/core/model/beam/charge_exchange.pyx +++ b/cherab/core/model/beam/charge_exchange.pyx @@ -158,7 +158,7 @@ cdef class BeamCXLine(BeamModel): interaction_energy = ms_to_evamu(interaction_speed) # calculate the composite charge-exchange emission coefficient - emission_rate = self._composite_cx_rate(x, y, z, interaction_energy, donor_velocity, receiver_temperature, receiver_density) + emission_rate = self._composite_cx_rate(x, y, z, interaction_energy, donor_velocity, receiver_temperature) # spectral line emission in W/m^3/str radiance = RECIP_4_PI * donor_density * receiver_density * emission_rate @@ -169,7 +169,7 @@ cdef class BeamCXLine(BeamModel): @cython.wraparound(False) @cython.cdivision(True) cdef double _composite_cx_rate(self, double x, double y, double z, double interaction_energy, - Vector3D donor_velocity, double receiver_temperature, double receiver_density) except? -1e999: + Vector3D donor_velocity, double receiver_temperature) except? -1e999: """ Performs a beam population weighted average of the effective cx rates. @@ -188,23 +188,23 @@ cdef class BeamCXLine(BeamModel): :param interaction_energy: The donor-receiver interaction energy in eV/amu. :param donor_velocity: A Vector defining the donor particle velocity in m/s. :param receiver_temperature: The receiver species temperature in eV. - :param receiver_density: The receiver species density in m^-3 :return: The composite charge exchange rate in W.m^3. """ cdef: - double z_effective, b_field, rate, total_population, population, effective_rate + double z_effective, b_field, rate, total_population, population, effective_rate, ion_density BeamCXPEC cx_rate list population_data - # calculate z_effective and the B-field magnitude + # calculate ion density, z_effective and the B-field magnitude + ion_density = self._plasma.ion_density(x, y, z) z_effective = self._plasma.z_effective(x, y, z) b_field = self._plasma.get_b_field().evaluate(x, y, z).get_length() # rate for the ground state (metastable = 1) rate = self._ground_beam_rate.evaluate(interaction_energy, receiver_temperature, - receiver_density, + ion_density, z_effective, b_field) @@ -219,7 +219,7 @@ cdef class BeamCXLine(BeamModel): effective_rate = cx_rate.evaluate(interaction_energy, receiver_temperature, - receiver_density, + ion_density, z_effective, b_field) diff --git a/cherab/core/tests/test_beamcxline.py b/cherab/core/tests/test_beamcxline.py index ccb0c855..f20c4861 100644 --- a/cherab/core/tests/test_beamcxline.py +++ b/cherab/core/tests/test_beamcxline.py @@ -36,7 +36,7 @@ class ConstantBeamCXPEC(BeamCXPEC): """ def __init__(self, donor_metastable, value): - self.donor_metastable = donor_metastable + super().__init__(donor_metastable) self.value = value def evaluate(self, energy, temperature, density, z_effective, b_field): diff --git a/cherab/openadas/rates/cx.pxd b/cherab/openadas/rates/cx.pxd index 393027d0..4afcadfc 100644 --- a/cherab/openadas/rates/cx.pxd +++ b/cherab/openadas/rates/cx.pxd @@ -25,7 +25,6 @@ cdef class BeamCXPEC(CoreBeamCXPEC): cdef readonly: dict raw_data double wavelength - int donor_metastable Function1D _eb, _ti, _ni, _zeff, _b readonly tuple beam_energy_range readonly tuple density_range diff --git a/cherab/openadas/rates/cx.pyx b/cherab/openadas/rates/cx.pyx index cb827a8b..dfdcf8e8 100644 --- a/cherab/openadas/rates/cx.pyx +++ b/cherab/openadas/rates/cx.pyx @@ -37,7 +37,7 @@ cdef class BeamCXPEC(CoreBeamCXPEC): @cython.cdivision(True) def __init__(self, int donor_metastable, double wavelength, dict data, bint extrapolate=False): - self.donor_metastable = donor_metastable + super().__init__(donor_metastable) self.wavelength = wavelength self.raw_data = data @@ -79,7 +79,7 @@ cdef class BeamCXPEC(CoreBeamCXPEC): :param energy: Interaction energy in eV/amu. :param temperature: Receiver ion temperature in eV. - :param density: Receiver ion density in m^-3 + :param density: Plasma total ion density in m^-3 :param z_effective: Plasma Z-effective. :param b_field: Magnetic field magnitude in Tesla. :return: The effective cx rate in W.m^3 From 5208b016b9deb9c2abbe0ba7d0f89c4fa822112c Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 28 Jun 2024 00:39:23 +0200 Subject: [PATCH 02/11] Update figures for CX spectroscopy in documentation. --- .../CXS_multi_sightlines.png | Bin 59708 -> 56528 bytes .../active_spectroscopy/CXS_spectrum.png | Bin 24577 -> 26470 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/source/demonstrations/active_spectroscopy/CXS_multi_sightlines.png b/docs/source/demonstrations/active_spectroscopy/CXS_multi_sightlines.png index b04c94c0f5d8951b21edaff49875ea09ffebd141..f94e95ab45872636f40cb1cdda7bac29b4abbbc0 100644 GIT binary patch literal 56528 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

npWdp%+a4*>b82!^VTaD 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 IbxsLQ0K{d>jQ{`u diff --git a/docs/source/demonstrations/active_spectroscopy/CXS_spectrum.png b/docs/source/demonstrations/active_spectroscopy/CXS_spectrum.png index 75b083d70b5d0aa7758419b32a19629393701ecc..a258c6edf44d476882434bf440d92f28c16cbb39 100644 GIT binary patch literal 26470 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 literal 24577 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 MihIHK{OgDQ1N8Q7Jpcdz From b2230cb647e477dfe2f514a8536f0cb24a45e6c9 Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 28 Jun 2024 00:48:09 +0200 Subject: [PATCH 03/11] Update changelog. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c70837fb..43f62a09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ New: Bug fixes: * Fix deprecated transforms being cached in LaserMaterial after laser.transform update (#420) * Fix IRVB calculate sensitivity method. +* Fix missing donor_metastable attribute in the core BeamCXPEC class (#411). +* **Fix the receiver ion density being passed to the BeamCXPEC instead of the total ion density in the BeamCXLine. Also fix incorrect BeamCXPEC dosctrings. Attention!!! The results of CX spectroscopy are affected by this change. (#441)** Release 1.4.0 (3 Feb 2023) ------------------- From 645d697f4541d852adc16f5c3e2386c5c64cb8d7 Mon Sep 17 00:00:00 2001 From: vsnever Date: Thu, 11 Jul 2024 00:32:46 +0200 Subject: [PATCH 04/11] Brake variable declaration line in BeamCXLine._composite_cx_rate() into several lines. --- cherab/core/model/beam/charge_exchange.pyx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cherab/core/model/beam/charge_exchange.pyx b/cherab/core/model/beam/charge_exchange.pyx index 12650ddb..83fe237f 100644 --- a/cherab/core/model/beam/charge_exchange.pyx +++ b/cherab/core/model/beam/charge_exchange.pyx @@ -192,7 +192,10 @@ cdef class BeamCXLine(BeamModel): """ cdef: - double z_effective, b_field, rate, total_population, population, effective_rate, ion_density + double ion_density, z_effective + double b_field + double rate, effective_rate + double population, total_population BeamCXPEC cx_rate list population_data From dc8e00c2dc835ce33ef4c1a7a4336d7a7c1fc01a Mon Sep 17 00:00:00 2001 From: vsnever Date: Sat, 20 Jul 2024 00:52:16 +0200 Subject: [PATCH 05/11] Add setUp to the TestCases containing Plasma to ensure that Plasma state is unchanged between the tests. --- cherab/core/tests/test_beam.py | 58 +++++++++++++----------- cherab/core/tests/test_beamcxline.py | 46 +++++++++++-------- cherab/core/tests/test_bremsstrahlung.py | 19 +++++--- cherab/core/tests/test_lineshapes.py | 13 ++++-- 4 files changed, 80 insertions(+), 56 deletions(-) diff --git a/cherab/core/tests/test_beam.py b/cherab/core/tests/test_beam.py index ef10126f..7d2ec203 100644 --- a/cherab/core/tests/test_beam.py +++ b/cherab/core/tests/test_beam.py @@ -55,32 +55,38 @@ def beam_stopping_rate(self, beam_ion, plasma_ion, charge): class TestBeam(unittest.TestCase): - atomic_data = MockAtomicData() - - world = World() - - plasma_density = 1.e19 - plasma_temperature = 1.e3 - plasma_species = [(deuterium, 1, plasma_density, plasma_temperature, Vector3D(0, 0, 0))] - plasma = build_constant_slab_plasma(length=1, width=1, height=1, electron_density=plasma_density, - electron_temperature=plasma_temperature, - plasma_species=plasma_species) - plasma.atomic_data = atomic_data - plasma.parent = world - - beam = Beam(transform=translate(0.5, 0, 0)) - beam.atomic_data = atomic_data - beam.plasma = plasma - beam.attenuator = SingleRayAttenuator(clamp_to_zero=True) - beam.energy = 50000 - beam.power = 1e6 - beam.temperature = 10 - beam.element = deuterium - beam.parent = world - beam.sigma = 0.2 - beam.divergence_x = 1. - beam.divergence_y = 2. - beam.length = 10. + def setUp(self): + + self.atomic_data = MockAtomicData() + + self.world = World() + + self.plasma_density = 1.e19 + self.plasma_temperature = 1.e3 + plasma_species = [(deuterium, 1, self.plasma_density, self.plasma_temperature, Vector3D(0, 0, 0))] + plasma = build_constant_slab_plasma(length=1, width=1, height=1, + electron_density=self.plasma_density, + electron_temperature=self.plasma_temperature, + plasma_species=plasma_species) + plasma.atomic_data = self.atomic_data + plasma.parent = self.world + + beam = Beam(transform=translate(0.5, 0, 0)) + beam.atomic_data = self.atomic_data + beam.plasma = plasma + beam.attenuator = SingleRayAttenuator(clamp_to_zero=True) + beam.energy = 50000 + beam.power = 1e6 + beam.temperature = 10 + beam.element = deuterium + beam.parent = self.world + beam.sigma = 0.2 + beam.divergence_x = 1. + beam.divergence_y = 2. + beam.length = 10. + + self.plasma = plasma + self.beam = beam def test_beam_density(self): diff --git a/cherab/core/tests/test_beamcxline.py b/cherab/core/tests/test_beamcxline.py index ccb0c855..250da0e8 100644 --- a/cherab/core/tests/test_beamcxline.py +++ b/cherab/core/tests/test_beamcxline.py @@ -76,25 +76,33 @@ def wavelength(self, ion, charge, transition): class TestBeamCXLine(unittest.TestCase): - world = World() - - atomic_data = MockAtomicData() - - plasma_species = [(deuterium, 1, 1.e19, 200., Vector3D(0, 0, 0))] - plasma = build_constant_slab_plasma(length=1, width=1, height=1, electron_density=1e19, electron_temperature=200., - plasma_species=plasma_species, b_field=Vector3D(0, 10., 0)) - plasma.atomic_data = atomic_data - plasma.parent = world - - beam = Beam(transform=translate(0.5, 0, 0)) - beam.atomic_data = atomic_data - beam.plasma = plasma - beam.attenuator = SingleRayAttenuator(clamp_to_zero=True) - beam.energy = 50000 - beam.power = 1e6 - beam.temperature = 10 - beam.element = deuterium - beam.parent = world + def setUp(self): + + self.world = World() + + self.atomic_data = MockAtomicData() + + plasma_species = [(deuterium, 1, 1.e19, 200., Vector3D(0, 0, 0))] + plasma = build_constant_slab_plasma(length=1, width=1, height=1, + electron_density=1e19, + electron_temperature=200., + plasma_species=plasma_species, + b_field=Vector3D(0, 10., 0)) + plasma.atomic_data = self.atomic_data + plasma.parent = self.world + + beam = Beam(transform=translate(0.5, 0, 0)) + beam.atomic_data = self.atomic_data + beam.plasma = plasma + beam.attenuator = SingleRayAttenuator(clamp_to_zero=True) + beam.energy = 50000 + beam.power = 1e6 + beam.temperature = 10 + beam.element = deuterium + beam.parent = self.world + + self.plasma = plasma + self.beam = beam def test_default_lineshape(self): # setting up the model diff --git a/cherab/core/tests/test_bremsstrahlung.py b/cherab/core/tests/test_bremsstrahlung.py index 5373776b..a77a1da5 100644 --- a/cherab/core/tests/test_bremsstrahlung.py +++ b/cherab/core/tests/test_bremsstrahlung.py @@ -34,13 +34,18 @@ class TestBremsstrahlung(unittest.TestCase): - world = World() - - plasma_species = [(deuterium, 1, 1.e19, 2000., Vector3D(0, 0, 0)), (nitrogen, 7, 1.e18, 2000., Vector3D(0, 0, 0))] - plasma = build_constant_slab_plasma(length=1, width=1, height=1, electron_density=1e19, electron_temperature=2000., - plasma_species=plasma_species) - plasma.parent = world - plasma.atomic_data = AtomicData() + def setUp(self): + + self.world = World() + + plasma_species = [(deuterium, 1, 1.e19, 2000., Vector3D(0, 0, 0)), + (nitrogen, 7, 1.e18, 2000., Vector3D(0, 0, 0))] + self.plasma = build_constant_slab_plasma(length=1, width=1, height=1, + electron_density=1e19, + electron_temperature=2000., + plasma_species=plasma_species) + self.plasma.parent = self.world + self.plasma.atomic_data = AtomicData() def test_bremsstrahlung_model(self): # setting up the model diff --git a/cherab/core/tests/test_lineshapes.py b/cherab/core/tests/test_lineshapes.py index da4dc41d..97a32f1f 100644 --- a/cherab/core/tests/test_lineshapes.py +++ b/cherab/core/tests/test_lineshapes.py @@ -42,10 +42,15 @@ class TestLineShapes(unittest.TestCase): - plasma_species = [(deuterium, 0, 1.e18, 5., Vector3D(2.e4, 0, 0)), - (nitrogen, 1, 1.e17, 10., Vector3D(1.e4, 5.e4, 0))] - plasma = build_constant_slab_plasma(length=1, width=1, height=1, electron_density=1e19, electron_temperature=20., - plasma_species=plasma_species, b_field=Vector3D(0, 5., 0)) + def setUp(self): + + plasma_species = [(deuterium, 0, 1.e18, 5., Vector3D(2.e4, 0, 0)), + (nitrogen, 1, 1.e17, 10., Vector3D(1.e4, 5.e4, 0))] + self.plasma = build_constant_slab_plasma(length=1, width=1, height=1, + electron_density=1e19, + electron_temperature=20., + plasma_species=plasma_species, + b_field=Vector3D(0, 5., 0)) def test_gaussian_line(self): # setting up a line shape model From 3ad37ad8d014506a4dde2a3dbe75fcebae34afd4 Mon Sep 17 00:00:00 2001 From: vsnever Date: Sat, 20 Jul 2024 17:54:26 +0200 Subject: [PATCH 06/11] Make atomic rates return zero if plasma or beam parameters <= 0. --- cherab/openadas/rates/atomic.pyx | 21 +++++------------ cherab/openadas/rates/beam.pyx | 30 +++++------------------- cherab/openadas/rates/cx.pyx | 4 ++-- cherab/openadas/rates/pec.pyx | 14 ++++------- cherab/openadas/rates/radiated_power.pyx | 21 +++++------------ 5 files changed, 24 insertions(+), 66 deletions(-) diff --git a/cherab/openadas/rates/atomic.pyx b/cherab/openadas/rates/atomic.pyx index 04500124..bccd1ff3 100644 --- a/cherab/openadas/rates/atomic.pyx +++ b/cherab/openadas/rates/atomic.pyx @@ -50,11 +50,8 @@ cdef class IonisationRate(CoreIonisationRate): cpdef double evaluate(self, double density, double temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(density), log10(temperature)) @@ -97,11 +94,8 @@ cdef class RecombinationRate(CoreRecombinationRate): cpdef double evaluate(self, double density, double temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(density), log10(temperature)) @@ -143,11 +137,8 @@ cdef class ThermalCXRate(CoreThermalCXRate): cpdef double evaluate(self, double density, double temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(density), log10(temperature)) diff --git a/cherab/openadas/rates/beam.pyx b/cherab/openadas/rates/beam.pyx index f40af8dd..58bdaa87 100644 --- a/cherab/openadas/rates/beam.pyx +++ b/cherab/openadas/rates/beam.pyx @@ -78,14 +78,8 @@ cdef class BeamStoppingRate(CoreBeamStoppingRate): """ # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if energy < 1.e-300: - energy = 1.e-300 - - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if energy <= 0 or density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** (self._npl_eb.evaluate(log10(energy), log10(density)) + self._tp.evaluate(log10(temperature))) @@ -152,14 +146,8 @@ cdef class BeamPopulationRate(CoreBeamPopulationRate): """ # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if energy < 1.e-300: - energy = 1.e-300 - - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if energy <= 0 or density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** (self._npl_eb.evaluate(log10(energy), log10(density)) + self._tp.evaluate(log10(temperature))) @@ -228,14 +216,8 @@ cdef class BeamEmissionPEC(CoreBeamEmissionPEC): """ # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if energy < 1.e-300: - energy = 1.e-300 - - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if energy <= 0 or density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** (self._npl_eb.evaluate(log10(energy), log10(density)) + self._tp.evaluate(log10(temperature))) diff --git a/cherab/openadas/rates/cx.pyx b/cherab/openadas/rates/cx.pyx index cb827a8b..342a9dbc 100644 --- a/cherab/openadas/rates/cx.pyx +++ b/cherab/openadas/rates/cx.pyx @@ -88,8 +88,8 @@ cdef class BeamCXPEC(CoreBeamCXPEC): cdef double rate # need to handle zeros for log-log interpolation - if energy < 1.e-300: - energy = 1.e-300 + if energy <= 0: + return 0 rate = 10 ** self._eb.evaluate(log10(energy)) diff --git a/cherab/openadas/rates/pec.pyx b/cherab/openadas/rates/pec.pyx index eafc6c64..c33e2bc2 100644 --- a/cherab/openadas/rates/pec.pyx +++ b/cherab/openadas/rates/pec.pyx @@ -56,11 +56,8 @@ cdef class ImpactExcitationPEC(CoreImpactExcitationPEC): cpdef double evaluate(self, double density, double temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(density), log10(temperature)) @@ -108,11 +105,8 @@ cdef class RecombinationPEC(CoreRecombinationPEC): cpdef double evaluate(self, double density, double temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if density < 1.e-300: - density = 1.e-300 - - if temperature < 1.e-300: - temperature = 1.e-300 + if density <= 0 or temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(density), log10(temperature)) diff --git a/cherab/openadas/rates/radiated_power.pyx b/cherab/openadas/rates/radiated_power.pyx index 570ced92..bf9c1667 100644 --- a/cherab/openadas/rates/radiated_power.pyx +++ b/cherab/openadas/rates/radiated_power.pyx @@ -49,11 +49,8 @@ cdef class LineRadiationPower(CoreLineRadiationPower): cdef double evaluate(self, double electron_density, double electron_temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if electron_density < 1.e-300: - electron_density = 1.e-300 - - if electron_temperature < 1.e-300: - electron_temperature = 1.e-300 + if electron_density <= 0 or electron_temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(electron_density), log10(electron_temperature)) @@ -95,11 +92,8 @@ cdef class ContinuumPower(CoreContinuumPower): cdef double evaluate(self, double electron_density, double electron_temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if electron_density < 1.e-300: - electron_density = 1.e-300 - - if electron_temperature < 1.e-300: - electron_temperature = 1.e-300 + if electron_density <= 0 or electron_temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(electron_density), log10(electron_temperature)) @@ -140,11 +134,8 @@ cdef class CXRadiationPower(CoreCXRadiationPower): cdef double evaluate(self, double electron_density, double electron_temperature) except? -1e999: # need to handle zeros, also density and temperature can become negative due to cubic interpolation - if electron_density < 1.e-300: - electron_density = 1.e-300 - - if electron_temperature < 1.e-300: - electron_temperature = 1.e-300 + if electron_density <= 0 or electron_temperature <= 0: + return 0 # calculate rate and convert from log10 space to linear space return 10 ** self._rate.evaluate(log10(electron_density), log10(electron_temperature)) From d81096abed284094f3f7c33339212783e499217d Mon Sep 17 00:00:00 2001 From: vsnever Date: Mon, 22 Jul 2024 14:15:27 +0200 Subject: [PATCH 07/11] Correct and expand documentation for the core AtomicData class --- cherab/core/atomic/interface.pyx | 63 +++++++++++++++++--- docs/source/atomic/atomic_data.rst | 1 + docs/source/atomic/atomic_data_interface.rst | 19 ++++++ 3 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 docs/source/atomic/atomic_data_interface.rst diff --git a/cherab/core/atomic/interface.pyx b/cherab/core/atomic/interface.pyx index 286ebfb4..3e44d52c 100644 --- a/cherab/core/atomic/interface.pyx +++ b/cherab/core/atomic/interface.pyx @@ -1,6 +1,6 @@ -# Copyright 2016-2022 Euratom -# Copyright 2016-2022 United Kingdom Atomic Energy Authority -# Copyright 2016-2022 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -29,70 +29,117 @@ cdef class AtomicData: cpdef double wavelength(self, Element ion, int charge, tuple transition): """ - Returns the natural wavelength of the specified transition in nm. + The natural wavelength of the specified transition in nm. """ raise NotImplementedError("The wavelength() virtual method is not implemented for this atomic data source.") cpdef IonisationRate ionisation_rate(self, Element ion, int charge): + """ + Electron impact ionisation rate for a given species in m^3/s. + """ + raise NotImplementedError("The ionisation_rate() virtual method is not implemented for this atomic data source.") cpdef RecombinationRate recombination_rate(self, Element ion, int charge): + """ + Recombination rate for a given species in m^3/s. + """ + raise NotImplementedError("The recombination_rate() virtual method is not implemented for this atomic data source.") cpdef ThermalCXRate thermal_cx_rate(self, Element donor_ion, int donor_charge, Element receiver_ion, int receiver_charge): + """ + Thermal charge exchange effective rate coefficient for a given donor and receiver species in m^3/s. + """ + raise NotImplementedError("The thermal_cx_rate() virtual method is not implemented for this atomic data source.") cpdef list beam_cx_pec(self, Element donor_ion, Element receiver_ion, int receiver_charge, tuple transition): """ - Returns a list of applicable charge exchange emission rates in W.m^3. + A list of Effective charge exchange photon emission coefficient for a given donor (beam) in W.m^3. """ raise NotImplementedError("The cxs_rates() virtual method is not implemented for this atomic data source.") cpdef BeamStoppingRate beam_stopping_rate(self, Element beam_ion, Element plasma_ion, int charge): """ - Returns a list of applicable beam stopping coefficients in m^3/s. + Beam stopping coefficient for a given beam and target species in m^3/s. """ raise NotImplementedError("The beam_stopping() virtual method is not implemented for this atomic data source.") cpdef BeamPopulationRate beam_population_rate(self, Element beam_ion, int metastable, Element plasma_ion, int charge): """ - Returns a list of applicable dimensionless beam population coefficients. + Dimensionless Beam population coefficient for a given beam and target species. """ raise NotImplementedError("The beam_population() virtual method is not implemented for this atomic data source.") cpdef BeamEmissionPEC beam_emission_pec(self, Element beam_ion, Element plasma_ion, int charge, tuple transition): """ - Returns a list of applicable beam emission coefficients in W.m^3. + The beam photon emission coefficient for a given beam and target species + and a given transition in W.m^3. """ raise NotImplementedError("The beam_emission() virtual method is not implemented for this atomic data source.") cpdef ImpactExcitationPEC impact_excitation_pec(self, Element ion, int charge, tuple transition): + """ + Electron impact excitation photon emission coefficient for a given species in W.m^3. + """ + raise NotImplementedError("The impact_excitation() virtual method is not implemented for this atomic data source.") cpdef RecombinationPEC recombination_pec(self, Element ion, int charge, tuple transition): + """ + Recombination photon emission coefficient for a given species in W.m^3. + """ + raise NotImplementedError("The recombination() virtual method is not implemented for this atomic data source.") cpdef TotalRadiatedPower total_radiated_power(self, Element element): + """ + The total (summed over all charge states) radiated power + in equilibrium conditions for a given species in W.m^3. + """ + raise NotImplementedError("The total_radiated_power() virtual method is not implemented for this atomic data source.") cpdef LineRadiationPower line_radiated_power_rate(self, Element element, int charge): + """ + Line radiated power coefficient for a given species in W.m^3. + """ + raise NotImplementedError("The line_radiated_power_rate() virtual method is not implemented for this atomic data source.") cpdef ContinuumPower continuum_radiated_power_rate(self, Element element, int charge): + """ + Continuum radiated power coefficient for a given species in W.m^3. + """ + raise NotImplementedError("The continuum_radiated_power_rate() virtual method is not implemented for this atomic data source.") cpdef CXRadiationPower cx_radiated_power_rate(self, Element element, int charge): + """ + Charge exchange radiated power coefficient for a given species in W.m^3. + """ + raise NotImplementedError("The cx_radiated_power_rate() virtual method is not implemented for this atomic data source.") cpdef FractionalAbundance fractional_abundance(self, Element ion, int charge): + """ + Fractional abundance of a given species in thermodynamic equilibrium. + """ + raise NotImplementedError("The fractional_abundance() virtual method is not implemented for this atomic data source.") cpdef ZeemanStructure zeeman_structure(self, Line line, object b_field=None): + r""" + Wavelengths and ratios of :math:`\pi`-/:math:`\sigma`-polarised Zeeman components + for any given value of magnetic field strength. + """ + raise NotImplementedError("The zeeman_structure() virtual method is not implemented for this atomic data source.") cpdef FreeFreeGauntFactor free_free_gaunt_factor(self): diff --git a/docs/source/atomic/atomic_data.rst b/docs/source/atomic/atomic_data.rst index 650d89b4..6eeb09a1 100644 --- a/docs/source/atomic/atomic_data.rst +++ b/docs/source/atomic/atomic_data.rst @@ -7,3 +7,4 @@ Atomic Data emission_lines rate_coefficients gaunt_factors + atomic_data_interface diff --git a/docs/source/atomic/atomic_data_interface.rst b/docs/source/atomic/atomic_data_interface.rst new file mode 100644 index 00000000..0d54ff67 --- /dev/null +++ b/docs/source/atomic/atomic_data_interface.rst @@ -0,0 +1,19 @@ + +Atomic Data Interface +===================== + +Abstract (interface) class +-------------------------- + +Abstract atomic data interface. + +.. autoclass:: cherab.core.atomic.interface.AtomicData + :members: + +OpenADAS atomic data source +--------------------------- + +Interface to local atomic data repository. + +.. autoclass:: cherab.openadas.openadas.OpenADAS + :members: From 8934c8ccec63b74d40fd599bbf57e188a437dccc Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 24 Jul 2024 22:51:09 +0200 Subject: [PATCH 08/11] Improve documentation for openadas repository install and manipulation functions. --- cherab/openadas/install.py | 61 ++++---- cherab/openadas/repository/atomic.py | 143 +++++++++++++++--- cherab/openadas/repository/beam/cx.py | 97 ++++++++++-- cherab/openadas/repository/beam/emission.py | 74 ++++++++- cherab/openadas/repository/beam/population.py | 72 ++++++++- cherab/openadas/repository/beam/stopping.py | 69 ++++++++- cherab/openadas/repository/pec.py | 125 ++++++++++++--- cherab/openadas/repository/radiated_power.py | 140 ++++++++++++++--- cherab/openadas/repository/wavelength.py | 42 ++++- docs/source/atomic/atomic_data.rst | 2 + docs/source/atomic/openadas.rst | 29 ++++ docs/source/atomic/repository.rst | 83 ++++++++++ 12 files changed, 798 insertions(+), 139 deletions(-) create mode 100644 docs/source/atomic/openadas.rst create mode 100644 docs/source/atomic/repository.rst diff --git a/cherab/openadas/install.py b/cherab/openadas/install.py index 27e0c5f4..d634cde7 100644 --- a/cherab/openadas/install.py +++ b/cherab/openadas/install.py @@ -269,14 +269,17 @@ def install_adf15(element, ionisation, file_path, download=False, repository_pat def install_adf21(beam_species, target_ion, target_charge, file_path, download=False, repository_path=None, adas_path=None): - # """ - # Adds the rate defined in an ADF21 file to the repository. - # - # :param file_path: Path relative to ADAS root. - # :param download: Attempt to download file if not present (Default=True). - # :param repository_path: Path to the repository in which to install the rates (optional). - # :param adas_path: Path to ADAS files repository (optional). - # """ + """ + Adds the beam stopping rate defined in an ADF21 file to the repository. + + :param beam_species: Beam neutral atom (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param file_path: Path relative to ADAS root. + :param download: Attempt to download file if not present (Default=True). + :param repository_path: Path to the repository in which to install the rates (optional). + :param adas_path: Path to ADAS files repository (optional). + """ print('Installing {}...'.format(file_path)) path = _locate_adas_file(file_path, download, adas_path, repository_path) @@ -289,15 +292,18 @@ def install_adf21(beam_species, target_ion, target_charge, file_path, download=F def install_adf22bmp(beam_species, beam_metastable, target_ion, target_charge, file_path, download=False, repository_path=None, adas_path=None): - pass - # """ - # Adds the rate defined in an ADF21 file to the repository. - # - # :param file_path: Path relative to ADAS root. - # :param download: Attempt to download file if not present (Default=True). - # :param repository_path: Path to the repository in which to install the rates (optional). - # :param adas_path: Path to ADAS files repository (optional). - # """ + """ + Adds the beam population rate defined in an ADF22 BMP file to the repository. + + :param beam_species: Beam neutral atom (Element/Isotope). + :param beam_metastable: Metastable/excitation level of beam neutral atom. + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param file_path: Path relative to ADAS root. + :param download: Attempt to download file if not present (Default=True). + :param repository_path: Path to the repository in which to install the rates (optional). + :param adas_path: Path to ADAS files repository (optional). + """ print('Installing {}...'.format(file_path)) path = _locate_adas_file(file_path, download, adas_path, repository_path) @@ -310,15 +316,18 @@ def install_adf22bmp(beam_species, beam_metastable, target_ion, target_charge, f def install_adf22bme(beam_species, target_ion, target_charge, transition, file_path, download=False, repository_path=None, adas_path=None): - pass - # """ - # Adds the rate defined in an ADF21 file to the repository. - # - # :param file_path: Path relative to ADAS root. - # :param download: Attempt to download file if not present (Default=True). - # :param repository_path: Path to the repository in which to install the rates (optional). - # :param adas_path: Path to ADAS files repository (optional). - # """ + """ + Adds the beam emission rate defined in an ADF22 BME file to the repository. + + :param beam_species: Beam neutral atom (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param transition: Tuple containing (initial level, final level). + :param file_path: Path relative to ADAS root. + :param download: Attempt to download file if not present (Default=True). + :param repository_path: Path to the repository in which to install the rates (optional). + :param adas_path: Path to ADAS files repository (optional). + """ print('Installing {}...'.format(file_path)) path = _locate_adas_file(file_path, download, adas_path, repository_path) diff --git a/cherab/openadas/repository/atomic.py b/cherab/openadas/repository/atomic.py index c24234f3..cb8add6c 100644 --- a/cherab/openadas/repository/atomic.py +++ b/cherab/openadas/repository/atomic.py @@ -1,6 +1,6 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -34,8 +34,15 @@ def add_ionisation_rate(species, charge, rate, repository_path=None): function instead. The update function avoids repeatedly opening and closing the rate files. - :param repository_path: - :return: + :param species: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param rate: Ionisation rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with ionisation rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ update_ionisation_rates({ @@ -47,11 +54,21 @@ def add_ionisation_rate(species, charge, rate, repository_path=None): def update_ionisation_rates(rates, repository_path=None): """ - Ionisation rate file structure - - /ionisation/.json + Updates the ionisation rate files `/ionisation/.json` + in atomic data repository. File contains multiple rates, indexed by the ion charge state. + + :param rates: Dictionary in the form {: {: }}, where + + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the ionisation rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with ionisation rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -75,8 +92,15 @@ def add_recombination_rate(species, charge, rate, repository_path=None): function instead. The update function avoids repeatedly opening and closing the rate files. - :param repository_path: - :return: + :param species: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param rate: Recombination rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with recombination rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ update_recombination_rates({ @@ -88,11 +112,21 @@ def add_recombination_rate(species, charge, rate, repository_path=None): def update_recombination_rates(rates, repository_path=None): """ - Ionisation rate file structure - - /recombination/.json + Updates the recombination rate files `/recombination/.json` + in the atomic data repository. File contains multiple rates, indexed by the ion charge state. + + :param rates: Dictionary in the form {: {: }}, where + + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the recombination rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with recombination rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -109,7 +143,6 @@ def update_recombination_rates(rates, repository_path=None): def add_thermal_cx_rate(donor_element, donor_charge, receiver_element, rate, repository_path=None): - """ Adds a single thermal charge exchange rate to the repository. @@ -118,11 +151,16 @@ def add_thermal_cx_rate(donor_element, donor_charge, receiver_element, rate, rep the rate files. :param donor_element: Element donating the electron. - :param donor_charge: Charge of the donating atom/ion - :param receiver_element: Element receiving the electron - :param rate: rates - :param repository_path: - :return: + :param donor_charge: Charge of the donating atom/ion. + :param receiver_element: Element receiving the electron. + :param receiver_charge: Charge of the receiving atom/ion. + :param rate: Thermal CX rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with thermal CX rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ rates2update = RecursiveDict() @@ -133,11 +171,25 @@ def add_thermal_cx_rate(donor_element, donor_charge, receiver_element, rate, rep def update_thermal_cx_rates(rates, repository_path=None): """ - Thermal charge exchange rate file structure - - /thermal_cx///.json + Updates the thermal charge exchange rate files + `/thermal_cx///.json` + in the atomic data repository. File contains multiple rates, indexed by the ion charge state. + + :param rates: Dictionary in the form: + + | { : { : { : { : } } } }, where + | is the element donating the electron. + | is the charge of the donating atom/ion. + | is the element receiving the electron. + | is the charge of the receiving atom/ion. + | is the thermal CX rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with thermal CX rate in m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -203,6 +255,21 @@ def _update_and_write_adf11(species, rate_data, path): def get_ionisation_rate(element, charge, repository_path=None): + """ + Reads the ionisation rate for the given species and charge + from the atomic data repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param repository_path: Path to the atomic data repository. + + :return rate: Ionisation rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with ionisation rate in m^3.s^-1. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -224,6 +291,21 @@ def get_ionisation_rate(element, charge, repository_path=None): def get_recombination_rate(element, charge, repository_path=None): + """ + Reads the recombination rate for the given species and charge + from the atomic data repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param repository_path: Path to the atomic data repository. + + :return rate: Recombination rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with recombination rate in m^3.s^-1. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -245,6 +327,23 @@ def get_recombination_rate(element, charge, repository_path=None): def get_thermal_cx_rate(donor_element, donor_charge, receiver_element, receiver_charge, repository_path=None): + """ + Reads the thermal charge exchange rate for the given species and charge + from the atomic data repository. + + :param donor_element: Element donating the electron. + :param donor_charge: Charge of the donating atom/ion. + :param receiver_element: Element receiving the electron. + :param receiver_charge: Charge of the receiving atom/ion. + :param repository_path: Path to the atomic data repository. + + :return rate: Thermal CX rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with thermal CX rate in m^3.s^-1. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH diff --git a/cherab/openadas/repository/beam/cx.py b/cherab/openadas/repository/beam/cx.py index 65bc3ceb..ef79c102 100644 --- a/cherab/openadas/repository/beam/cx.py +++ b/cherab/openadas/repository/beam/cx.py @@ -1,6 +1,6 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -29,19 +29,33 @@ def add_beam_cx_rate(donor_ion, donor_metastable, receiver_ion, receiver_charge, transition, rate, repository_path=None): """ - Adds a single beam CX rate to the repository. + Adds a single beam CX PEC to the repository. If adding multiple rate, consider using the update_beam_cx_rates() function instead. The update function avoid repeatedly opening and closing the rate files. - :param donor_ion: - :param donor_metastable: - :param receiver_ion: - :param receiver_charge: - :param rate: - :param repository_path: - :return: + :param donor_ion: Beam neutral atom (Element/Isotope) donating the electron. + :param donor_metastable: Metastable/excited level of beam neutral atom. + :param receiver_ion: Element/Isotope receiving the electron. + :param receiver_charge: Charge of the receiving atom/ion. + :param transition: Tuple containing (initial level, final level). + :param rate: Beam CX PEC dictionary containing the following entries: + + | 'eb': array-like of size (N) with beam energy in eV/amu, + | 'ti': array-like of size (M) with receiver ion temperature in eV, + | 'ni': array-like of size (K) with plasma ion density in m^-3, + | 'z': array-like of size (L) with plasma Z-effective, + | 'b': array-like of size (J) with magnetic field strength in Tesla, + | 'qeb': array-like of size (N) with CX PEC energy component in photon.m^3.s-1, + | 'qti': array-like of size (M) with CX PEC temperature component in photon.m^3.s-1, + | 'qni': array-like of size (K) with CX PEC density component in photon.m^3.s-1, + | 'qz': array-like of size (L) with CX PEC Zeff component in photon.m^3.s-1, + | 'qb': array-like of size (J) with CX PEC B-field component in photon.m^3.s-1, + | 'qref': reference CX PEC in photon.m^3.s-1. + | The total beam CX PEC: q = qeb * qti * qni * qz * qb / qref^4. + + :param repository_path: Path to the atomic data repository. """ update_beam_cx_rates({ @@ -58,10 +72,37 @@ def add_beam_cx_rate(donor_ion, donor_metastable, receiver_ion, receiver_charge, def update_beam_cx_rates(rates, repository_path=None): - # organisation in repository: - # beam/cx/donor_ion/receiver_ion/receiver_charge.json - # inside json file: - # transition: [list of donor_metastables with rates] + """ + Updates the beam CX PEC files + beam/cx///.json + in the atomic data repository. + + File contains multiple metastable-resolved rates, indexed by transition. + + :param rates: Dictionary in the form: + + | { : { : { : { : {: } } } } }, where + | is the beam neutral atom (Element/Isotope) donating the electron. + | is the metastable/excited level of beam neutral atom. + | is the Element/Isotope receiving the electron. + | is the charge of the receiving atom/ion. + | is the tuple containing (initial level, final level). + | is the beam CX PEC dictionary containing the following entries: + | 'eb': array-like of size (N) with beam energy in eV/amu, + | 'ti': array-like of size (M) with receiver ion temperature in eV, + | 'ni': array-like of size (K) with plasma ion density in m^-3, + | 'z': array-like of size (L) with plasma Z-effective, + | 'b': array-like of size (J) with magnetic field strength in Tesla, + | 'qeb': array-like of size (N) with CX PEC energy component in photon.m^3.s-1, + | 'qti': array-like of size (M) with CX PEC temperature component in photon.m^3.s-1, + | 'qni': array-like of size (K) with CX PEC density component in photon.m^3.s-1, + | 'qz': array-like of size (L) with CX PEC Zeff component in photon.m^3.s-1, + | 'qb': array-like of size (J) with CX PEC B-field component in photon.m^3.s-1, + | 'qref': reference CX PEC in photon.m^3.s-1. + | The total beam CX PEC: q = qeb * qti * qni * qz * qb / qref^4. + + :param repository_path: Path to the atomic data repository. + """ def sanitise_and_validate(data, x_key, x_name, y_key, y_name): """ @@ -167,6 +208,32 @@ def sanitise_and_validate(data, x_key, x_name, y_key, y_name): def get_beam_cx_rates(donor_ion, receiver_ion, receiver_charge, transition, repository_path=None): + """ + Reads a single beam CX PEC from the repository. + + :param donor_ion: Beam neutral atom (Element/Isotope) donating the electron. + :param donor_metastable: Metastable/excited level of beam neutral atom. + :param receiver_ion: Element/Isotope receiving the electron. + :param receiver_charge: Charge of the receiving atom/ion. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return rate: Beam CX PEC dictionary containing the following entries: + + | 'eb': 1D array of size (N) with beam energy in eV/amu, + | 'ti': 1D array of size (M) with receiver ion temperature in eV, + | 'ni': 1D array of size (K) with plasma ion density in m^-3, + | 'z': 1D array of size (L) with plasma Z-effective, + | 'b': 1D array of size (J) with magnetic field strength in Tesla, + | 'qeb': 1D array of size (N) with CX PEC energy component in photon.m^3.s-1, + | 'qti': 1D array of size (M) with CX PEC temperature component in photon.m^3.s-1, + | 'qni': 1D array of size (K) with CX PEC density component in photon.m^3.s-1, + | 'qz': 1D array of size (L) with CX PEC Zeff component in photon.m^3.s-1, + | 'qb': 1D array of size (J) with CX PEC B-field component in photon.m^3.s-1, + | 'qref': reference CX PEC in photon.m^3.s-1. + | The total beam CX PEC: q = qeb * qti * qni * qz * qb / qref^4. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH path = os.path.join(repository_path, 'beam/cx/{}/{}/{}.json'.format(donor_ion.symbol.lower(), receiver_ion.symbol.lower(), receiver_charge)) diff --git a/cherab/openadas/repository/beam/emission.py b/cherab/openadas/repository/beam/emission.py index b6cd14f2..c7c6e2e1 100644 --- a/cherab/openadas/repository/beam/emission.py +++ b/cherab/openadas/repository/beam/emission.py @@ -1,6 +1,6 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -36,8 +36,24 @@ def add_beam_emission_rate(beam_species, target_ion, target_charge, transition, function instead. The update function avoid repeatedly opening and closing the rate files. - :param repository_path: - :return: + :param beam_species: Beam neutral species (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param transition: Tuple containing (initial level, final level). + :param rate: Beam emission rate dictionary containing the following entries: + + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n' array-like of size (M) with target electron density in m^-3, + | 't' array-like of size (K) with target electron temperature in eV, + | 'sen' array-like of size (N, M) with beam emission rate energy component in photon.m^3.s^-1. + | 'st' array-like of size (K) with beam emission rate temperature component in photon.m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam emission rate in photon.m^3.s^-1. + | The total beam emission rate: s = sen * st / sref. + + :param repository_path: Path to the atomic data repository. """ update_beam_emission_rates({ @@ -53,11 +69,32 @@ def add_beam_emission_rate(beam_species, target_ion, target_charge, transition, def update_beam_emission_rates(rates, repository_path=None): """ - Beam emission rate file structure - + Updates the beam emission rate files: /beam/emission///.json + in the atomic repository. File contains multiple rates, indexed by transition. + + :param rates: Dictionary in the form: + + | { : { : { : {: } } } }, where + | is the beam neutral species (Element/Isotope) + | is the target species (Element/Isotope). + | is the charge of the target species. + | is the tuple containing (initial level, final level). + | Beam emission rate dictionary containing the following entries: + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n' array-like of size (M) with target electron density in m^-3, + | 't' array-like of size (K) with target electron temperature in eV, + | 'sen' array-like of size (N, M) with beam emission rate energy component in photon.m^3.s^-1. + | 'st' array-like of size (K) with beam emission rate temperature component in photon.m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam emission rate in photon.m^3.s^-1. + | The total beam emission rate: s = sen * st / sref. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -136,6 +173,29 @@ def update_beam_emission_rates(rates, repository_path=None): def get_beam_emission_rate(beam_species, target_ion, target_charge, transition, repository_path=None): + """ + Reads a single beam emission rate from the repository. + + :param beam_species: Beam neutral species (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return rate: Beam emission rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n' 1D array of size (M) with target electron density in m^-3, + | 't' 1D array of size (K) with target electron temperature in eV, + | 'sen' 2D array of size (N, M) with beam emission rate energy component in photon.m^3.s^-1. + | 'st' 1D array of size (K) with beam emission rate temperature component in photon.m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam emission rate in photon.m^3.s^-1. + | The total beam emission rate: s = sen * st / sref. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH path = os.path.join(repository_path, 'beam/emission/{}/{}/{}.json'.format(beam_species.symbol.lower(), target_ion.symbol.lower(), target_charge)) diff --git a/cherab/openadas/repository/beam/population.py b/cherab/openadas/repository/beam/population.py index 54c57df1..9ecfa6eb 100644 --- a/cherab/openadas/repository/beam/population.py +++ b/cherab/openadas/repository/beam/population.py @@ -31,12 +31,24 @@ def add_beam_population_rate(beam_species, beam_metastable, target_ion, target_c """ Adds a single beam population rate to the repository. - :param beam_species: - :param beam_metastable: - :param target_ion: - :param target_charge: - :param rate: - :return: + :param beam_species: Beam neutral species (Element/Isotope). + :param beam_metastable: Metastable level of beam neutral atom. + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param rate: Beam population rate dictionary containing the following entries: + + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n': array-like of size (M) with target electron density in m^-3, + | 't': array-like of size (K) with target electron temperature in eV, + | 'sen': array-like of size (N, M) with dimensionless beam population rate energy component. + | 'st': array-like of size (K) with dimensionless beam population rate temperature component. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference dimensionless beam population rate. + | The total beam population rate: s = sen * st / sref. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -102,11 +114,32 @@ def add_beam_population_rate(beam_species, beam_metastable, target_ion, target_c def update_beam_population_rates(rates, repository_path=None): """ - Beam population rate file structure - + Updates the beam population rate files /beam/population////.json + in the atomic data repository. Each json file contains a single rate, so it can simply be replaced. + + :param rates: Dictionary in the form: + + | { : { : { : {: } } } }, where + | is the beam neutral species (Element/Isotope) + | is the metastable level of beam neutral atom. + | is the target species (Element/Isotope). + | is the charge of the target species. + | is the beam population rate dictionary containing the following fields: + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n': array-like of size (M) with target electron density in m^-3, + | 't': array-like of size (K) with target electron temperature in eV, + | 'sen': array-like of size (N, M) with dimensionless beam population rate energy component. + | 'st': array-like of size (K) with dimensionless beam population rate temperature component. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference dimensionless beam population rate. + | The total beam population rate: s = sen * st / sref. + + :param repository_path: Path to the atomic data repository. """ for beam_species, beam_metastables in rates.items(): @@ -117,6 +150,29 @@ def update_beam_population_rates(rates, repository_path=None): def get_beam_population_rate(beam_species, beam_metastable, target_ion, target_charge, repository_path=None): + """ + Reads a single beam population rate from the repository. + + :param beam_species: Beam neutral species (Element/Isotope). + :param beam_metastable: Metastable level of beam neutral atom. + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param repository_path: Path to the atomic data repository. + + :return rate: Beam population rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n': 1D array of size (M) with target electron density in m^-3, + | 't': 1D array of size (K) with target electron temperature in eV, + | 'sen': 2D array of size (N, M) with dimensionless beam population rate energy component. + | 'st': 1D array of size (K) with dimensionless beam population rate temperature component. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference dimensionless beam population rate. + | The total beam population rate: s = sen * st / sref. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH path = os.path.join(repository_path, 'beam/population/{}/{}/{}/{}.json'.format(beam_species.symbol.lower(), beam_metastable, target_ion.symbol.lower(), target_charge)) diff --git a/cherab/openadas/repository/beam/stopping.py b/cherab/openadas/repository/beam/stopping.py index cf8d1492..46d8caae 100644 --- a/cherab/openadas/repository/beam/stopping.py +++ b/cherab/openadas/repository/beam/stopping.py @@ -31,11 +31,23 @@ def add_beam_stopping_rate(beam_species, target_ion, target_charge, rate, reposi """ Adds a single beam stopping/excitation rate to the repository. - :param beam_species: - :param target_ion: - :param target_charge: - :param rate: - :return: + :param beam_species: Beam neutral atom (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param rate: Beam stopping rate dictionary containing the following entries: + + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n': array-like of size (M) with target electron density in m^-3, + | 't': array-like of size (K) with target electron temperature in eV, + | 'sen': array-like of size (N, M) with beam stopping rate energy component in m^3.s^-1. + | 'st': array-like of size (K) with beam stopping rate temperature component in m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam stopping rate in m^3.s^-1. + | The total beam stopping rate: s = sen * st / sref. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -98,11 +110,30 @@ def add_beam_stopping_rate(beam_species, target_ion, target_charge, rate, reposi def update_beam_stopping_rates(rates, repository_path=None): """ - Beam stopping rate file structure - - /beam/stopping///.json + Updates the beam stopping rate files + /beam/stopping////.json + in the atomic data repository. Each json file contains a single rate, so it can simply be replaced. + + :param rates: Dictionary in the form: + + | { : { : { : {: } } } }, where + | is the beam neutral species (Element/Isotope). + | is the target species (Element/Isotope). + | is the charge of the target species. + | is the beam stopping rate dictionary containing the following entries: + | 'e': array-like of size (N) with interaction energy in eV/amu, + | 'n': array-like of size (M) with target electron density in m^-3, + | 't': array-like of size (K) with target electron temperature in eV, + | 'sen': array-like of size (N, M) with beam stopping rate energy component in m^3.s^-1. + | 'st': array-like of size (K) with beam stopping rate temperature component in m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam stopping rate in m^3.s^-1. + | The total beam stopping rate: s = sen * st / sref. + """ for beam_species, target_ions in rates.items(): @@ -112,6 +143,28 @@ def update_beam_stopping_rates(rates, repository_path=None): def get_beam_stopping_rate(beam_species, target_ion, target_charge, repository_path=None): + """ + Reads a single beam stopping/excitation rate from the repository. + + :param beam_species: Beam neutral atom (Element/Isotope). + :param target_ion: Target species (Element/Isotope). + :param target_charge: Charge of the target species. + :param repository_path: Path to the atomic data repository. + + :return rate: Beam stopping rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n': 1D array of size (M) with target electron density in m^-3, + | 't': 1D array of size (K) with target electron temperature in eV, + | 'sen': 2D array of size (N, M) with beam stopping rate energy component in m^3.s^-1. + | 'st': 1D array of size (K) with beam stopping rate temperature component in m^3.s^-1. + | 'eref': reference interaction energy in eV/amu, + | 'nref': reference target electron density in m^-3, + | 'tref': reference target electron temperature in eV, + | 'sref': reference beam stopping rate in m^3.s^-1. + | The total beam stopping rate: s = sen * st / sref. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH path = os.path.join(repository_path, 'beam/stopping/{}/{}/{}.json'.format(beam_species.symbol.lower(), target_ion.symbol.lower(), target_charge)) diff --git a/cherab/openadas/repository/pec.py b/cherab/openadas/repository/pec.py index 8eb867fc..13fc055e 100644 --- a/cherab/openadas/repository/pec.py +++ b/cherab/openadas/repository/pec.py @@ -1,6 +1,6 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -36,12 +36,16 @@ def add_pec_excitation_rate(element, charge, transition, rate, repository_path=N instead. The update function avoid repeatedly opening and closing the rate files. - :param element: - :param charge: - :param transition: - :param rate: - :param repository_path: - :return: + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param rate: Excitation PEC dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with excitation PEC in photon.m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ update_pec_rates({ @@ -63,12 +67,16 @@ def add_pec_recombination_rate(element, charge, transition, rate, repository_pat instead. The update function avoid repeatedly opening and closing the rate files. - :param element: - :param charge: - :param transition: - :param rate: - :param repository_path: - :return: + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param rate: Recombination PEC dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with recombination PEC in photon.m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ update_pec_rates({ @@ -84,18 +92,22 @@ def add_pec_recombination_rate(element, charge, transition, rate, repository_pat def add_pec_thermalcx_rate(element, charge, transition, rate, repository_path=None): """ - Adds a single PEC thermalcx rate to the repository. + Adds a single PEC thermal charge exchange rate to the repository. If adding multiple rate, consider using the update_pec_rates() function instead. The update function avoid repeatedly opening and closing the rate files. - :param element: - :param charge: - :param transition: - :param rate: - :param repository_path: - :return: + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param rate: Thermal CX PEC dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with thermal CX PEC in photon.m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ update_pec_rates({ @@ -111,9 +123,24 @@ def add_pec_thermalcx_rate(element, charge, transition, rate, repository_path=No def update_pec_rates(rates, repository_path=None): """ - PEC rate file structure + Updates the PEC files /pec///.json. + in the atomic data repository. + + File contains multiple PECs, indexed by the transition. + + :param rates: Dictionary in the form: - /pec///.json + | { : { : { : { : } } } }, where + | is the one of the following PEC types: 'excitation', 'recombination', 'thermalcx'. + | is the plasma species (Element/Isotope). + | is the charge of the plasma species. + | is the tuple containing (initial level, final level). + | is the PEC dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with PEC in photon.m^3.s^-1. + + :param repository_path: Path to the atomic data repository. """ valid_classes = [ @@ -184,14 +211,64 @@ def update_pec_rates(rates, repository_path=None): def get_pec_excitation_rate(element, charge, transition, repository_path=None): + """ + Reads the excitation PEC from the repository for the given + element, charge and transition. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return rate: Excitation PEC dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with excitation PEC in photon.m^3.s^-1. + + """ + return _get_pec_rate('excitation', element, charge, transition, repository_path) def get_pec_recombination_rate(element, charge, transition, repository_path=None): + """ + Reads the recombination PEC from the repository for the given + element, charge and transition. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return rate: Recombination PEC dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with recombination PEC in photon.m^3.s^-1. + + """ + return _get_pec_rate('recombination', element, charge, transition, repository_path) def get_pec_thermalcx_rate(element, charge, transition, repository_path=None): + """ + Reads the thermal charge exchange PEC from the repository for the given + element, charge and transition. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return rate: Thermal CX PEC dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with thermal CX PEC in photon.m^3.s^-1. + + """ return _get_pec_rate('thermalcx', element, charge, transition, repository_path) diff --git a/cherab/openadas/repository/radiated_power.py b/cherab/openadas/repository/radiated_power.py index a6a4b390..7b908cfc 100644 --- a/cherab/openadas/repository/radiated_power.py +++ b/cherab/openadas/repository/radiated_power.py @@ -1,7 +1,7 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -29,13 +29,21 @@ def add_line_power_rate(species, charge, rate, repository_path=None): """ - Adds a single LineRadiationPower rate to the repository. + Adds a single line radiated power rate to the repository. If adding multiple rates, consider using the update_line_power_rates() function instead. The update function avoids repeatedly opening and closing the rate files. - :param repository_path: + :param species: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param rate: Line radiated power rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with line radiated power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ update_line_power_rates({ @@ -47,13 +55,22 @@ def add_line_power_rate(species, charge, rate, repository_path=None): def update_line_power_rates(rates, repository_path=None): """ - Update the repository of LineRadiationPower rates. - - LineRadiationPower rate file structure - + Update the files for the line radiated power rates: /radiated_power/line/.json + in the atomic data repository. File contains multiple rates, indexed by the ion's charge state. + + :param rates: Dictionary in the form {: {: }}, where + + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the line radiated rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with line radiated power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -71,13 +88,21 @@ def update_line_power_rates(rates, repository_path=None): def add_continuum_power_rate(species, charge, rate, repository_path=None): """ - Adds a single ContinuumPower rate to the repository. + Adds a single continuum power rate to the repository. If adding multiple rates, consider using the update_continuum_power_rates() function instead. The update function avoids repeatedly opening and closing the rate files. - :param repository_path: + :param species: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param rate: Continuum power rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with continuum power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ update_line_power_rates({ @@ -89,13 +114,22 @@ def add_continuum_power_rate(species, charge, rate, repository_path=None): def update_continuum_power_rates(rates, repository_path=None): """ - Update the repository of ContinuumPower rates. - - ContinuumPower rate file structure - + Update the files for the continuum power rates: /radiated_power/continuum/.json + in the atomic data repository. File contains multiple rates, indexed by ion's charge state. + + :param rates: Dictionary in the form {: {: }}, where + + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the continuum power rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with continuum power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -113,13 +147,22 @@ def update_continuum_power_rates(rates, repository_path=None): def add_cx_power_rate(species, charge, rate, repository_path=None): """ - Adds a single CXRadiationPower rate to the repository. + Adds a single CX radiation power rate to the repository + (charge exchage with neutral hydrogen). If adding multiple rates, consider using the update_cx_power_rates() function instead. The update function avoids repeatedly opening and closing the rate files. - :param repository_path: + :param species: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param rate: CX power rate dictionary containing the following entries: + + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with CX power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ update_line_power_rates({ @@ -131,13 +174,23 @@ def add_cx_power_rate(species, charge, rate, repository_path=None): def update_cx_power_rates(rates, repository_path=None): """ - Update the repository of CXRadiationPower rates. - - CXRadiationPower rate file structure - + Update the files for the CX radiation power rates + (charge exchage with neutral hydrogen): /radiated_power/cx/.json + in the atomic data repository. File contains multiple rates, indexed by ion's charge state. + + :param rates: Dictionary in the form {: {: }}, where + + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the thermal CX power rate dictionary containing the following entries: + | 'ne': array-like of size (N) with electron density in m^-3, + | 'te': array-like of size (M) with electron temperature in eV, + | 'rate': array-like of size (N, M) with thermal CX power rate in W.m^3. + + :param repository_path: Path to the atomic data repository. """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -199,6 +252,21 @@ def _update_and_write_adf11(species, rate_data, path): def get_line_radiated_power_rate(element, charge, repository_path=None): + """ + Reads the line radiated power rate for the given species and charge + from the atomic data repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param repository_path: Path to the atomic data repository. + + :return rate: Line radiated power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with line radiated power rate in W.m^3. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -220,6 +288,21 @@ def get_line_radiated_power_rate(element, charge, repository_path=None): def get_continuum_radiated_power_rate(element, charge, repository_path=None): + """ + Reads the continuum power rate for the given species and charge + from the atomic data repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param repository_path: Path to the atomic data repository. + + :return rate: Continuum power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with continuum power rate in W.m^3. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -241,6 +324,21 @@ def get_continuum_radiated_power_rate(element, charge, repository_path=None): def get_cx_radiated_power_rate(element, charge, repository_path=None): + """ + Reads the CX radiation power rate for the given species and charge + from the atomic data repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param repository_path: Path to the atomic data repository. + + :return rate: CX radiation power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with CX radiation power rate in W.m^3. + + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH diff --git a/cherab/openadas/repository/wavelength.py b/cherab/openadas/repository/wavelength.py index 5981e9e6..83758f51 100644 --- a/cherab/openadas/repository/wavelength.py +++ b/cherab/openadas/repository/wavelength.py @@ -1,6 +1,6 @@ -# Copyright 2016-2018 Euratom -# Copyright 2016-2018 United Kingdom Atomic Energy Authority -# Copyright 2016-2018 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -35,11 +35,11 @@ def add_wavelength(element, charge, transition, wavelength, repository_path=None function instead. The update function avoid repeatedly opening and closing the rate files. - :param element: - :param charge: - :param transition: - :param wavelength: - :param repository_path: + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param wavelength: Transition's wavelength in nm. + :param repository_path: Path to the atomic data repository. """ update_wavelengths({ @@ -52,6 +52,22 @@ def add_wavelength(element, charge, transition, wavelength, repository_path=None def update_wavelengths(wavelengths, repository_path=None): + """ + Updates the wavelength files `/wavelength//.json` + in atomic data repository. + + File contains multiple rates, indexed by the transitions. + + :param wavelengths: Dictionary in the form: + + | { : { : { : } } }, where + | is the plasma species (Element/Isotope), + | is the charge of the plasma species, + | is the tuple containing (initial level, final level), + | is the transition's wavelength in nm. + + :param repository_path: Path to the atomic data repository. + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH @@ -90,6 +106,16 @@ def update_wavelengths(wavelengths, repository_path=None): def get_wavelength(element, charge, transition, repository_path=None): + """ + Reads the wavelength for the given species, charge and transition from the repository. + + :param element: Plasma species (Element/Isotope). + :param charge: Charge of the plasma species. + :param transition: Tuple containing (initial level, final level). + :param repository_path: Path to the atomic data repository. + + :return wavelength: Wavelength in nm. + """ repository_path = repository_path or DEFAULT_REPOSITORY_PATH path = os.path.join(repository_path, 'wavelength/{}/{}.json'.format(element.symbol.lower(), charge)) diff --git a/docs/source/atomic/atomic_data.rst b/docs/source/atomic/atomic_data.rst index 650d89b4..802943af 100644 --- a/docs/source/atomic/atomic_data.rst +++ b/docs/source/atomic/atomic_data.rst @@ -7,3 +7,5 @@ Atomic Data emission_lines rate_coefficients gaunt_factors + repository + openadas \ No newline at end of file diff --git a/docs/source/atomic/openadas.rst b/docs/source/atomic/openadas.rst new file mode 100644 index 00000000..3dde4242 --- /dev/null +++ b/docs/source/atomic/openadas.rst @@ -0,0 +1,29 @@ +Open-ADAS +--------- + +Although a typical Open-ADAS data set is installed to the local atomic data repository +using the `populate()` function, additional atomic data can be installed manually. + +The following functions allow to parse the Open-ADAS files and install the rates of the atomic processes +to the local atomic data repository. + +Parse +^^^^^ + +.. autofunction:: cherab.openadas.parse.adf11.parse_adf11 + +.. autofunction:: cherab.openadas.parse.adf12.parse_adf12 + +.. autofunction:: cherab.openadas.parse.adf15.parse_adf15 + +.. autofunction:: cherab.openadas.parse.adf21.parse_adf21 + +.. autofunction:: cherab.openadas.parse.adf22.parse_adf22bmp + +.. autofunction:: cherab.openadas.parse.adf22.parse_adf22bme + +Install +^^^^^^^ + +.. automodule:: cherab.openadas.install + :members: diff --git a/docs/source/atomic/repository.rst b/docs/source/atomic/repository.rst new file mode 100644 index 00000000..3a93085e --- /dev/null +++ b/docs/source/atomic/repository.rst @@ -0,0 +1,83 @@ + +Atomic data repository +---------------------- + +The following functions allow to manipulate the local atomic data repository: +add the rates of the atomic processes, update existing ones or get the data +already present in the repository. + +The default repository is created at `~/.cherab/openadas/repository`. +Cherab supports multiple atomic data repositories. The user can configure different +repositories by setting the `repository_path` parameter. +The data in these repositories can be accessed through the `OpenADAS` atomic data provider +by specifying the `data_path` parameter. + +To create the new atomic data repository at the default location and populate it with a typical +set of rates and wavelengths from Open-ADAS, do: + +.. code-block:: pycon + + >>> from cherab.openadas.repository import populate + >>> populate() + +.. autofunction:: cherab.openadas.repository.create.populate + +Wavelength +^^^^^^^^^^ + +.. automodule:: cherab.openadas.repository.wavelength + :members: + +Ionisation +^^^^^^^^^^ + +.. autofunction:: cherab.openadas.repository.atomic.add_ionisation_rate + +.. autofunction:: cherab.openadas.repository.atomic.get_ionisation_rate + +.. autofunction:: cherab.openadas.repository.atomic.update_ionisation_rates + +Recombination +^^^^^^^^^^^^^ + +.. autofunction:: cherab.openadas.repository.atomic.add_recombination_rate + +.. autofunction:: cherab.openadas.repository.atomic.get_recombination_rate + +.. autofunction:: cherab.openadas.repository.atomic.update_recombination_rates + +Thermal Charge Exchange +^^^^^^^^^^^^^^^^^^^^^^^ + +.. autofunction:: cherab.openadas.repository.atomic.add_thermal_cx_rate + +.. autofunction:: cherab.openadas.repository.atomic.get_thermal_cx_rate + +.. autofunction:: cherab.openadas.repository.atomic.update_thermal_cx_rates + +Photon Emissivity Coefficients +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. automodule:: cherab.openadas.repository.pec + :members: + +Radiated Power +^^^^^^^^^^^^^^ + +.. automodule:: cherab.openadas.repository.radiated_power + :members: + +Beam +^^^^ + +.. automodule:: cherab.openadas.repository.beam.cx + :members: + +.. automodule:: cherab.openadas.repository.beam.emission + :members: + +.. automodule:: cherab.openadas.repository.beam.population + :members: + +.. automodule:: cherab.openadas.repository.beam.stopping + :members: From 9710d18a2956bbc815649d17450c6e8dcc495efe Mon Sep 17 00:00:00 2001 From: vsnever Date: Sat, 27 Jul 2024 21:18:29 +0200 Subject: [PATCH 09/11] Improve documentation for openadas atomic data interpolators. --- cherab/openadas/rates/atomic.pyx | 78 +++++++++++++++----- cherab/openadas/rates/beam.pyx | 81 +++++++++++++++++---- cherab/openadas/rates/cx.pyx | 50 ++++++++++--- cherab/openadas/rates/pec.pyx | 58 +++++++++++---- cherab/openadas/rates/radiated_power.pyx | 69 ++++++++++++++++-- docs/source/atomic/atomic_data.rst | 1 + docs/source/atomic/data_interpolators.rst | 89 +++++++++++++++++++++++ docs/source/atomic/rate_coefficients.rst | 31 +++++++- 8 files changed, 393 insertions(+), 64 deletions(-) create mode 100644 docs/source/atomic/data_interpolators.rst diff --git a/cherab/openadas/rates/atomic.pyx b/cherab/openadas/rates/atomic.pyx index 04500124..903baf9f 100644 --- a/cherab/openadas/rates/atomic.pyx +++ b/cherab/openadas/rates/atomic.pyx @@ -1,7 +1,7 @@ -# Copyright 2016-2021 Euratom -# Copyright 2016-2021 United Kingdom Atomic Energy Authority -# Copyright 2016-2021 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -24,12 +24,26 @@ from raysect.core.math.function.float cimport Interpolator2DArray cdef class IonisationRate(CoreIonisationRate): + """ + Ionisation rate. + + Data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param dict data: Ionisation rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with ionisation rate in m^3.s^-1. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, dict data, extrapolate=False): - """ - :param data: Dictionary containing rate data. - :param extrapolate: Enable extrapolation (default=False). - """ self.raw_data = data @@ -62,7 +76,7 @@ cdef class IonisationRate(CoreIonisationRate): cdef class NullIonisationRate(CoreIonisationRate): """ - A PEC rate that always returns zero. + An ionisation rate that always returns zero. Needed for use cases where the required atomic data is missing. """ @@ -71,12 +85,26 @@ cdef class NullIonisationRate(CoreIonisationRate): cdef class RecombinationRate(CoreRecombinationRate): + """ + Recombination rate. + + Data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param dict data: Recombination rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with recombination rate in m^3.s^-1. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, dict data, extrapolate=False): - """ - :param data: Dictionary containing rate data. - :param extrapolate: Enable extrapolation (default=False). - """ self.raw_data = data @@ -109,7 +137,7 @@ cdef class RecombinationRate(CoreRecombinationRate): cdef class NullRecombinationRate(CoreRecombinationRate): """ - A PEC rate that always returns zero. + A recombination rate that always returns zero. Needed for use cases where the required atomic data is missing. """ @@ -118,12 +146,26 @@ cdef class NullRecombinationRate(CoreRecombinationRate): cdef class ThermalCXRate(CoreThermalCXRate): + """ + Thermal charge exchange rate. + + Data is interpolated with cubic spline in log-log space. + Linear extrapolation is used if extrapolate is True. + + :param dict data: CX rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with thermal CX rate in m^3.s^-1. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, dict data, extrapolate=False): - """ - :param data: Dictionary containing rate data. - :param extrapolate: Enable extrapolation (default=False). - """ self.raw_data = data @@ -155,7 +197,7 @@ cdef class ThermalCXRate(CoreThermalCXRate): cdef class NullThermalCXRate(CoreThermalCXRate): """ - A PEC rate that always returns zero. + A thermal CX rate that always returns zero. Needed for use cases where the required atomic data is missing. """ diff --git a/cherab/openadas/rates/beam.pyx b/cherab/openadas/rates/beam.pyx index f40af8dd..7059e243 100644 --- a/cherab/openadas/rates/beam.pyx +++ b/cherab/openadas/rates/beam.pyx @@ -1,6 +1,6 @@ -# Copyright 2016-2021 Euratom -# Copyright 2016-2021 United Kingdom Atomic Energy Authority -# Copyright 2016-2021 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -31,8 +31,26 @@ cdef class BeamStoppingRate(CoreBeamStoppingRate): """ The beam stopping coefficient interpolation class. - :param data: A dictionary holding the beam coefficient data. - :param extrapolate: Set to True to enable extrapolation, False to disable (default). + Data is interpolated with cubic spline in log-log space. + Linear and quadratic extrapolations are used for "sen" and "st" respectively + if extrapolate is True. + + :param dict data: A beam stopping rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n': 1D array of size (M) with target electron density in m^-3, + | 't': 1D array of size (K) with target electron temperature in eV, + | 'sen': 2D array of size (N, M) with beam stopping rate energy component in m^3.s^-1. + | 'st': 1D array of size (K) with beam stopping rate temperature component in m^3.s^-1. + | 'sref': reference beam stopping rate in m^3.s^-1. + | The total beam stopping rate: s = sen * st / sref. + + :param bint extrapolate: Set to True to enable extrapolation, False to disable (default). + + :ivar tuple beam_energy_range: Interaction energy interpolation range. + :ivar tuple density_range: Target electron density interpolation range. + :ivar tuple temperature_range: Target electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. """ @cython.cdivision(True) @@ -93,7 +111,7 @@ cdef class BeamStoppingRate(CoreBeamStoppingRate): cdef class NullBeamStoppingRate(CoreBeamStoppingRate): """ - A beam rate that always returns zero. + A beam stopping rate that always returns zero. Needed for use cases where the required atomic data is missing. """ @@ -105,8 +123,26 @@ cdef class BeamPopulationRate(CoreBeamPopulationRate): """ The beam population coefficient interpolation class. - :param data: A dictionary holding the beam coefficient data. - :param extrapolate: Set to True to enable extrapolation, False to disable (default). + Data is interpolated with cubic spline in log-log space. + Linear and quadratic extrapolations are used for "sen" and "st" respectively + if extrapolate is True. + + :param dict data: Beam population rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n': 1D array of size (M) with target electron density in m^-3, + | 't': 1D array of size (K) with target electron temperature in eV, + | 'sen': 2D array of size (N, M) with dimensionless beam population rate energy component. + | 'st': 1D array of size (K) with dimensionless beam population rate temperature component. + | 'sref': reference dimensionless beam population rate. + | The total beam population rate: s = sen * st / sref. + + :param bint extrapolate: Set to True to enable extrapolation, False to disable (default). + + :ivar tuple beam_energy_range: Interaction energy interpolation range. + :ivar tuple density_range: Target electron density interpolation range. + :ivar tuple temperature_range: Target electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. """ @cython.cdivision(True) @@ -167,7 +203,7 @@ cdef class BeamPopulationRate(CoreBeamPopulationRate): cdef class NullBeamPopulationRate(CoreBeamPopulationRate): """ - A beam rate that always returns zero. + A beam population rate that always returns zero. Needed for use cases where the required atomic data is missing. """ @@ -179,9 +215,26 @@ cdef class BeamEmissionPEC(CoreBeamEmissionPEC): """ The beam emission coefficient interpolation class. - :param data: A dictionary holding the beam coefficient data. - :param wavelength: The natural wavelength of the emission line associated with the rate data in nm. - :param extrapolate: Set to True to enable extrapolation, False to disable (default). + Data is interpolated with cubic spline in log-log space. + Linear and quadratic extrapolations are used for "sen" and "st" respectively + if extrapolate is True. + + :param dict data: Beam emission rate dictionary containing the following entries: + + | 'e': 1D array of size (N) with interaction energy in eV/amu, + | 'n' 1D array of size (M) with target electron density in m^-3, + | 't' 1D array of size (K) with target electron temperature in eV, + | 'sen' 2D array of size (N, M) with beam emission rate energy component in photon.m^3.s^-1. + | 'st' 1D array of size (K) with beam emission rate temperature component in photon.m^3.s^-1. + | 'sref': reference beam emission rate in photon.m^3.s^-1. + + :param double wavelength: The natural wavelength of the emission line associated with the rate data in nm. + :param bint extrapolate: Set to True to enable extrapolation, False to disable (default). + + :ivar tuple beam_energy_range: Interaction energy interpolation range. + :ivar tuple density_range: Target electron density interpolation range. + :ivar tuple temperature_range: Target electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. """ @cython.cdivision(True) @@ -194,7 +247,7 @@ cdef class BeamEmissionPEC(CoreBeamEmissionPEC): e = data["e"] # eV/amu n = data["n"] # m^-3 t = data["t"] # eV - sen = np.log10(PhotonToJ.to(data["sen"], wavelength)) # W.m^3/s + sen = np.log10(PhotonToJ.to(data["sen"], wavelength)) # W.m^3 st = np.log10(data["st"] / data["sref"]) # dimensionless # store limits of data @@ -243,7 +296,7 @@ cdef class BeamEmissionPEC(CoreBeamEmissionPEC): cdef class NullBeamEmissionPEC(CoreBeamEmissionPEC): """ - A beam rate that always returns zero. + A beam emission PEC that always returns zero. Needed for use cases where the required atomic data is missing. """ diff --git a/cherab/openadas/rates/cx.pyx b/cherab/openadas/rates/cx.pyx index cb827a8b..ef6ff535 100644 --- a/cherab/openadas/rates/cx.pyx +++ b/cherab/openadas/rates/cx.pyx @@ -1,6 +1,6 @@ -# Copyright 2016-2021 Euratom -# Copyright 2016-2021 United Kingdom Atomic Energy Authority -# Copyright 2016-2021 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -26,12 +26,42 @@ from raysect.core.math.function.float cimport Interpolator1DArray, Constant1D cdef class BeamCXPEC(CoreBeamCXPEC): """ - The effective cx rate interpolation class. - - :param donor_metastable: The metastable state of the donor species for which the rate data applies. - :param wavelength: The natural wavelength of the emission line associated with the rate data in nm. - :param data: A dictionary holding the rate data. - :param extrapolate: Set to True to enable extrapolation, False to disable (default). + Effective charge exchange photon emission coefficient. + + The data for "qeb" is interpolated with a cubic spline in log-log space. + The data for "qti", "qni", "qz" and "qb" are interpolated with a cubic spline + in linear space. + + Quadratic extrapolation is used for "qeb" and nearest neighbour extrapolation is used for + "qti", "qni", "qz" and "qb" if extrapolate is True. + + :param int donor_metastable: The metastable state of the donor species for which the rate data applies. + :param double wavelength: The natural wavelength of the emission line associated with the rate data in nm. + :param data: Beam CX PEC dictionary containing the following entries: + + | 'eb': 1D array of size (N) with beam energy in eV/amu, + | 'ti': 1D array of size (M) with receiver ion temperature in eV, + | 'ni': 1D array of size (K) with receiver ion density in m^-3, + | 'z': 1D array of size (L) with receiver Z-effective, + | 'b': 1D array of size (J) with magnetic field strength in Tesla, + | 'qeb': 1D array of size (N) with CX PEC energy component in photon.m^3.s-1, + | 'qti': 1D array of size (M) with CX PEC temperature component in photon.m^3.s-1, + | 'qni': 1D array of size (K) with CX PEC density component in photon.m^3.s-1, + | 'qz': 1D array of size (L) with CX PEC Zeff component in photon.m^3.s-1, + | 'qb': 1D array of size (J) with CX PEC B-field component in photon.m^3.s-1, + | 'qref': reference CX PEC in photon.m^3.s-1. + | The total beam CX PEC: q = qeb * qti * qni * qz * qb / qref^4. + + :param bint extrapolate: Set to True to enable extrapolation, False to disable (default). + + :ivar tuple beam_energy_range: Interaction energy interpolation range. + :ivar tuple density_range: Receiver ion density interpolation range. + :ivar tuple temperature_range: Receiver ion temperature interpolation range. + :ivar tuple zeff_range: Z-effective interpolation range. + :ivar tuple b_field_range: Magnetic field strength interpolation range. + :ivar int donor_metastable: The metastable state of the donor species. + :ivar double wavelength: The natural wavelength of the emission line in nm. + :ivar dict raw_data: Dictionary containing the raw data. """ @cython.cdivision(True) @@ -79,7 +109,7 @@ cdef class BeamCXPEC(CoreBeamCXPEC): :param energy: Interaction energy in eV/amu. :param temperature: Receiver ion temperature in eV. - :param density: Receiver ion density in m^-3 + :param density: Plasma total ion density in m^-3 :param z_effective: Plasma Z-effective. :param b_field: Magnetic field magnitude in Tesla. :return: The effective cx rate in W.m^3 diff --git a/cherab/openadas/rates/pec.pyx b/cherab/openadas/rates/pec.pyx index eafc6c64..fb6f392c 100644 --- a/cherab/openadas/rates/pec.pyx +++ b/cherab/openadas/rates/pec.pyx @@ -1,6 +1,6 @@ -# Copyright 2016-2021 Euratom -# Copyright 2016-2021 United Kingdom Atomic Energy Authority -# Copyright 2016-2021 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -25,13 +25,27 @@ from cherab.core.utility.conversion import PhotonToJ cdef class ImpactExcitationPEC(CoreImpactExcitationPEC): + """ + Electron impact excitation photon emission coefficient. + + The data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param double wavelength: Resting wavelength of corresponding emission line in nm. + :param dict data: Excitation PEC dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with excitation PEC in photon.m^3.s^-1. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, double wavelength, dict data, extrapolate=False): - """ - :param wavelength: Resting wavelength of corresponding emission line in nm. - :param data: Dictionary containing rate data. - :param extrapolate: Enable extrapolation (default=False). - """ self.wavelength = wavelength self.raw_data = data @@ -68,7 +82,7 @@ cdef class ImpactExcitationPEC(CoreImpactExcitationPEC): cdef class NullImpactExcitationPEC(CoreImpactExcitationPEC): """ - A PEC rate that always returns zero. + A electron impact excitation PEC rate that always returns zero. Needed for use cases where the required atomic data is missing. """ @@ -77,13 +91,27 @@ cdef class NullImpactExcitationPEC(CoreImpactExcitationPEC): cdef class RecombinationPEC(CoreRecombinationPEC): + """ + Recombination photon emission coefficient. + + The data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param double wavelength: Resting wavelength of corresponding emission line in nm. + :param dict data: Rcombination PEC dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with recombination PEC in photon.m^3.s^-1. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, double wavelength, dict data, extrapolate=False): - """ - :param wavelength: Resting wavelength of corresponding emission line in nm. - :param data: Dictionary containing rate data. - :param extrapolate: Enable extrapolation (default=False). - """ self.wavelength = wavelength self.raw_data = data @@ -120,7 +148,7 @@ cdef class RecombinationPEC(CoreRecombinationPEC): cdef class NullRecombinationPEC(CoreRecombinationPEC): """ - A PEC rate that always returns zero. + A recombination PEC rate that always returns zero. Needed for use cases where the required atomic data is missing. """ diff --git a/cherab/openadas/rates/radiated_power.pyx b/cherab/openadas/rates/radiated_power.pyx index 570ced92..32371c8f 100644 --- a/cherab/openadas/rates/radiated_power.pyx +++ b/cherab/openadas/rates/radiated_power.pyx @@ -1,7 +1,7 @@ -# Copyright 2016-2021 Euratom -# Copyright 2016-2021 United Kingdom Atomic Energy Authority -# Copyright 2016-2021 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas +# Copyright 2016-2024 Euratom +# Copyright 2016-2024 United Kingdom Atomic Energy Authority +# Copyright 2016-2024 Centro de Investigaciones Energéticas, Medioambientales y Tecnológicas # # Licensed under the EUPL, Version 1.1 or – as soon they will be approved by the # European Commission - subsequent versions of the EUPL (the "Licence"); @@ -24,7 +24,26 @@ from raysect.core.math.function.float cimport Interpolator2DArray cdef class LineRadiationPower(CoreLineRadiationPower): - """Base class for radiated powers.""" + """ + Line radiated power coefficient. + + The data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param Element species: Element object defining the ion type. + :param int ionisation: Charge state of the ion. + :param dict data: Line radiated power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with radiated power rate in W.m^3. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, species, ionisation, dict data, extrapolate=False): @@ -70,7 +89,26 @@ cdef class NullLineRadiationPower(CoreLineRadiationPower): cdef class ContinuumPower(CoreContinuumPower): - """Base class for radiated powers.""" + """ + Recombination continuum radiated power coefficient. + + The data is interpolated with cubic spline in log-log space. + Nearest neighbour extrapolation is used if extrapolate is True. + + :param Element species: Element object defining the ion type. + :param int ionisation: Charge state of the ion. + :param dict data: Recombination continuum radiated power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with radiated power rate in W.m^3. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, species, ionisation, dict data, extrapolate=False): @@ -116,7 +154,26 @@ cdef class NullContinuumPower(CoreContinuumPower): cdef class CXRadiationPower(CoreCXRadiationPower): - """Base class for radiated powers.""" + """ + Charge exchange radiated power coefficient. + + The data is interpolated with cubic spline in log-log space. + Linear extrapolation is used if extrapolate is True. + + :param Element species: Element object defining the ion type. + :param int ionisation: Charge state of the ion. + :param dict data: CX radiated power rate dictionary containing the following entries: + + | 'ne': 1D array of size (N) with electron density in m^-3, + | 'te': 1D array of size (M) with electron temperature in eV, + | 'rate': 2D array of size (N, M) with radiated power rate in W.m^3. + + :param bint extrapolate: Enable extrapolation (default=False). + + :ivar tuple density_range: Electron density interpolation range. + :ivar tuple temperature_range: Electron temperature interpolation range. + :ivar dict raw_data: Dictionary containing the raw data. + """ def __init__(self, species, ionisation, dict data, extrapolate=False): diff --git a/docs/source/atomic/atomic_data.rst b/docs/source/atomic/atomic_data.rst index 650d89b4..edd24b0d 100644 --- a/docs/source/atomic/atomic_data.rst +++ b/docs/source/atomic/atomic_data.rst @@ -7,3 +7,4 @@ Atomic Data emission_lines rate_coefficients gaunt_factors + data_interpolators diff --git a/docs/source/atomic/data_interpolators.rst b/docs/source/atomic/data_interpolators.rst new file mode 100644 index 00000000..56fa0327 --- /dev/null +++ b/docs/source/atomic/data_interpolators.rst @@ -0,0 +1,89 @@ +Atomic data interpolators +========================= + +The following classes interpolate atomic data defined on a numerical grid. + + +Atomic Processes +^^^^^^^^^^^^^^^^ + +.. autoclass:: cherab.openadas.rates.atomic.IonisationRate + :members: + +.. autoclass:: cherab.openadas.rates.atomic.NullIonisationRate + :members: + +.. autoclass:: cherab.openadas.rates.atomic.RecombinationRate + :members: + +.. autoclass:: cherab.openadas.rates.atomic.NullRecombinationRate + :members: + +.. autoclass:: cherab.openadas.rates.atomic.ThermalCXRate + :members: + +.. autoclass:: cherab.openadas.rates.atomic.NullThermalCXRate + :members: + +Photon Emissivity Coefficients +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: cherab.openadas.rates.pec.ImpactExcitationPEC + :members: + +.. autoclass:: cherab.openadas.rates.pec.NullImpactExcitationPEC + :members: + +.. autoclass:: cherab.openadas.rates.pec.RecombinationPEC + :members: + +.. autoclass:: cherab.openadas.rates.pec.NullRecombinationPEC + :members: + +Beam-Plasma Interaction Rates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: cherab.openadas.rates.cx.BeamCXPEC + :members: + +.. autoclass:: cherab.openadas.rates.cx.NullBeamCXPEC + :members: + +.. autoclass:: cherab.openadas.rates.beam.BeamStoppingRate + :members: + +.. autoclass:: cherab.openadas.rates.beam.NullBeamStoppingRate + :members: + +.. autoclass:: cherab.openadas.rates.beam.BeamPopulationRate + :members: + +.. autoclass:: cherab.openadas.rates.beam.NullBeamPopulationRate + :members: + +.. autoclass:: cherab.openadas.rates.beam.BeamEmissionPEC + :members: + +.. autoclass:: cherab.openadas.rates.beam.NullBeamEmissionPEC + :members: + +Radiated Power +^^^^^^^^^^^^^^ + +.. autoclass:: cherab.openadas.rates.radiated_power.LineRadiationPower + :members: + +.. autoclass:: cherab.openadas.rates.radiated_power.NullLineRadiationPower + :members: + +.. autoclass:: cherab.openadas.rates.radiated_power.ContinuumPower + :members: + +.. autoclass:: cherab.openadas.rates.radiated_power.NullContinuumPower + :members: + +.. autoclass:: cherab.openadas.rates.radiated_power.CXRadiationPower + :members: + +.. autoclass:: cherab.openadas.rates.radiated_power.NullCXRadiationPower + :members: diff --git a/docs/source/atomic/rate_coefficients.rst b/docs/source/atomic/rate_coefficients.rst index b6547820..82116bf3 100644 --- a/docs/source/atomic/rate_coefficients.rst +++ b/docs/source/atomic/rate_coefficients.rst @@ -15,6 +15,35 @@ provide theoretical equations. Cherab emission models only need to know how to c them after they have been instantiated. +Atomic Processes +^^^^^^^^^^^^^^^^ + +.. autoclass:: cherab.core.atomic.rates.IonisationRate + +.. autoclass:: cherab.core.atomic.rates.RecombinationRate + +.. autoclass:: cherab.core.atomic.rates.ThermalCXRate + +The `IonisationRate`, `RecombinationRate` and `ThermalCXRate` classes all share +the same call signatures. + +.. function:: __call__(density, temperature) + + Returns an effective rate coefficient at the specified plasma conditions. + + This function just wraps the cython evaluate() method. + +.. function:: evaluate(density, temperature) + + an effective recombination rate coefficient at the specified plasma conditions. + + This function needs to be implemented by the atomic data provider. + + :param float density: Electron density in m^-3 + :param float temperature: Electron temperature in eV. + :return: The effective ionisation rate in [m^3.s^-1]. + + Photon Emissivity Coefficients ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,8 +68,8 @@ the same call signatures. This function needs to be implemented by the atomic data provider. - :param float temperature: Receiver ion temperature in eV. :param float density: Receiver ion density in m^-3 + :param float temperature: Receiver ion temperature in eV. :return: The effective PEC rate [Wm^3]. Some example code for requesting PEC objects and sampling them with the __call__() From ccdd28072a2f4463ca3809c75319f318250b7137 Mon Sep 17 00:00:00 2001 From: vsnever Date: Tue, 30 Jul 2024 23:58:33 +0200 Subject: [PATCH 10/11] Update CHANGELOG. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c70837fb..a71951eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ New: * **Beam dispersion calculation has changed from sigma(z) = sigma + z * tan(alpha) to sigma(z) = sqrt(sigma^2 + (z * tan(alpha))^2) for consistancy with the Gaussian beam model. Attention!!! The results of BES and CX spectroscopy are affected by this change. (#414)** * Improved beam direction calculation to allow for natural broadening of the BES line shape due to beam divergence. (#414) * Add kwargs to invert_regularised_nnls to pass them to scipy.optimize.nnls. (#438) +* All interpolated atomic rates now return 0 if plasma parameters <= 0, which matches the behaviour of emission models. (#450) Bug fixes: * Fix deprecated transforms being cached in LaserMaterial after laser.transform update (#420) From b173acc02df33cd199dcdb7ac00d2a09c91fc1a7 Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 31 Jul 2024 00:03:27 +0200 Subject: [PATCH 11/11] Add an empty line after code-block directive. --- cherab/core/model/beam/charge_exchange.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/cherab/core/model/beam/charge_exchange.pyx b/cherab/core/model/beam/charge_exchange.pyx index 83fe237f..9eb562a0 100644 --- a/cherab/core/model/beam/charge_exchange.pyx +++ b/cherab/core/model/beam/charge_exchange.pyx @@ -61,6 +61,7 @@ cdef class BeamCXLine(BeamModel): :ivar Line line: The emission line object. .. code-block:: pycon + >>> from cherab.core.model import BeamCXLine >>> from cherab.core.atomic import carbon >>> from cherab.core.model import ParametrisedZeemanTriplet