From d4b0b99830ef523c8626ce82aef7b2ab3c9bd65b Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 16 Jun 2021 20:00:22 +0300 Subject: [PATCH 01/81] Added first spectroscopic instruments. --- .../tools/observers/spectroscopy/__init__.py | 20 ++ .../observers/spectroscopy/instrument.py | 84 ++++++ .../observers/spectroscopy/polychromator.py | 150 ++++++++++ .../observers/spectroscopy/spectrometer.py | 273 ++++++++++++++++++ 4 files changed, 527 insertions(+) create mode 100644 cherab/tools/observers/spectroscopy/__init__.py create mode 100644 cherab/tools/observers/spectroscopy/instrument.py create mode 100644 cherab/tools/observers/spectroscopy/polychromator.py create mode 100644 cherab/tools/observers/spectroscopy/spectrometer.py diff --git a/cherab/tools/observers/spectroscopy/__init__.py b/cherab/tools/observers/spectroscopy/__init__.py new file mode 100644 index 00000000..1d8cb4cd --- /dev/null +++ b/cherab/tools/observers/spectroscopy/__init__.py @@ -0,0 +1,20 @@ + +# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# +# 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from .instrument import SpectroscopicInstrument +from .polychromator import PolychromatorFilter, Polychromator +from .spectrometer import Spectrometer, CzernyTurnerSpectrometer, SurveySpectrometer diff --git a/cherab/tools/observers/spectroscopy/instrument.py b/cherab/tools/observers/spectroscopy/instrument.py new file mode 100644 index 00000000..b3d6c65d --- /dev/null +++ b/cherab/tools/observers/spectroscopy/instrument.py @@ -0,0 +1,84 @@ + +# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# +# 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +class SpectroscopicInstrument: + """ + Base class for spectroscopic instruments (spectrometers, polychromators, etc.). + This is an abstract class. + + :param str name: Instrument name. + """ + + def __init__(self, name=''): + self.name = name + self._clear_spectral_settings() + + @property + def name(self): + """ Instrument name.""" + return self._name + + @name.setter + def name(self, value): + self._name = str(value) + self._pipeline_properties = None + + @property + def pipeline_properties(self): + """ + The list of properties (class, name, filter) of the pipelines used with + this instrument. + """ + if self._pipeline_properties is None: + self._update_pipeline_properties() + + return self._pipeline_properties + + @property + def min_wavelength(self): + """ Lower wavelength bound for spectral range.""" + if self._min_wavelength is None: + self._update_spectral_settings() + + return self._min_wavelength + + @property + def max_wavelength(self): + """ Upper wavelength bound for spectral range.""" + if self._max_wavelength is None: + self._update_spectral_settings() + + return self._max_wavelength + + @property + def spectral_bins(self): + """ The number of spectral samples over the wavelength range.""" + if self._spectral_bins is None: + self._update_spectral_settings() + + return self._spectral_bins + + def _clear_spectral_settings(self): + self._min_wavelength = None + self._max_wavelength = None + self._spectral_bins = None + + def _update_spectral_settings(self): + raise NotImplementedError("To be defined in subclass.") + + def _update_pipeline_properties(self): + raise NotImplementedError("To be defined in subclass.") diff --git a/cherab/tools/observers/spectroscopy/polychromator.py b/cherab/tools/observers/spectroscopy/polychromator.py new file mode 100644 index 00000000..7b2a2374 --- /dev/null +++ b/cherab/tools/observers/spectroscopy/polychromator.py @@ -0,0 +1,150 @@ + +# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# +# 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import numpy as np +from raysect.optical import InterpolatedSF +from raysect.optical.observer import RadiancePipeline0D + +from .instrument import SpectroscopicInstrument + + +class PolychromatorFilter(InterpolatedSF): + """ + Defines a symmetrical trapezoidal polychromator filter as a Raysect's InterpolatedSF. + + :param float wavelength: Central wavelength of the filter in nm. + :param float window: Size of the filtering window in nm. Default is 3. + :param float flat_top: Size of the flat top part of the filter in nm. + Default is None (equal to window). + :param str name: Filter name (e.g. "H-alpha filter"). Default is ''. + + """ + + def __init__(self, wavelength, window=3., flat_top=None, name=''): + + if wavelength <= 0: + raise ValueError("Argument 'wavelength' must be positive.") + + if window <= 0: + raise ValueError("Argument 'window' must be positive.") + + flat_top = flat_top or window - 1.e-15 + + if flat_top <= 0: + raise ValueError("Argument 'flat_top' must be positive.") + if flat_top > window: + raise ValueError("Argument 'flat_top' must be less or equal than 'window'.") + if flat_top == window: + flat_top = window - 1.e-15 + + self._window = window + self._flat_top = flat_top + self._wavelength = wavelength + self._name = str(name) + + wavelengths = [wavelength - 0.5 * window, + wavelength - 0.5 * flat_top, + wavelength + 0.5 * flat_top, + wavelength + 0.5 * window] + samples = [0, 1, 1, 0] + super().__init__(wavelengths, samples, normalise=False) + + @property + def window(self): + """ Size of the filtering window in nm.""" + return self._window + + @property + def flat_top(self): + """ Size of the flat top part of the filter in nm.""" + return self._flat_top + + @property + def wavelength(self): + """ Central wavelength of the filter in nm.""" + return self._wavelength + + @property + def name(self): + """ Filter name.""" + return self._name + + +class Polychromator(SpectroscopicInstrument): + """ + A polychromator assembly with a set of different filters. + + :param list filters: List of the `PolychromatorFilter` instances. + :param int min_bins_per_window: Minimal number of spectral bins + per filtering window. Default is 10. + """ + + def __init__(self, filters, min_bins_per_window=10, name=''): + super().__init__(name) + self.min_bins_per_window = min_bins_per_window + self.filters = filters + + @property + def min_bins_per_window(self): + """ + Minimal number of spectral bins per filtering window. + """ + return self._min_bins_per_window + + @min_bins_per_window.setter + def min_bins_per_window(self, value): + + value = int(value) + if value <= 0: + raise ValueError("Attribute 'min_bins_per_window' must be positive.") + + self._min_bins_per_window = value + self._clear_spectral_settings() + + @property + def filters(self): + """ + List of the PolychromatorFilter instances. + """ + return self._filters + + @filters.setter + def filters(self, value): + for poly_filter in value: + if not isinstance(poly_filter, PolychromatorFilter): + raise TypeError('Property filters must contain only PolychromatorFilter instances.') + + self._filters = value + self._clear_spectral_settings() + self._pipeline_properties = None + + def _update_pipeline_properties(self): + self._pipeline_properties = [(RadiancePipeline0D, self._name + ': ' + poly_filter.name, poly_filter) for poly_filter in self._filters] + + def _update_spectral_settings(self): + + min_wavelength = np.inf + max_wavelength = 0 + step = np.inf + for poly_filter in self._filters: + step = min(step, poly_filter.window / self._min_bins_per_window) + min_wavelength = min(min_wavelength, poly_filter.wavelength - 0.5 * poly_filter.window) + max_wavelength = max(max_wavelength, poly_filter.wavelength + 0.5 * poly_filter.window) + + self._min_wavelength = min_wavelength + self._max_wavelength = max_wavelength + self._spectral_bins = int(np.ceil((max_wavelength - min_wavelength) / step)) diff --git a/cherab/tools/observers/spectroscopy/spectrometer.py b/cherab/tools/observers/spectroscopy/spectrometer.py new file mode 100644 index 00000000..74e098c4 --- /dev/null +++ b/cherab/tools/observers/spectroscopy/spectrometer.py @@ -0,0 +1,273 @@ + +# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# +# 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import numpy as np +from raysect.optical.observer import SpectralRadiancePipeline0D + +from .instrument import SpectroscopicInstrument + + +class Spectrometer(SpectroscopicInstrument): + """ + Spectrometer base class. + This is an abstract class. + + :param int spectral_bins: The number of spectral samples over the wavelength range. + :param float reference_wavelength: Wavelength (in nm) corresponding to + the centre of reference bin. + :param int reference_bin: Reference bin index. Can be negative to specify the offset. + Default is None (spectral_bins // 2). + :param str name: Spectrometer name. + """ + + def __init__(self, spectral_bins, reference_wavelength, reference_bin=None, name=''): + super().__init__(name) + self.spectral_bins = spectral_bins + if reference_bin is None: + self.reference_bin = self._spectral_bins // 2 + else: + self.reference_bin = reference_bin + self.reference_wavelength = reference_wavelength + + @property + def spectral_bins(self): + """ + The number of spectral samples over the wavelength range. + """ + return self._spectral_bins + + @spectral_bins.setter + def spectral_bins(self, value): + + value = int(value) + if value <= 0: + raise ValueError("Attribute 'spectral_bins' must be > 0.") + + self._spectral_bins = value + self._clear_spectral_settings() + + @property + def reference_wavelength(self): + """ + Wavelength (in nm) corresponding to the centre of reference bin. + """ + return self._reference_wavelength + + @reference_wavelength.setter + def reference_wavelength(self, value): + + if value <= 0: + raise ValueError("Attribute 'reference_wavelength' must be > 0.") + + self._reference_wavelength = value + self._clear_spectral_settings() + + @property + def reference_bin(self): + """ + Reference bin index. + """ + return self._reference_bin + + @reference_bin.setter + def reference_bin(self, value): + + value = int(value) + + self._reference_bin = value + self._clear_spectral_settings() + + def _update_pipeline_properties(self): + self._pipeline_properties = [(SpectralRadiancePipeline0D, self._name, None)] + + def _clear_spectral_settings(self): + self._min_wavelength = None + self._max_wavelength = None + + +class SurveySpectrometer(Spectrometer): + """ + Survey spectrometer with a constant spectral resolution. + + Note: survey spectrometers usually have non-constant spectral resolution + in the supported wavelength range. However, Raysect does not support + the observers with variable spectral resolution. + + :param float resolution: Spectral resolution in nm (can be negative). + :param int spectral_bins: The number of spectral samples over the wavelength range. + :param float reference_wavelength: Wavelength (in nm) corresponding to + the centre of reference bin. + :param int reference_bin: Reference bin index. Can be negative to specify the offset. + Default is None (spectral_bins // 2). + :param str name: Spectrometer name. + """ + + def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bin=None, name=''): + super().__init__(spectral_bins, reference_wavelength, reference_bin, name) + self.resolution = resolution + + @property + def resolution(self): + """ + Spectrometer resolution. + """ + return self._resolution + + @resolution.setter + def resolution(self, value): + """ + Spectral resolution in nm (can be negative). + """ + if value == 0: + raise ValueError("Attribute 'resolution' must be non-zero.") + + self._resolution = value + self._clear_spectral_settings() + + def _update_spectral_settings(self): + + if self._resolution > 0: + self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * self._resolution + self._max_wavelength = self._min_wavelength + self._spectral_bins * self._resolution + else: + self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * self._resolution + self._max_wavelength = self._min_wavelength - self._spectral_bins * self._resolution + + +class CzernyTurnerSpectrometer(Spectrometer): + """ + Czerny-Turner high-resolution spectrometer. + + :param int diffraction_order: Diffraction order. + :param float grating: Diffraction grating in nm-1. + :param float focal_length: Focal length in nm. + :param float pixel_spacing: Pixel to pixel spacing on CCD in nm. + :param float diffraction_angle: Angle between incident and diffracted light in degrees. + :param int spectral_bins: The number of spectral samples over the wavelength range. + :param float reference_wavelength: Wavelength (in nm) corresponding to + the centre of reference bin. + :param int reference_bin: Reference bin index. Default is None (spectral_bins // 2). + :param str name: Spectrometer name. + """ + + def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, spectral_bins, + reference_wavelength, reference_bin=None, name=''): + super().__init__(spectral_bins, reference_wavelength, reference_bin, name) + self.diffraction_order = diffraction_order + self.grating = grating + self.focal_length = focal_length + self.pixel_spacing = pixel_spacing + self.diffraction_angle = diffraction_angle + + @property + def diffraction_order(self): + """ Diffraction order.""" + return self._diffraction_order + + @diffraction_order.setter + def diffraction_order(self, value): + + value = int(value) + if value <= 0: + raise ValueError("Attribute 'diffraction_order' must be positive.") + + self._diffraction_order = value + self._clear_spectral_settings() + + @property + def grating(self): + """ Diffraction grating in nm-1.""" + return self._grating + + @grating.setter + def grating(self, value): + + if value <= 0: + raise ValueError("Attribute 'grating' must be positive.") + + self._grating = value + self._clear_spectral_settings() + + @property + def focal_length(self): + """ Focal length in nm.""" + return self._focal_length + + @focal_length.setter + def focal_length(self, value): + + if value <= 0: + raise ValueError("Attribute 'focal_length' must be positive.") + + self._focal_length = value + self._clear_spectral_settings() + + @property + def pixel_spacing(self): + """ Pixel to pixel spacing on CCD in nm.""" + return self._pixel_spacing + + @pixel_spacing.setter + def pixel_spacing(self, value): + + if value == 0: + raise ValueError("Attribute 'pixel_spacing' must be non-zero.") + + self._pixel_spacing = value + self._clear_spectral_settings() + + @property + def diffraction_angle(self): + """ Angle between incident and diffracted light in degrees.""" + return np.rad2deg(self._diffraction_angle) + + @diffraction_angle.setter + def diffraction_angle(self, value): + + if value <= 0: + raise ValueError("Attribute 'diffraction_angle' must be positive.") + + self._diffraction_angle = np.deg2rad(value) + self._clear_spectral_settings() + + def _update_spectral_settings(self): + + resolution = self.resolution() + + if resolution > 0: + self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * resolution + self._max_wavelength = self._min_wavelength + self._spectral_bins * resolution + else: + self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * resolution + self._max_wavelength = self._min_wavelength - self._spectral_bins * resolution + + def resolution(self): + """ + Calculates spectral resolution in nm. + + :return: resolution + """ + grating = self._grating + m = self._diffraction_order + dxdp = self._pixel_spacing + angle = self._diffraction_angle + fl = self._focal_length + + p = 0.5 * m * grating * self._reference_wavelength + resolution = dxdp * (np.sqrt(np.cos(angle)**2 - p * p) - p * np.tan(angle)) / (m * fl * grating) + + return resolution From f63798976a964455f92fcd247451feb5a763ab9c Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 16 Jun 2021 21:33:18 +0300 Subject: [PATCH 02/81] Made 'resolution' a property of CzernyTurnerSpectrometer. --- .../observers/spectroscopy/spectrometer.py | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/cherab/tools/observers/spectroscopy/spectrometer.py b/cherab/tools/observers/spectroscopy/spectrometer.py index 74e098c4..fcbe31cf 100644 --- a/cherab/tools/observers/spectroscopy/spectrometer.py +++ b/cherab/tools/observers/spectroscopy/spectrometer.py @@ -244,22 +244,10 @@ def diffraction_angle(self, value): self._diffraction_angle = np.deg2rad(value) self._clear_spectral_settings() - def _update_spectral_settings(self): - - resolution = self.resolution() - - if resolution > 0: - self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * resolution - self._max_wavelength = self._min_wavelength + self._spectral_bins * resolution - else: - self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * resolution - self._max_wavelength = self._min_wavelength - self._spectral_bins * resolution - + @property def resolution(self): """ - Calculates spectral resolution in nm. - - :return: resolution + Spectral resolution in nm. """ grating = self._grating m = self._diffraction_order @@ -268,6 +256,17 @@ def resolution(self): fl = self._focal_length p = 0.5 * m * grating * self._reference_wavelength - resolution = dxdp * (np.sqrt(np.cos(angle)**2 - p * p) - p * np.tan(angle)) / (m * fl * grating) + _resolution = dxdp * (np.sqrt(np.cos(angle)**2 - p * p) - p * np.tan(angle)) / (m * fl * grating) + + return _resolution + + def _update_spectral_settings(self): + + resolution = self.resolution - return resolution + if resolution > 0: + self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * resolution + self._max_wavelength = self._min_wavelength + self._spectral_bins * resolution + else: + self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * resolution + self._max_wavelength = self._min_wavelength - self._spectral_bins * resolution From 439f5b286f03797eff1dea2693dca36d28e06c5a Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 26 Jul 2021 18:10:21 +0300 Subject: [PATCH 03/81] Added Sphinx documentation and unit tests for spectroscopic instruments. --- .../tests/test_spectroscopic_instruments.py | 145 ++++++++++++++++++ docs/source/tools/observers.rst | 31 ++++ 2 files changed, 176 insertions(+) create mode 100644 cherab/tools/tests/test_spectroscopic_instruments.py diff --git a/cherab/tools/tests/test_spectroscopic_instruments.py b/cherab/tools/tests/test_spectroscopic_instruments.py new file mode 100644 index 00000000..d79b6445 --- /dev/null +++ b/cherab/tools/tests/test_spectroscopic_instruments.py @@ -0,0 +1,145 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import unittest +import numpy as np + +from raysect.optical.observer.pipeline import RadiancePipeline0D, SpectralRadiancePipeline0D +from cherab.tools.observers.spectroscopy import PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer + + +class TestPolychromatorFilter(unittest.TestCase): + """ + Test for PolychromatorFilter class. + """ + + def test_spectrum(self): + wavelength = 500. + window = 6. + flat_top = 2. + poly_filter = PolychromatorFilter(wavelength, window, flat_top, 'test_filter') + wavelengths = np.linspace(496., 504., 9) + spectrum_true = np.array([0, 0, 0.5, 1., 1., 1., 0.5, 0, 0]) + spectrum_test = np.array([poly_filter(wvl) for wvl in wavelengths]) + self.assertTrue(np.all(spectrum_true == spectrum_test)) + + +class TestPolychromator(unittest.TestCase): + """ + Test cases for Polychromator class. + """ + + def setUp(self): + self.poly_filters_default = [PolychromatorFilter(400., 6., 2., 'filter 1'), + PolychromatorFilter(700., 8., 4., 'filter 2')] + self.min_bins_per_window_default = 10 + + def test_pipeline_properties(self): + polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default, 'test polychromator') + pipeline_properties_true = [(RadiancePipeline0D, 'test polychromator: filter 1', self.poly_filters_default[0]), + (RadiancePipeline0D, 'test polychromator: filter 2', self.poly_filters_default[1])] + self.assertSequenceEqual(pipeline_properties_true, polychromator.pipeline_properties) + + def test_spectral_properties(self): + polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default) + min_wavelength_true = 397. + max_wavelength_true = 704. + spectral_bins_true = 512 + self.assertTrue(polychromator.min_wavelength == min_wavelength_true and + polychromator.max_wavelength == max_wavelength_true and + polychromator.spectral_bins == spectral_bins_true) + + def test_filter_change(self): + """ Checks if the spectral properties are updated correctly when the filters are replaced.""" + polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default) + polychromator.min_bins_per_window = 20 + polychromator.filters = [PolychromatorFilter(500., 5., 2., 'filter 1'), + PolychromatorFilter(600., 7., 4., 'filter 2')] + min_wavelength_true = 497.5 + max_wavelength_true = 603.5 + spectral_bins_true = 424 + self.assertTrue(polychromator.min_wavelength == min_wavelength_true and + polychromator.max_wavelength == max_wavelength_true and + polychromator.spectral_bins == spectral_bins_true) + + +class TestSurveySpectrometer(unittest.TestCase): + """ + Test cases for SurveySpectrometer class. + """ + + def test_pipeline_properties(self): + resolution = 0.1 + reference_wavelength = 500 + reference_bin = 50 + spectral_bins = 200 + spectrometer = SurveySpectrometer(resolution, spectral_bins, reference_wavelength, reference_bin, name='test spectrometer') + pipeline_properties_true = [(SpectralRadiancePipeline0D, 'test spectrometer', None)] + self.assertSequenceEqual(pipeline_properties_true, spectrometer.pipeline_properties) + + def test_spectral_properties(self): + resolution = 0.1 + reference_wavelength = 500 + reference_bin = 50 + spectral_bins = 200 + spectrometer = SurveySpectrometer(resolution, spectral_bins, reference_wavelength, reference_bin, name='test spectrometer') + min_wavelength_true = 494.95 + max_wavelength_true = 514.95 + self.assertTrue(spectrometer.min_wavelength == min_wavelength_true and + spectrometer.max_wavelength == max_wavelength_true) + + +class TestCzernyTurnerSpectrometer(unittest.TestCase): + """ + Test cases for CzernyTurnerSpectrometer class. + """ + + def setUp(self): + self.diffraction_order = 1 + self.grating = 2.e-3 + self.focal_length = 1.e9 + self.pixel_spacing = 2.e4 + self.diffraction_angle = 10. + self.spectral_bins = 512 + self.reference_bin = 255 + + def test_resolution(self): + wavelengths = [350., 550., 750.] + resolutions_true = np.array([8.587997e-3, 7.199328e-3, 5.0599164e-3]) + spectrometer = CzernyTurnerSpectrometer(self.diffraction_order, self.grating, self.focal_length, self.pixel_spacing, + self.diffraction_angle, self.spectral_bins, 500., self.reference_bin, + name='test spectrometer') + resolutions = [] + for wvl in wavelengths: + spectrometer.reference_wavelength = wvl + resolutions.append(spectrometer.resolution) + self.assertTrue(np.all(np.abs(resolutions / resolutions_true - 1.) < 1.e-7)) + + def test_spectral_properties(self): + wavelength = 500. + min_wavelength_true = 498.0575 + max_wavelength_true = 501.9501 + spectrometer = CzernyTurnerSpectrometer(self.diffraction_order, self.grating, self.focal_length, self.pixel_spacing, + self.diffraction_angle, self.spectral_bins, wavelength, self.reference_bin, + name='test spectrometer') + self.assertTrue(abs(spectrometer.min_wavelength - min_wavelength_true) < 1.e-4 and + abs(spectrometer.max_wavelength - max_wavelength_true) < 1.e-4) + + +if __name__ == '__main__': + unittest.main() diff --git a/docs/source/tools/observers.rst b/docs/source/tools/observers.rst index 57dd5636..493bab2b 100644 --- a/docs/source/tools/observers.rst +++ b/docs/source/tools/observers.rst @@ -61,3 +61,34 @@ bolometer etendue :math:`G`, which is given by: .. autoclass:: cherab.tools.observers.bolometry.BolometerFoil :members: + + +.. _observers_spectroscopic_instruments: + +Spectroscopic instruments +------------------------- + +Spectroscopic instruments such as polychromators, survey and high-resolution spectrometers +simplify the setup of rendering pipelines and observers' spectral properties. The Cherab core +package provides base classes for spectroscopic instruments, so machine-specific packages +can build more advance instruments from them, such as instruments with spectral properties +based on the actual experimental setup for a given shot/pulse. + +.. autoclass:: cherab.tools.observers.spectroscopy.SpectroscopicInstrument + :members: + +.. autoclass:: cherab.tools.observers.spectroscopy.PolychromatorFilter + :members: + +.. autoclass:: cherab.tools.observers.spectroscopy.Polychromator + :members: + +.. autoclass:: cherab.tools.observers.spectroscopy.Spectrometer + :members: + +.. autoclass:: cherab.tools.observers.spectroscopy.SurveySpectrometer + :members: + +.. autoclass:: cherab.tools.observers.spectroscopy.CzernyTurnerSpectrometer + :members: + From 829b231dc2fc1e478d9b587d5ac3ad3bce754218 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 29 Jul 2021 23:35:29 +0300 Subject: [PATCH 04/81] Aligned the docs for spectroscopic instruments with the style used in Cherab. --- .../observers/spectroscopy/instrument.py | 20 +++++---- .../observers/spectroscopy/polychromator.py | 18 +++----- .../observers/spectroscopy/spectrometer.py | 45 ++++++------------- 3 files changed, 33 insertions(+), 50 deletions(-) diff --git a/cherab/tools/observers/spectroscopy/instrument.py b/cherab/tools/observers/spectroscopy/instrument.py index b3d6c65d..a2a59f60 100644 --- a/cherab/tools/observers/spectroscopy/instrument.py +++ b/cherab/tools/observers/spectroscopy/instrument.py @@ -21,6 +21,12 @@ class SpectroscopicInstrument: This is an abstract class. :param str name: Instrument name. + + :ivar list pipeline_properties: The list of properties (class, name, filter) of + the pipelines used with this instrument. + :ivar float min_wavelength: Lower wavelength bound for spectral range. + :ivar float max_wavelength: Upper wavelength bound for spectral range. + :ivar int spectral_bins: The number of spectral samples over the wavelength range. """ def __init__(self, name=''): @@ -29,7 +35,7 @@ def __init__(self, name=''): @property def name(self): - """ Instrument name.""" + # Instrument name. return self._name @name.setter @@ -39,10 +45,8 @@ def name(self, value): @property def pipeline_properties(self): - """ - The list of properties (class, name, filter) of the pipelines used with - this instrument. - """ + # The list of properties (class, name, filter) of the pipelines used with + # this instrument. if self._pipeline_properties is None: self._update_pipeline_properties() @@ -50,7 +54,7 @@ def pipeline_properties(self): @property def min_wavelength(self): - """ Lower wavelength bound for spectral range.""" + # Lower wavelength bound for spectral range. if self._min_wavelength is None: self._update_spectral_settings() @@ -58,7 +62,7 @@ def min_wavelength(self): @property def max_wavelength(self): - """ Upper wavelength bound for spectral range.""" + # Upper wavelength bound for spectral range. if self._max_wavelength is None: self._update_spectral_settings() @@ -66,7 +70,7 @@ def max_wavelength(self): @property def spectral_bins(self): - """ The number of spectral samples over the wavelength range.""" + # The number of spectral samples over the wavelength range. if self._spectral_bins is None: self._update_spectral_settings() diff --git a/cherab/tools/observers/spectroscopy/polychromator.py b/cherab/tools/observers/spectroscopy/polychromator.py index 7b2a2374..789a66f8 100644 --- a/cherab/tools/observers/spectroscopy/polychromator.py +++ b/cherab/tools/observers/spectroscopy/polychromator.py @@ -65,22 +65,22 @@ def __init__(self, wavelength, window=3., flat_top=None, name=''): @property def window(self): - """ Size of the filtering window in nm.""" + # Size of the filtering window in nm. return self._window @property def flat_top(self): - """ Size of the flat top part of the filter in nm.""" + # Size of the flat top part of the filter in nm. return self._flat_top @property def wavelength(self): - """ Central wavelength of the filter in nm.""" + # Central wavelength of the filter in nm. return self._wavelength @property def name(self): - """ Filter name.""" + # Filter name. return self._name @@ -91,6 +91,7 @@ class Polychromator(SpectroscopicInstrument): :param list filters: List of the `PolychromatorFilter` instances. :param int min_bins_per_window: Minimal number of spectral bins per filtering window. Default is 10. + :param str name: Polychromator name. """ def __init__(self, filters, min_bins_per_window=10, name=''): @@ -100,14 +101,11 @@ def __init__(self, filters, min_bins_per_window=10, name=''): @property def min_bins_per_window(self): - """ - Minimal number of spectral bins per filtering window. - """ + # Minimal number of spectral bins per filtering window. return self._min_bins_per_window @min_bins_per_window.setter def min_bins_per_window(self, value): - value = int(value) if value <= 0: raise ValueError("Attribute 'min_bins_per_window' must be positive.") @@ -117,9 +115,7 @@ def min_bins_per_window(self, value): @property def filters(self): - """ - List of the PolychromatorFilter instances. - """ + # List of the PolychromatorFilter instances. return self._filters @filters.setter diff --git a/cherab/tools/observers/spectroscopy/spectrometer.py b/cherab/tools/observers/spectroscopy/spectrometer.py index fcbe31cf..99bd5425 100644 --- a/cherab/tools/observers/spectroscopy/spectrometer.py +++ b/cherab/tools/observers/spectroscopy/spectrometer.py @@ -45,14 +45,11 @@ def __init__(self, spectral_bins, reference_wavelength, reference_bin=None, name @property def spectral_bins(self): - """ - The number of spectral samples over the wavelength range. - """ + # The number of spectral samples over the wavelength range. return self._spectral_bins @spectral_bins.setter def spectral_bins(self, value): - value = int(value) if value <= 0: raise ValueError("Attribute 'spectral_bins' must be > 0.") @@ -62,14 +59,11 @@ def spectral_bins(self, value): @property def reference_wavelength(self): - """ - Wavelength (in nm) corresponding to the centre of reference bin. - """ + # Wavelength (in nm) corresponding to the centre of reference bin. return self._reference_wavelength @reference_wavelength.setter def reference_wavelength(self, value): - if value <= 0: raise ValueError("Attribute 'reference_wavelength' must be > 0.") @@ -78,14 +72,11 @@ def reference_wavelength(self, value): @property def reference_bin(self): - """ - Reference bin index. - """ + # Reference bin index. return self._reference_bin @reference_bin.setter def reference_bin(self, value): - value = int(value) self._reference_bin = value @@ -114,6 +105,8 @@ class SurveySpectrometer(Spectrometer): :param int reference_bin: Reference bin index. Can be negative to specify the offset. Default is None (spectral_bins // 2). :param str name: Spectrometer name. + + :ivar float resolution: Spectral resolution in nm (can be negative). """ def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bin=None, name=''): @@ -122,16 +115,11 @@ def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bi @property def resolution(self): - """ - Spectrometer resolution. - """ + # Spectral resolution in nm (can be negative). return self._resolution @resolution.setter def resolution(self, value): - """ - Spectral resolution in nm (can be negative). - """ if value == 0: raise ValueError("Attribute 'resolution' must be non-zero.") @@ -162,6 +150,8 @@ class CzernyTurnerSpectrometer(Spectrometer): the centre of reference bin. :param int reference_bin: Reference bin index. Default is None (spectral_bins // 2). :param str name: Spectrometer name. + + :ivar float resolution: Spectral resolution in nm (can be negative). """ def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, spectral_bins, @@ -175,12 +165,11 @@ def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diff @property def diffraction_order(self): - """ Diffraction order.""" + # Diffraction order. return self._diffraction_order @diffraction_order.setter def diffraction_order(self, value): - value = int(value) if value <= 0: raise ValueError("Attribute 'diffraction_order' must be positive.") @@ -190,12 +179,11 @@ def diffraction_order(self, value): @property def grating(self): - """ Diffraction grating in nm-1.""" + # Diffraction grating in nm-1. return self._grating @grating.setter def grating(self, value): - if value <= 0: raise ValueError("Attribute 'grating' must be positive.") @@ -204,12 +192,11 @@ def grating(self, value): @property def focal_length(self): - """ Focal length in nm.""" + # Focal length in nm. return self._focal_length @focal_length.setter def focal_length(self, value): - if value <= 0: raise ValueError("Attribute 'focal_length' must be positive.") @@ -218,12 +205,11 @@ def focal_length(self, value): @property def pixel_spacing(self): - """ Pixel to pixel spacing on CCD in nm.""" + # Pixel to pixel spacing on CCD in nm. return self._pixel_spacing @pixel_spacing.setter def pixel_spacing(self, value): - if value == 0: raise ValueError("Attribute 'pixel_spacing' must be non-zero.") @@ -232,12 +218,11 @@ def pixel_spacing(self, value): @property def diffraction_angle(self): - """ Angle between incident and diffracted light in degrees.""" + # Angle between incident and diffracted light in degrees. return np.rad2deg(self._diffraction_angle) @diffraction_angle.setter def diffraction_angle(self, value): - if value <= 0: raise ValueError("Attribute 'diffraction_angle' must be positive.") @@ -246,9 +231,7 @@ def diffraction_angle(self, value): @property def resolution(self): - """ - Spectral resolution in nm. - """ + # Spectral resolution in nm (can be negative). grating = self._grating m = self._diffraction_order dxdp = self._pixel_spacing From b674e01b72daea43675c5fe15516c9150021cf6b Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 3 Aug 2021 20:33:38 +0300 Subject: [PATCH 05/81] Moved spectroscopic instruments from 'observers' to 'spectroscopy' submodule. Added code examples to docstrings. Added 'pipelines' property. --- .../{observers => }/spectroscopy/__init__.py | 4 +- .../spectroscopy/instrument.py | 17 ++++++- .../spectroscopy/polychromator.py | 21 ++++++++- .../spectroscopy/spectrometer.py | 45 ++++++++++++++++++- .../tests/test_spectroscopic_instruments.py | 2 +- docs/source/tools/observers.rst | 30 ------------- docs/source/tools/spectroscopy.rst | 38 ++++++++++++++++ docs/source/tools/tools.rst | 1 + 8 files changed, 122 insertions(+), 36 deletions(-) rename cherab/tools/{observers => }/spectroscopy/__init__.py (81%) rename cherab/tools/{observers => }/spectroscopy/instrument.py (80%) rename cherab/tools/{observers => }/spectroscopy/polychromator.py (83%) rename cherab/tools/{observers => }/spectroscopy/spectrometer.py (78%) create mode 100644 docs/source/tools/spectroscopy.rst diff --git a/cherab/tools/observers/spectroscopy/__init__.py b/cherab/tools/spectroscopy/__init__.py similarity index 81% rename from cherab/tools/observers/spectroscopy/__init__.py rename to cherab/tools/spectroscopy/__init__.py index 1d8cb4cd..207aaf87 100644 --- a/cherab/tools/observers/spectroscopy/__init__.py +++ b/cherab/tools/spectroscopy/__init__.py @@ -1,5 +1,7 @@ -# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); diff --git a/cherab/tools/observers/spectroscopy/instrument.py b/cherab/tools/spectroscopy/instrument.py similarity index 80% rename from cherab/tools/observers/spectroscopy/instrument.py rename to cherab/tools/spectroscopy/instrument.py index a2a59f60..fc0409b1 100644 --- a/cherab/tools/observers/spectroscopy/instrument.py +++ b/cherab/tools/spectroscopy/instrument.py @@ -1,5 +1,7 @@ -# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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,6 +26,7 @@ class SpectroscopicInstrument: :ivar list pipeline_properties: The list of properties (class, name, filter) of the pipelines used with this instrument. + :ivar list pipelines: The list of pipelines. Each call returns a list with new instances. :ivar float min_wavelength: Lower wavelength bound for spectral range. :ivar float max_wavelength: Upper wavelength bound for spectral range. :ivar int spectral_bins: The number of spectral samples over the wavelength range. @@ -52,6 +55,18 @@ def pipeline_properties(self): return self._pipeline_properties + @property + def pipelines(self): + # The list of pipelines. Each call returns a list with new instances. + pl_list = [] + for (pl_class, pl_name, pl_filter) in self.pipeline_properties: + if pl_filter is None: + pl_list.append(pl_class(name=pl_name)) + else: + pl_list.append(pl_class(name=pl_name, filter=pl_filter)) + + return pl_list + @property def min_wavelength(self): # Lower wavelength bound for spectral range. diff --git a/cherab/tools/observers/spectroscopy/polychromator.py b/cherab/tools/spectroscopy/polychromator.py similarity index 83% rename from cherab/tools/observers/spectroscopy/polychromator.py rename to cherab/tools/spectroscopy/polychromator.py index 789a66f8..2d13a898 100644 --- a/cherab/tools/observers/spectroscopy/polychromator.py +++ b/cherab/tools/spectroscopy/polychromator.py @@ -1,5 +1,7 @@ -# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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,7 +33,6 @@ class PolychromatorFilter(InterpolatedSF): :param float flat_top: Size of the flat top part of the filter in nm. Default is None (equal to window). :param str name: Filter name (e.g. "H-alpha filter"). Default is ''. - """ def __init__(self, wavelength, window=3., flat_top=None, name=''): @@ -92,6 +93,22 @@ class Polychromator(SpectroscopicInstrument): :param int min_bins_per_window: Minimal number of spectral bins per filtering window. Default is 10. :param str name: Polychromator name. + + .. code-block:: pycon + + >>> from raysect.optical import World + >>> from raysect.optical.observer import FibreOptic + >>> from cherab.tools.spectroscopy import Polychromator, PolychromatorFilter + >>> + >>> world = World() + >>> h_alpha_filter = PolychromatorFilter(656.1, name='H-alpha filter') + >>> ciii_465nm_filter = PolychromatorFilter(464.8, name='CIII 465 nm filter') + >>> polychromator = Polychromator([h_alpha_filter, ciii_465nm_filter], name='MyPolychromator') + >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) + >>> fibreoptic.min_wavelength = polychromator.min_wavelength + >>> fibreoptic.max_wavelength = polychromator.max_wavelength + >>> fibreoptic.spectral_bins = polychromator.spectral_bins + >>> fibreoptic.pipelines = polychromator.pipelines """ def __init__(self, filters, min_bins_per_window=10, name=''): diff --git a/cherab/tools/observers/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py similarity index 78% rename from cherab/tools/observers/spectroscopy/spectrometer.py rename to cherab/tools/spectroscopy/spectrometer.py index 99bd5425..e982918e 100644 --- a/cherab/tools/observers/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -1,5 +1,7 @@ -# Copyright 2014-2017 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); @@ -107,6 +109,32 @@ class SurveySpectrometer(Spectrometer): :param str name: Spectrometer name. :ivar float resolution: Spectral resolution in nm (can be negative). + + .. code-block:: pycon + + >>> from numpy import ceil + >>> from raysect.optical import World + >>> from raysect.optical.observer import FibreOptic + >>> from cherab.tools.spectroscopy import SurveySpectrometer, Polychromator, PolychromatorFilter + >>> + >>> world = World() + >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) + >>> # Here, the fibre optic is "connected" to both survey spectrometer and polychromator. + >>> + >>> # setting up the polychromator + >>> h_alpha_filter = PolychromatorFilter(656.1, name='H-alpha filter') + >>> ciii_465nm_filter = PolychromatorFilter(464.8, name='CIII 465 nm filter') + >>> polychromator = Polychromator([h_alpha_filter, ciii_465nm_filter], name='MyPolychromator') + >>> + >>> # setting up the survey spectrometer + >>> spectrometer = SurveySpectrometer(0.1, 1024, 500, name='MySpectrometer') + >>> + >>> fibreoptic.min_wavelength = min(spectrometer.min_wavelength, polychromator.min_wavelength) + >>> fibreoptic.max_wavelength = max(spectrometer.max_wavelength, polychromator.max_wavelength) + >>> bin_width = min((spectrometer.max_wavelength - spectrometer.min_wavelength) / spectrometer.spectral_bins, + >>> (polychromator.max_wavelength - polychromator.min_wavelength) / polychromator.spectral_bins) + >>> fibreoptic.spectral_bins = int(ceil((fibreoptic.max_wavelength - fibreoptic.min_wavelength) / bin_width)) + >>> fibreoptic.pipelines = spectrometer.pipelines + polychromator.pipelines """ def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bin=None, name=''): @@ -152,6 +180,21 @@ class CzernyTurnerSpectrometer(Spectrometer): :param str name: Spectrometer name. :ivar float resolution: Spectral resolution in nm (can be negative). + + .. code-block:: pycon + + >>> from raysect.optical import World + >>> from raysect.optical.observer import FibreOptic + >>> from cherab.tools.spectroscopy import CzernyTurnerSpectrometer + >>> + >>> world = World() + >>> hires_spectrometer = CzernyTurnerSpectrometer(1, 2.e-3, 1.e9, 2.e4, 10., 512, 600., + >>> name='MySpectrometer') + >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) + >>> fibreoptic.min_wavelength = hires_spectrometer.min_wavelength + >>> fibreoptic.max_wavelength = hires_spectrometer.max_wavelength + >>> fibreoptic.spectral_bins = hires_spectrometer.spectral_bins + >>> fibreoptic.pipelines = hires_spectrometer.pipelines """ def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, spectral_bins, diff --git a/cherab/tools/tests/test_spectroscopic_instruments.py b/cherab/tools/tests/test_spectroscopic_instruments.py index d79b6445..883dc8c6 100644 --- a/cherab/tools/tests/test_spectroscopic_instruments.py +++ b/cherab/tools/tests/test_spectroscopic_instruments.py @@ -20,7 +20,7 @@ import numpy as np from raysect.optical.observer.pipeline import RadiancePipeline0D, SpectralRadiancePipeline0D -from cherab.tools.observers.spectroscopy import PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer +from cherab.tools.spectroscopy import PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer class TestPolychromatorFilter(unittest.TestCase): diff --git a/docs/source/tools/observers.rst b/docs/source/tools/observers.rst index 493bab2b..3feda8d0 100644 --- a/docs/source/tools/observers.rst +++ b/docs/source/tools/observers.rst @@ -62,33 +62,3 @@ bolometer etendue :math:`G`, which is given by: .. autoclass:: cherab.tools.observers.bolometry.BolometerFoil :members: - -.. _observers_spectroscopic_instruments: - -Spectroscopic instruments -------------------------- - -Spectroscopic instruments such as polychromators, survey and high-resolution spectrometers -simplify the setup of rendering pipelines and observers' spectral properties. The Cherab core -package provides base classes for spectroscopic instruments, so machine-specific packages -can build more advance instruments from them, such as instruments with spectral properties -based on the actual experimental setup for a given shot/pulse. - -.. autoclass:: cherab.tools.observers.spectroscopy.SpectroscopicInstrument - :members: - -.. autoclass:: cherab.tools.observers.spectroscopy.PolychromatorFilter - :members: - -.. autoclass:: cherab.tools.observers.spectroscopy.Polychromator - :members: - -.. autoclass:: cherab.tools.observers.spectroscopy.Spectrometer - :members: - -.. autoclass:: cherab.tools.observers.spectroscopy.SurveySpectrometer - :members: - -.. autoclass:: cherab.tools.observers.spectroscopy.CzernyTurnerSpectrometer - :members: - diff --git a/docs/source/tools/spectroscopy.rst b/docs/source/tools/spectroscopy.rst new file mode 100644 index 00000000..406222c4 --- /dev/null +++ b/docs/source/tools/spectroscopy.rst @@ -0,0 +1,38 @@ + +Spectroscopy +============ + +The tools for plasma spectroscopy. + +.. _spectroscopy_instruments: + +Spectroscopic instruments +------------------------- + +Spectroscopic instruments such as polychromators, survey and high-resolution spectrometers +simplify the setup of properties of the observers and rendering pipelines. The instruments +are not connected to the scenegraph, so they cannot observe the world. However, the instruments +have properties, such as `min_wavelength`, `max_wavelength`, `spectral_bins`, +`pipeline_properties`, with which the observer can be configured. +The Cherab core package provides base classes for spectroscopic instruments, +so machine-specific packages can build more advance instruments from them, such as instruments +with spectral properties based on the actual experimental setup for a given shot/pulse. + +.. autoclass:: cherab.tools.spectroscopy.SpectroscopicInstrument + :members: + +.. autoclass:: cherab.tools.spectroscopy.PolychromatorFilter + :members: + +.. autoclass:: cherab.tools.spectroscopy.Polychromator + :members: + +.. autoclass:: cherab.tools.spectroscopy.Spectrometer + :members: + +.. autoclass:: cherab.tools.spectroscopy.SurveySpectrometer + :members: + +.. autoclass:: cherab.tools.spectroscopy.CzernyTurnerSpectrometer + :members: + diff --git a/docs/source/tools/tools.rst b/docs/source/tools/tools.rst index 3b356121..19f58e95 100644 --- a/docs/source/tools/tools.rst +++ b/docs/source/tools/tools.rst @@ -8,6 +8,7 @@ Tools materials primitives observers + spectroscopy tomography utility From 996a36ad913d95752cd09905194bea3c17405387 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 3 Aug 2021 21:24:33 +0300 Subject: [PATCH 06/81] Made Instrument.pipelines() a funstion instead of property to avoid confusion. --- cherab/tools/spectroscopy/instrument.py | 5 ++--- cherab/tools/spectroscopy/polychromator.py | 2 +- cherab/tools/spectroscopy/spectrometer.py | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cherab/tools/spectroscopy/instrument.py b/cherab/tools/spectroscopy/instrument.py index fc0409b1..f503c7f3 100644 --- a/cherab/tools/spectroscopy/instrument.py +++ b/cherab/tools/spectroscopy/instrument.py @@ -26,7 +26,6 @@ class SpectroscopicInstrument: :ivar list pipeline_properties: The list of properties (class, name, filter) of the pipelines used with this instrument. - :ivar list pipelines: The list of pipelines. Each call returns a list with new instances. :ivar float min_wavelength: Lower wavelength bound for spectral range. :ivar float max_wavelength: Upper wavelength bound for spectral range. :ivar int spectral_bins: The number of spectral samples over the wavelength range. @@ -55,9 +54,9 @@ def pipeline_properties(self): return self._pipeline_properties - @property def pipelines(self): - # The list of pipelines. Each call returns a list with new instances. + """ Returns a list of new pipelines according to `pipeline_properties`.""" + pl_list = [] for (pl_class, pl_name, pl_filter) in self.pipeline_properties: if pl_filter is None: diff --git a/cherab/tools/spectroscopy/polychromator.py b/cherab/tools/spectroscopy/polychromator.py index 2d13a898..27366a45 100644 --- a/cherab/tools/spectroscopy/polychromator.py +++ b/cherab/tools/spectroscopy/polychromator.py @@ -108,7 +108,7 @@ class Polychromator(SpectroscopicInstrument): >>> fibreoptic.min_wavelength = polychromator.min_wavelength >>> fibreoptic.max_wavelength = polychromator.max_wavelength >>> fibreoptic.spectral_bins = polychromator.spectral_bins - >>> fibreoptic.pipelines = polychromator.pipelines + >>> fibreoptic.pipelines = polychromator.pipelines() """ def __init__(self, filters, min_bins_per_window=10, name=''): diff --git a/cherab/tools/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py index e982918e..de67e36a 100644 --- a/cherab/tools/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -134,7 +134,7 @@ class SurveySpectrometer(Spectrometer): >>> bin_width = min((spectrometer.max_wavelength - spectrometer.min_wavelength) / spectrometer.spectral_bins, >>> (polychromator.max_wavelength - polychromator.min_wavelength) / polychromator.spectral_bins) >>> fibreoptic.spectral_bins = int(ceil((fibreoptic.max_wavelength - fibreoptic.min_wavelength) / bin_width)) - >>> fibreoptic.pipelines = spectrometer.pipelines + polychromator.pipelines + >>> fibreoptic.pipelines = spectrometer.pipelines() + polychromator.pipelines() """ def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bin=None, name=''): @@ -194,7 +194,7 @@ class CzernyTurnerSpectrometer(Spectrometer): >>> fibreoptic.min_wavelength = hires_spectrometer.min_wavelength >>> fibreoptic.max_wavelength = hires_spectrometer.max_wavelength >>> fibreoptic.spectral_bins = hires_spectrometer.spectral_bins - >>> fibreoptic.pipelines = hires_spectrometer.pipelines + >>> fibreoptic.pipelines = hires_spectrometer.pipelines() """ def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, spectral_bins, From 6b48415bcb3a0b18a9cbb5f738cffa2aa80762ee Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 11 Nov 2021 21:12:41 +0300 Subject: [PATCH 07/81] Renamed SpectroscopicInstrument.pipelines() to SpectroscopicInstrument.new_pipelines() to avoid confusion. --- cherab/tools/spectroscopy/instrument.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherab/tools/spectroscopy/instrument.py b/cherab/tools/spectroscopy/instrument.py index f503c7f3..e593cafe 100644 --- a/cherab/tools/spectroscopy/instrument.py +++ b/cherab/tools/spectroscopy/instrument.py @@ -54,7 +54,7 @@ def pipeline_properties(self): return self._pipeline_properties - def pipelines(self): + def new_pipelines(self): """ Returns a list of new pipelines according to `pipeline_properties`.""" pl_list = [] From 808126a194150261ac0ea2ea289e46fb7f7fa226 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Sat, 13 Nov 2021 18:32:08 +0300 Subject: [PATCH 08/81] Improved implementation of Polychromator and PolychromatorFilter. --- cherab/tools/spectroscopy/__init__.py | 2 +- cherab/tools/spectroscopy/polychromator.py | 126 +++++++++++++++------ 2 files changed, 91 insertions(+), 37 deletions(-) diff --git a/cherab/tools/spectroscopy/__init__.py b/cherab/tools/spectroscopy/__init__.py index 207aaf87..74bf4d16 100644 --- a/cherab/tools/spectroscopy/__init__.py +++ b/cherab/tools/spectroscopy/__init__.py @@ -18,5 +18,5 @@ # under the Licence. from .instrument import SpectroscopicInstrument -from .polychromator import PolychromatorFilter, Polychromator +from .polychromator import PolychromatorFilter, TrapezoidalFilter, Polychromator from .spectrometer import Spectrometer, CzernyTurnerSpectrometer, SurveySpectrometer diff --git a/cherab/tools/spectroscopy/polychromator.py b/cherab/tools/spectroscopy/polychromator.py index 27366a45..0a72c970 100644 --- a/cherab/tools/spectroscopy/polychromator.py +++ b/cherab/tools/spectroscopy/polychromator.py @@ -26,7 +26,78 @@ class PolychromatorFilter(InterpolatedSF): """ - Defines a symmetrical trapezoidal polychromator filter as a Raysect's InterpolatedSF. + Defines a polychromator filter as a Raysect's InterpolatedSF. + + :param object wavelengths: 1D array of wavelengths in nanometers. + :param object samples: 1D array of spectral samples. + :param bool normalise: True/false toggle for whether to normalise the + spectral function so its integral equals 1. + :param str name: Filter name (e.g. "H-alpha filter"). Default is ''. + + :ivar float min_wavelength: Lower wavelength bound of the filter's spectral range in nm. + :ivar float max_wavelength: Upper wavelength bound of the filter's spectral range in nm. + """ + + def __init__(self, wavelengths, samples, normalise=False, name=''): + + wavelengths = np.array(wavelengths, dtype=np.float64) + samples = np.array(samples, dtype=np.float64) + + if wavelengths.ndim != 1: + raise ValueError("Wavelength array must be 1D.") + + if samples.shape[0] != wavelengths.shape[0]: + raise ValueError("Wavelength and sample arrays must be the same length.") + + indices = np.argsort(wavelengths) + wavelengths = wavelengths[indices] + samples = samples[indices] + + self._min_wavelength = wavelengths[0] + self._max_wavelength = wavelengths[-1] + self._window = self._max_wavelength - self._min_wavelength + self._central_wavelength = 0.5 * (self._max_wavelength + self._min_wavelength) + + # setting the ends of the filter to zero, if they are not + if samples[0] != 0: + wavelengths = np.insert(wavelengths, 0, wavelengths[0] * (1. - 1.e-15)) + samples = np.insert(samples, 0, 0) + if samples[-1] != 0: + wavelengths = np.append(wavelengths, wavelengths[-1] * (1. + 1.e-15)) + samples = np.append(samples, 0) + + super().__init__(wavelengths, samples, normalise) + self._name = str(name) + + @property + def name(self): + # Filter name. + return self._name + + @property + def min_wavelength(self): + # Lower wavelength bound of the filter's spectral range in nm. + return self._min_wavelength + + @property + def max_wavelength(self): + # Upper wavelength bound of the filter's spectral range in nm. + return self._max_wavelength + + @property + def window(self): + # Size of the filtering window in nm. + return self._window + + @property + def central_wavelength(self): + # Central wavelength of the filter in nm. + return self._central_wavelength + + +class TrapezoidalFilter(PolychromatorFilter): + """ + Symmetrical trapezoidal polychromator filter. :param float wavelength: Central wavelength of the filter in nm. :param float window: Size of the filtering window in nm. Default is 3. @@ -35,55 +106,38 @@ class PolychromatorFilter(InterpolatedSF): :param str name: Filter name (e.g. "H-alpha filter"). Default is ''. """ - def __init__(self, wavelength, window=3., flat_top=None, name=''): + def __init__(self, central_wavelength, window=3., flat_top=None, name=''): - if wavelength <= 0: - raise ValueError("Argument 'wavelength' must be positive.") + if central_wavelength <= 0: + raise ValueError("Argument 'central_wavelength' must be positive.") if window <= 0: raise ValueError("Argument 'window' must be positive.") - flat_top = flat_top or window - 1.e-15 + flat_top = flat_top or window if flat_top <= 0: raise ValueError("Argument 'flat_top' must be positive.") if flat_top > window: raise ValueError("Argument 'flat_top' must be less or equal than 'window'.") - if flat_top == window: - flat_top = window - 1.e-15 - self._window = window self._flat_top = flat_top - self._wavelength = wavelength - self._name = str(name) - wavelengths = [wavelength - 0.5 * window, - wavelength - 0.5 * flat_top, - wavelength + 0.5 * flat_top, - wavelength + 0.5 * window] - samples = [0, 1, 1, 0] - super().__init__(wavelengths, samples, normalise=False) + if flat_top == window: + flat_top -= flat_top * 1.e-15 - @property - def window(self): - # Size of the filtering window in nm. - return self._window + wavelengths = [central_wavelength - 0.5 * window, + central_wavelength - 0.5 * flat_top, + central_wavelength + 0.5 * flat_top, + central_wavelength + 0.5 * window] + samples = [0, 1, 1, 0] + super().__init__(wavelengths, samples, normalise=False, name=name) @property def flat_top(self): # Size of the flat top part of the filter in nm. return self._flat_top - @property - def wavelength(self): - # Central wavelength of the filter in nm. - return self._wavelength - - @property - def name(self): - # Filter name. - return self._name - class Polychromator(SpectroscopicInstrument): """ @@ -98,17 +152,17 @@ class Polychromator(SpectroscopicInstrument): >>> from raysect.optical import World >>> from raysect.optical.observer import FibreOptic - >>> from cherab.tools.spectroscopy import Polychromator, PolychromatorFilter + >>> from cherab.tools.spectroscopy import Polychromator, TrapezoidalFilter >>> >>> world = World() - >>> h_alpha_filter = PolychromatorFilter(656.1, name='H-alpha filter') - >>> ciii_465nm_filter = PolychromatorFilter(464.8, name='CIII 465 nm filter') + >>> h_alpha_filter = TrapezoidalFilter(656.1, name='H-alpha filter') + >>> ciii_465nm_filter = TrapezoidalFilter(464.8, name='CIII 465 nm filter') >>> polychromator = Polychromator([h_alpha_filter, ciii_465nm_filter], name='MyPolychromator') >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) >>> fibreoptic.min_wavelength = polychromator.min_wavelength >>> fibreoptic.max_wavelength = polychromator.max_wavelength >>> fibreoptic.spectral_bins = polychromator.spectral_bins - >>> fibreoptic.pipelines = polychromator.pipelines() + >>> fibreoptic.pipelines = polychromator.new_pipelines() """ def __init__(self, filters, min_bins_per_window=10, name=''): @@ -155,8 +209,8 @@ def _update_spectral_settings(self): step = np.inf for poly_filter in self._filters: step = min(step, poly_filter.window / self._min_bins_per_window) - min_wavelength = min(min_wavelength, poly_filter.wavelength - 0.5 * poly_filter.window) - max_wavelength = max(max_wavelength, poly_filter.wavelength + 0.5 * poly_filter.window) + min_wavelength = min(min_wavelength, poly_filter.min_wavelength) + max_wavelength = max(max_wavelength, poly_filter.max_wavelength) self._min_wavelength = min_wavelength self._max_wavelength = max_wavelength From 5172888fa6eaa17186dbd72bfdbfce800c17ade3 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Sat, 13 Nov 2021 20:02:01 +0300 Subject: [PATCH 09/81] Updated the tests for the Polychromator and the filters. --- .../tests/test_spectroscopic_instruments.py | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/cherab/tools/tests/test_spectroscopic_instruments.py b/cherab/tools/tests/test_spectroscopic_instruments.py index 883dc8c6..ab33f170 100644 --- a/cherab/tools/tests/test_spectroscopic_instruments.py +++ b/cherab/tools/tests/test_spectroscopic_instruments.py @@ -20,7 +20,7 @@ import numpy as np from raysect.optical.observer.pipeline import RadiancePipeline0D, SpectralRadiancePipeline0D -from cherab.tools.spectroscopy import PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer +from cherab.tools.spectroscopy import TrapezoidalFilter, PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer class TestPolychromatorFilter(unittest.TestCase): @@ -28,11 +28,26 @@ class TestPolychromatorFilter(unittest.TestCase): Test for PolychromatorFilter class. """ + def test_spectrum(self): + wavelengths = [658, 654, 656] # unsorted + samples = [0.5, 0.5, 1] # non-zero at the ends + poly_filter = PolychromatorFilter(wavelengths, samples, name='test_filter') + wavelengths = np.linspace(653., 659., 7) + spectrum_true = np.array([0, 0.5, 0.75, 1., 0.75, 0.5, 0]) + spectrum_test = np.array([poly_filter(wvl) for wvl in wavelengths]) + self.assertTrue(np.all(spectrum_true == spectrum_test)) + + +class TestTrapezoidalFilter(unittest.TestCase): + """ + Test for TrapezoidalFilter class. + """ + def test_spectrum(self): wavelength = 500. window = 6. flat_top = 2. - poly_filter = PolychromatorFilter(wavelength, window, flat_top, 'test_filter') + poly_filter = TrapezoidalFilter(wavelength, window, flat_top, 'test_filter') wavelengths = np.linspace(496., 504., 9) spectrum_true = np.array([0, 0, 0.5, 1., 1., 1., 0.5, 0, 0]) spectrum_test = np.array([poly_filter(wvl) for wvl in wavelengths]) @@ -44,10 +59,9 @@ class TestPolychromator(unittest.TestCase): Test cases for Polychromator class. """ - def setUp(self): - self.poly_filters_default = [PolychromatorFilter(400., 6., 2., 'filter 1'), - PolychromatorFilter(700., 8., 4., 'filter 2')] - self.min_bins_per_window_default = 10 + poly_filters_default = (TrapezoidalFilter(400., 6., 2., 'filter 1'), + TrapezoidalFilter(700., 8., 4., 'filter 2')) + min_bins_per_window_default = 10 def test_pipeline_properties(self): polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default, 'test polychromator') @@ -68,8 +82,8 @@ def test_filter_change(self): """ Checks if the spectral properties are updated correctly when the filters are replaced.""" polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default) polychromator.min_bins_per_window = 20 - polychromator.filters = [PolychromatorFilter(500., 5., 2., 'filter 1'), - PolychromatorFilter(600., 7., 4., 'filter 2')] + polychromator.filters = [TrapezoidalFilter(500., 5., 2., 'filter 1'), + TrapezoidalFilter(600., 7., 4., 'filter 2')] min_wavelength_true = 497.5 max_wavelength_true = 603.5 spectral_bins_true = 424 @@ -109,14 +123,13 @@ class TestCzernyTurnerSpectrometer(unittest.TestCase): Test cases for CzernyTurnerSpectrometer class. """ - def setUp(self): - self.diffraction_order = 1 - self.grating = 2.e-3 - self.focal_length = 1.e9 - self.pixel_spacing = 2.e4 - self.diffraction_angle = 10. - self.spectral_bins = 512 - self.reference_bin = 255 + diffraction_order = 1 + grating = 2.e-3 + focal_length = 1.e9 + pixel_spacing = 2.e4 + diffraction_angle = 10. + spectral_bins = 512 + reference_bin = 255 def test_resolution(self): wavelengths = [350., 550., 750.] From 7dc613d0cf75e6c985e8c043c7efe21f734dee0f Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 18 Nov 2021 14:18:00 +0300 Subject: [PATCH 10/81] Reimplemented spectrometers in response to reviewer's comments. --- cherab/tools/spectroscopy/__init__.py | 2 +- cherab/tools/spectroscopy/spectrometer.py | 319 ++++++++++-------- .../tests/test_spectroscopic_instruments.py | 67 ++-- docs/source/tools/spectroscopy.rst | 12 +- 4 files changed, 221 insertions(+), 179 deletions(-) diff --git a/cherab/tools/spectroscopy/__init__.py b/cherab/tools/spectroscopy/__init__.py index 74bf4d16..23bbbe1f 100644 --- a/cherab/tools/spectroscopy/__init__.py +++ b/cherab/tools/spectroscopy/__init__.py @@ -19,4 +19,4 @@ from .instrument import SpectroscopicInstrument from .polychromator import PolychromatorFilter, TrapezoidalFilter, Polychromator -from .spectrometer import Spectrometer, CzernyTurnerSpectrometer, SurveySpectrometer +from .spectrometer import Spectrometer, CzernyTurnerSpectrometer diff --git a/cherab/tools/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py index de67e36a..c640179d 100644 --- a/cherab/tools/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -18,6 +18,7 @@ # under the Licence. import numpy as np +from raysect.optical import Spectrum from raysect.optical.observer import SpectralRadiancePipeline0D from .instrument import SpectroscopicInstrument @@ -25,161 +26,165 @@ class Spectrometer(SpectroscopicInstrument): """ - Spectrometer base class. - This is an abstract class. - - :param int spectral_bins: The number of spectral samples over the wavelength range. - :param float reference_wavelength: Wavelength (in nm) corresponding to - the centre of reference bin. - :param int reference_bin: Reference bin index. Can be negative to specify the offset. - Default is None (spectral_bins // 2). - :param str name: Spectrometer name. - """ - - def __init__(self, spectral_bins, reference_wavelength, reference_bin=None, name=''): - super().__init__(name) - self.spectral_bins = spectral_bins - if reference_bin is None: - self.reference_bin = self._spectral_bins // 2 - else: - self.reference_bin = reference_bin - self.reference_wavelength = reference_wavelength + Spectrometer that can accommodate multiple spectra. - @property - def spectral_bins(self): - # The number of spectral samples over the wavelength range. - return self._spectral_bins - - @spectral_bins.setter - def spectral_bins(self, value): - value = int(value) - if value <= 0: - raise ValueError("Attribute 'spectral_bins' must be > 0.") + Spectrometer is initialized with a sequence of calibration arrays (one array per accommodated + spectrum) containing the wavelengths of the pixel borders. Namely, the values + :math:`w_{k}^{i}` and :math:`w_{k}^{i+1}` define the spectral range of the pixel :math:`p_i` + of the `k`-th spectrum. After the spectrum is ray-traced, it can be recalibrated with + `spectrometer.calibrate(spectrum)`. - self._spectral_bins = value - self._clear_spectral_settings() - - @property - def reference_wavelength(self): - # Wavelength (in nm) corresponding to the centre of reference bin. - return self._reference_wavelength - - @reference_wavelength.setter - def reference_wavelength(self, value): - if value <= 0: - raise ValueError("Attribute 'reference_wavelength' must be > 0.") - - self._reference_wavelength = value - self._clear_spectral_settings() + Note that Raysect cannot raytrace the spectra with non-constant spectral resolution. + Thus, the actual number of spectral bins of raytraced spectrum is defined with + `min_bins_per_pixel` attribute. - @property - def reference_bin(self): - # Reference bin index. - return self._reference_bin - - @reference_bin.setter - def reference_bin(self, value): - value = int(value) - - self._reference_bin = value - self._clear_spectral_settings() - - def _update_pipeline_properties(self): - self._pipeline_properties = [(SpectralRadiancePipeline0D, self._name, None)] - - def _clear_spectral_settings(self): - self._min_wavelength = None - self._max_wavelength = None - - -class SurveySpectrometer(Spectrometer): - """ - Survey spectrometer with a constant spectral resolution. - - Note: survey spectrometers usually have non-constant spectral resolution - in the supported wavelength range. However, Raysect does not support - the observers with variable spectral resolution. - - :param float resolution: Spectral resolution in nm (can be negative). - :param int spectral_bins: The number of spectral samples over the wavelength range. - :param float reference_wavelength: Wavelength (in nm) corresponding to - the centre of reference bin. - :param int reference_bin: Reference bin index. Can be negative to specify the offset. - Default is None (spectral_bins // 2). + :param tuple wavelength_to_pixel: Wavelength-to-pixel calibration arrays. + :param int min_bins_per_pixel: Minimal number of spectral bins + per pixel. Default is 1. :param str name: Spectrometer name. - :ivar float resolution: Spectral resolution in nm (can be negative). + :ivar tuple wavelengths: Central wavelengths of the pixels. .. code-block:: pycon - >>> from numpy import ceil - >>> from raysect.optical import World + >>> from raysect.optical import World, Spectrum >>> from raysect.optical.observer import FibreOptic - >>> from cherab.tools.spectroscopy import SurveySpectrometer, Polychromator, PolychromatorFilter + >>> from cherab.tools.spectroscopy import Spectrometer + >>> from matplotlib import pyplot as plt + >>> + >>> wavelength_to_pixel = ([400., 400.5, 401.5, 402., 404.], + >>> [600., 600.5, 601.5, 602., 604., 607.]) + >>> spectrometer = Spectrometer(wavelength_to_pixel, min_bins_per_pixel=5, + >>> name='MySpectrometer') >>> >>> world = World() >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) - >>> # Here, the fibre optic is "connected" to both survey spectrometer and polychromator. + >>> fibreoptic.min_wavelength = spectrometer.min_wavelength + >>> fibreoptic.max_wavelength = spectrometer.max_wavelength + >>> fibreoptic.spectral_bins = spectrometer.spectral_bins + >>> fibreoptic.pipelines = spectrometer.new_pipelines() + >>> ... + >>> fibreoptic.observe() + >>> spectrum = Spectrum(fibreoptic.min_wavelength, fibreoptic.max_wavelength, fibreoptic.spectral_bins) + >>> spectrum.samples[:] = fibreoptic.pipelines[0].mean + >>> calibrated_spectra = spectrometer.calibrate(spectrum) + >>> wavelengths = spectrometer.wavelengths >>> - >>> # setting up the polychromator - >>> h_alpha_filter = PolychromatorFilter(656.1, name='H-alpha filter') - >>> ciii_465nm_filter = PolychromatorFilter(464.8, name='CIII 465 nm filter') - >>> polychromator = Polychromator([h_alpha_filter, ciii_465nm_filter], name='MyPolychromator') - >>> - >>> # setting up the survey spectrometer - >>> spectrometer = SurveySpectrometer(0.1, 1024, 500, name='MySpectrometer') - >>> - >>> fibreoptic.min_wavelength = min(spectrometer.min_wavelength, polychromator.min_wavelength) - >>> fibreoptic.max_wavelength = max(spectrometer.max_wavelength, polychromator.max_wavelength) - >>> bin_width = min((spectrometer.max_wavelength - spectrometer.min_wavelength) / spectrometer.spectral_bins, - >>> (polychromator.max_wavelength - polychromator.min_wavelength) / polychromator.spectral_bins) - >>> fibreoptic.spectral_bins = int(ceil((fibreoptic.max_wavelength - fibreoptic.min_wavelength) / bin_width)) - >>> fibreoptic.pipelines = spectrometer.pipelines() + polychromator.pipelines() + >>> plt.plot(wavelengths[0], calibrated_spectra[0]) + >>> plt.show() """ - def __init__(self, resolution, spectral_bins, reference_wavelength, reference_bin=None, name=''): - super().__init__(spectral_bins, reference_wavelength, reference_bin, name) - self.resolution = resolution + def __init__(self, wavelength_to_pixel, min_bins_per_pixel=1, name=''): + + self.min_bins_per_pixel = min_bins_per_pixel + self.wavelength_to_pixel = wavelength_to_pixel + super().__init__(name) + + @property + def wavelength_to_pixel(self): + # Wavelength-to-pixel calibration arrays. + return self._wavelength_to_pixel + + @wavelength_to_pixel.setter + def wavelength_to_pixel(self, value): + _wavelength_to_pixel = [] + _wavelengths = [] + for wl2pix in value: + wl2pix = np.array(wl2pix, dtype=float) + if wl2pix.ndim != 1: + raise ValueError('Attribute wavelength_to_pixel must only contain one-dimensional arrays.') + if wl2pix.size < 2: + raise ValueError('Attribute wavelength_to_pixel must only contain arrays of at least 2 elements.') + if np.any(np.diff(wl2pix) <= 0): + raise ValueError('Attribute wavelength_to_pixel must only contain monotonically increasing arrays.') + wl2pix.flags.writeable = False + _wavelength_to_pixel.append(wl2pix) + wl_center = 0.5 * (wl2pix[1:] + wl2pix[:-1]) + wl_center.flags.writeable = False + _wavelengths.append(wl_center) + self._wavelength_to_pixel = tuple(_wavelength_to_pixel) + self._wavelengths = tuple(_wavelengths) + self._clear_spectral_settings() + + @property + def wavelengths(self): + # Central wavelengths of the pixels. + return self._wavelengths @property - def resolution(self): - # Spectral resolution in nm (can be negative). - return self._resolution + def min_bins_per_pixel(self): + # Minimal number of spectral bins per pixel. + return self._min_bins_per_pixel - @resolution.setter - def resolution(self, value): - if value == 0: - raise ValueError("Attribute 'resolution' must be non-zero.") + @min_bins_per_pixel.setter + def min_bins_per_pixel(self, value): + value = int(value) + if value <= 0: + raise ValueError("Attribute 'min_bins_per_pixel' must be positive.") - self._resolution = value + self._min_bins_per_pixel = value self._clear_spectral_settings() - def _update_spectral_settings(self): + def _update_pipeline_properties(self): + self._pipeline_properties = [(SpectralRadiancePipeline0D, self._name, None)] - if self._resolution > 0: - self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * self._resolution - self._max_wavelength = self._min_wavelength + self._spectral_bins * self._resolution - else: - self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * self._resolution - self._max_wavelength = self._min_wavelength - self._spectral_bins * self._resolution + def _update_spectral_settings(self): + self._min_wavelength = min(wl2pix[0] for wl2pix in self._wavelength_to_pixel) + self._max_wavelength = max(wl2pix[-1] for wl2pix in self._wavelength_to_pixel) + step = min(np.diff(wl2pix).min() for wl2pix in self._wavelength_to_pixel) / self._min_bins_per_pixel + self._spectral_bins = int(np.ceil((self._max_wavelength - self._min_wavelength) / step)) + + def calibrate(self, spectrum): + """ + Calibrates the spectrum according to the `wavelength_to_pixel` arrays + by averaging it over the pixel widths. + + :param Spectrum spectrum: Spectrum to calibrate. + + :returns: A tuple of calibrated spectra as ndarrays. + """ + if not isinstance(spectrum, Spectrum): + raise TypeError('Argument spectrum must be a Spectrum instance.') + if spectrum.min_wavelength > self.min_wavelength or spectrum.max_wavelength < self.max_wavelength: + raise ValueError('Unable to calibrate the spectrum. ' + 'The spectrum has narrower range ({}, {}) than the spectrometer ({}, {}).'.format(spectrum.min_wavelength, + spectrum.max_wavelength, + self.min_wavelength, + self.max_wavelength)) + calibrated_spectra = [] + for wl2pix in self.wavelength_to_pixel: + calibrated_spectrum = np.zeros(wl2pix.size - 1) + for i in range(wl2pix.size - 1): + calibrated_spectrum[i] = spectrum.integrate(wl2pix[i], wl2pix[i + 1]) / (wl2pix[i + 1] - wl2pix[i]) + calibrated_spectra.append(calibrated_spectrum) + + return calibrated_spectra class CzernyTurnerSpectrometer(Spectrometer): """ - Czerny-Turner high-resolution spectrometer. + Czerny-Turner spectrometer. + + The Czerny-Turner spectrometer is initialized with the parameters of the diffraction scheme + and a sequence of accommodated spectra, each of which is determined by the lower wavelength + bound and the number of pixels. + + This spectrometer automatically fills the wavelength-to-pixel calibration arrays + according to the parameters of the diffraction scheme. :param int diffraction_order: Diffraction order. :param float grating: Diffraction grating in nm-1. :param float focal_length: Focal length in nm. :param float pixel_spacing: Pixel to pixel spacing on CCD in nm. :param float diffraction_angle: Angle between incident and diffracted light in degrees. - :param int spectral_bins: The number of spectral samples over the wavelength range. - :param float reference_wavelength: Wavelength (in nm) corresponding to - the centre of reference bin. - :param int reference_bin: Reference bin index. Default is None (spectral_bins // 2). + :param tuple accommodated_spectra: A sequence of (`min_wavelength`, `pixels`) pairs, specifying + the lower wavelength bound and the number of pixels + of accommodated spectra. + :param int min_bins_per_pixel: Minimal number of spectral bins + per pixel. Default is 1. :param str name: Spectrometer name. - :ivar float resolution: Spectral resolution in nm (can be negative). + :ivar tuple wavelength_to_pixel: Wavelength-to-pixel calibration arrays. .. code-block:: pycon @@ -188,23 +193,26 @@ class CzernyTurnerSpectrometer(Spectrometer): >>> from cherab.tools.spectroscopy import CzernyTurnerSpectrometer >>> >>> world = World() - >>> hires_spectrometer = CzernyTurnerSpectrometer(1, 2.e-3, 1.e9, 2.e4, 10., 512, 600., + >>> hires_spectrometer = CzernyTurnerSpectrometer(1, 2.e-3, 1.e9, 2.e4, 10., + >>> ((600., 512), (700., 128)), >>> name='MySpectrometer') >>> fibreoptic = FibreOptic(name="MyFibreOptic", parent=world) >>> fibreoptic.min_wavelength = hires_spectrometer.min_wavelength >>> fibreoptic.max_wavelength = hires_spectrometer.max_wavelength >>> fibreoptic.spectral_bins = hires_spectrometer.spectral_bins - >>> fibreoptic.pipelines = hires_spectrometer.pipelines() + >>> fibreoptic.pipelines = hires_spectrometer.new_pipelines() """ - def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, spectral_bins, - reference_wavelength, reference_bin=None, name=''): - super().__init__(spectral_bins, reference_wavelength, reference_bin, name) + def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, + accommodated_spectra, min_bins_per_pixel=1, name=''): self.diffraction_order = diffraction_order self.grating = grating self.focal_length = focal_length self.pixel_spacing = pixel_spacing self.diffraction_angle = diffraction_angle + self.accommodated_spectra = accommodated_spectra + self.min_bins_per_pixel = min_bins_per_pixel + self.name = name @property def diffraction_order(self): @@ -253,8 +261,8 @@ def pixel_spacing(self): @pixel_spacing.setter def pixel_spacing(self, value): - if value == 0: - raise ValueError("Attribute 'pixel_spacing' must be non-zero.") + if value <= 0: + raise ValueError("Attribute 'pixel_spacing' must be positive.") self._pixel_spacing = value self._clear_spectral_settings() @@ -273,26 +281,53 @@ def diffraction_angle(self, value): self._clear_spectral_settings() @property - def resolution(self): - # Spectral resolution in nm (can be negative). + def accommodated_spectra(self): + return self._accommodated_spectra + + @accommodated_spectra.setter + def accommodated_spectra(self, value): + _wavelength_to_pixel = [] + _wavelengths = [] + for min_wavelength, pixels in value: + if min_wavelength <= 0: + raise ValueError('The value of min_wavelength in accommodated_spectra must be positive.') + if pixels <= 0: + raise ValueError('The value of pixels in accommodated_spectra must be positive.') + pixels = int(pixels) + wl2pix = np.zeros(pixels + 1) + wl2pix[0] = min_wavelength + for i in range(1, pixels + 1): + wl2pix[i] = wl2pix[i - 1] + self.resolution(wl2pix[i - 1]) + wl2pix.flags.writeable = False + _wavelength_to_pixel.append(wl2pix) + wl_center = 0.5 * (wl2pix[1:] + wl2pix[:-1]) + wl_center.flags.writeable = False + _wavelengths.append(wl_center) + self._accommodated_spectra = value + self._wavelength_to_pixel = tuple(_wavelength_to_pixel) + self._wavelengths = tuple(_wavelengths) + self._clear_spectral_settings() + + @property + def wavelength_to_pixel(self): + # Wavelength-to-pixel calibration arrays. + return self._wavelength_to_pixel + + def resolution(self, wavelength): + """ + Calculates spectral resolution in nm for a given wavelength. + + :param wavelength: Wavelength in nm. + + :returns: Resolution in nm. + """ grating = self._grating m = self._diffraction_order dxdp = self._pixel_spacing angle = self._diffraction_angle fl = self._focal_length - p = 0.5 * m * grating * self._reference_wavelength + p = 0.5 * m * grating * wavelength _resolution = dxdp * (np.sqrt(np.cos(angle)**2 - p * p) - p * np.tan(angle)) / (m * fl * grating) return _resolution - - def _update_spectral_settings(self): - - resolution = self.resolution - - if resolution > 0: - self._min_wavelength = self._reference_wavelength - (self._reference_bin + 0.5) * resolution - self._max_wavelength = self._min_wavelength + self._spectral_bins * resolution - else: - self._min_wavelength = self._reference_wavelength + (self._spectral_bins - self._reference_bin - 0.5) * resolution - self._max_wavelength = self._min_wavelength - self._spectral_bins * resolution diff --git a/cherab/tools/tests/test_spectroscopic_instruments.py b/cherab/tools/tests/test_spectroscopic_instruments.py index ab33f170..a8d843d6 100644 --- a/cherab/tools/tests/test_spectroscopic_instruments.py +++ b/cherab/tools/tests/test_spectroscopic_instruments.py @@ -19,8 +19,9 @@ import unittest import numpy as np +from raysect.optical import Spectrum from raysect.optical.observer.pipeline import RadiancePipeline0D, SpectralRadiancePipeline0D -from cherab.tools.spectroscopy import TrapezoidalFilter, PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, SurveySpectrometer +from cherab.tools.spectroscopy import TrapezoidalFilter, PolychromatorFilter, Polychromator, CzernyTurnerSpectrometer, Spectrometer class TestPolychromatorFilter(unittest.TestCase): @@ -92,30 +93,35 @@ def test_filter_change(self): polychromator.spectral_bins == spectral_bins_true) -class TestSurveySpectrometer(unittest.TestCase): +class TestSpectrometer(unittest.TestCase): """ - Test cases for SurveySpectrometer class. + Test cases for Spectrometer class. """ def test_pipeline_properties(self): - resolution = 0.1 - reference_wavelength = 500 - reference_bin = 50 - spectral_bins = 200 - spectrometer = SurveySpectrometer(resolution, spectral_bins, reference_wavelength, reference_bin, name='test spectrometer') + wavelength_to_pixel = ([400., 400.5],) + spectrometer = Spectrometer(wavelength_to_pixel, name='test spectrometer') pipeline_properties_true = [(SpectralRadiancePipeline0D, 'test spectrometer', None)] self.assertSequenceEqual(pipeline_properties_true, spectrometer.pipeline_properties) def test_spectral_properties(self): - resolution = 0.1 - reference_wavelength = 500 - reference_bin = 50 - spectral_bins = 200 - spectrometer = SurveySpectrometer(resolution, spectral_bins, reference_wavelength, reference_bin, name='test spectrometer') - min_wavelength_true = 494.95 - max_wavelength_true = 514.95 + wavelength_to_pixel = ([400., 400.5, 401.5, 402., 404.], [600., 600.5, 601.5, 602., 604., 607.]) + spectrometer = Spectrometer(wavelength_to_pixel, min_bins_per_pixel=2, name='test spectrometer') + min_wavelength_true = 400. + max_wavelength_true = 607. + spectra_bins_true = 828 self.assertTrue(spectrometer.min_wavelength == min_wavelength_true and - spectrometer.max_wavelength == max_wavelength_true) + spectrometer.max_wavelength == max_wavelength_true and + spectrometer.spectral_bins == spectra_bins_true) + + def test_calibration(self): + wavelength_to_pixel = ([400., 400.5, 401.5, 402., 404.],) + spectrometer = Spectrometer(wavelength_to_pixel, name='test spectrometer') + spectrum = Spectrum(399, 405, 12) + s, ds = np.linspace(0, 6., 13, retstep=True) + spectrum.samples[:] = s[:-1] + 0.5 * ds + calibrated_spectra = spectrometer.calibrate(spectrum) + self.assertTrue(np.all(calibrated_spectra[0] == np.array([1.25, 2., 2.75, 4.]))) class TestCzernyTurnerSpectrometer(unittest.TestCase): @@ -128,30 +134,27 @@ class TestCzernyTurnerSpectrometer(unittest.TestCase): focal_length = 1.e9 pixel_spacing = 2.e4 diffraction_angle = 10. - spectral_bins = 512 - reference_bin = 255 + accommodated_spectra = ((400., 64), (500., 32)) + min_bins_per_pixel = 2 def test_resolution(self): - wavelengths = [350., 550., 750.] + wavelengths = np.array([350., 550., 750.]) resolutions_true = np.array([8.587997e-3, 7.199328e-3, 5.0599164e-3]) spectrometer = CzernyTurnerSpectrometer(self.diffraction_order, self.grating, self.focal_length, self.pixel_spacing, - self.diffraction_angle, self.spectral_bins, 500., self.reference_bin, - name='test spectrometer') - resolutions = [] - for wvl in wavelengths: - spectrometer.reference_wavelength = wvl - resolutions.append(spectrometer.resolution) + self.diffraction_angle, self.accommodated_spectra, name='test spectrometer') + resolutions = spectrometer.resolution(wavelengths) self.assertTrue(np.all(np.abs(resolutions / resolutions_true - 1.) < 1.e-7)) def test_spectral_properties(self): - wavelength = 500. - min_wavelength_true = 498.0575 - max_wavelength_true = 501.9501 + min_wavelength_true = 400 + max_wavelength_true = 500.24326 + spectra_bins_true = 26377 spectrometer = CzernyTurnerSpectrometer(self.diffraction_order, self.grating, self.focal_length, self.pixel_spacing, - self.diffraction_angle, self.spectral_bins, wavelength, self.reference_bin, - name='test spectrometer') - self.assertTrue(abs(spectrometer.min_wavelength - min_wavelength_true) < 1.e-4 and - abs(spectrometer.max_wavelength - max_wavelength_true) < 1.e-4) + self.diffraction_angle, self.accommodated_spectra, + min_bins_per_pixel=self.min_bins_per_pixel, name='test spectrometer') + self.assertTrue(spectrometer.min_wavelength == min_wavelength_true and + spectrometer.spectral_bins == spectra_bins_true and + abs(spectrometer.max_wavelength - max_wavelength_true) < 1.e-5) if __name__ == '__main__': diff --git a/docs/source/tools/spectroscopy.rst b/docs/source/tools/spectroscopy.rst index 406222c4..a116dd77 100644 --- a/docs/source/tools/spectroscopy.rst +++ b/docs/source/tools/spectroscopy.rst @@ -9,7 +9,7 @@ The tools for plasma spectroscopy. Spectroscopic instruments ------------------------- -Spectroscopic instruments such as polychromators, survey and high-resolution spectrometers +Spectroscopic instruments such as polychromators and spectrometers simplify the setup of properties of the observers and rendering pipelines. The instruments are not connected to the scenegraph, so they cannot observe the world. However, the instruments have properties, such as `min_wavelength`, `max_wavelength`, `spectral_bins`, @@ -24,15 +24,19 @@ with spectral properties based on the actual experimental setup for a given shot .. autoclass:: cherab.tools.spectroscopy.PolychromatorFilter :members: -.. autoclass:: cherab.tools.spectroscopy.Polychromator +.. autoclass:: cherab.tools.spectroscopy.TrapezoidalFilter + :show-inheritance: :members: -.. autoclass:: cherab.tools.spectroscopy.Spectrometer +.. autoclass:: cherab.tools.spectroscopy.Polychromator + :show-inheritance: :members: -.. autoclass:: cherab.tools.spectroscopy.SurveySpectrometer +.. autoclass:: cherab.tools.spectroscopy.Spectrometer + :show-inheritance: :members: .. autoclass:: cherab.tools.spectroscopy.CzernyTurnerSpectrometer + :show-inheritance: :members: From 6e7c75ed4a367fd328113b98588aca877d21a0f3 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 23 Nov 2021 20:43:59 +0300 Subject: [PATCH 11/81] Renamed SpectroscopicInstrument's new_pipelines() to create_pipeline(). --- cherab/tools/spectroscopy/instrument.py | 4 ++-- cherab/tools/spectroscopy/polychromator.py | 2 +- cherab/tools/spectroscopy/spectrometer.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cherab/tools/spectroscopy/instrument.py b/cherab/tools/spectroscopy/instrument.py index e593cafe..b2baf152 100644 --- a/cherab/tools/spectroscopy/instrument.py +++ b/cherab/tools/spectroscopy/instrument.py @@ -54,8 +54,8 @@ def pipeline_properties(self): return self._pipeline_properties - def new_pipelines(self): - """ Returns a list of new pipelines according to `pipeline_properties`.""" + def create_pipelines(self): + """ Returns a list of new pipelines created according to `pipeline_properties`.""" pl_list = [] for (pl_class, pl_name, pl_filter) in self.pipeline_properties: diff --git a/cherab/tools/spectroscopy/polychromator.py b/cherab/tools/spectroscopy/polychromator.py index 0a72c970..f81c6158 100644 --- a/cherab/tools/spectroscopy/polychromator.py +++ b/cherab/tools/spectroscopy/polychromator.py @@ -162,7 +162,7 @@ class Polychromator(SpectroscopicInstrument): >>> fibreoptic.min_wavelength = polychromator.min_wavelength >>> fibreoptic.max_wavelength = polychromator.max_wavelength >>> fibreoptic.spectral_bins = polychromator.spectral_bins - >>> fibreoptic.pipelines = polychromator.new_pipelines() + >>> fibreoptic.pipelines = polychromator.create_pipelines() """ def __init__(self, filters, min_bins_per_window=10, name=''): diff --git a/cherab/tools/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py index c640179d..436f301a 100644 --- a/cherab/tools/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -62,7 +62,7 @@ class Spectrometer(SpectroscopicInstrument): >>> fibreoptic.min_wavelength = spectrometer.min_wavelength >>> fibreoptic.max_wavelength = spectrometer.max_wavelength >>> fibreoptic.spectral_bins = spectrometer.spectral_bins - >>> fibreoptic.pipelines = spectrometer.new_pipelines() + >>> fibreoptic.pipelines = spectrometer.create_pipelines() >>> ... >>> fibreoptic.observe() >>> spectrum = Spectrum(fibreoptic.min_wavelength, fibreoptic.max_wavelength, fibreoptic.spectral_bins) @@ -200,7 +200,7 @@ class CzernyTurnerSpectrometer(Spectrometer): >>> fibreoptic.min_wavelength = hires_spectrometer.min_wavelength >>> fibreoptic.max_wavelength = hires_spectrometer.max_wavelength >>> fibreoptic.spectral_bins = hires_spectrometer.spectral_bins - >>> fibreoptic.pipelines = hires_spectrometer.new_pipelines() + >>> fibreoptic.pipelines = hires_spectrometer.create_pipelines() """ def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, From e11a6d510f9709eaa4104576e7b767a412a3c061 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 14 Dec 2021 01:17:23 +0300 Subject: [PATCH 12/81] In CzernyTurnerSpectrometer invoke wavelength_to_pixel update when changing the property which affects the resolution. --- cherab/tools/spectroscopy/spectrometer.py | 31 +++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/cherab/tools/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py index 436f301a..5fbe3710 100644 --- a/cherab/tools/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -205,6 +205,7 @@ class CzernyTurnerSpectrometer(Spectrometer): def __init__(self, diffraction_order, grating, focal_length, pixel_spacing, diffraction_angle, accommodated_spectra, min_bins_per_pixel=1, name=''): + self._accommodated_spectra = None self.diffraction_order = diffraction_order self.grating = grating self.focal_length = focal_length @@ -226,7 +227,8 @@ def diffraction_order(self, value): raise ValueError("Attribute 'diffraction_order' must be positive.") self._diffraction_order = value - self._clear_spectral_settings() + # resolution has changed, recalculating wavelength_to_pixel + self._update_wavelength_to_pixel() @property def grating(self): @@ -239,7 +241,8 @@ def grating(self, value): raise ValueError("Attribute 'grating' must be positive.") self._grating = value - self._clear_spectral_settings() + # resolution has changed, recalculating wavelength_to_pixel + self._update_wavelength_to_pixel() @property def focal_length(self): @@ -252,7 +255,8 @@ def focal_length(self, value): raise ValueError("Attribute 'focal_length' must be positive.") self._focal_length = value - self._clear_spectral_settings() + # resolution has changed, recalculating wavelength_to_pixel + self._update_wavelength_to_pixel() @property def pixel_spacing(self): @@ -265,7 +269,8 @@ def pixel_spacing(self, value): raise ValueError("Attribute 'pixel_spacing' must be positive.") self._pixel_spacing = value - self._clear_spectral_settings() + # resolution has changed, recalculating wavelength_to_pixel + self._update_wavelength_to_pixel() @property def diffraction_angle(self): @@ -278,7 +283,8 @@ def diffraction_angle(self, value): raise ValueError("Attribute 'diffraction_angle' must be positive.") self._diffraction_angle = np.deg2rad(value) - self._clear_spectral_settings() + # resolution has changed, recalculating wavelength_to_pixel + self._update_wavelength_to_pixel() @property def accommodated_spectra(self): @@ -286,13 +292,22 @@ def accommodated_spectra(self): @accommodated_spectra.setter def accommodated_spectra(self, value): - _wavelength_to_pixel = [] - _wavelengths = [] for min_wavelength, pixels in value: if min_wavelength <= 0: raise ValueError('The value of min_wavelength in accommodated_spectra must be positive.') if pixels <= 0: raise ValueError('The value of pixels in accommodated_spectra must be positive.') + self._accommodated_spectra = value + self._update_wavelength_to_pixel() + + def _update_wavelength_to_pixel(self): + + if self._accommodated_spectra is None: + return + + _wavelength_to_pixel = [] + _wavelengths = [] + for min_wavelength, pixels in self._accommodated_spectra: pixels = int(pixels) wl2pix = np.zeros(pixels + 1) wl2pix[0] = min_wavelength @@ -303,9 +318,9 @@ def accommodated_spectra(self, value): wl_center = 0.5 * (wl2pix[1:] + wl2pix[:-1]) wl_center.flags.writeable = False _wavelengths.append(wl_center) - self._accommodated_spectra = value self._wavelength_to_pixel = tuple(_wavelength_to_pixel) self._wavelengths = tuple(_wavelengths) + self._clear_spectral_settings() @property From 27e99f1083027c698731289cdcb07bf4744248f2 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Tue, 14 Dec 2021 11:37:14 +0000 Subject: [PATCH 13/81] Add compatibility with raysect 0.8.0 Only changes needed to build the project without errors are included. --- .github/workflows/ci.yml | 4 ++-- cherab/core/VERSION | 2 +- cherab/tools/raytransfer/roughconductor.pyx | 5 +++-- pyproject.toml | 2 +- requirements.txt | 2 +- setup.py | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19ec060b..5fc5e55f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,8 +27,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Python dependencies run: python -m pip install cython>=0.28 numpy==${{ matrix.numpy-version }} scipy matplotlib - - name: Install Raysect from pypi - run: pip install raysect + - name: Install Raysect from Github + run: pip install git+https://github.com/raysect/source@development --global-option=build_ext --global-option="-j2" - name: Build cherab run: dev/build.sh - name: Run tests diff --git a/cherab/core/VERSION b/cherab/core/VERSION index f0bb29e7..fa710d85 100644 --- a/cherab/core/VERSION +++ b/cherab/core/VERSION @@ -1 +1 @@ -1.3.0 +1.4.0dev1 diff --git a/cherab/tools/raytransfer/roughconductor.pyx b/cherab/tools/raytransfer/roughconductor.pyx index 04edf6f2..faef9cf1 100644 --- a/cherab/tools/raytransfer/roughconductor.pyx +++ b/cherab/tools/raytransfer/roughconductor.pyx @@ -18,7 +18,7 @@ # under the Licence. # -from raysect.optical cimport Point3D, Vector3D, AffineMatrix3D, World, Ray, Spectrum, new_vector3d +from raysect.optical cimport Point3D, Vector3D, AffineMatrix3D, World, Ray, Spectrum, new_vector3d, Intersection from libc.math cimport M_PI, sqrt from raysect.optical.material cimport RoughConductor cimport cython @@ -34,7 +34,8 @@ cdef class RToptimisedRoughConductor(RoughConductor): @cython.cdivision(True) cpdef Spectrum evaluate_shading(self, World world, Ray ray, Vector3D s_incoming, Vector3D s_outgoing, Point3D w_reflection_origin, Point3D w_transmission_origin, bint back_face, - AffineMatrix3D world_to_surface, AffineMatrix3D surface_to_world): + AffineMatrix3D world_to_surface, AffineMatrix3D surface_to_world, + Intersection intersection): cdef: double n, k diff --git a/pyproject.toml b/pyproject.toml index 8c92c2a1..503024fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,2 @@ [build-system] -requires = ["setuptools", "wheel", "numpy>=1.14", "cython>=0.28", "raysect==0.7.1"] +requires = ["setuptools", "wheel", "numpy>=1.14", "cython>=0.28", "raysect==0.8.0"] diff --git a/requirements.txt b/requirements.txt index 2b5e7b4e..d9462771 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ cython>=0.28 numpy>=1.14 scipy matplotlib -raysect==0.7.1 \ No newline at end of file +raysect==0.8.0 diff --git a/setup.py b/setup.py index db4bb706..76674a0a 100644 --- a/setup.py +++ b/setup.py @@ -130,7 +130,7 @@ "numpy>=1.14", "scipy", "matplotlib", - "raysect==0.7.1", + "raysect==0.8.0", "cython>=0.28", ], packages=find_packages(), From 95c89bcd88f89d586c779a25a9d624f61b7b8784 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 24 Jan 2022 21:59:49 +0300 Subject: [PATCH 14/81] Added more accurate Gaunt factor for Bremsstrahlung emission model. --- cherab/core/atomic/__init__.pxd | 1 + cherab/core/atomic/__init__.py | 1 + .../maxwellian_free_free_gaunt_factor.json | 946 ++++++++++++++++++ cherab/core/atomic/gaunt.pxd | 39 + cherab/core/atomic/gaunt.pyx | 152 +++ cherab/core/atomic/interface.pxd | 9 +- cherab/core/atomic/interface.pyx | 19 +- cherab/core/model/plasma/bremsstrahlung.pxd | 13 +- cherab/core/model/plasma/bremsstrahlung.pyx | 22 +- cherab/core/utility/constants.pxd | 7 +- cherab/core/utility/constants.pyx | 8 +- demos/emission_models/bremsstrahlung.py | 84 ++ docs/source/atomic/atomic_data.rst | 1 + docs/source/atomic/gaunt_factors.rst | 23 + 14 files changed, 1296 insertions(+), 29 deletions(-) create mode 100644 cherab/core/atomic/data/maxwellian_free_free_gaunt_factor.json create mode 100644 cherab/core/atomic/gaunt.pxd create mode 100644 cherab/core/atomic/gaunt.pyx create mode 100755 demos/emission_models/bremsstrahlung.py create mode 100644 docs/source/atomic/gaunt_factors.rst diff --git a/cherab/core/atomic/__init__.pxd b/cherab/core/atomic/__init__.pxd index 0aa3cb90..3b2aa5c6 100644 --- a/cherab/core/atomic/__init__.pxd +++ b/cherab/core/atomic/__init__.pxd @@ -22,4 +22,5 @@ from cherab.core.atomic.line cimport Line from cherab.core.atomic.interface cimport AtomicData from cherab.core.atomic.rates cimport * from cherab.core.atomic.zeeman cimport ZeemanStructure +from cherab.core.atomic.gaunt cimport * diff --git a/cherab/core/atomic/__init__.py b/cherab/core/atomic/__init__.py index 3bb11780..35a7f80e 100644 --- a/cherab/core/atomic/__init__.py +++ b/cherab/core/atomic/__init__.py @@ -22,3 +22,4 @@ from .interface import AtomicData from .rates import * from .zeeman import ZeemanStructure +from .gaunt import * diff --git a/cherab/core/atomic/data/maxwellian_free_free_gaunt_factor.json b/cherab/core/atomic/data/maxwellian_free_free_gaunt_factor.json new file mode 100644 index 00000000..124e0622 --- /dev/null +++ b/cherab/core/atomic/data/maxwellian_free_free_gaunt_factor.json @@ -0,0 +1,946 @@ +{ + "u": [ + 0.0001, + 0.001, + 0.01, + 0.1, + 1.0, + 10.0, + 100.0, + 1000.0, + 10000.0 + ], + "gamma2": [ + 1e-08, + 1.5848931924611143e-08, + 2.511886431509582e-08, + 3.981071705534969e-08, + 6.30957344480193e-08, + 1e-07, + 1.584893192461114e-07, + 2.5118864315095823e-07, + 3.981071705534969e-07, + 6.30957344480193e-07, + 1e-06, + 1.584893192461114e-06, + 2.5118864315095823e-06, + 3.981071705534969e-06, + 6.30957344480193e-06, + 1e-05, + 1.584893192461114e-05, + 2.5118864315095822e-05, + 3.9810717055349695e-05, + 6.309573444801929e-05, + 0.0001, + 0.00015848931924611142, + 0.00025118864315095795, + 0.00039810717055349735, + 0.000630957344480193, + 0.001, + 0.001584893192461114, + 0.0025118864315095794, + 0.003981071705534973, + 0.00630957344480193, + 0.01, + 0.015848931924611134, + 0.025118864315095794, + 0.039810717055349734, + 0.06309573444801933, + 0.1, + 0.15848931924611134, + 0.251188643150958, + 0.3981071705534972, + 0.6309573444801932, + 1.0, + 1.5848931924611136, + 2.51188643150958, + 3.9810717055349722, + 6.309573444801933, + 10.0, + 15.848931924611133, + 25.118864315095795, + 39.810717055349734, + 63.09573444801933, + 100.0, + 158.48931924611142, + 251.18864315095797, + 398.1071705534973, + 630.957344480193, + 1000.0, + 1584.893192461114, + 2511.88643150958, + 3981.0717055349733, + 6309.57344480193, + 10000.0, + 15848.93192461114, + 25118.864315095823, + 39810.71705534969, + 63095.7344480193, + 100000.0, + 158489.3192461114, + 251188.6431509582, + 398107.1705534969, + 630957.344480193, + 1000000.0, + 1584893.1924611141, + 2511886.4315095823, + 3981071.7055349695, + 6309573.44480193, + 10000000.0, + 15848931.924611142, + 25118864.315095823, + 39810717.05534969, + 63095734.448019296, + 100000000.0, + 158489319.2461111, + 251188643.1509582, + 398107170.5534969, + 630957344.4801943, + 1000000000.0, + 1584893192.4611108, + 2511886431.509582, + 3981071705.5349693, + 6309573444.801943, + 10000000000.0 + ], + "gaunt_factor": [ + [ + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.528, + 5.527, + 5.527, + 5.527, + 5.527, + 5.526, + 5.525, + 5.523, + 5.52, + 5.516, + 5.51, + 5.501, + 5.489, + 5.472, + 5.449, + 5.419, + 5.379, + 5.329, + 5.267, + 5.193, + 5.107, + 5.01, + 4.904, + 4.792, + 4.676, + 4.557, + 4.436, + 4.315, + 4.194, + 4.073, + 3.953, + 3.833, + 3.714, + 3.596, + 3.479, + 3.363, + 3.249, + 3.136, + 3.025, + 2.916, + 2.808, + 2.703, + 2.6, + 2.5, + 2.402, + 2.307, + 2.215, + 2.127, + 2.042, + 1.96, + 1.882, + 1.807, + 1.737, + 1.67, + 1.608, + 1.549, + 1.494, + 1.444, + 1.397, + 1.354, + 1.314, + 1.278, + 1.246, + 1.217, + 1.19, + 1.167, + 1.146, + 1.127, + 1.11, + 1.096, + 1.083, + 1.072 + ], + [ + 4.259, + 4.259, + 4.259, + 4.259, + 4.259, + 4.259, + 4.259, + 4.259, + 4.259, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.26, + 4.259, + 4.258, + 4.257, + 4.254, + 4.249, + 4.241, + 4.231, + 4.216, + 4.195, + 4.167, + 4.131, + 4.083, + 4.025, + 3.955, + 3.873, + 3.782, + 3.682, + 3.577, + 3.468, + 3.357, + 3.245, + 3.134, + 3.024, + 2.915, + 2.808, + 2.703, + 2.601, + 2.5, + 2.403, + 2.308, + 2.216, + 2.127, + 2.042, + 1.96, + 1.882, + 1.808, + 1.737, + 1.671, + 1.608, + 1.549, + 1.495, + 1.444, + 1.397, + 1.354, + 1.314, + 1.279, + 1.246, + 1.217, + 1.19, + 1.167, + 1.146, + 1.127, + 1.11, + 1.096, + 1.083, + 1.072, + 1.062, + 1.054, + 1.046, + 1.04, + 1.034, + 1.03, + 1.026, + 1.022, + 1.019, + 1.016 + ], + [ + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.002, + 3.003, + 3.003, + 3.003, + 3.004, + 3.004, + 3.005, + 3.006, + 3.007, + 3.008, + 3.01, + 3.011, + 3.013, + 3.015, + 3.016, + 3.018, + 3.018, + 3.016, + 3.012, + 3.004, + 2.991, + 2.971, + 2.944, + 2.907, + 2.86, + 2.803, + 2.735, + 2.658, + 2.574, + 2.486, + 2.396, + 2.306, + 2.216, + 2.129, + 2.045, + 1.963, + 1.885, + 1.811, + 1.74, + 1.673, + 1.61, + 1.552, + 1.497, + 1.446, + 1.399, + 1.355, + 1.316, + 1.28, + 1.247, + 1.218, + 1.191, + 1.167, + 1.146, + 1.128, + 1.111, + 1.096, + 1.084, + 1.072, + 1.063, + 1.054, + 1.047, + 1.04, + 1.035, + 1.03, + 1.026, + 1.022, + 1.019, + 1.016, + 1.014, + 1.012, + 1.01, + 1.009, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004 + ], + [ + 1.806, + 1.806, + 1.806, + 1.807, + 1.807, + 1.807, + 1.807, + 1.807, + 1.807, + 1.807, + 1.807, + 1.808, + 1.808, + 1.808, + 1.809, + 1.81, + 1.81, + 1.812, + 1.813, + 1.815, + 1.817, + 1.819, + 1.823, + 1.827, + 1.832, + 1.838, + 1.846, + 1.855, + 1.865, + 1.877, + 1.89, + 1.903, + 1.914, + 1.923, + 1.928, + 1.926, + 1.917, + 1.898, + 1.869, + 1.831, + 1.785, + 1.733, + 1.678, + 1.622, + 1.566, + 1.512, + 1.461, + 1.413, + 1.369, + 1.328, + 1.291, + 1.257, + 1.227, + 1.199, + 1.175, + 1.153, + 1.133, + 1.116, + 1.101, + 1.087, + 1.076, + 1.065, + 1.056, + 1.049, + 1.042, + 1.036, + 1.031, + 1.027, + 1.023, + 1.02, + 1.017, + 1.015, + 1.013, + 1.011, + 1.009, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001 + ], + [ + 0.8424, + 0.8425, + 0.8425, + 0.8426, + 0.8426, + 0.8427, + 0.8428, + 0.8429, + 0.8431, + 0.8433, + 0.8436, + 0.8439, + 0.8443, + 0.8449, + 0.8455, + 0.8464, + 0.8474, + 0.8487, + 0.8504, + 0.8525, + 0.8552, + 0.8586, + 0.8628, + 0.8682, + 0.875, + 0.8835, + 0.8944, + 0.9079, + 0.925, + 0.9461, + 0.9719, + 1.003, + 1.04, + 1.081, + 1.126, + 1.172, + 1.216, + 1.253, + 1.279, + 1.294, + 1.296, + 1.287, + 1.27, + 1.248, + 1.224, + 1.2, + 1.178, + 1.157, + 1.137, + 1.12, + 1.104, + 1.091, + 1.079, + 1.068, + 1.059, + 1.051, + 1.044, + 1.038, + 1.032, + 1.028, + 1.024, + 1.021, + 1.018, + 1.015, + 1.013, + 1.011, + 1.01, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002, + 1.002, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0 + ], + [ + 0.3035, + 0.3035, + 0.3035, + 0.3035, + 0.3036, + 0.3036, + 0.3037, + 0.3038, + 0.3039, + 0.304, + 0.3042, + 0.3044, + 0.3046, + 0.305, + 0.3054, + 0.3059, + 0.3066, + 0.3074, + 0.3084, + 0.3098, + 0.3114, + 0.3136, + 0.3163, + 0.3197, + 0.324, + 0.3296, + 0.3367, + 0.3457, + 0.3573, + 0.3722, + 0.3913, + 0.4156, + 0.4464, + 0.485, + 0.5328, + 0.5905, + 0.6581, + 0.7343, + 0.8157, + 0.8975, + 0.9731, + 1.037, + 1.084, + 1.113, + 1.127, + 1.129, + 1.124, + 1.115, + 1.104, + 1.093, + 1.083, + 1.073, + 1.064, + 1.056, + 1.049, + 1.042, + 1.036, + 1.032, + 1.027, + 1.023, + 1.02, + 1.017, + 1.015, + 1.013, + 1.011, + 1.01, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002, + 1.002, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0 + ], + [ + 0.09801, + 0.09802, + 0.09803, + 0.09804, + 0.09806, + 0.09808, + 0.0981, + 0.09814, + 0.09818, + 0.09823, + 0.09829, + 0.09838, + 0.09848, + 0.09861, + 0.09877, + 0.09898, + 0.09924, + 0.09957, + 0.09999, + 0.1005, + 0.1012, + 0.102, + 0.1031, + 0.1045, + 0.1062, + 0.1084, + 0.1113, + 0.115, + 0.1198, + 0.126, + 0.134, + 0.1445, + 0.1582, + 0.1759, + 0.199, + 0.2286, + 0.2662, + 0.3132, + 0.3706, + 0.4388, + 0.5173, + 0.6044, + 0.6967, + 0.7898, + 0.8782, + 0.9561, + 1.019, + 1.064, + 1.091, + 1.104, + 1.107, + 1.103, + 1.096, + 1.087, + 1.078, + 1.069, + 1.061, + 1.054, + 1.047, + 1.041, + 1.036, + 1.031, + 1.027, + 1.023, + 1.02, + 1.017, + 1.015, + 1.013, + 1.011, + 1.009, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002, + 1.002, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001, + 1.0, + 1.0 + ], + [ + 0.03107, + 0.03107, + 0.03107, + 0.03108, + 0.03108, + 0.03109, + 0.0311, + 0.03111, + 0.03112, + 0.03114, + 0.03116, + 0.03119, + 0.03122, + 0.03127, + 0.03132, + 0.03139, + 0.03148, + 0.03159, + 0.03173, + 0.03191, + 0.03214, + 0.03242, + 0.03279, + 0.03325, + 0.03384, + 0.0346, + 0.03558, + 0.03684, + 0.03847, + 0.0406, + 0.04337, + 0.04702, + 0.05181, + 0.05812, + 0.06644, + 0.07735, + 0.09158, + 0.11, + 0.1335, + 0.1631, + 0.1998, + 0.2445, + 0.2981, + 0.361, + 0.4334, + 0.5146, + 0.6031, + 0.696, + 0.7892, + 0.8773, + 0.9548, + 1.017, + 1.062, + 1.089, + 1.102, + 1.104, + 1.101, + 1.094, + 1.085, + 1.076, + 1.068, + 1.06, + 1.053, + 1.046, + 1.04, + 1.035, + 1.03, + 1.026, + 1.023, + 1.019, + 1.017, + 1.014, + 1.012, + 1.011, + 1.009, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002, + 1.001, + 1.001, + 1.001, + 1.001, + 1.001 + ], + [ + 0.009826, + 0.009827, + 0.009828, + 0.00983, + 0.009831, + 0.009834, + 0.009836, + 0.00984, + 0.009845, + 0.00985, + 0.009857, + 0.009866, + 0.009877, + 0.009892, + 0.009909, + 0.009932, + 0.00996, + 0.009996, + 0.01004, + 0.0101, + 0.01017, + 0.01026, + 0.01038, + 0.01053, + 0.01072, + 0.01097, + 0.01128, + 0.01169, + 0.01222, + 0.01291, + 0.01381, + 0.015, + 0.01656, + 0.01863, + 0.02137, + 0.02499, + 0.02975, + 0.03597, + 0.04404, + 0.05439, + 0.06753, + 0.08403, + 0.1046, + 0.1299, + 0.161, + 0.1987, + 0.244, + 0.2979, + 0.3609, + 0.4334, + 0.5146, + 0.6031, + 0.696, + 0.7891, + 0.8772, + 0.9547, + 1.017, + 1.061, + 1.089, + 1.101, + 1.104, + 1.1, + 1.093, + 1.085, + 1.076, + 1.068, + 1.06, + 1.053, + 1.046, + 1.04, + 1.035, + 1.03, + 1.026, + 1.023, + 1.019, + 1.017, + 1.014, + 1.012, + 1.011, + 1.009, + 1.008, + 1.007, + 1.006, + 1.005, + 1.004, + 1.004, + 1.003, + 1.003, + 1.002, + 1.002, + 1.002 + ] + ], + "reference": "M.A. de Avillez and D. Breitschwerdt, Temperature-averaged and total free-free Gaunt factors for κ and Maxwellian distributions of electrons, 2015, Astron. & Astrophys. 580, A124" +} diff --git a/cherab/core/atomic/gaunt.pxd b/cherab/core/atomic/gaunt.pxd new file mode 100644 index 00000000..42afa0da --- /dev/null +++ b/cherab/core/atomic/gaunt.pxd @@ -0,0 +1,39 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from cherab.core.math cimport Function2D + + +cdef class FreeFreeGauntFactor(): + + cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999 + + +cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): + + cdef: + readonly tuple u_range, gamma2_range + readonly dict raw_data + double _u_min, _u_max, _gamma2_min, _gamma2_max + Function2D _gaunt_factor + + +cdef class MaxwellianFreeFreeGauntFactor(InterpolatedFreeFreeGauntFactor): + + pass + diff --git a/cherab/core/atomic/gaunt.pyx b/cherab/core/atomic/gaunt.pyx new file mode 100644 index 00000000..1927281a --- /dev/null +++ b/cherab/core/atomic/gaunt.pyx @@ -0,0 +1,152 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from os import path +import numpy as np +import json + +from libc.math cimport log10, log, M_PI, sqrt +from raysect.core.math.function.float cimport Interpolator2DArray +from cherab.core.utility.constants cimport RYDBERG_CONSTANT_EV, SPEED_OF_LIGHT, ELEMENTARY_CHARGE, PLANCK_CONSTANT + +cimport cython + + +DEF EULER_GAMMA = 0.5772156649015329 + +cdef double PH_TO_EV_FACTOR = PLANCK_CONSTANT * SPEED_OF_LIGHT * 1e9 / ELEMENTARY_CHARGE + + +cdef class FreeFreeGauntFactor(): + """ + The base class for temperature-averaged free-free Gaunt factors. + """ + + cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999: + """ + Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. + + :param double zeff: Effective Z of the plasma. + :param double temperature: Electron temperature in eV. + :param double wavelength: Spectral wavelength. + + :return: free-free Gaunt factor + """ + raise NotImplementedError("The evaluate() virtual method must be implemented.") + + def __call__(self, double zeff, double temperature, double wavelength): + """ + Returns self.evaluate(zeff, temperature, wavelength). + """ + + return self.evaluate(zeff, temperature, wavelength) + + +cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): + r""" + The temperature-averaged free-free Gaunt factors interpolated in the space of parameters: + :math:`u = h{\nu}/kT` and :math:`{\gamma}^{2} = Z_{eff}^{2}Ry/kT`. + See T.R. Carson, 1988, Astron. & Astrophys., 189, + `319 `_ for details. + + The cubic interpolation in a semi-log space is used. + + The Born approximation is used outside the interpolation range. + + :param object u: A 1D array-like object of real values. + :param object gamma2: A 1D array-like object of real values. + :param object gaunt_factor: 2D array-like object of real values + storing the Gaunt factor values at u, gamma2. + + :ivar tuple u_range: The interpolation range of `u` parameter. + :ivar tuple gamma2_range: The interpolation range of :math:`\\gamma^2` parameter. + :ivar dict raw_data: Dictionary containing the raw data. + """ + + def __init__(self, object u, object gamma2, object gaunt_factor): + + u = np.array(u, dtype=np.float64) + u.flags.writeable = False + gamma2 = np.array(gamma2, dtype=np.float64) + gamma2.flags.writeable = False + gaunt_factor = np.array(gaunt_factor, dtype=np.float64) + gaunt_factor.flags.writeable = False + + self.raw_data = {'u': u, 'gamma2': gamma2, 'gaunt_factor': gaunt_factor} + + self._u_min = u.min() + self._u_max = u.max() + self._gamma2_min = gamma2.min() + self._gamma2_max = gamma2.max() + + self.u_range = (self._u_min, self._u_max) + self.gamma2_range = (self._gamma2_min, self._gamma2_max) + + self._gaunt_factor = Interpolator2DArray(np.log10(u), np.log10(gamma2), gaunt_factor, 'cubic', 'none', 0, 0) + + @cython.cdivision(True) + cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999: + """ + Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. + + :param double zeff: Effective Z of the plasma. + :param double temperature: Electron temperature in eV. + :param double wavelength: Spectral wavelength. + + :return: free-free Gaunt factor + """ + + cdef: + double u, gamma2 + + if zeff == 0: + + return 0 + + gamma2 = zeff * zeff * RYDBERG_CONSTANT_EV / temperature + u = PH_TO_EV_FACTOR / (temperature * wavelength) + + # classical limit + if u >= self._u_max or gamma2 >= self._gamma2_max: + + return 1 + + # Born approximation limit + if u < self._u_min or gamma2 < self._gamma2_min: + + return sqrt(3) / M_PI * (log(4 / u) - EULER_GAMMA) + + return self._gaunt_factor.evaluate(log10(u), log10(gamma2)) + + +cdef class MaxwellianFreeFreeGauntFactor(InterpolatedFreeFreeGauntFactor): + r""" + The Maxwellian-averaged free-free Gaunt factor interpolated over the data from Table A.1 in + M.A. de Avillez and D. Breitschwerdt, "Temperature-averaged and total free-free Gaunt factors + for κ and Maxwellian distributions of electrons", 2015, Astron. & Astrophys. 580, + `A124 `_. + + The Born approximation is used outside the interpolation range. + """ + + def __init__(self): + + with open(path.join(path.dirname(__file__), "data/maxwellian_free_free_gaunt_factor.json")) as f: + data = json.load(f) + + super().__init__(data['u'], data['gamma2'], data['gaunt_factor']) diff --git a/cherab/core/atomic/interface.pxd b/cherab/core/atomic/interface.pxd index 9ada928e..66d8faf8 100644 --- a/cherab/core/atomic/interface.pxd +++ b/cherab/core/atomic/interface.pxd @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -19,6 +19,7 @@ from cherab.core.atomic.elements cimport Element from cherab.core.atomic.line cimport Line from cherab.core.atomic.zeeman cimport ZeemanStructure +from cherab.core.atomic.gaunt cimport FreeFreeGauntFactor from cherab.core.atomic.rates cimport * @@ -56,3 +57,5 @@ cdef class AtomicData: cpdef ZeemanStructure zeeman_structure(self, Line line, object b_field=*) + cpdef FreeFreeGauntFactor free_free_gaunt_factor(self) + diff --git a/cherab/core/atomic/interface.pyx b/cherab/core/atomic/interface.pyx index e5219205..286ebfb4 100644 --- a/cherab/core/atomic/interface.pyx +++ b/cherab/core/atomic/interface.pyx @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -16,6 +16,8 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. +from .gaunt import MaxwellianFreeFreeGauntFactor + cdef class AtomicData: """ @@ -92,3 +94,14 @@ cdef class AtomicData: cpdef ZeemanStructure zeeman_structure(self, Line line, object b_field=None): raise NotImplementedError("The zeeman_structure() virtual method is not implemented for this atomic data source.") + + cpdef FreeFreeGauntFactor free_free_gaunt_factor(self): + """ + Returns the Maxwellian-averaged free-free Gaunt factor interpolated over the data + from Table A.1 in M.A. de Avillez and D. Breitschwerdt, 2015, Astron. & Astrophys. 580, + `A124 `_. + + The Born approximation is used outside the interpolation range. + """ + + return MaxwellianFreeFreeGauntFactor() diff --git a/cherab/core/model/plasma/bremsstrahlung.pxd b/cherab/core/model/plasma/bremsstrahlung.pxd index 4da3422f..7005fcef 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pxd +++ b/cherab/core/model/plasma/bremsstrahlung.pxd @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -18,16 +18,13 @@ # cython: language_level=3 -from cherab.core.atomic cimport Line +from cherab.core.atomic cimport FreeFreeGauntFactor from cherab.core.plasma cimport PlasmaModel -from cherab.core.species cimport Species cdef class Bremsstrahlung(PlasmaModel): cdef: - Line _line - double _wavelength - Species _target_species + FreeFreeGauntFactor _gaunt_factor cdef double _bremsstrahlung(self, double wvl, double te, double ne, double zeff) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 473fb76b..250e125a 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -58,6 +58,12 @@ cdef class Bremsstrahlung(PlasmaModel): double lower_sample, upper_sample int i + # initialise Gaunt factor on first run + if self._gaunt_factor is None: + if self._atomic_data is None: + raise RuntimeError("The emission model is not connected to an atomic data source.") + self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() + ne = self._plasma.get_electron_distribution().density(point.x, point.y, point.z) if ne == 0: return spectrum @@ -74,7 +80,7 @@ cdef class Bremsstrahlung(PlasmaModel): lower_sample = self._bremsstrahlung(lower_wavelength, te, ne, z_effective) for i in range(spectrum.bins): - upper_wavelength = spectrum.min_wavelength + spectrum.delta_wavelength * i + upper_wavelength = spectrum.min_wavelength + spectrum.delta_wavelength * (i + 1) upper_sample = self._bremsstrahlung(upper_wavelength, te, ne, z_effective) spectrum.samples_mv[i] += 0.5 * (lower_sample + upper_sample) @@ -87,21 +93,21 @@ cdef class Bremsstrahlung(PlasmaModel): @cython.cdivision(True) cdef double _bremsstrahlung(self, double wvl, double te, double ne, double zeff): """ - :param wvl: in nm + :param wvl: in nm :param te: in eV :param ne: in m^-3 :param zeff: a.u. - :return: + :return: """ cdef double gaunt_factor, radiance, pre_factor # gaunt factor - gaunt_factor = max(1., 0.6183 * log(te) - 0.0821) + gaunt_factor = self._gaunt_factor(zeff, te, wvl) # bremsstrahlung equation W/m^3/str/nm pre_factor = 0.95e-19 * RECIP_4_PI * gaunt_factor * ne * ne * zeff / (sqrt(te) * wvl) - radiance = pre_factor * exp(- EXP_FACTOR / (te * wvl)) * PH_TO_J_FACTOR + radiance = pre_factor * exp(- EXP_FACTOR / (te * wvl)) * PH_TO_J_FACTOR # convert to W/m^3/str/nm return radiance / wvl diff --git a/cherab/core/utility/constants.pxd b/cherab/core/utility/constants.pxd index fd3fa568..9cce304d 100644 --- a/cherab/core/utility/constants.pxd +++ b/cherab/core/utility/constants.pxd @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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,3 +29,4 @@ cdef: double PLANCK_CONSTANT double ELECTRON_CLASSICAL_RADIUS double ELECTRON_REST_MASS + double RYDBERG_CONSTANT_EV diff --git a/cherab/core/utility/constants.pyx b/cherab/core/utility/constants.pyx index 348e28c3..03e70617 100644 --- a/cherab/core/utility/constants.pyx +++ b/cherab/core/utility/constants.pyx @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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,4 +31,4 @@ cdef: double PLANCK_CONSTANT = 6.62607015e-34 double ELECTRON_CLASSICAL_RADIUS = 2.8179403262e-15 double ELECTRON_REST_MASS = 9.1093837015e-31 - + double RYDBERG_CONSTANT_EV = 13.605693122994 diff --git a/demos/emission_models/bremsstrahlung.py b/demos/emission_models/bremsstrahlung.py new file mode 100755 index 00000000..b1da93f6 --- /dev/null +++ b/demos/emission_models/bremsstrahlung.py @@ -0,0 +1,84 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +# External imports +import matplotlib.pyplot as plt +from scipy.constants import electron_mass, atomic_mass +from raysect.optical import World, Vector3D, Point3D, Ray +from raysect.primitive import Sphere +from raysect.optical.material.emitter.inhomogeneous import NumericalIntegrator + +# Cherab imports +from cherab.core import Species, Maxwellian, Plasma +from cherab.core.atomic.elements import deuterium, nitrogen +from cherab.core.model import Bremsstrahlung +from cherab.openadas import OpenADAS +from cherab.tools.plasmas import GaussianVolume + + +# tunables +ion_density = 1e20 +sigma = 1. + +# setup scenegraph +world = World() + +# create atomic data source +adas = OpenADAS(permit_extrapolation=True) + +# PLASMA ---------------------------------------------------------------------- +plasma = Plasma(parent=world) +plasma.atomic_data = adas +plasma.geometry = Sphere(sigma) +plasma.geometry_transform = None +plasma.integrator = NumericalIntegrator(step=0.01 * sigma) + +# define basic distributions +d_density = GaussianVolume(ion_density, sigma) +n_density = d_density * 0.01 +e_density = GaussianVolume(ion_density, sigma) +temperature = GaussianVolume(1000, sigma) +bulk_velocity = Vector3D(0, 0, 0) + +deuterium_mass = deuterium.atomic_weight * atomic_mass +d_distribution = Maxwellian(d_density, temperature, bulk_velocity, deuterium_mass) +nitrogen_mass = nitrogen.atomic_weight * atomic_mass +n_distribution = Maxwellian(n_density, temperature, bulk_velocity, nitrogen_mass) +e_distribution = Maxwellian(e_density, temperature, bulk_velocity, electron_mass) + +d1_species = Species(deuterium, 1, d_distribution) +n1_species = Species(nitrogen, 1, n_distribution) + +# define species +plasma.b_field = Vector3D(1.0, 1.0, 1.0) +plasma.electron_distribution = e_distribution +plasma.composition = [d1_species, n1_species] + +# add Bremsstrahlung to the plasma +plasma.models = [Bremsstrahlung()] + +# Ray-trace and plot the results +r = Ray(origin=Point3D(0, 0, -5), direction=Vector3D(0, 0, 1), + min_wavelength=380, max_wavelength=800, bins=256) +s = r.trace(world) +plt.plot(s.wavelengths, s.samples) +plt.xlabel('Wavelength (nm)') +plt.ylabel('Radiance (W/m^2/str/nm)') +plt.title('Observed Bremsstrahlung spectrum') +plt.show() diff --git a/docs/source/atomic/atomic_data.rst b/docs/source/atomic/atomic_data.rst index df3bc2db..650d89b4 100644 --- a/docs/source/atomic/atomic_data.rst +++ b/docs/source/atomic/atomic_data.rst @@ -6,3 +6,4 @@ Atomic Data elements_and_isotopes emission_lines rate_coefficients + gaunt_factors diff --git a/docs/source/atomic/gaunt_factors.rst b/docs/source/atomic/gaunt_factors.rst new file mode 100644 index 00000000..b7950ff9 --- /dev/null +++ b/docs/source/atomic/gaunt_factors.rst @@ -0,0 +1,23 @@ + +Gaunt factors +------------- + +This includes classes for temperature-averaged Gaunt factors used to calculate Bremsstrahlung (free-free Gaunt factor) +and radiative recombination continuum (bound-free Gaunt factor) emission. + + +Free-free Gaunt factors +^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: cherab.core.atomic.gaunt.FreeFreeGauntFactor + :members: + :special-members: __call__ + +.. autoclass:: cherab.core.atomic.gaunt.InterpolatedFreeFreeGauntFactor + :show-inheritance: + :members: + +.. autoclass:: cherab.core.atomic.gaunt.MaxwellianFreeFreeGauntFactor + :show-inheritance: + :members: + From 0246b9d6dc037c02f5e2a4b9eb8b4e8558292eef Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 27 Jan 2022 23:35:17 +0300 Subject: [PATCH 15/81] Improve FreeFreeGauntFactor.__call__() docstring and update CHANGELOG. --- CHANGELOG.md | 11 ++++++++++- cherab/core/atomic/gaunt.pyx | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e211f506..30e9f43f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,18 @@ Project Changelog ================= -Release 1.3.0 (8 Dec 2021) +Release 1.4.0 (TBD) ------------------- +Bug fixes: +* Fix wavelength indexing in Bremsstrahlung emission model. (#352) + +New: +* Add new classes for free-free Gaunt factors and improve accuracy of the Gaunt factor used in Bremsstrahlung emission model. (#352) + +Release 1.3.0 (8 Dec 2021) +-------------------------- + API changes: * Use of Cherab's interpolators is now deprecated in favour of those upstream in Raysect. diff --git a/cherab/core/atomic/gaunt.pyx b/cherab/core/atomic/gaunt.pyx index 1927281a..911362a6 100644 --- a/cherab/core/atomic/gaunt.pyx +++ b/cherab/core/atomic/gaunt.pyx @@ -51,7 +51,13 @@ cdef class FreeFreeGauntFactor(): def __call__(self, double zeff, double temperature, double wavelength): """ - Returns self.evaluate(zeff, temperature, wavelength). + Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. + + :param double zeff: Effective Z of the plasma. + :param double temperature: Electron temperature in eV. + :param double wavelength: Spectral wavelength. + + :return: free-free Gaunt factor """ return self.evaluate(zeff, temperature, wavelength) From 349ae82aeb4bc6afa0fe676037e06efa69eeb887 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 17 Feb 2022 18:00:20 +0300 Subject: [PATCH 16/81] Use summation over charged species instead of Zeff in Bremsstrahlung model. --- cherab/core/atomic/gaunt.pxd | 2 +- cherab/core/atomic/gaunt.pyx | 20 ++--- cherab/core/model/plasma/bremsstrahlung.pxd | 9 +- cherab/core/model/plasma/bremsstrahlung.pyx | 98 ++++++++++++++++----- 4 files changed, 95 insertions(+), 34 deletions(-) diff --git a/cherab/core/atomic/gaunt.pxd b/cherab/core/atomic/gaunt.pxd index 42afa0da..827831b6 100644 --- a/cherab/core/atomic/gaunt.pxd +++ b/cherab/core/atomic/gaunt.pxd @@ -21,7 +21,7 @@ from cherab.core.math cimport Function2D cdef class FreeFreeGauntFactor(): - cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999 + cpdef double evaluate(self, double z, double temperature, double wavelength) except? -1e999 cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): diff --git a/cherab/core/atomic/gaunt.pyx b/cherab/core/atomic/gaunt.pyx index 911362a6..eb1dbe59 100644 --- a/cherab/core/atomic/gaunt.pyx +++ b/cherab/core/atomic/gaunt.pyx @@ -37,11 +37,11 @@ cdef class FreeFreeGauntFactor(): The base class for temperature-averaged free-free Gaunt factors. """ - cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999: + cpdef double evaluate(self, double z, double temperature, double wavelength) except? -1e999: """ Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. - :param double zeff: Effective Z of the plasma. + :param double z: Species charge or effective plasma charge. :param double temperature: Electron temperature in eV. :param double wavelength: Spectral wavelength. @@ -49,24 +49,24 @@ cdef class FreeFreeGauntFactor(): """ raise NotImplementedError("The evaluate() virtual method must be implemented.") - def __call__(self, double zeff, double temperature, double wavelength): + def __call__(self, double z, double temperature, double wavelength): """ Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. - :param double zeff: Effective Z of the plasma. + :param double z: Species charge or effective plasma charge. :param double temperature: Electron temperature in eV. :param double wavelength: Spectral wavelength. :return: free-free Gaunt factor """ - return self.evaluate(zeff, temperature, wavelength) + return self.evaluate(z, temperature, wavelength) cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): r""" The temperature-averaged free-free Gaunt factors interpolated in the space of parameters: - :math:`u = h{\nu}/kT` and :math:`{\gamma}^{2} = Z_{eff}^{2}Ry/kT`. + :math:`u = h{\nu}/kT` and :math:`{\gamma}^{2} = Z^{2}Ry/kT`. See T.R. Carson, 1988, Astron. & Astrophys., 189, `319 `_ for details. @@ -106,11 +106,11 @@ cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): self._gaunt_factor = Interpolator2DArray(np.log10(u), np.log10(gamma2), gaunt_factor, 'cubic', 'none', 0, 0) @cython.cdivision(True) - cpdef double evaluate(self, double zeff, double temperature, double wavelength) except? -1e999: + cpdef double evaluate(self, double z, double temperature, double wavelength) except? -1e999: """ Returns the temperature-averaged free-free Gaunt factor for the supplied parameters. - :param double zeff: Effective Z of the plasma. + :param double z: Species charge or effective plasma charge. :param double temperature: Electron temperature in eV. :param double wavelength: Spectral wavelength. @@ -120,11 +120,11 @@ cdef class InterpolatedFreeFreeGauntFactor(FreeFreeGauntFactor): cdef: double u, gamma2 - if zeff == 0: + if z == 0: return 0 - gamma2 = zeff * zeff * RYDBERG_CONSTANT_EV / temperature + gamma2 = z * z * RYDBERG_CONSTANT_EV / temperature u = PH_TO_EV_FACTOR / (temperature * wavelength) # classical limit diff --git a/cherab/core/model/plasma/bremsstrahlung.pxd b/cherab/core/model/plasma/bremsstrahlung.pxd index 7005fcef..f29cd6b0 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pxd +++ b/cherab/core/model/plasma/bremsstrahlung.pxd @@ -18,6 +18,7 @@ # cython: language_level=3 +from numpy cimport ndarray from cherab.core.atomic cimport FreeFreeGauntFactor from cherab.core.plasma cimport PlasmaModel @@ -26,5 +27,11 @@ cdef class Bremsstrahlung(PlasmaModel): cdef: FreeFreeGauntFactor _gaunt_factor + ndarray _species_charge, _species_density + double[::1] _species_density_mv, _species_charge_mv + + cdef double _bremsstrahlung(self, double wvl, double te, double ne) + + cdef int _populate_cache(self) except -1 + - cdef double _bremsstrahlung(self, double wvl, double te, double ne, double zeff) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 250e125a..1384d647 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -18,7 +18,10 @@ # cython: language_level=3 +import numpy as np from raysect.optical cimport Spectrum, Point3D, Vector3D +from cherab.core cimport Plasma, AtomicData +from cherab.core.species cimport Species from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, SPEED_OF_LIGHT, PLANCK_CONSTANT from libc.math cimport sqrt, log, exp cimport cython @@ -38,11 +41,18 @@ cdef class Bremsstrahlung(PlasmaModel): et. al., 'ITER LIDAR performance analysis', Rev. Sci. Instrum. 79, 10E727 (2008), .. math:: - \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} g_{ff} n_e^2 Z_{eff} T_e^{1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, + \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} \\sum_{i} \\left(g_{ff}(Z_i, T_e, \\lambda) n_i Z_i^2\\right) n_e T_e^{1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, where the emission :math:`\\epsilon (\\lambda)` is in units of radiance (ph/s/sr/m^3/nm). """ + def __init__(self, Plasma plasma=None, AtomicData atomic_data=None): + + super().__init__(plasma, atomic_data) + + # ensure that cache is initialised + self._change() + def __repr__(self): return '' @@ -53,35 +63,38 @@ cdef class Bremsstrahlung(PlasmaModel): cpdef Spectrum emission(self, Point3D point, Vector3D direction, Spectrum spectrum): cdef: - double ne, te, z_effective + double ne, te double lower_wavelength, upper_wavelength double lower_sample, upper_sample + Species species int i - # initialise Gaunt factor on first run + # cache data on first run if self._gaunt_factor is None: - if self._atomic_data is None: - raise RuntimeError("The emission model is not connected to an atomic data source.") - self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() + self._populate_cache() ne = self._plasma.get_electron_distribution().density(point.x, point.y, point.z) - if ne == 0: + if ne <= 0: return spectrum te = self._plasma.get_electron_distribution().effective_temperature(point.x, point.y, point.z) - if te == 0: - return spectrum - z_effective = self._plasma.z_effective(point.x, point.y, point.z) - if z_effective == 0: + if te <= 0: return spectrum + # collect densities of charged species + i = 0 + for species in self._plasma.get_composition(): + if species.charge > 0: + self._species_density_mv[i] = species.distribution.density(point.x, point.y, point.z) + i += 1 + # numerically integrate using trapezium rule # todo: add sub-sampling to increase numerical accuracy lower_wavelength = spectrum.min_wavelength - lower_sample = self._bremsstrahlung(lower_wavelength, te, ne, z_effective) + lower_sample = self._bremsstrahlung(lower_wavelength, te, ne) for i in range(spectrum.bins): upper_wavelength = spectrum.min_wavelength + spectrum.delta_wavelength * (i + 1) - upper_sample = self._bremsstrahlung(upper_wavelength, te, ne, z_effective) + upper_sample = self._bremsstrahlung(upper_wavelength, te, ne) spectrum.samples_mv[i] += 0.5 * (lower_sample + upper_sample) @@ -91,23 +104,64 @@ cdef class Bremsstrahlung(PlasmaModel): return spectrum @cython.cdivision(True) - cdef double _bremsstrahlung(self, double wvl, double te, double ne, double zeff): + @cython.boundscheck(False) + @cython.wraparound(False) + cdef double _bremsstrahlung(self, double wvl, double te, double ne): """ - :param wvl: in nm - :param te: in eV - :param ne: in m^-3 - :param zeff: a.u. + :param double wvl: Wavelength in nm. + :param double te: Electron temperature in eV + :param double ne: Electron dencity in m^-3 :return: """ - cdef double gaunt_factor, radiance, pre_factor + cdef double ni_gff_z2, radiance, pre_factor, ni, z + cdef int i - # gaunt factor - gaunt_factor = self._gaunt_factor(zeff, te, wvl) + ni_gff_z2 = 0 + for i in range(self._species_charge_mv.shape[0]): + z = self._species_charge_mv[i] + ni = self._species_density_mv[i] + if ni > 0: + ni_gff_z2 += ni * self._gaunt_factor.evaluate(z, te, wvl) * z * z # bremsstrahlung equation W/m^3/str/nm - pre_factor = 0.95e-19 * RECIP_4_PI * gaunt_factor * ne * ne * zeff / (sqrt(te) * wvl) + pre_factor = 0.95e-19 * RECIP_4_PI * ni_gff_z2 * ne / (sqrt(te) * wvl) radiance = pre_factor * exp(- EXP_FACTOR / (te * wvl)) * PH_TO_J_FACTOR # convert to W/m^3/str/nm return radiance / wvl + + cdef int _populate_cache(self) except -1: + + cdef list species_charge + cdef Species species + + if self._plasma is None: + raise RuntimeError("The emission model is not connected to a plasma object.") + + if self._atomic_data is None: + raise RuntimeError("The emission model is not connected to an atomic data source.") + + # initialise Gaunt factor on first run + self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() + + species_charge = [] + for species in self._plasma.get_composition(): + if species.charge > 0: + species_charge.append(species.charge) + + # Gaunt factor takes Z as double to support Zeff, so caching Z as float64 + self._species_charge = np.array(species_charge, dtype=np.float64) + self._species_charge_mv = self._species_charge + + self._species_density = np.zeros_like(self._species_charge) + self._species_density_mv = self._species_density + + def _change(self): + + # clear cache to force regeneration on first use + self._gaunt_factor = None + self._species_charge = None + self._species_charge_mv = None + self._species_density = None + self._species_density_mv = None From bbe65d56c682d01c25b116b64b7fe9afc400022e Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 8 Mar 2022 23:26:14 +0300 Subject: [PATCH 17/81] Add gaunt factor as optional parameter of the Bremsstrahlung emission model. --- cherab/core/model/plasma/bremsstrahlung.pxd | 1 + cherab/core/model/plasma/bremsstrahlung.pyx | 36 +++++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pxd b/cherab/core/model/plasma/bremsstrahlung.pxd index f29cd6b0..f8251b28 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pxd +++ b/cherab/core/model/plasma/bremsstrahlung.pxd @@ -27,6 +27,7 @@ cdef class Bremsstrahlung(PlasmaModel): cdef: FreeFreeGauntFactor _gaunt_factor + bint _user_provided_gaunt_factor ndarray _species_charge, _species_density double[::1] _species_density_mv, _species_charge_mv diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 1384d647..ba4b9cf6 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -21,6 +21,7 @@ import numpy as np from raysect.optical cimport Spectrum, Point3D, Vector3D from cherab.core cimport Plasma, AtomicData +from cherab.core.atomic cimport FreeFreeGauntFactor from cherab.core.species cimport Species from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, SPEED_OF_LIGHT, PLANCK_CONSTANT from libc.math cimport sqrt, log, exp @@ -44,15 +45,34 @@ cdef class Bremsstrahlung(PlasmaModel): \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} \\sum_{i} \\left(g_{ff}(Z_i, T_e, \\lambda) n_i Z_i^2\\right) n_e T_e^{1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, where the emission :math:`\\epsilon (\\lambda)` is in units of radiance (ph/s/sr/m^3/nm). + + :ivar Plasma plasma: The plasma to which this emission model is attached. Default is None. + :ivar AtomicData atomic_data: The atomic data provider for this model. Default is None. + :ivar FreeFreeGauntFactor gaunt_factor: Free-free Gaunt factor as a function of Z, Te and + wavelength. If not provided, + the `atomic_data` is used. """ - def __init__(self, Plasma plasma=None, AtomicData atomic_data=None): + def __init__(self, Plasma plasma=None, AtomicData atomic_data=None, FreeFreeGauntFactor gaunt_factor=None): super().__init__(plasma, atomic_data) + self.gaunt_factor = gaunt_factor + # ensure that cache is initialised self._change() + @property + def gaunt_factor(self): + + return self._gaunt_factor + + @gaunt_factor.setter + def gaunt_factor(self, value): + + self._gaunt_factor = value + self._user_provided_gaunt_factor = True if value else False + def __repr__(self): return '' @@ -70,7 +90,7 @@ cdef class Bremsstrahlung(PlasmaModel): int i # cache data on first run - if self._gaunt_factor is None: + if self._species_charge is None: self._populate_cache() ne = self._plasma.get_electron_distribution().density(point.x, point.y, point.z) @@ -139,11 +159,12 @@ cdef class Bremsstrahlung(PlasmaModel): if self._plasma is None: raise RuntimeError("The emission model is not connected to a plasma object.") - if self._atomic_data is None: - raise RuntimeError("The emission model is not connected to an atomic data source.") + if self._gaunt_factor is None: + if self._atomic_data is None: + raise RuntimeError("The emission model is not connected to an atomic data source.") - # initialise Gaunt factor on first run - self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() + # initialise Gaunt factor on first run using the atomic data + self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() species_charge = [] for species in self._plasma.get_composition(): @@ -160,7 +181,8 @@ cdef class Bremsstrahlung(PlasmaModel): def _change(self): # clear cache to force regeneration on first use - self._gaunt_factor = None + if not self._user_provided_gaunt_factor: + self._gaunt_factor = None self._species_charge = None self._species_charge_mv = None self._species_density = None From a8236300f40f345aee0923f2721a9310c119da67 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 23 Mar 2022 22:21:08 +0300 Subject: [PATCH 18/81] Replace pipeline_properties with pipeline_classes and pipeline_kwargs to match the new connect_pipelines() interface of the group observers. --- cherab/tools/spectroscopy/instrument.py | 52 ++++++++++++------- cherab/tools/spectroscopy/polychromator.py | 10 ++-- cherab/tools/spectroscopy/spectrometer.py | 7 ++- .../tests/test_spectroscopic_instruments.py | 23 +++++--- 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/cherab/tools/spectroscopy/instrument.py b/cherab/tools/spectroscopy/instrument.py index b2baf152..0e0d666c 100644 --- a/cherab/tools/spectroscopy/instrument.py +++ b/cherab/tools/spectroscopy/instrument.py @@ -24,14 +24,16 @@ class SpectroscopicInstrument: :param str name: Instrument name. - :ivar list pipeline_properties: The list of properties (class, name, filter) of - the pipelines used with this instrument. + :ivar list pipeline_classes: The list of pipeline classes used with this instrument. + :ivar list pipeline_kwargs: The list of dicts with keywords passed to init methods of + pipeline classes used with this instrument. :ivar float min_wavelength: Lower wavelength bound for spectral range. :ivar float max_wavelength: Upper wavelength bound for spectral range. :ivar int spectral_bins: The number of spectral samples over the wavelength range. """ def __init__(self, name=''): + self._pipeline_classes = None self.name = name self._clear_spectral_settings() @@ -43,28 +45,39 @@ def name(self): @name.setter def name(self, value): self._name = str(value) - self._pipeline_properties = None + self._pipeline_kwargs = None @property - def pipeline_properties(self): - # The list of properties (class, name, filter) of the pipelines used with - # this instrument. - if self._pipeline_properties is None: - self._update_pipeline_properties() + def pipeline_classes(self): + # The list of pipeline classes used with this instrument. + if self._pipeline_classes is None: + self._update_pipeline_classes() - return self._pipeline_properties + return self._pipeline_classes + + @property + def pipeline_kwargs(self): + # The list of dicts with keywords passed to init methods of + # pipeline classes used with this instrument. + if self._pipeline_kwargs is None: + self._update_pipeline_kwargs() + + return self._pipeline_kwargs def create_pipelines(self): - """ Returns a list of new pipelines created according to `pipeline_properties`.""" + """ Returns a list of new pipelines created according to `pipeline_classes` + and keyword arguments.""" + if self._pipeline_classes is None: + self._update_pipeline_classes() + if self._pipeline_kwargs is None: + self._update_pipeline_kwargs() - pl_list = [] - for (pl_class, pl_name, pl_filter) in self.pipeline_properties: - if pl_filter is None: - pl_list.append(pl_class(name=pl_name)) - else: - pl_list.append(pl_class(name=pl_name, filter=pl_filter)) + pipelines = [] + for PipelineClass, kwargs in zip(self._pipeline_classes, self._pipeline_kwargs): + pipeline = PipelineClass(**kwargs) + pipelines.append(pipeline) - return pl_list + return pipelines @property def min_wavelength(self): @@ -98,5 +111,8 @@ def _clear_spectral_settings(self): def _update_spectral_settings(self): raise NotImplementedError("To be defined in subclass.") - def _update_pipeline_properties(self): + def _update_pipeline_classes(self): + raise NotImplementedError("To be defined in subclass.") + + def _update_pipeline_kwargs(self): raise NotImplementedError("To be defined in subclass.") diff --git a/cherab/tools/spectroscopy/polychromator.py b/cherab/tools/spectroscopy/polychromator.py index f81c6158..56fb6e18 100644 --- a/cherab/tools/spectroscopy/polychromator.py +++ b/cherab/tools/spectroscopy/polychromator.py @@ -197,10 +197,14 @@ def filters(self, value): self._filters = value self._clear_spectral_settings() - self._pipeline_properties = None + self._pipeline_classes = None + self._pipeline_kwargs = None - def _update_pipeline_properties(self): - self._pipeline_properties = [(RadiancePipeline0D, self._name + ': ' + poly_filter.name, poly_filter) for poly_filter in self._filters] + def _update_pipeline_classes(self): + self._pipeline_classes = [RadiancePipeline0D for poly_filter in self._filters] + + def _update_pipeline_kwargs(self): + self._pipeline_kwargs = [{'name': self._name + ': ' + poly_filter.name, 'filter': poly_filter} for poly_filter in self._filters] def _update_spectral_settings(self): diff --git a/cherab/tools/spectroscopy/spectrometer.py b/cherab/tools/spectroscopy/spectrometer.py index 5fbe3710..585ac3f4 100644 --- a/cherab/tools/spectroscopy/spectrometer.py +++ b/cherab/tools/spectroscopy/spectrometer.py @@ -125,8 +125,11 @@ def min_bins_per_pixel(self, value): self._min_bins_per_pixel = value self._clear_spectral_settings() - def _update_pipeline_properties(self): - self._pipeline_properties = [(SpectralRadiancePipeline0D, self._name, None)] + def _update_pipeline_classes(self): + self._pipeline_classes = [SpectralRadiancePipeline0D] + + def _update_pipeline_kwargs(self): + self._pipeline_kwargs = [{'name': self._name}] def _update_spectral_settings(self): self._min_wavelength = min(wl2pix[0] for wl2pix in self._wavelength_to_pixel) diff --git a/cherab/tools/tests/test_spectroscopic_instruments.py b/cherab/tools/tests/test_spectroscopic_instruments.py index a8d843d6..211f7830 100644 --- a/cherab/tools/tests/test_spectroscopic_instruments.py +++ b/cherab/tools/tests/test_spectroscopic_instruments.py @@ -64,12 +64,17 @@ class TestPolychromator(unittest.TestCase): TrapezoidalFilter(700., 8., 4., 'filter 2')) min_bins_per_window_default = 10 - def test_pipeline_properties(self): + def test_pipeline_classes(self): polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default, 'test polychromator') - pipeline_properties_true = [(RadiancePipeline0D, 'test polychromator: filter 1', self.poly_filters_default[0]), - (RadiancePipeline0D, 'test polychromator: filter 2', self.poly_filters_default[1])] - self.assertSequenceEqual(pipeline_properties_true, polychromator.pipeline_properties) + pipeline_classes_true = [RadiancePipeline0D, RadiancePipeline0D] + self.assertSequenceEqual(pipeline_classes_true, polychromator.pipeline_classes) + def test_pipeline_kwargs(self): + polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default, 'test polychromator') + pipeline_kwargs_true = [{'name': 'test polychromator: filter 1', 'filter': self.poly_filters_default[0]}, + {'name': 'test polychromator: filter 2', 'filter': self.poly_filters_default[1]}] + self.assertSequenceEqual(pipeline_kwargs_true, polychromator.pipeline_kwargs) + def test_spectral_properties(self): polychromator = Polychromator(self.poly_filters_default, self.min_bins_per_window_default) min_wavelength_true = 397. @@ -98,11 +103,15 @@ class TestSpectrometer(unittest.TestCase): Test cases for Spectrometer class. """ - def test_pipeline_properties(self): + def test_pipeline_classes(self): + wavelength_to_pixel = ([400., 400.5],) + spectrometer = Spectrometer(wavelength_to_pixel, name='test spectrometer') + self.assertSequenceEqual([SpectralRadiancePipeline0D], spectrometer.pipeline_classes) + + def test_pipeline_kwargs(self): wavelength_to_pixel = ([400., 400.5],) spectrometer = Spectrometer(wavelength_to_pixel, name='test spectrometer') - pipeline_properties_true = [(SpectralRadiancePipeline0D, 'test spectrometer', None)] - self.assertSequenceEqual(pipeline_properties_true, spectrometer.pipeline_properties) + self.assertSequenceEqual([{'name': 'test spectrometer'}], spectrometer.pipeline_kwargs) def test_spectral_properties(self): wavelength_to_pixel = ([400., 400.5, 401.5, 402., 404.], [600., 600.5, 601.5, 602., 604., 607.]) From 3b7764444432f98883961803ddbfd3dfb27e7e5d Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 23 Mar 2022 23:51:03 +0300 Subject: [PATCH 19/81] Update CHANGELOG.md. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c5ca2d2..9c91c98e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ New: * Add a demo for observer group handling and plotting. * Add verbose parameter to SartOpencl solver (default is False). (#358) * Add Generomak core plasma profiles. (#360) +* Add common spectroscopic instruments: Polychromator, SurveySpectrometer, CzernyTurnerSpectrometer. (#299) Bug Fixes: ---------- From 0f83e5d77cf4e868c28e697d87afbe26a537d3bd Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 4 Aug 2022 14:14:08 +0300 Subject: [PATCH 20/81] Add Generomak blended plasma profiles. --- CHANGELOG.md | 1 + cherab/generomak/plasma/__init__.py | 5 +- .../generomak/plasma/data/edge/carbon0.json | 3646 ++++++++--------- .../generomak/plasma/data/edge/hydrogen0.json | 454 +- cherab/generomak/plasma/plasma.py | 292 +- demos/generomak/plasma/plot_2d_plasma.py | 128 + demos/generomak/plasma/plot_2d_profiles.py | 144 + 7 files changed, 2504 insertions(+), 2166 deletions(-) create mode 100755 demos/generomak/plasma/plot_2d_plasma.py create mode 100755 demos/generomak/plasma/plot_2d_profiles.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 27b5ecac..1d628df8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ New: * Add verbose parameter to SartOpencl solver (default is False). (#358) * Add Generomak core plasma profiles. (#360) * Add toroidal_mesh_from_polygon for making mesh for not fully-360 degrees axisymmetric elements. (#365) +* Add Generomak full plasma profiles obtained by blending the core and edge profiles. (#372) Bug Fixes: ---------- diff --git a/cherab/generomak/plasma/__init__.py b/cherab/generomak/plasma/__init__.py index 8a28ab1a..7cccf703 100644 --- a/cherab/generomak/plasma/__init__.py +++ b/cherab/generomak/plasma/__init__.py @@ -1,2 +1,3 @@ -from .plasma import get_edge_distributions, get_edge_interpolators, get_edge_plasma -from .plasma import get_core_distributions, get_core_plasma \ No newline at end of file +from .plasma import get_2d_distributions, get_edge_interpolators, get_edge_plasma +from .plasma import get_core_distributions, get_core_plasma +from .plasma import get_full_profiles, get_plasma diff --git a/cherab/generomak/plasma/data/edge/carbon0.json b/cherab/generomak/plasma/data/edge/carbon0.json index beee5028..cc58c95c 100644 --- a/cherab/generomak/plasma/data/edge/carbon0.json +++ b/cherab/generomak/plasma/data/edge/carbon0.json @@ -36,52 +36,52 @@ 0.8826349542181627, 0.8899903230020518, 0.8899903230020518, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7047757257456048, 0.7047757257456048, 0.7072344434153071, @@ -94,10 +94,10 @@ 0.771280502896162, 0.7378957943285048, 0.7378957943285048, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6668202352525383, 0.6668202352525383, 0.6939803492353266, @@ -114,56 +114,56 @@ 0.7550529537931084, 0.6698586018699858, 0.6698586018699858, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.8777104035584131, 0.8777104035584131, 0.8904284769390789, @@ -232,52 +232,52 @@ 0.8826349542181627, 0.8899903230020518, 0.8899903230020518, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7047757257456048, 0.7047757257456048, 0.7072344434153071, @@ -290,10 +290,10 @@ 0.771280502896162, 0.7378957943285048, 0.7378957943285048, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6668202352525383, 0.6668202352525383, 0.6939803492353266, @@ -310,56 +310,56 @@ 0.7550529537931084, 0.6698586018699858, 0.6698586018699858, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.8777104035584131, 0.8777104035584131, 0.8904284769390789, @@ -428,52 +428,52 @@ 0.9488695364408866, 0.9776952595352856, 0.9776952595352856, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7381857748401043, 0.7381857748401043, 0.7252051835877666, @@ -486,10 +486,10 @@ 0.6707223018957097, 0.6653150953392322, 0.6653150953392322, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6712374760547157, 0.6712374760547157, 0.6863147774504369, @@ -506,62 +506,62 @@ 0.7169300660266651, 0.7016922330175489, 0.7016922330175489, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 0.989668471223005, - 0.989668471223005, - 0.9084402862412485, - 0.9084402862412485, - 0.9888120737628983, - 0.9888120737628983, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 0.989668471223005, + 0.989668471223005, + 0.9084402862412485, + 0.9084402862412485, + 0.9888120737628983, + 0.9888120737628983, 0.9238193646007199, 0.9238193646007199, 0.9402302268252902, @@ -624,52 +624,52 @@ 1.0141940442254633, 1.0314660474570372, 1.0314660474570372, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7425897836430437, 0.7425897836430437, 0.7658060128718618, @@ -682,10 +682,10 @@ 0.671465665626478, 0.6819424130985049, 0.6819424130985049, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7291516897755482, 0.7291516897755482, 0.7241049927832115, @@ -702,56 +702,56 @@ 0.7451781374562225, 0.6630318889047037, 0.6630318889047037, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 1.041544898725567, 1.041544898725567, 0.9741726142287506, @@ -820,52 +820,52 @@ 1.0599891197764155, 1.0291050094043501, 1.0291050094043501, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7562683004400875, 0.7562683004400875, 0.7327700174161945, @@ -878,10 +878,10 @@ 0.6702462619986006, 0.7024151245985529, 0.7024151245985529, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.697839411880975, 0.697839411880975, 0.7256309169217358, @@ -898,56 +898,56 @@ 0.7184151082807516, 0.6821155525602305, 0.6821155525602305, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.9521070696129001, 0.9521070696129001, 0.875934444566366, @@ -1016,52 +1016,52 @@ 0.9521600600249424, 0.9985453326739754, 0.9985453326739754, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7107102149886928, 0.7107102149886928, 0.6925560368645347, @@ -1074,10 +1074,10 @@ 0.7163705771532305, 0.7085061508892283, 0.7085061508892283, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6568431829970128, 0.6568431829970128, 0.6666301188861303, @@ -1094,56 +1094,56 @@ 0.6694595197797648, 0.7170387931147423, 0.7170387931147423, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 20.447996996565863, 20.447996996565863, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.9327311785025072, 0.9327311785025072, 0.9597158436652123, @@ -1212,52 +1212,52 @@ 1.0298700935866976, 0.9528687209652565, 0.9528687209652565, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6387338189080094, 0.6387338189080094, 0.6234247702803535, @@ -1270,10 +1270,10 @@ 0.6924896272079825, 0.6741197425302109, 0.6741197425302109, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7490929991929967, 0.7490929991929967, 0.7573533243775917, @@ -1290,56 +1290,56 @@ 0.6863972902004013, 0.7098833398665082, 0.7098833398665082, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 29.736571479671202, 29.736571479671202, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 41.119296463288705, 41.119296463288705, 20.70607715528574, 20.70607715528574, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 20.447996996565863, 20.447996996565863, 11.907214594917132, 11.907214594917132, 11.053179545995052, 11.053179545995052, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.9374114989121731, 0.9374114989121731, 1.0162759619923405, @@ -1408,52 +1408,52 @@ 0.9172602251294597, 1.034558340712888, 1.034558340712888, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7698504483370217, 0.7698504483370217, 0.6974013203590386, @@ -1466,10 +1466,10 @@ 0.7918775452569733, 0.6937161461562047, 0.6937161461562047, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6507337442545676, 0.6507337442545676, 0.6520238017651679, @@ -1486,60 +1486,60 @@ 0.668291795847024, 0.715565672142988, 0.715565672142988, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 29.736571479671202, 29.736571479671202, 28.954414273401518, 28.954414273401518, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 41.119296463288705, 41.119296463288705, 20.70607715528574, 20.70607715528574, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 20.436121901400792, 20.436121901400792, 22.917604227150402, 22.917604227150402, 11.053179545995052, 11.053179545995052, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 1.0904314561361903, - 1.0904314561361903, - 1.085821664779066, - 1.085821664779066, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 1.0904314561361903, + 1.0904314561361903, + 1.085821664779066, + 1.085821664779066, 1.0145245945460468, 1.0145245945460468, 0.9934922693423827, @@ -1606,50 +1606,50 @@ 1.078138055032951, 0.6426753943036221, 0.6426753943036221, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7200699195816633, 0.7200699195816633, 0.755049895453662, @@ -1662,10 +1662,10 @@ 0.6385266008067373, 0.6417090838687141, 0.6417090838687141, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6539603547857009, 0.6539603547857009, 0.6483565406933778, @@ -1682,30 +1682,30 @@ 0.6835863641736272, 0.6922198691857843, 0.6922198691857843, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 29.736571479671202, 29.736571479671202, 28.954414273401518, 28.954414273401518, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 12.009592819963695, 12.009592819963695, 20.87818801631581, 20.87818801631581, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 20.462200798766613, 20.462200798766613, 23.184476175552565, @@ -1714,22 +1714,22 @@ 11.053179545995052, 40.216868497908706, 40.216868497908706, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 47.12362569631633, 47.12362569631633, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 1.271636695208476, 1.271636695208476, 1.077981642815545, @@ -1802,50 +1802,50 @@ 1.6613708772886773, 1.8250934621981263, 1.8250934621981263, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6754564865286883, 0.6754564865286883, 0.6830080259427875, @@ -1858,10 +1858,10 @@ 0.6935655385422379, 0.6392340134452367, 0.6392340134452367, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6822174139883256, 0.6822174139883256, 0.6678244940626191, @@ -1878,30 +1878,30 @@ 0.7375110677091551, 0.6868580384002779, 0.6868580384002779, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 29.736571479671202, 29.736571479671202, 28.954414273401518, 28.954414273401518, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 11.486304075009997, 11.486304075009997, 21.400253425490913, 21.400253425490913, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 20.46202541236162, 20.46202541236162, 28.1268806720096, @@ -1910,22 +1910,22 @@ 11.053179545995052, 40.216868497908706, 40.216868497908706, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 47.12362569631633, 47.12362569631633, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 4.073020328419045, 4.073020328419045, 1.5613878937645274, @@ -1990,58 +1990,58 @@ 1.9632484541651354, 2.1295862313767837, 2.1295862313767837, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6763005882159183, 0.6763005882159183, 0.7898026179802595, @@ -2054,10 +2054,10 @@ 0.6937591501537277, 0.7556495172304454, 0.7556495172304454, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.648692521126856, 0.648692521126856, 0.681328248605578, @@ -2074,18 +2074,18 @@ 0.6840589712407453, 0.7241738366283028, 0.7241738366283028, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 29.736571479671202, 29.736571479671202, 28.592746909327357, @@ -2110,38 +2110,38 @@ 10.298871329064708, 47.12362569631633, 47.12362569631633, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 4.25838478430837, - 4.25838478430837, - 2.2399058404942385, - 2.2399058404942385, - 1.6997660820960394, - 1.6997660820960394, - 1.4481581186260142, - 1.4481581186260142, - 1.6029574676720695, - 1.6029574676720695, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 4.25838478430837, + 4.25838478430837, + 2.2399058404942385, + 2.2399058404942385, + 1.6997660820960394, + 1.6997660820960394, + 1.4481581186260142, + 1.4481581186260142, + 1.6029574676720695, + 1.6029574676720695, 1.4764963798616977, 1.4764963798616977, 1.0559663423477441, @@ -2180,64 +2180,64 @@ 2.054170888626254, 3.687400861196182, 3.687400861196182, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7016610254721765, 0.7016610254721765, 0.7150149213822576, @@ -2250,10 +2250,10 @@ 0.7040376672975498, 0.7555713111217425, 0.7555713111217425, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6900798429694239, 0.6900798429694239, 0.7153411650615797, @@ -2270,18 +2270,18 @@ 0.6640386443184142, 0.6994095259037463, 0.6994095259037463, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 27.739809741851474, 27.739809741851474, 38.84926023705824, @@ -2306,38 +2306,38 @@ 10.298871329064708, 47.12362569631633, 47.12362569631633, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 12.78479636097352, 12.78479636097352, 3.6748473139947193, @@ -2368,72 +2368,72 @@ 3.527400649883651, 19.403170249953853, 19.403170249953853, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.691325710595777, 0.691325710595777, 0.6673680525040038, @@ -2446,10 +2446,10 @@ 0.7359544353459845, 0.6783759523982673, 0.6783759523982673, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6720141694439417, 0.6720141694439417, 0.6500762012735732, @@ -2466,18 +2466,18 @@ 0.6696363417318444, 0.6958262131290076, 0.6958262131290076, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 27.613459752902624, 27.613459752902624, 50.56896491975679, @@ -2502,42 +2502,42 @@ 9.900632466719646, 47.12362569631633, 47.12362569631633, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 12.102842213837954, 12.102842213837954, 1.7662817818874772, @@ -2564,72 +2564,72 @@ 4.423797944365727, 5.186650225483191, 5.186650225483191, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 6.087607566495069, 6.087607566495069, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6851429341217069, 0.6851429341217069, 0.6554378448138072, @@ -2642,10 +2642,10 @@ 0.7649226520925533, 0.6514028964424405, 0.6514028964424405, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.674137093925438, 0.674137093925438, 0.6775360949372078, @@ -2662,14 +2662,14 @@ 0.6772589719343018, 0.6916349149553257, 0.6916349149553257, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 10.416500681534718, 10.416500681534718, 36.59624148531928, @@ -2700,40 +2700,40 @@ 47.12362569631633, 7.919889561939525, 7.919889561939525, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 3.4987177325168757, 3.4987177325168757, 1.6479893314933964, @@ -2758,74 +2758,74 @@ 1.2275594077849972, 5.494688671136869, 5.494688671136869, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 6.087607566495069, 6.087607566495069, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7292143545266557, 0.7292143545266557, 0.6891375623444526, @@ -2838,10 +2838,10 @@ 0.7586520575858056, 0.6745911012955143, 0.6745911012955143, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6433718218861504, 0.6433718218861504, 0.6992843212317127, @@ -2858,14 +2858,14 @@ 0.6969783957041531, 0.7316343748400964, 0.7316343748400964, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 10.685891702999333, 10.685891702999333, 36.59624148531928, @@ -2896,36 +2896,36 @@ 8.577289612376159, 7.137119439478731, 7.137119439478731, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 9.916620092213877, 9.916620092213877, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 6.42574718762251, 6.42574718762251, 3.179734301380406, @@ -2956,72 +2956,72 @@ 2.9325974429358705, 23.358836476453074, 23.358836476453074, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 33.60428485689675, 33.60428485689675, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 6.087607566495069, 6.087607566495069, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 32.071443253865354, 32.071443253865354, 15.43404108838102, 15.43404108838102, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7621497992711334, 0.7621497992711334, 0.7179255867240416, @@ -3034,10 +3034,10 @@ 0.767890115166915, 0.7059415772256232, 0.7059415772256232, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.636204010449949, 0.636204010449949, 0.6790766242069662, @@ -3054,14 +3054,14 @@ 0.6941961806191215, 0.649713319935984, 0.649713319935984, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 12.239578698037612, 12.239578698037612, 19.242109356589207, @@ -3094,20 +3094,20 @@ 5.711142083726083, 6.620745038277721, 6.620745038277721, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 13.11318150205903, 13.11318150205903, 6.593562642107537, @@ -3156,50 +3156,50 @@ 33.669584773135576, 33.49419462323778, 33.49419462323778, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 8.171498524051001, 8.171498524051001, 38.45923270405153, 38.45923270405153, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 15.860288098546818, 15.860288098546818, 32.071443253865354, @@ -3208,16 +3208,16 @@ 15.43404108838102, 18.948368959923304, 18.948368959923304, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7029588848691198, 0.7029588848691198, 0.6739359300879681, @@ -3230,10 +3230,10 @@ 0.7166222347991128, 0.7328946603524116, 0.7328946603524116, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6357189827797727, 0.6357189827797727, 0.6683781783326145, @@ -3250,14 +3250,14 @@ 0.6741188063038498, 0.7088372005305378, 0.7088372005305378, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 12.229961156704775, 12.229961156704775, 18.50145319245743, @@ -3354,42 +3354,42 @@ 30.909596326069007, 27.39453570136138, 27.39453570136138, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 5.20877762345397, 5.20877762345397, 6.623242890209321, 6.623242890209321, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 4.480751652255091, 4.480751652255091, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 9.424871565066152, 9.424871565066152, 25.002127199915215, @@ -3404,16 +3404,16 @@ 15.43404108838102, 18.948368959923304, 18.948368959923304, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 15.397359739550415, 15.397359739550415, 15.397359739550415, 15.397359739550415, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6738766357517608, 0.6738766357517608, 0.6770712897564328, @@ -3426,10 +3426,10 @@ 0.7541213461486544, 0.6783959252273055, 0.6783959252273055, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6463107612640417, 0.6463107612640417, 0.666387511428406, @@ -3446,14 +3446,14 @@ 0.6821862064429534, 0.7122229695430697, 0.7122229695430697, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 23.867441447158193, 23.867441447158193, 18.074834812501706, @@ -3550,38 +3550,38 @@ 27.39453570136138, 35.695627926627225, 35.695627926627225, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 59.91215073481093, 59.91215073481093, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 5.20877762345397, 5.20877762345397, 6.623242890209321, 6.623242890209321, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 6.289243511711331, 6.289243511711331, 6.692733355640737, @@ -3604,12 +3604,12 @@ 24.511241873472486, 8.926741719040699, 8.926741719040699, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6638601995739754, 0.6638601995739754, 0.6726811995187293, @@ -3622,10 +3622,10 @@ 0.7778953790434571, 0.6578610482968759, 0.6578610482968759, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6443494918675741, 0.6443494918675741, 1.0633255808672593, @@ -3642,12 +3642,12 @@ 0.6765483137110837, 0.6952242195787759, 0.6952242195787759, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 5.307164528277598, 5.307164528277598, 20.442098770490496, @@ -3746,34 +3746,34 @@ 1.2827860276983667, 35.69119083782619, 35.69119083782619, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 59.91215073481093, 59.91215073481093, 59.91215073481093, 59.91215073481093, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 5.20877762345397, 5.20877762345397, 6.623242890209321, 6.623242890209321, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 0.6666763684683721, 0.6666763684683721, 0.7227419720315307, @@ -3802,10 +3802,10 @@ 6.311529444012602, 1.1100967036072755, 1.1100967036072755, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6891511064191441, 0.6891511064191441, 0.6774362932071071, @@ -3818,10 +3818,10 @@ 0.7280618598760566, 0.7217131216756966, 0.7217131216756966, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.702498199084334, 0.702498199084334, 0.8427326122145906, @@ -3838,12 +3838,12 @@ 0.6723606980277558, 0.6898971539988143, 0.6898971539988143, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 13.651777548017844, 13.651777548017844, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 7.851858361329716, 7.851858361329716, 18.578210646904243, @@ -3942,26 +3942,26 @@ 1.2281109075268166, 28.424399054118275, 28.424399054118275, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 47.648711995883474, 47.648711995883474, 52.974239043858134, 52.974239043858134, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 38.28753003771493, 38.28753003771493, 7.8610140309910435, 7.8610140309910435, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 0.6666763684683721, 0.6666763684683721, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 33.80948695073779, 33.80948695073779, 5.20877762345397, @@ -4014,10 +4014,10 @@ 0.7272484039983822, 0.6604385418842652, 0.6604385418842652, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6681542954021136, 0.6681542954021136, 0.8068853162416049, @@ -4154,8 +4154,8 @@ 0.6666763684683721, 0.6666763684683721, 0.6666763684683721, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 33.80948695073779, 33.80948695073779, 33.80948695073779, @@ -4210,10 +4210,10 @@ 0.743756196858879, 0.6876543925430885, 0.6876543925430885, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7303031233696048, 0.7303031233696048, 0.7414673730661835, @@ -4348,8 +4348,8 @@ 2.796235137205228, 0.6666763684683721, 0.6666763684683721, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, 33.80948695073779, 33.80948695073779, 21.166854066104175, @@ -4406,10 +4406,10 @@ 0.7093227899365309, 0.6636280778514962, 0.6636280778514962, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.726225420661078, 0.726225420661078, 0.703051009543059, @@ -4602,10 +4602,10 @@ 0.7129741351601812, 0.6611613086350877, 0.6611613086350877, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6949256881997445, 0.6949256881997445, 0.6979661769302773, @@ -4798,10 +4798,10 @@ 0.6918136717752184, 0.7215496565530365, 0.7215496565530365, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6959255779534731, 0.6959255779534731, 0.6880125303337811, @@ -4994,10 +4994,10 @@ 0.6835688879482187, 0.7268541902852392, 0.7268541902852392, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6848245547438186, 0.6848245547438186, 0.679257503139944, @@ -5190,10 +5190,10 @@ 0.683777479181487, 0.7169371189319192, 0.7169371189319192, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6898697537739775, 0.6898697537739775, 0.688960740392373, @@ -5386,10 +5386,10 @@ 0.6829814371141303, 0.714735239360631, 0.714735239360631, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6944113878520088, 0.6944113878520088, 0.6889494432609483, @@ -5582,10 +5582,10 @@ 0.6810513128479442, 0.7179132285360741, 0.7179132285360741, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7000713755260022, 0.7000713755260022, 0.6947092950801328, @@ -5778,10 +5778,10 @@ 0.6677305593510484, 0.7192147080082807, 0.7192147080082807, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6944829155460022, 0.6944829155460022, 0.6939876518009437, @@ -5974,10 +5974,10 @@ 0.6723199409734995, 0.7051740588547367, 0.7051740588547367, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6991042536949145, 0.6991042536949145, 0.6833483130175272, @@ -6170,10 +6170,10 @@ 0.6985494459532857, 0.684618210453817, 0.684618210453817, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.6994964077100628, 0.6994964077100628, 0.7044508551982791, @@ -6366,10 +6366,10 @@ 0.6881025953097255, 0.7203669529985169, 0.7203669529985169, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7151509862800808, 0.7151509862800808, 0.747833337831589, @@ -6562,10 +6562,10 @@ 0.6867911294229997, 0.7382354572523369, 0.7382354572523369, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7029822905281491, 0.7029822905281491, 0.7433765258618795, @@ -6758,10 +6758,10 @@ 0.705876852776521, 0.7732053842947257, 0.7732053842947257, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7010752598455384, 0.7010752598455384, 0.7448947105291513, @@ -6954,10 +6954,10 @@ 0.7567317324888662, 0.7563844549239631, 0.7563844549239631, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.7127471938902338, 0.7127471938902338, 0.7629452796026733, @@ -7150,10 +7150,10 @@ 0.7424246333129336, 0.8932101927033845, 0.8932101927033845, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.8063032955204114, 0.8063032955204114, 0.7377027444528318, @@ -7346,10 +7346,10 @@ 0.7424246333129336, 0.8932101927033845, 0.8932101927033845, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, + 152.00613642203447, 0.8063032955204114, 0.8063032955204114, 0.7377027444528318, @@ -14901,4 +14901,4 @@ 0.0, 0.0 ] -} \ No newline at end of file +} diff --git a/cherab/generomak/plasma/data/edge/hydrogen0.json b/cherab/generomak/plasma/data/edge/hydrogen0.json index 50252db1..b255b8b3 100644 --- a/cherab/generomak/plasma/data/edge/hydrogen0.json +++ b/cherab/generomak/plasma/data/edge/hydrogen0.json @@ -36,22 +36,22 @@ 1.972944700927401, 2.1469916156572784, 2.1469916156572784, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 1060.8616203299343, - 1060.8616203299343, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 237.02952717009856, 237.02952717009856, 510.5159897120308, @@ -94,10 +94,10 @@ 3.2178661145048255, 3.0058149630960105, 3.0058149630960105, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.228549122630633, 4.228549122630633, 4.632909532245744, @@ -114,8 +114,8 @@ 3.701953002018378, 3.344396295820652, 3.344396295820652, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 390.9182712497354, 390.9182712497354, 368.29180845487235, @@ -160,10 +160,10 @@ 327.66094502911096, 224.2842595343954, 224.2842595343954, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 2.28095818054478, 2.28095818054478, 2.2121432336404925, @@ -232,22 +232,22 @@ 1.972944700927401, 2.1469916156572784, 2.1469916156572784, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 1060.8616203299343, - 1060.8616203299343, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 237.02952717009856, 237.02952717009856, 510.5159897120308, @@ -290,10 +290,10 @@ 3.2178661145048255, 3.0058149630960105, 3.0058149630960105, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.228549122630633, 4.228549122630633, 4.632909532245744, @@ -310,8 +310,8 @@ 3.701953002018378, 3.344396295820652, 3.344396295820652, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 390.9182712497354, 390.9182712497354, 368.29180845487235, @@ -356,10 +356,10 @@ 327.66094502911096, 224.2842595343954, 224.2842595343954, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 2.28095818054478, 2.28095818054478, 2.2121432336404925, @@ -432,14 +432,14 @@ 773.3934409631391, 773.3934409631391, 773.3934409631391, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 1060.8616203299343, 1060.8616203299343, 172.10538098510307, @@ -486,10 +486,10 @@ 3.032072679696813, 3.370428818774048, 3.370428818774048, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 5.3896244750752, 5.3896244750752, 4.462110574008034, @@ -624,14 +624,14 @@ 2.147574884680287, 2.194014083967723, 2.194014083967723, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 773.3934409631391, 773.3934409631391, 773.3934409631391, 773.3934409631391, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 298.78233138681514, 298.78233138681514, 59.11285621707551, @@ -682,10 +682,10 @@ 3.1739117848101137, 3.592521996547854, 3.592521996547854, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.050162985962009, 4.050162985962009, 4.408568162903317, @@ -748,10 +748,10 @@ 223.31419795253365, 240.54622431848549, 240.54622431848549, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 2.3245336506386725, 2.3245336506386725, 2.224360425917933, @@ -820,10 +820,10 @@ 2.2302022287512653, 2.315271438417445, 2.315271438417445, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 69.51090013212614, 69.51090013212614, 492.924708325262, @@ -878,10 +878,10 @@ 2.9181949735012807, 3.2768293386558027, 3.2768293386558027, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.324206553120909, 4.324206553120909, 4.620829840413214, @@ -946,8 +946,8 @@ 156.99101750849775, 232.87885497898233, 232.87885497898233, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 2.2079833302574556, 2.2079833302574556, 2.2547071423586873, @@ -1016,10 +1016,10 @@ 2.1893738964614062, 2.04235408915594, 2.04235408915594, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 52.38173633232502, 52.38173633232502, 101.12902445436613, @@ -1074,10 +1074,10 @@ 3.4798216262090365, 3.1222993731414017, 3.1222993731414017, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.816413082204519, 4.816413082204519, 4.044458683573587, @@ -1142,8 +1142,8 @@ 92.01574712267337, 270.2239009185301, 270.2239009185301, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 2.2063231512587396, 2.2063231512587396, 2.1501370865704437, @@ -1212,8 +1212,8 @@ 2.3205649246785858, 2.1310041774083195, 2.1310041774083195, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, 100.91711897977912, 100.91711897977912, 44.17568980724506, @@ -1270,10 +1270,10 @@ 2.962358144089624, 2.6885652983502446, 2.6885652983502446, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.510954002590953, 4.510954002590953, 5.1300036622553815, @@ -1466,10 +1466,10 @@ 3.091068609355341, 3.595791860736873, 3.595791860736873, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.758281560358844, 3.758281560358844, 4.7689404762596235, @@ -1662,10 +1662,10 @@ 3.178992185951452, 3.0699698744951243, 3.0699698744951243, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.2251648103863184, 3.2251648103863184, 4.289231195965626, @@ -1858,10 +1858,10 @@ 2.525787178593943, 2.825822761312346, 2.825822761312346, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.9410852499050995, 3.9410852499050995, 3.3806876751642854, @@ -2054,10 +2054,10 @@ 3.019009700524693, 2.3753950839355458, 2.3753950839355458, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.197689853464683, 4.197689853464683, 3.755099077296867, @@ -2250,10 +2250,10 @@ 2.877357840683626, 3.041679111143497, 3.041679111143497, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.5308683699103307, 3.5308683699103307, 3.276232088652468, @@ -2446,10 +2446,10 @@ 2.7262409819915026, 4.0978295780089375, 4.0978295780089375, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.0636950981772966, 3.0636950981772966, 3.487733612772186, @@ -2642,10 +2642,10 @@ 2.8434261886757737, 2.888884534812159, 2.888884534812159, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 2.965325731994167, 2.965325731994167, 3.2970243030020376, @@ -2838,10 +2838,10 @@ 2.6858381957903403, 2.9947567566386066, 2.9947567566386066, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 2.707415654396568, 2.707415654396568, 3.4228154272283566, @@ -3034,10 +3034,10 @@ 3.1050752422844288, 2.5827768999906664, 2.5827768999906664, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.3679896994428393, 3.3679896994428393, 3.7827563898925267, @@ -3230,10 +3230,10 @@ 3.2214229008659983, 3.112208101269813, 3.112208101269813, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.079169463159205, 4.079169463159205, 4.373918362861358, @@ -3426,10 +3426,10 @@ 3.182294755648022, 3.540194869675025, 3.540194869675025, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.426191958807458, 3.426191958807458, 3.890835422082432, @@ -3622,10 +3622,10 @@ 2.9324045178903795, 3.031484542296727, 3.031484542296727, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.048504929076378, 4.048504929076378, 4.101542214851699, @@ -3818,10 +3818,10 @@ 3.1031142849634143, 3.186577866420189, 3.186577866420189, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 5.138463029164361, 5.138463029164361, 4.226479438221542, @@ -4014,10 +4014,10 @@ 2.9823071305632336, 3.301914899852422, 3.301914899852422, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.230204495667361, 4.230204495667361, 3.7793528325791326, @@ -4210,10 +4210,10 @@ 2.7946538508812133, 3.6766072947235355, 3.6766072947235355, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.347594361434184, 4.347594361434184, 3.2985799991388465, @@ -4406,10 +4406,10 @@ 2.9905828098601517, 3.2936387212347777, 3.2936387212347777, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.6020830522235667, 3.6020830522235667, 3.408852235202427, @@ -4602,10 +4602,10 @@ 2.990016392911645, 2.251912069764962, 2.251912069764962, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.33474979388571, 3.33474979388571, 3.552615972053928, @@ -4798,10 +4798,10 @@ 3.1068532609744706, 2.035272972280783, 2.035272972280783, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.346502929963464, 3.346502929963464, 3.4188598084373263, @@ -4994,10 +4994,10 @@ 3.050768558393544, 2.5736518761388956, 2.5736518761388956, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.719975297055793, 3.719975297055793, 3.6058544216667188, @@ -5190,10 +5190,10 @@ 2.9544671289969644, 2.6266115175413303, 2.6266115175413303, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.621674275397029, 3.621674275397029, 3.7044403682147324, @@ -5386,10 +5386,10 @@ 2.7672878919291497, 2.397112914080858, 2.397112914080858, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.811473760389393, 3.811473760389393, 3.8450036464581223, @@ -5582,10 +5582,10 @@ 2.630605459198078, 2.492375257046721, 2.492375257046721, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.876404241706099, 3.876404241706099, 3.662145218877284, @@ -5778,10 +5778,10 @@ 2.8051830270294658, 2.551368128365802, 2.551368128365802, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.877623582918886, 3.877623582918886, 4.0914143677369355, @@ -5974,10 +5974,10 @@ 2.6751353808596363, 2.908345372861055, 2.908345372861055, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.916432724608066, 3.916432724608066, 4.1287282310971465, @@ -6170,10 +6170,10 @@ 2.6903946222448782, 2.7719752652440692, 2.7719752652440692, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 3.539496944130319, 3.539496944130319, 4.011383928346568, @@ -6366,10 +6366,10 @@ 2.4393379088563094, 2.553484436847679, 2.553484436847679, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.608095663939136, 4.608095663939136, 4.553307572453338, @@ -6562,10 +6562,10 @@ 2.4487560963893076, 2.596682670133111, 2.596682670133111, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.667622184284084, 4.667622184284084, 4.634387022273851, @@ -6758,10 +6758,10 @@ 2.540889570856143, 3.099676149689748, 3.099676149689748, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.975413715838775, 4.975413715838775, 4.372279592238767, @@ -6954,10 +6954,10 @@ 2.8814299260339857, 2.778316014312814, 2.778316014312814, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 4.494170272614275, 4.494170272614275, 4.624706129623908, @@ -7150,10 +7150,10 @@ 3.1383402387080377, 3.087223090784384, 3.087223090784384, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 5.0891368198545335, 5.0891368198545335, 4.804279214073222, @@ -7346,10 +7346,10 @@ 3.1383402387080377, 3.087223090784384, 3.087223090784384, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, - 6241509074460.763, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, + 1060.8616203299343, 5.0891368198545335, 5.0891368198545335, 4.804279214073222, @@ -14901,4 +14901,4 @@ 0.0, 0.0 ] -} \ No newline at end of file +} diff --git a/cherab/generomak/plasma/plasma.py b/cherab/generomak/plasma/plasma.py index f06335b4..65fef528 100644 --- a/cherab/generomak/plasma/plasma.py +++ b/cherab/generomak/plasma/plasma.py @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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,8 @@ from raysect.core import Vector3D, translate from raysect.core.math.function.float.function2d.interpolate import Discrete2DMesh -from raysect.core.math.function.float import Arg1D, Exp1D, Constant1D +from raysect.core.math.function.float import Arg1D, Exp1D, Constant1D, Interpolator1DArray, Blend2D +from raysect.core.math.function.vector3d import Constant2D as ConstantVector2D, Blend2D as BlendVector2D from raysect.primitive import Cylinder, Subtract from cherab.core import AtomicData, Plasma, Maxwellian, Species @@ -106,64 +107,66 @@ def get_edge_interpolators(): profiles["mesh"]["triangles"], profiles["electron"]["temperature"], limit=False) ne = Discrete2DMesh.instance(te, profiles["electron"]["density"], limit=False) + ve = ConstantVector2D(Vector3D(0, 1.e-10, 0)) # avoid zero-length vectors for blending mesh_interp["electron"]["temperature"] = te mesh_interp["electron"]["density"] = ne + mesh_interp["electron"]["velocity"] = ve for elem_name, elem_data in profiles["composition"].items(): for stage, stage_data in elem_data.items(): t = Discrete2DMesh.instance(te, stage_data["temperature"], limit=False) n = Discrete2DMesh.instance(te, stage_data["density"], limit=False) + v = ConstantVector2D(Vector3D(0, 1.e-10, 0)) # avoid zero-length vectors for blending mesh_interp["composition"][elem_name][stage]["temperature"] = t mesh_interp["composition"][elem_name][stage]["density"] = n + mesh_interp["composition"][elem_name][stage]["velocity"] = v mesh_interp["composition"][elem_name][stage]["element"] = stage_data["element"] return mesh_interp.freeze() -def get_edge_distributions(): +def get_2d_distributions(profiles_2d=None): """ - Provides Generomak edge Maxwellian distribution of plasma species + Provides Generomak Maxwellian distribution of plasma species for 2d profiles + :param profiles_2d: Dictionary with 2D profile interpolators in the shape + returned by the get_edge_interpolators() or get_full_profiles() functions. + If not specified, will use the value returned by get_edge_interpolators(). :return: Dictionary holding instances of Maxwellian distributions for plasma species. """ - mesh_interp = get_edge_interpolators() - - zero_vector = Vector3D(0, 0, 0) + profiles_2d = profiles_2d or get_edge_interpolators() dists = RecursiveDict() - n3d = AxisymmetricMapper(mesh_interp["electron"]["density"]) - t3d = AxisymmetricMapper(mesh_interp["electron"]["temperature"]) + n3d = AxisymmetricMapper(profiles_2d["electron"]["density"]) + t3d = AxisymmetricMapper(profiles_2d["electron"]["temperature"]) + v3d = VectorAxisymmetricMapper(profiles_2d["electron"]["velocity"]) - dists["electron"] = Maxwellian(n3d, t3d, zero_vector, electron_mass) + dists["electron"] = Maxwellian(n3d, t3d, v3d, electron_mass) - for elem_name, elem_data in mesh_interp["composition"].items(): + for elem_name, elem_data in profiles_2d["composition"].items(): for stage, stage_data in elem_data.items(): - # get element or isotope - try: - element = lookup_isotope(elem_name) - except ValueError: - element = lookup_element(elem_name) + spec_cherab = _get_cherab_element(elem_name) n3d = AxisymmetricMapper(stage_data["density"]) t3d = AxisymmetricMapper(stage_data["temperature"]) - mass = element.atomic_weight * atomic_mass - dists["composition"][elem_name][stage]["distribution"] = Maxwellian(n3d, t3d, zero_vector, mass) - dists["composition"][elem_name][stage]["element"] = element + v3d = VectorAxisymmetricMapper(stage_data["velocity"]) + mass = spec_cherab.atomic_weight * atomic_mass + dists["composition"][elem_name][stage] = Maxwellian(n3d, t3d, v3d, mass) return dists.freeze() def get_edge_plasma(atomic_data=None, parent=None, name="Generomak edge plasma"): """ - Provides Generomak Edge plasma. + Provides Generomak default edge plasma. - :param atomic_data: Instance of AtomicData, default isOpenADAS() + :param atomic_data: Instance of AtomicData, default is OpenADAS() :param parent: parent of the plasma node, defaults None :param name: name of the plasma node, defaults "Generomak edge plasma" :return: populated Plasma object @@ -172,12 +175,8 @@ def get_edge_plasma(atomic_data=None, parent=None, name="Generomak edge plasma") # load Generomak equilibrium equilibrium = load_equilibrium() - # create or check atomic_data - if atomic_data is not None: - if not isinstance(atomic_data, AtomicData): - raise ValueError("atomic_data has to be of type AtomicData") - else: - atomic_data = OpenADAS() + # get edge distributions + distributions = get_2d_distributions() # base plasma geometry on mesh vertices profiles_dir = os.path.join(os.path.dirname(__file__), "data/edge") @@ -188,38 +187,10 @@ def get_edge_plasma(atomic_data=None, parent=None, name="Generomak edge plasma") vertex_coords = np.asarray(mesh["vertex_coords"]) r_range = (vertex_coords[:, 0].min(), vertex_coords[:, 0].max()) z_range = (vertex_coords[:, 1].min(), vertex_coords[:, 1].max()) - plasma_height = z_range[1] - z_range[0] - - padding = 1e-3 # enlarge for safety - - outer_column = Cylinder(radius=r_range[1], height=plasma_height) - inner_column = Cylinder(radius=r_range[0], height=plasma_height + 2 * padding) - inner_column.transform = translate(0, 0, -padding) - - plasma_geometry = Subtract(outer_column, inner_column) - geometry_transform = translate(0, 0, z_range[0]) - - # get distributions - dists = get_edge_distributions() - # create plasma composition list - plasma_composition = [] - for elem_data in dists["composition"].values(): - for stage, stage_data in elem_data.items(): - species = Species(stage_data["element"], stage, stage_data["distribution"]) - plasma_composition.append(species) - - # Populate plasma - plasma = Plasma(parent=parent) - plasma.name = name - plasma.geometry = plasma_geometry - plasma.atomic_data = atomic_data - plasma.electron_distribution = dists["electron"] - plasma.composition = plasma_composition - plasma.geometry_transform = geometry_transform - plasma.b_field = VectorAxisymmetricMapper(equilibrium.b_field) - - return plasma + return get_plasma(equilibrium=equilibrium, distributions=distributions, + r_range=r_range, z_range=z_range, atomic_data=atomic_data, + parent=parent, name=name) def get_double_parabola(v_min, v_max, convexity, concavity, xmin=0, xmax=1): @@ -245,7 +216,7 @@ def get_double_parabola(v_min, v_max, convexity, concavity, xmin=0, xmax=1): :return: Function1D """ - x = Arg1D() #the free parameter + x = Arg1D() # the free parameter # funciton for the normalised free variable x_norm = ClampInput1D((x - xmin) / (xmax - xmin), 0, 1) @@ -271,7 +242,7 @@ def get_exponential_growth(initial_value, growth_rate, initial_position=1): :return: Function1D """ - x = Arg1D() #the free parameter + x = Arg1D() # the free parameter return initial_value * Exp1D((x - initial_position) * growth_rate) @@ -288,7 +259,6 @@ def get_maxwellian_distribution(equilibrium, f1d_density, f1d_temperature, f1d_v :return: Maxwellian distribution """ - # map profiles to 3D f3d_te = equilibrium.map3d(f1d_temperature) f3d_ne = equilibrium.map3d(f1d_density) @@ -308,28 +278,29 @@ def get_edge_profile_values(r, z, edge_interpolators=None): returned by the get_edge_interpolators function. :return: Dictionary of edge values at [R, Z] """ + # load edge interpolators if not passed as argument if edge_interpolators is None: edge_interp = get_edge_interpolators() else: edge_interp = edge_interpolators # create recursive dictionary to store profile values - lcfs_values = RecursiveDict() + values = RecursiveDict() # add electron values - lcfs_values["electron"]["temperature"] = edge_interp["electron"]["temperature"](r, z) - lcfs_values["electron"]["density"] = edge_interp["electron"]["density"](r, z) + values["electron"]["temperature"] = edge_interp["electron"]["temperature"](r, z) + values["electron"]["density"] = edge_interp["electron"]["density"](r, z) # add species values for spec, desc in edge_interp['composition'].items(): for chrg, chrg_desc in desc.items(): for prop, val in chrg_desc.items(): if prop in ["temperature", "density"]: - lcfs_values["composition"][spec][chrg][prop] = val(r, z) + values["composition"][spec][chrg][prop] = val(r, z) else: - lcfs_values["composition"][spec][chrg][prop] = val + values["composition"][spec][chrg][prop] = val - return lcfs_values.freeze() + return values.freeze() def get_core_profiles_arguments(**kwargs): @@ -371,26 +342,26 @@ def get_core_profiles_arguments(**kwargs): :return: dictionary of profile arguments """ - + core_args = {"ne_core": 5e19, "ne_convexity": 1.09, - "ne_concavity": 0.24, "te_core": 3e3, - "te_convexity": 2.35, "te_concavity": 1.26, - "nh_core": 5e19, "nh_convexity": 1.09, - "nh_concavity": 0.24, "th_core": 2.8e3, - "th_convexity": 1, "th_concavity": 0.82, - "th0_fraction": 0.8, "nh0_decay": 20, - "timp_core": 2.7e3, "timp_convexity": 1, - "timp_concavity": 0.82, "nimp_core": 5e17, - "nimp_convexity": 1.09, "nimp_concavity": 0.24, - "nimp_decay": 30, - "vtor_core": 1e5, "vtor_edge": 1e4, - "vtor_convexity": 2, "vtor_concavity": 4, - "vpol_lcfs": 2e4, "vpol_decay": 0.08} + "ne_concavity": 0.24, "te_core": 3e3, + "te_convexity": 2.35, "te_concavity": 1.26, + "nh_core": 5e19, "nh_convexity": 1.09, + "nh_concavity": 0.24, "th_core": 2.8e3, + "th_convexity": 1, "th_concavity": 0.82, + "th0_fraction": 0.8, "nh0_decay": 20, + "timp_core": 2.7e3, "timp_convexity": 1, + "timp_concavity": 0.82, "nimp_core": 5e17, + "nimp_convexity": 1.09, "nimp_concavity": 0.24, + "nimp_decay": 30, + "vtor_core": 1e5, "vtor_edge": 1e4, + "vtor_convexity": 2, "vtor_concavity": 4, + "vpol_lcfs": 2e4, "vpol_decay": 0.08} if not kwargs: return core_args - # change passed values of core args + # change passed values of core args for key, item in kwargs.items(): core_args[key] = item @@ -419,15 +390,23 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): z = 0 lcfs_values = get_edge_profile_values(r, z) + # manually correcting the LCFS densities for neutral species and low ionised carbon + # to better match the edge profiles + lcfs_values["composition"]["hydrogen"][0]["density"] = 1.e15 + lcfs_values["composition"]["carbon"][0]["density"] = 1.e5 + lcfs_values["composition"]["carbon"][1]["density"] = 1.5e5 + lcfs_values["composition"]["carbon"][2]["density"] = 1.e9 + lcfs_values["composition"]["carbon"][3]["density"] = 1.e13 + if core_args is None: core_args = get_core_profiles_arguments() # toroidal rotation profile f1d_vtor = get_double_parabola(core_args["vtor_edge"], core_args["vtor_core"], - core_args["vtor_convexity"], core_args["vtor_concavity"]) + core_args["vtor_convexity"], core_args["vtor_concavity"], xmin=1, xmax=0) # poloidal rotation profile - f1d_vpol = get_exponential_growth(core_args["vpol_lcfs"], core_args["vpol_decay"]) + f1d_vpol = get_exponential_growth(core_args["vpol_lcfs"], core_args["vpol_decay"]) # velocity normal to magnetic surfaces f1d_vnorm = Constant1D(0) @@ -442,7 +421,7 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): profiles["electron"]["f1d_density"] = get_double_parabola(lcfs_values["electron"]["density"], core_args["ne_core"], core_args["ne_convexity"], core_args["ne_concavity"], xmin=1, xmax=0) - profiles["electron"]["f1d_vtor"] = Constant1D(0) + profiles["electron"]["f1d_vtor"] = Constant1D(1.e-10) # avoid zero-length vectors for blending profiles["electron"]["f1d_vpol"] = Constant1D(0) profiles["electron"]["f1d_vnorm"] = Constant1D(0) @@ -461,7 +440,8 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): profiles["composition"]["hydrogen"][0]["f1d_temperature"] = core_args["th0_fraction"] * get_double_parabola(lcfs_values["composition"]["hydrogen"][0]["temperature"], core_args["th_core"], core_args["th_convexity"], core_args["th_concavity"], xmin=1, xmax=0) - profiles["composition"]["hydrogen"][0]["f1d_density"] = get_exponential_growth(lcfs_values["composition"]["hydrogen"][0]["density"], core_args["nh0_decay"]) + profiles["composition"]["hydrogen"][0]["f1d_density"] = get_exponential_growth( + lcfs_values["composition"]["hydrogen"][0]["density"], core_args["nh0_decay"]) profiles["composition"]["hydrogen"][0]["f1d_vtor"] = f1d_vtor profiles["composition"]["hydrogen"][0]["f1d_vpol"] = f1d_vpol profiles["composition"]["hydrogen"][0]["f1d_vnorm"] = f1d_vnorm @@ -471,7 +451,7 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): core_args["timp_core"], core_args["timp_convexity"], core_args["timp_concavity"], xmin=1, xmax=0) profiles["composition"]["carbon"][6]["f1d_density"] = get_double_parabola(lcfs_values["composition"]["carbon"][6]["density"], core_args["nimp_core"], - core_args["nimp_convexity"], core_args["nimp_concavity"], xmin=1, xmax=0) + core_args["nimp_convexity"], core_args["nimp_concavity"], xmin=1, xmax=0) profiles["composition"]["carbon"][6]["f1d_vtor"] = f1d_vtor profiles["composition"]["carbon"][6]["f1d_vpol"] = f1d_vpol profiles["composition"]["carbon"][6]["f1d_vnorm"] = f1d_vnorm @@ -481,7 +461,8 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): profiles["composition"]["carbon"][chrg]["f1d_temperature"] = get_double_parabola(lcfs_values["composition"]["carbon"][chrg]["temperature"], core_args["timp_core"], core_args["timp_convexity"], core_args["timp_concavity"], xmin=1, xmax=0) - profiles["composition"]["carbon"][chrg]["f1d_density"] = get_exponential_growth(lcfs_values["composition"]["carbon"][chrg]["density"], core_args["nimp_decay"]) + profiles["composition"]["carbon"][chrg]["f1d_density"] = get_exponential_growth( + lcfs_values["composition"]["carbon"][chrg]["density"], core_args["nimp_decay"]) profiles["composition"]["carbon"][chrg]["f1d_vtor"] = f1d_vtor profiles["composition"]["carbon"][chrg]["f1d_vpol"] = f1d_vpol profiles["composition"]["carbon"][chrg]["f1d_vnorm"] = f1d_vnorm @@ -493,8 +474,8 @@ def get_core_distributions(profiles=None, equilibrium=None): """ Returns a dictionary of core plasma species Maxwellian distributions. - :param profiles: Dictionary of core particle profiles. The dictionary has to have the same form - as the one returned by the function get_core_profiles_description. + :param profiles: Dictionary of core particle profiles. The dictionary has to have the same form + as the one returned by the function get_core_profiles_description. The default value is the value returned by the call get_core_profiles_description(). :param equilibrium: an instance of EFITEquilibrium. :return: dictionary of core plasma species with Maxwellian distribution @@ -510,23 +491,20 @@ def get_core_distributions(profiles=None, equilibrium=None): # build a dictionary with Maxwellian distributions species = RecursiveDict() species["electron"] = get_maxwellian_distribution(equilibrium, rest_mass=electron_mass, - **profiles["electron"]) + **profiles["electron"]) for name, spec in profiles["composition"].items(): spec_cherab = _get_cherab_element(name) for chrg, desc in spec.items(): rest_mass = atomic_mass * spec_cherab.atomic_weight - species["composition"][name][chrg] = get_maxwellian_distribution(equilibrium, rest_mass=rest_mass, **desc) + species["composition"][name][chrg] = get_maxwellian_distribution(equilibrium, rest_mass=rest_mass, **desc) return species.freeze() -def get_core_plasma(distributions=None, atomic_data=None, parent=None, name="Generomak core plasma"): +def get_core_plasma(atomic_data=None, parent=None, name="Generomak core plasma"): """ - Provides Generomak core plasma. + Provides Generomak default core plasma. - :param distributions: A dictionary of plasma distributions. Has to have the same format as the - dictionary returned by get_core_distributions. The default value - is the value returned by the call get_core_distributions(). :param atomic_data: Instance of AtomicData, default is OpenADAS() :param parent: parent of the plasma node, defaults None :param name: name of the plasma node, defaults "Generomak edge plasma" @@ -536,33 +514,119 @@ def get_core_plasma(distributions=None, atomic_data=None, parent=None, name="Gen # load Generomak equilibrium equilibrium = load_equilibrium() + # load core distributions + distributions = get_core_distributions(equilibrium=equilibrium) + + return get_plasma(equilibrium=equilibrium, distributions=distributions, + atomic_data=atomic_data, parent=parent, name=name) + + +def get_full_profiles(equilibrium=None, core_profiles=None, edge_profiles=None, mask=None): + """ + Blends core and edge profiles using the mask function as a modulator. + + :param equilibrium: an instance of EFITEquilibrium. The default value is the value returned by + load_equilibrium(). + :param core_profiles: Dictionary of core particle profiles. The dictionary has to have + the same form as the one returned by the function + get_core_profiles_description. + The default value is the value returned by the call + get_core_profiles_description(). + :param edge_profiles: Dictionary with edge interpolators in the shape + returned by the get_edge_interpolators function. + If not specified, will use the value returned by + get_edge_interpolators(). + :param Function2D mask: Scalar 2D function returning a value in the range [0, 1]. + If not specified, will use core profiles for psi_normal < 0.94, + the edge profiles for psi_normal > 1 and a weighted sum of core and + edge profiles for 0.94 < psi_normal < 1, with the edge profile weight + increasing from 0 to 1 linearly. + + :return: dictionary of blended plasma profiles with the sturcture identical to edge_profiles. + """ + + equilibrium = equilibrium or load_equilibrium() + + core_profiles = core_profiles or get_core_profiles_description() + + edge_profiles = edge_profiles or get_edge_interpolators() + + mask = mask or equilibrium.map2d(Interpolator1DArray([0, 0.94, 1.0, 1.1], [1, 1, 0, 0], 'linear', 'none', 0)) + + # blended core and edge profiles + blended_profiles = RecursiveDict() + + # map core profiles to 2D using the equilibrium + te_core = equilibrium.map2d(core_profiles["electron"]["f1d_temperature"]) + ne_core = equilibrium.map2d(core_profiles["electron"]["f1d_density"]) + ve_core = equilibrium.map_vector2d(core_profiles["electron"]["f1d_vtor"], + core_profiles["electron"]["f1d_vpol"], + core_profiles["electron"]["f1d_vnorm"]) + + blended_profiles["electron"]["temperature"] = Blend2D(edge_profiles["electron"]["temperature"], te_core, mask) + blended_profiles["electron"]["density"] = Blend2D(edge_profiles["electron"]["density"], ne_core, mask) + blended_profiles["electron"]["velocity"] = BlendVector2D(edge_profiles["electron"]["velocity"], ve_core, mask) + + for element, states in core_profiles["composition"].items(): + for charge, state in states.items(): + t_core = equilibrium.map2d(state["f1d_temperature"]) + n_core = equilibrium.map2d(state["f1d_density"]) + v_core = equilibrium.map_vector2d(state["f1d_vtor"], state["f1d_vpol"], state["f1d_vnorm"]) + + edge_state = edge_profiles["composition"][element][charge] + + blended_profiles["composition"][element][charge]["temperature"] = Blend2D(edge_state["temperature"], t_core, mask) + blended_profiles["composition"][element][charge]["density"] = Blend2D(edge_state["density"], n_core, mask) + blended_profiles["composition"][element][charge]["velocity"] = BlendVector2D(edge_state["velocity"], v_core, mask) + + return blended_profiles.freeze() + + +def get_plasma(equilibrium=None, distributions=None, r_range=None, z_range=None, atomic_data=None, parent=None, name="Generomak plasma"): + """ + Provides Generomak plasma. The full (core + edge) plasma is returned by default. + + :param equilibrium: an instance of EFITEquilibrium. The default value is the value returned by load_equilibrium(). + :param distributions: A dictionary of plasma distributions. Has to have the same format as the + dictionary returned by get_core_distributions or get_2d_distributions. + The default value is the value returned by the call: + get_2d_distributions(get_full_profiles(equilibrium)). + :param r_range: Plasma domain range (min, max) in R direction in meters. + :param z_range: Plasma domain range (min, max) in Z direction in meters. + :param atomic_data: Instance of AtomicData, default is OpenADAS() + :param parent: parent of the plasma node, defaults None + :param name: name of the plasma node, defaults "Generomak plasma" + :return: populated Plasma object + """ + + equilibrium = equilibrium or load_equilibrium() + + distributions = distributions or get_2d_distributions(get_full_profiles(equilibrium=equilibrium)) + + r_range = r_range or equilibrium.r_range + z_range = z_range or equilibrium.z_range + # create or check atomic_data if atomic_data is not None: if not isinstance(atomic_data, AtomicData): - raise ValueError("atomic_data has to be of type AtomicData") + raise ValueError("atomic_data has to be of type AtomicData") else: atomic_data = OpenADAS() - # construct plasma primitive shape - padding = 1e-3 #enlarge for safety - plasma_height = equilibrium.z_range[1] - equilibrium.z_range[0] - outer_column = Cylinder(radius=equilibrium.r_range[1], height=plasma_height) - inner_column = Cylinder(radius=equilibrium.r_range[0], height=plasma_height + 2 * padding) + # construct plasma primitive shape + padding = 1e-3 # enlarge for safety + plasma_height = z_range[1] - z_range[0] + outer_column = Cylinder(radius=r_range[1], height=plasma_height) + inner_column = Cylinder(radius=r_range[0], height=plasma_height + 2 * padding) inner_column.transform = translate(0, 0, -padding) plasma_geometry = Subtract(outer_column, inner_column) # coordinate transform of the plasma frame - geometry_transform = translate(0, 0, equilibrium.z_range[0]) - - # load core distributions if needed - if distributions is None: - dists = get_core_distributions() - else: - dists = distributions + geometry_transform = translate(0, 0, z_range[0]) # create plasma composition list plasma_composition = [] - for elem_name, elem_data in dists["composition"].items(): + for elem_name, elem_data in distributions["composition"].items(): for stage, stage_data in elem_data.items(): elem = _get_cherab_element(elem_name) species = Species(elem, stage, stage_data) @@ -573,7 +637,7 @@ def get_core_plasma(distributions=None, atomic_data=None, parent=None, name="Gen plasma.name = name plasma.geometry = plasma_geometry plasma.atomic_data = atomic_data - plasma.electron_distribution = dists["electron"] + plasma.electron_distribution = distributions["electron"] plasma.composition = plasma_composition plasma.geometry_transform = geometry_transform plasma.b_field = VectorAxisymmetricMapper(equilibrium.b_field) diff --git a/demos/generomak/plasma/plot_2d_plasma.py b/demos/generomak/plasma/plot_2d_plasma.py new file mode 100755 index 00000000..5fd0f729 --- /dev/null +++ b/demos/generomak/plasma/plot_2d_plasma.py @@ -0,0 +1,128 @@ + +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import numpy as np +from matplotlib.colors import SymLogNorm +from matplotlib import pyplot as plt + +from cherab.core.math import sample3d +from cherab.core.atomic.elements import hydrogen, carbon + +from cherab.generomak.plasma.plasma import get_core_plasma, get_edge_plasma, get_plasma + +""" +This demo does the same plots as the plot_2d_profiles.py demo, but sampling the profiles from the Plasma objects. +""" + + +def plot_profiles(core_profile, edge_profile, full_profile, r_range, z_range, label): + + # Sample core profile on a regular grid + _, _, _, core_profile_samples = sample3d(core_profile, r_range, (0, 0, 1), z_range) + core_profile_samples = core_profile_samples.squeeze() + + # Sample edge profile on a regular grid + _, _, _, edge_profile_samples = sample3d(edge_profile, r_range, (0, 0, 1), z_range) + edge_profile_samples = edge_profile_samples.squeeze() + + # Sample blended profile on a regular grid + _, _, _, full_profile_samples = sample3d(full_profile, r_range, (0, 0, 1), z_range) + full_profile_samples = full_profile_samples.squeeze() + + fig = plt.figure(figsize=(9.5, 5.), tight_layout=True) + + vmax = full_profile_samples.max() + linthresh = 0.01 * min(core_profile_samples.max(), edge_profile_samples.max()) + color_norm = SymLogNorm(linthresh, vmin=0, vmax=vmax) + + core_profile_samples[core_profile_samples == 0] = np.nan + edge_profile_samples[edge_profile_samples == 0] = np.nan + full_profile_samples[full_profile_samples == 0] = np.nan + + ax_core = fig.add_subplot(131) + ax_core.imshow(core_profile_samples.T, extent=[r_range[0], r_range[1], z_range[0], z_range[1]], origin='lower', norm=color_norm, cmap='gnuplot') + ax_core.text(0.99, 0.99, 'Core', ha='right', va='top', transform=ax_core.transAxes) + ax_core.set_xlim(r_range[0], r_range[1]) + ax_core.set_ylim(z_range[0], z_range[1]) + ax_core.set_xlabel('R, m') + ax_core.set_ylabel('Z, m') + + ax_edge = fig.add_subplot(132, sharex=ax_core, sharey=ax_core) + img = ax_edge.imshow(edge_profile_samples.T, extent=[r_range[0], r_range[1], z_range[0], z_range[1]], origin='lower', norm=color_norm, cmap='gnuplot') + ax_edge.text(0.99, 0.99, 'Edge', ha='right', va='top', transform=ax_edge.transAxes) + ax_edge.set_xlabel('R, m') + + ax_blend = fig.add_subplot(133, sharex=ax_core, sharey=ax_core) + img = ax_blend.imshow(full_profile_samples.T, extent=[r_range[0], r_range[1], z_range[0], z_range[1]], origin='lower', norm=color_norm, cmap='gnuplot') + ax_blend.text(0.99, 0.99, 'Blended', ha='right', va='top', transform=ax_blend.transAxes) + ax_blend.set_xlabel('R, m') + + fig.colorbar(img, label=label) + + return fig + + +# get Generomak core plasma +core_plasma = get_core_plasma() + +# get Generomak edge plasma +edge_plasma = get_edge_plasma() + +# get Generomak full plasma (blended core and edge profiles) +full_plasma = get_plasma() + +# plasma domain +r_range = (0.78, 2.23, 290) +z_range = (-1.74, 1.49, 647) + +# Plotting plasma profiles +plot_profiles(core_plasma.electron_distribution.density, + edge_plasma.electron_distribution.density, + full_plasma.electron_distribution.density, + r_range, z_range, 'Electron density, m-3') + +plot_profiles(core_plasma.electron_distribution.effective_temperature, + edge_plasma.electron_distribution.effective_temperature, + full_plasma.electron_distribution.effective_temperature, + r_range, z_range, 'Electron temperature, eV') + +plot_profiles(core_plasma.composition.get(hydrogen, 1).distribution.effective_temperature, + edge_plasma.composition.get(hydrogen, 1).distribution.effective_temperature, + full_plasma.composition.get(hydrogen, 1).distribution.effective_temperature, + r_range, z_range, 'Ion temperature, eV') + +for element, charges in ((hydrogen, (0, 1)), (carbon, (0, 1, 2, 3, 4, 5, 6))): + for charge in charges: + state_str = ' {}+'.format(charge) if charge else ' 0' + plot_profiles(core_plasma.composition.get(element, charge).distribution.density, + edge_plasma.composition.get(element, charge).distribution.density, + full_plasma.composition.get(element, charge).distribution.density, + r_range, z_range, '{} density, m-3'.format(element.name + state_str)) + +plot_profiles(core_plasma.composition.get(hydrogen, 0).distribution.effective_temperature, + edge_plasma.composition.get(hydrogen, 0).distribution.effective_temperature, + full_plasma.composition.get(hydrogen, 0).distribution.effective_temperature, + r_range, z_range, 'neutral hydrogen effective temperature, eV') + +plot_profiles(core_plasma.composition.get(carbon, 0).distribution.effective_temperature, + edge_plasma.composition.get(carbon, 0).distribution.effective_temperature, + full_plasma.composition.get(carbon, 0).distribution.effective_temperature, + r_range, z_range, 'neutral carbon effective temperature, eV') + +plt.show() diff --git a/demos/generomak/plasma/plot_2d_profiles.py b/demos/generomak/plasma/plot_2d_profiles.py new file mode 100755 index 00000000..22a28c48 --- /dev/null +++ b/demos/generomak/plasma/plot_2d_profiles.py @@ -0,0 +1,144 @@ + +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import numpy as np +from matplotlib.colors import SymLogNorm +from matplotlib.collections import PolyCollection +from matplotlib import pyplot as plt + +from cherab.core.math import sample2d +from cherab.core.utility import RecursiveDict + +from cherab.generomak.equilibrium import load_equilibrium +from cherab.generomak.plasma.plasma import get_core_profiles_description, load_edge_profiles, get_full_profiles + +""" +This demo plots core, edge and blended Generomak 2D plasma profiles. +""" + + +def plot_profiles(core_profile, edge_mesh, edge_data, full_profile, label): + + # get grid parameters + vertex_coords = np.asarray(edge_mesh["vertex_coords"]) + triangles = np.asarray(edge_mesh["triangles"]) + rl, ru = (vertex_coords[:, 0].min(), vertex_coords[:, 0].max()) + zl, zu = (vertex_coords[:, 1].min(), vertex_coords[:, 1].max()) + nr = 288 + nz = 647 + + edge_data = np.asarray(edge_data) + + # Sample core profile on a regular grid + _, _, core_profile_samples = sample2d(core_profile, (rl, ru, nr), (zl, zu, nz)) + + # Sample blended profile on a regular grid + _, _, profile_samples = sample2d(full_profile, (rl, ru, nr), (zl, zu, nz)) + + fig = plt.figure(figsize=(9.5, 5.), tight_layout=True) + + vmax = profile_samples.max() + linthresh = 0.01 * min(core_profile_samples.max(), edge_data.max()) + color_norm = SymLogNorm(linthresh, vmin=0, vmax=vmax) + + core_profile_samples[core_profile_samples == 0] = np.nan + profile_samples[profile_samples == 0] = np.nan + + ax_core = fig.add_subplot(131) + ax_core.imshow(core_profile_samples.T, extent=[rl, ru, zl, zu], origin='lower', norm=color_norm, cmap='gnuplot') + ax_core.text(0.99, 0.99, 'Core', ha='right', va='top', transform=ax_core.transAxes) + ax_core.set_xlim(rl, ru) + ax_core.set_ylim(zl, zu) + ax_core.set_xlabel('R, m') + ax_core.set_ylabel('Z, m') + + ax_edge = fig.add_subplot(132, sharex=ax_core, sharey=ax_core) + collection = PolyCollection(vertex_coords[triangles], norm=color_norm, cmap='gnuplot') + collection.set_array(edge_data) + ax_edge.add_collection(collection) + ax_edge.text(0.99, 0.99, 'Edge', ha='right', va='top', transform=ax_edge.transAxes) + ax_edge.set_aspect(1) + ax_edge.set_xlabel('R, m') + + ax_blend = fig.add_subplot(133, sharex=ax_core, sharey=ax_core) + img = ax_blend.imshow(profile_samples.T, extent=[rl, ru, zl, zu], origin='lower', norm=color_norm, cmap='gnuplot') + ax_blend.text(0.99, 0.99, 'Blended', ha='right', va='top', transform=ax_blend.transAxes) + ax_blend.set_xlabel('R, m') + + fig.colorbar(img, label=label) + + return fig + + +# load Generomak equilibrium +equilibrium = load_equilibrium() + +# load 1D core profiles, f(psi_norm) +core_profiles_1d = get_core_profiles_description() + +# load 2D edge profiles defined on a quadrilateral mesh +edge_data = load_edge_profiles() + +# load 2D plasma profiles covering both core and edge regions +# see the source code for the get_full_profiles() to learn how to blend core and edge profiles using a mask function +full_profiles = get_full_profiles(equilibrium, core_profiles_1d) + +# map core profiles to 2D using the equilibrium +core_profiles_2d = RecursiveDict() + +core_profiles_2d["electron"]["temperature"] = equilibrium.map2d(core_profiles_1d["electron"]["f1d_temperature"]) +core_profiles_2d["electron"]["density"] = equilibrium.map2d(core_profiles_1d["electron"]["f1d_density"]) + +for element, states in core_profiles_1d["composition"].items(): + for charge, state in states.items(): + core_profiles_2d["composition"][element][charge]["density"] = equilibrium.map2d(state["f1d_density"]) + core_profiles_2d["composition"][element][charge]["temperature"] = equilibrium.map2d(state["f1d_temperature"]) + +core_profiles_2d = core_profiles_2d.freeze() + +# Plotting plasma profiles +plot_profiles(core_profiles_2d["electron"]["density"], edge_data["mesh"], + edge_data["electron"]["density"], full_profiles["electron"]["density"], + 'Electron density, m-3') + +plot_profiles(core_profiles_2d["electron"]["temperature"], edge_data["mesh"], + edge_data["electron"]["temperature"], full_profiles["electron"]["temperature"], + 'Electron temperature, eV') + +plot_profiles(core_profiles_2d["composition"]["hydrogen"][1]["temperature"], edge_data["mesh"], + edge_data["composition"]["hydrogen"][1]["temperature"], + full_profiles["composition"]["hydrogen"][1]["temperature"], 'Ion temperature, eV') + +for element, states in core_profiles_2d["composition"].items(): + for charge, state in states.items(): + state_str = ' {}+'.format(charge) if charge else ' 0' + plot_profiles(state["density"], edge_data["mesh"], + edge_data["composition"][element][charge]["density"], + full_profiles["composition"][element][charge]["density"], + '{} density, m-3'.format(element + state_str)) + +plot_profiles(core_profiles_2d["composition"]["hydrogen"][0]["temperature"], edge_data["mesh"], + edge_data["composition"]["hydrogen"][0]["temperature"], + full_profiles["composition"]["hydrogen"][0]["temperature"], 'neutral hydrogen effective temperature, eV') + +plot_profiles(core_profiles_2d["composition"]["carbon"][0]["temperature"], edge_data["mesh"], + edge_data["composition"]["carbon"][0]["temperature"], + full_profiles["composition"]["carbon"][0]["temperature"], 'neutral carbon effective temperature, eV') + +plt.show() From e9a272f8f4e33aae728871021ebdfc0ead9ad1a6 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 4 Aug 2022 16:54:48 +0300 Subject: [PATCH 21/81] Correct Generomak plasma demo descriptions. --- demos/generomak/plasma/plot_2d_plasma.py | 8 ++++---- demos/generomak/plasma/plot_2d_profiles.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/demos/generomak/plasma/plot_2d_plasma.py b/demos/generomak/plasma/plot_2d_plasma.py index 5fd0f729..24750242 100755 --- a/demos/generomak/plasma/plot_2d_plasma.py +++ b/demos/generomak/plasma/plot_2d_plasma.py @@ -17,6 +17,10 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. +""" +This demo does the same plots as the plot_2d_profiles.py demo, but samples the profiles from the Plasma objects. +""" + import numpy as np from matplotlib.colors import SymLogNorm from matplotlib import pyplot as plt @@ -26,10 +30,6 @@ from cherab.generomak.plasma.plasma import get_core_plasma, get_edge_plasma, get_plasma -""" -This demo does the same plots as the plot_2d_profiles.py demo, but sampling the profiles from the Plasma objects. -""" - def plot_profiles(core_profile, edge_profile, full_profile, r_range, z_range, label): diff --git a/demos/generomak/plasma/plot_2d_profiles.py b/demos/generomak/plasma/plot_2d_profiles.py index 22a28c48..34daa025 100755 --- a/demos/generomak/plasma/plot_2d_profiles.py +++ b/demos/generomak/plasma/plot_2d_profiles.py @@ -17,6 +17,10 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. +""" +This demo plots core, edge and blended Generomak 2D plasma profiles. +""" + import numpy as np from matplotlib.colors import SymLogNorm from matplotlib.collections import PolyCollection @@ -28,10 +32,6 @@ from cherab.generomak.equilibrium import load_equilibrium from cherab.generomak.plasma.plasma import get_core_profiles_description, load_edge_profiles, get_full_profiles -""" -This demo plots core, edge and blended Generomak 2D plasma profiles. -""" - def plot_profiles(core_profile, edge_mesh, edge_data, full_profile, label): From 1f945c1faaa265b1d8494d1ba6f1915a21550f67 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 18 Aug 2022 18:30:24 +0300 Subject: [PATCH 22/81] Fix the docstring for the Bremsstrahlung model (#375). --- cherab/core/model/plasma/bremsstrahlung.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index ba4b9cf6..2ba7245b 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -42,7 +42,7 @@ cdef class Bremsstrahlung(PlasmaModel): et. al., 'ITER LIDAR performance analysis', Rev. Sci. Instrum. 79, 10E727 (2008), .. math:: - \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} \\sum_{i} \\left(g_{ff}(Z_i, T_e, \\lambda) n_i Z_i^2\\right) n_e T_e^{1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, + \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} \\sum_{i} \\left(g_{ff}(Z_i, T_e, \\lambda) n_i Z_i^2\\right) n_e T_e^{-1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, where the emission :math:`\\epsilon (\\lambda)` is in units of radiance (ph/s/sr/m^3/nm). From b202dbb2ac2762c0f9259044e98dab8b5b1b7754 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 30 Aug 2022 20:35:12 +0300 Subject: [PATCH 23/81] Add Gaussian quadrature integrator and tests. --- cherab/core/math/integrators/__init__.pxd | 20 ++ cherab/core/math/integrators/__init__.py | 19 ++ .../core/math/integrators/integrators1d.pxd | 36 ++++ .../core/math/integrators/integrators1d.pyx | 199 ++++++++++++++++++ cherab/core/math/tests/test_integrators.py | 78 +++++++ 5 files changed, 352 insertions(+) create mode 100644 cherab/core/math/integrators/__init__.pxd create mode 100644 cherab/core/math/integrators/__init__.py create mode 100644 cherab/core/math/integrators/integrators1d.pxd create mode 100644 cherab/core/math/integrators/integrators1d.pyx create mode 100644 cherab/core/math/tests/test_integrators.py diff --git a/cherab/core/math/integrators/__init__.pxd b/cherab/core/math/integrators/__init__.pxd new file mode 100644 index 00000000..db06ef43 --- /dev/null +++ b/cherab/core/math/integrators/__init__.pxd @@ -0,0 +1,20 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from cherab.core.math.integrators.integrators1d cimport Integrator1D, GaussianQuadrature + diff --git a/cherab/core/math/integrators/__init__.py b/cherab/core/math/integrators/__init__.py new file mode 100644 index 00000000..86b7d58d --- /dev/null +++ b/cherab/core/math/integrators/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from .integrators1d import Integrator1D, GaussianQuadrature diff --git a/cherab/core/math/integrators/integrators1d.pxd b/cherab/core/math/integrators/integrators1d.pxd new file mode 100644 index 00000000..56ec342b --- /dev/null +++ b/cherab/core/math/integrators/integrators1d.pxd @@ -0,0 +1,36 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from numpy cimport ndarray +from raysect.core.math.function.float cimport Function1D + + +cdef class Integrator1D: + + cpdef (double, double) integrate(self, Function1D func, double a, double b) + + +cdef class GaussianQuadrature(Integrator1D): + + cdef: + int _min_order, _max_order + double _rtol + ndarray _roots, _weights + double[:] _roots_mv, _weights_mv + + cdef _build_cash(self) diff --git a/cherab/core/math/integrators/integrators1d.pyx b/cherab/core/math/integrators/integrators1d.pyx new file mode 100644 index 00000000..177be590 --- /dev/null +++ b/cherab/core/math/integrators/integrators1d.pyx @@ -0,0 +1,199 @@ +# cython: language_level=3 + +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import numpy as np +from scipy.special import roots_legendre + +from libc.math cimport INFINITY +cimport cython + + +cdef class Integrator1D: + """ + Compute a definite integral of a one-dimensional function. + """ + + cpdef (double, double) integrate(self, Function1D func, double a, double b): + """ + Integrates a one-dimensional function over the given interval. + + :param Function1D func: A function to integrate. + :param double a: Lower limit of integration. + :param double b: Upper limit of integration. + + :returns: Two-element tuple containing the integral of func from a to b + and an estimate of the absolute error in the result. + """ + + raise NotImplementedError("The integrate() virtual method must be implemented.") + + +cdef class GaussianQuadrature(Integrator1D): + """ + Compute an integral of a one-dimensional function over a finite interval + using fixed-tolerance Gaussian quadrature. + (see Scipy `quadrature `). + + :param double relative_tolerance: Iteration stops when relative error between + last two iterates is less than this value. Default is 1.e-7. + :param int max_order: Maximum order on Gaussian quadrature. Default is 50. + :param int min_order: Minimum order on Gaussian quadrature. Default is 1. + + :ivar double relative_tolerance: Iteration stops when relative error between + last two iterates is less than this value. + :ivar int max_order: Maximum order on Gaussian quadrature. + :ivar int min_order: Minimum order on Gaussian quadrature. + """ + + def __init__(self, double relative_tolerance=1.e-7, int max_order=50, int min_order=1): + + if min_order < 1 or max_order < 1: + raise ValueError("Order of Gaussian quadrature must be >= 1.") + + if min_order >= max_order: + raise ValueError("Minimum order of Gaussian quadrature must be less than the maximum order.") + + self._min_order = min_order + self._max_order = max_order + self._build_cash() + + self.relative_tolerance = relative_tolerance + + @property + def min_order(self): + """ + Minimum order on Gaussian quadrature. + + :rtype: int + """ + return self._min_order + + @min_order.setter + def min_order(self, int value): + + if value < 1: + raise ValueError("Order of Gaussian quadrature must be >= 1.") + + if value > self._max_order: + raise ValueError("Minimum order of Gaussian quadrature must be less than or equal to the maximum order.") + + self._min_order = value + + self._build_cash() + + @property + def max_order(self): + """ + Maximum order on Gaussian quadrature. + + :rtype: float + """ + return self._max_order + + @max_order.setter + def max_order(self, int value): + + if value < 1: + raise ValueError("Order of Gaussian quadrature must be >= 1.") + + if value < self._min_order: + raise ValueError("Maximum order of Gaussian quadrature must be greater than or equal to the minimum order.") + + self._max_order = value + + self._build_cash() + + @property + def relative_tolerance(self): + """ + Iteration stops when relative error between last two iterates is less than this value. + + :rtype: double + """ + return self._rtol + + @relative_tolerance.setter + def relative_tolerance(self, double value): + + if value <= 0: + raise ValueError("Relative tolerance must be positive.") + + self._rtol = value + + cdef _build_cash(self): + """ + Caches the roots and weights of the Gauss-Legendre quadrature. + """ + + cdef: + int order, n, i + + n = (self._max_order + self._min_order) * (self._max_order - self._min_order + 1) // 2 + + self._roots = np.zeros(n, dtype=np.float64) + self._weights = np.zeros(n, dtype=np.float64) + + i = 0 + for order in range(self._min_order, self._max_order + 1): + self._roots[i:i + order], self._weights[i:i + order] = roots_legendre(order) + i += order + + self._roots_mv = self._roots + self._weights_mv = self._weights + + @cython.boundscheck(False) + @cython.wraparound(False) + @cython.cdivision(True) + @cython.initializedcheck(False) + cpdef (double, double) integrate(self, Function1D func, double a, double b): + """ + Integrates a one-dimensional function over a finite interval. + + :param Function1D func: A function to integrate. + :param double a: Lower limit of integration. + :param double b: Upper limit of integration. + + :returns: Two-element tuple containing Gaussian quadrature approximation to integral + and difference between last two estimates of the integral. + """ + + cdef: + int order, i, ibegin + double newval, oldval, error, x + + oldval = INFINITY + ibegin = 0 + + for order in range(self._min_order, self._max_order): + newval = 0 + for i in range(ibegin, ibegin + order): + x = a + 0.5 * (b - a) * (self._roots_mv[i] + 1.) + newval += self._weights_mv[i] * func.evaluate(x) + newval *= 0.5 * (b - a) + + error = abs(newval - oldval) + oldval = newval + + ibegin += order + + if error < self._rtol * abs(newval): + break + + return newval, error diff --git a/cherab/core/math/tests/test_integrators.py b/cherab/core/math/tests/test_integrators.py new file mode 100644 index 00000000..4e563cb6 --- /dev/null +++ b/cherab/core/math/tests/test_integrators.py @@ -0,0 +1,78 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from raysect.core.math.function.float import Exp1D, Arg1D +from cherab.core.math.integrators import GaussianQuadrature +from math import sqrt, pi +from scipy.special import erf +import unittest + + +class TestGaussianQuadrature(unittest.TestCase): + """Gaussian quadrature integrator tests.""" + + def test_properties(self): + """Test property assignment.""" + min_order = 3 + max_order = 30 + reltol = 1.e-6 + quadrature = GaussianQuadrature(relative_tolerance=reltol, max_order=max_order, min_order=min_order) + + self.assertEqual(quadrature.relative_tolerance, reltol) + self.assertEqual(quadrature.max_order, max_order) + self.assertEqual(quadrature.min_order, min_order) + + min_order = 0 + max_order = 2 # < min_order + reltol = -1 + + with self.assertRaises(ValueError): + quadrature.max_order = max_order + + with self.assertRaises(ValueError): + quadrature.min_order = min_order + + with self.assertRaises(ValueError): + quadrature.relative_tolerance = reltol + + min_order = 1 + max_order = 20 + reltol = 1.e-5 + + quadrature.relative_tolerance = reltol + quadrature.min_order = min_order + quadrature.max_order = max_order + + self.assertEqual(quadrature.relative_tolerance, reltol) + self.assertEqual(quadrature.min_order, min_order) + self.assertEqual(quadrature.max_order, max_order) + + def test_integrate(self): + """Test integration.""" + func = (2 / sqrt(pi)) * Exp1D(- Arg1D() * Arg1D()) + quadrature = GaussianQuadrature() + a = -0.5 + b = 3. + result, error = quadrature.integrate(func, a, b) + exact_integral = erf(b) - erf(a) + + self.assertAlmostEqual(result, exact_integral, places=7) + + +if __name__ == '__main__': + unittest.main() From a32a6a716ae4a8ce8b46103163c0c8b793cf9fa2 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 31 Aug 2022 19:11:34 +0300 Subject: [PATCH 24/81] Fix an error in GaussianQuadrature. Increase default relative tolerance value. --- cherab/core/math/integrators/integrators1d.pyx | 10 +++++----- cherab/core/math/tests/test_integrators.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cherab/core/math/integrators/integrators1d.pyx b/cherab/core/math/integrators/integrators1d.pyx index 177be590..7f9ce421 100644 --- a/cherab/core/math/integrators/integrators1d.pyx +++ b/cherab/core/math/integrators/integrators1d.pyx @@ -52,7 +52,7 @@ cdef class GaussianQuadrature(Integrator1D): (see Scipy `quadrature `). :param double relative_tolerance: Iteration stops when relative error between - last two iterates is less than this value. Default is 1.e-7. + last two iterates is less than this value. Default is 1.e-5. :param int max_order: Maximum order on Gaussian quadrature. Default is 50. :param int min_order: Minimum order on Gaussian quadrature. Default is 1. @@ -62,13 +62,13 @@ cdef class GaussianQuadrature(Integrator1D): :ivar int min_order: Minimum order on Gaussian quadrature. """ - def __init__(self, double relative_tolerance=1.e-7, int max_order=50, int min_order=1): + def __init__(self, double relative_tolerance=1.e-5, int max_order=50, int min_order=1): if min_order < 1 or max_order < 1: raise ValueError("Order of Gaussian quadrature must be >= 1.") - if min_order >= max_order: - raise ValueError("Minimum order of Gaussian quadrature must be less than the maximum order.") + if min_order > max_order: + raise ValueError("Minimum order of Gaussian quadrature must be less than or equal to the maximum order.") self._min_order = min_order self._max_order = max_order @@ -181,7 +181,7 @@ cdef class GaussianQuadrature(Integrator1D): oldval = INFINITY ibegin = 0 - for order in range(self._min_order, self._max_order): + for order in range(self._min_order, self._max_order + 1): newval = 0 for i in range(ibegin, ibegin + order): x = a + 0.5 * (b - a) * (self._roots_mv[i] + 1.) diff --git a/cherab/core/math/tests/test_integrators.py b/cherab/core/math/tests/test_integrators.py index 4e563cb6..a60a4eea 100644 --- a/cherab/core/math/tests/test_integrators.py +++ b/cherab/core/math/tests/test_integrators.py @@ -65,13 +65,13 @@ def test_properties(self): def test_integrate(self): """Test integration.""" func = (2 / sqrt(pi)) * Exp1D(- Arg1D() * Arg1D()) - quadrature = GaussianQuadrature() + quadrature = GaussianQuadrature(relative_tolerance=1.e-8) a = -0.5 b = 3. result, error = quadrature.integrate(func, a, b) exact_integral = erf(b) - erf(a) - self.assertAlmostEqual(result, exact_integral, places=7) + self.assertAlmostEqual(result, exact_integral, places=8) if __name__ == '__main__': From c4a604d5133ea302a33bd61253aa3af781029c7a Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 31 Aug 2022 19:13:34 +0300 Subject: [PATCH 25/81] Add NumericallyIntegrableLineShapeModel class. Update StarkBroadenedLine to use numerical integration over the spectral bin. --- cherab/core/model/lineshape.pxd | 8 +++- cherab/core/model/lineshape.pyx | 65 ++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/cherab/core/model/lineshape.pxd b/cherab/core/model/lineshape.pxd index 711475b5..050d589e 100644 --- a/cherab/core/model/lineshape.pxd +++ b/cherab/core/model/lineshape.pxd @@ -24,6 +24,7 @@ cimport numpy as np from raysect.optical cimport Spectrum, Point3D, Vector3D from cherab.core cimport Line, Species, Plasma, Beam from cherab.core.math cimport Function1D, Function2D +from cherab.core.math.integrators cimport Integrator1D from cherab.core.atomic.zeeman cimport ZeemanStructure @@ -45,6 +46,11 @@ cdef class LineShapeModel: cpdef Spectrum add_line(self, double radiance, Point3D point, Vector3D direction, Spectrum spectrum) +cdef class NumericallyIntegrableLineShapeModel(LineShapeModel): + + cdef Integrator1D integrator + + cdef class GaussianLine(LineShapeModel): pass @@ -57,7 +63,7 @@ cdef class MultipletLineShape(LineShapeModel): double[:,::1] _multiplet_mv -cdef class StarkBroadenedLine(LineShapeModel): +cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): cdef double _aij, _bij, _cij diff --git a/cherab/core/model/lineshape.pyx b/cherab/core/model/lineshape.pyx index 5e346175..c0bb9711 100644 --- a/cherab/core/model/lineshape.pyx +++ b/cherab/core/model/lineshape.pyx @@ -22,10 +22,12 @@ import numpy as np cimport numpy as np from libc.math cimport sqrt, erf, M_SQRT2, floor, ceil, fabs from raysect.optical.spectrum cimport new_spectrum +from raysect.core.math.function.float cimport Function1D from cherab.core cimport Plasma from cherab.core.atomic.elements import hydrogen, deuterium, tritium, helium, helium3, beryllium, boron, carbon, nitrogen, oxygen, neon from cherab.core.math.function cimport autowrap_function1d, autowrap_function2d +from cherab.core.math.integrators cimport GaussianQuadrature from cherab.core.utility.constants cimport ATOMIC_MASS, ELEMENTARY_CHARGE, SPEED_OF_LIGHT cimport cython @@ -159,6 +161,24 @@ cdef class LineShapeModel: raise NotImplementedError('Child lineshape class must implement this method.') +cdef class NumericallyIntegrableLineShapeModel(LineShapeModel): + """ + Line shape model to be numerically integrated over the spectral bin. + + :param Line line: The emission line object for this line shape. + :param float wavelength: The rest wavelength for this emission line. + :param Species target_species: The target plasma species that is emitting. + :param Plasma plasma: The emitting plasma object. + :param Integrator1D integrator: Integrator1D instance to integrate the line shape + over the spectral bin. Default is `GaussianQuadrature()`. + """ + + def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, Integrator1D integrator=None): + + super().__init__(line, wavelength, target_species, plasma) + self.integrator = integrator or GaussianQuadrature() + + cdef class GaussianLine(LineShapeModel): """ Produces Gaussian line shape. @@ -289,7 +309,21 @@ cdef class MultipletLineShape(LineShapeModel): return spectrum -cdef class StarkBroadenedLine(LineShapeModel): +cdef class StarkFunction(Function1D): + + cdef double _a, _x0 + + def __init__(self, double wavelength, double lambda_1_2): + self._x0 = wavelength + self._a = (0.5 * lambda_1_2)**2.5 + + @cython.cdivision(True) + cdef double evaluate(self, double x) except? -1e999: + + return 1. / ((fabs(x - self._x0))**2.5 + self._a) + + +cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): """ Parametrised Stark broadened line shape based on the Model Microfield Method (MMM). Contains embedded atomic data in the form of fits to MMM. @@ -352,7 +386,8 @@ cdef class StarkBroadenedLine(LineShapeModel): Line(tritium, 0, (9, 3)): (5.588e-15, 0.7165, 0.033) } - def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, dict stark_model_coefficients=None): + def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, Integrator1D integrator=None, + dict stark_model_coefficients=None): stark_model_coefficients = stark_model_coefficients or self.STARK_MODEL_COEFFICIENTS_DEFAULT @@ -371,7 +406,7 @@ cdef class StarkBroadenedLine(LineShapeModel): except IndexError: raise ValueError('Stark broadening coefficients for {} is not currently available.'.format(line)) - super().__init__(line, wavelength, target_species, plasma) + super().__init__(line, wavelength, target_species, plasma, integrator) def show_supported_transitions(self): """ Prints all supported transitions.""" @@ -384,11 +419,14 @@ cdef class StarkBroadenedLine(LineShapeModel): @cython.cdivision(True) cpdef Spectrum add_line(self, double radiance, Point3D point, Vector3D direction, Spectrum spectrum): - cdef double ne, te, lambda_1_2, lambda_5_2, wvl - cdef double cutoff_lower_wavelength, cutoff_upper_wavelength - cdef double lower_value, lower_wavelength, upper_value, upper_wavelength - cdef int start, end, i - cdef Spectrum raw_lineshape + cdef: + double ne, te, lambda_1_2, lambda_5_2, wvl + double cutoff_lower_wavelength, cutoff_upper_wavelength + double lower_wavelength, upper_wavelength + double bin_integral + int start, end, i + Spectrum raw_lineshape + StarkFunction stark_funcion ne = self.plasma.get_electron_distribution().density(point.x, point.y, point.z) if ne <= 0.0: @@ -400,6 +438,8 @@ cdef class StarkBroadenedLine(LineShapeModel): lambda_1_2 = self._cij * ne**self._aij / (te**self._bij) + stark_funcion = StarkFunction(self.wavelength, lambda_1_2) + # calculate and check end of limits cutoff_lower_wavelength = self.wavelength - LORENZIAN_CUTOFF_GAMMA * lambda_1_2 if spectrum.max_wavelength < cutoff_lower_wavelength: @@ -413,21 +453,18 @@ cdef class StarkBroadenedLine(LineShapeModel): start = max(0, floor((cutoff_lower_wavelength - spectrum.min_wavelength) / spectrum.delta_wavelength)) end = min(spectrum.bins, ceil((cutoff_upper_wavelength - spectrum.min_wavelength) / spectrum.delta_wavelength)) - # TODO - replace with cumulative integrals # add line to spectrum raw_lineshape = spectrum.new_spectrum() lower_wavelength = raw_lineshape.min_wavelength + start * raw_lineshape.delta_wavelength - lower_value = 1 / ((fabs(lower_wavelength - self.wavelength))**2.5 + (0.5 * lambda_1_2)**2.5) - for i in range(start, end): + for i in range(start, end): upper_wavelength = raw_lineshape.min_wavelength + raw_lineshape.delta_wavelength * (i + 1) - upper_value = 1 / ((fabs(upper_wavelength - self.wavelength))**2.5 + (0.5 * lambda_1_2)**2.5) - raw_lineshape.samples_mv[i] += 0.5 * (upper_value + lower_value) + bin_integral, _ = self.integrator.integrate(stark_funcion, lower_wavelength, upper_wavelength) + raw_lineshape.samples_mv[i] += bin_integral lower_wavelength = upper_wavelength - lower_value = upper_value # perform normalisation raw_lineshape.div_scalar(raw_lineshape.total()) From 6308e0fac89ec830697e25c000c6867ceba6edc1 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 31 Aug 2022 19:55:23 +0300 Subject: [PATCH 26/81] Update changelog. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27b5ecac..1dfaac01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ New: * Add verbose parameter to SartOpencl solver (default is False). (#358) * Add Generomak core plasma profiles. (#360) * Add toroidal_mesh_from_polygon for making mesh for not fully-360 degrees axisymmetric elements. (#365) +* Add GaussianQuadrature integration method for Function1D. (#366) +* Add NumericallyIntegrableLineShapeModel for lineshapes that cannot be analytically integrated over a spectral bin. (#366) +* Add a numerical integration of StarkBroadenedLine over the spectral bin. (#366) Bug Fixes: ---------- From 526cc17342a6c7a3b910f138603c492e30adcc10 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Sun, 11 Sep 2022 03:05:02 +0300 Subject: [PATCH 27/81] Make Integrator1D a Function2D instance. --- .../core/math/integrators/integrators1d.pxd | 7 +-- .../core/math/integrators/integrators1d.pyx | 54 ++++++++++++------- cherab/core/math/tests/test_integrators.py | 14 +++-- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/cherab/core/math/integrators/integrators1d.pxd b/cherab/core/math/integrators/integrators1d.pxd index 56ec342b..8109e6d7 100644 --- a/cherab/core/math/integrators/integrators1d.pxd +++ b/cherab/core/math/integrators/integrators1d.pxd @@ -17,12 +17,13 @@ # under the Licence. from numpy cimport ndarray -from raysect.core.math.function.float cimport Function1D +from raysect.core.math.function.float cimport Function1D, Function2D -cdef class Integrator1D: +cdef class Integrator1D(Function2D): - cpdef (double, double) integrate(self, Function1D func, double a, double b) + cdef: + Function1D function cdef class GaussianQuadrature(Integrator1D): diff --git a/cherab/core/math/integrators/integrators1d.pyx b/cherab/core/math/integrators/integrators1d.pyx index 7f9ce421..1e69efd4 100644 --- a/cherab/core/math/integrators/integrators1d.pyx +++ b/cherab/core/math/integrators/integrators1d.pyx @@ -21,28 +21,35 @@ import numpy as np from scipy.special import roots_legendre +from raysect.core.math.function.float cimport autowrap_function1d + from libc.math cimport INFINITY cimport cython -cdef class Integrator1D: +cdef class Integrator1D(Function2D): """ Compute a definite integral of a one-dimensional function. + + :ivar Function1D integrand: A 1D function to integrate. """ - cpdef (double, double) integrate(self, Function1D func, double a, double b): + @property + def integrand(self): """ - Integrates a one-dimensional function over the given interval. - - :param Function1D func: A function to integrate. - :param double a: Lower limit of integration. - :param double b: Upper limit of integration. + A 1D function to integrate. - :returns: Two-element tuple containing the integral of func from a to b - and an estimate of the absolute error in the result. + :rtype: int """ + return self.function + + @integrand.setter + def integrand(self, object func): - raise NotImplementedError("The integrate() virtual method must be implemented.") + if func is None: + self.function = None + else: + self.function = autowrap_function1d(func) cdef class GaussianQuadrature(Integrator1D): @@ -51,18 +58,20 @@ cdef class GaussianQuadrature(Integrator1D): using fixed-tolerance Gaussian quadrature. (see Scipy `quadrature `). + :param object integrand: A 1D function to integrate. :param double relative_tolerance: Iteration stops when relative error between last two iterates is less than this value. Default is 1.e-5. :param int max_order: Maximum order on Gaussian quadrature. Default is 50. :param int min_order: Minimum order on Gaussian quadrature. Default is 1. + :ivar Function1D integrand: A 1D function to integrate. :ivar double relative_tolerance: Iteration stops when relative error between last two iterates is less than this value. :ivar int max_order: Maximum order on Gaussian quadrature. :ivar int min_order: Minimum order on Gaussian quadrature. """ - def __init__(self, double relative_tolerance=1.e-5, int max_order=50, int min_order=1): + def __init__(self, object integrand=None, double relative_tolerance=1.e-5, int max_order=50, int min_order=1): if min_order < 1 or max_order < 1: raise ValueError("Order of Gaussian quadrature must be >= 1.") @@ -74,6 +83,8 @@ cdef class GaussianQuadrature(Integrator1D): self._max_order = max_order self._build_cash() + self.integrand = integrand + self.relative_tolerance = relative_tolerance @property @@ -162,31 +173,34 @@ cdef class GaussianQuadrature(Integrator1D): @cython.wraparound(False) @cython.cdivision(True) @cython.initializedcheck(False) - cpdef (double, double) integrate(self, Function1D func, double a, double b): + cdef double evaluate(self, double a, double b) except? -1e999: """ Integrates a one-dimensional function over a finite interval. - :param Function1D func: A function to integrate. :param double a: Lower limit of integration. :param double b: Upper limit of integration. - :returns: Two-element tuple containing Gaussian quadrature approximation to integral - and difference between last two estimates of the integral. + :returns: Gaussian quadrature approximation to integral. """ cdef: int order, i, ibegin - double newval, oldval, error, x + double newval, oldval, error, x, c, d + + if self.function is None: + raise AttributeError("Integrand is not set.") oldval = INFINITY ibegin = 0 + c = 0.5 * (a + b) + d = 0.5 * (b - a) for order in range(self._min_order, self._max_order + 1): newval = 0 for i in range(ibegin, ibegin + order): - x = a + 0.5 * (b - a) * (self._roots_mv[i] + 1.) - newval += self._weights_mv[i] * func.evaluate(x) - newval *= 0.5 * (b - a) + x = c + d * self._roots_mv[i] + newval += self._weights_mv[i] * self.function.evaluate(x) + newval *= d error = abs(newval - oldval) oldval = newval @@ -196,4 +210,4 @@ cdef class GaussianQuadrature(Integrator1D): if error < self._rtol * abs(newval): break - return newval, error + return newval diff --git a/cherab/core/math/tests/test_integrators.py b/cherab/core/math/tests/test_integrators.py index a60a4eea..a62ffafd 100644 --- a/cherab/core/math/tests/test_integrators.py +++ b/cherab/core/math/tests/test_integrators.py @@ -31,11 +31,12 @@ def test_properties(self): min_order = 3 max_order = 30 reltol = 1.e-6 - quadrature = GaussianQuadrature(relative_tolerance=reltol, max_order=max_order, min_order=min_order) + quadrature = GaussianQuadrature(integrand=Arg1D, relative_tolerance=reltol, max_order=max_order, min_order=min_order) self.assertEqual(quadrature.relative_tolerance, reltol) self.assertEqual(quadrature.max_order, max_order) self.assertEqual(quadrature.min_order, min_order) + self.assertEqual(quadrature.integrand, Arg1D) min_order = 0 max_order = 2 # < min_order @@ -57,21 +58,26 @@ def test_properties(self): quadrature.relative_tolerance = reltol quadrature.min_order = min_order quadrature.max_order = max_order + quadrature.integrand = Exp1D self.assertEqual(quadrature.relative_tolerance, reltol) self.assertEqual(quadrature.min_order, min_order) self.assertEqual(quadrature.max_order, max_order) + self.assertEqual(quadrature.integrand, Exp1D) def test_integrate(self): """Test integration.""" - func = (2 / sqrt(pi)) * Exp1D(- Arg1D() * Arg1D()) quadrature = GaussianQuadrature(relative_tolerance=1.e-8) a = -0.5 b = 3. - result, error = quadrature.integrate(func, a, b) + + with self.assertRaises(AttributeError): # integrand is not set + quadrature(a, b) + + quadrature.integrand = (2 / sqrt(pi)) * Exp1D(- Arg1D() * Arg1D()) exact_integral = erf(b) - erf(a) - self.assertAlmostEqual(result, exact_integral, places=8) + self.assertAlmostEqual(quadrature(a, b), exact_integral, places=8) if __name__ == '__main__': From 86d908b4fe4cb7f523921992925c1e019914cedc Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Sun, 11 Sep 2022 03:08:35 +0300 Subject: [PATCH 28/81] Remove NumericallyIntegratedLineShapeModel. Add integrator to LineShapeModel. --- cherab/core/model/lineshape.pxd | 8 ++----- cherab/core/model/lineshape.pyx | 37 +++++++++++---------------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/cherab/core/model/lineshape.pxd b/cherab/core/model/lineshape.pxd index 050d589e..2591efe3 100644 --- a/cherab/core/model/lineshape.pxd +++ b/cherab/core/model/lineshape.pxd @@ -42,15 +42,11 @@ cdef class LineShapeModel: double wavelength Species target_species Plasma plasma + Integrator1D integrator cpdef Spectrum add_line(self, double radiance, Point3D point, Vector3D direction, Spectrum spectrum) -cdef class NumericallyIntegrableLineShapeModel(LineShapeModel): - - cdef Integrator1D integrator - - cdef class GaussianLine(LineShapeModel): pass @@ -63,7 +59,7 @@ cdef class MultipletLineShape(LineShapeModel): double[:,::1] _multiplet_mv -cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): +cdef class StarkBroadenedLine(LineShapeModel): cdef double _aij, _bij, _cij diff --git a/cherab/core/model/lineshape.pyx b/cherab/core/model/lineshape.pyx index c0bb9711..96c36495 100644 --- a/cherab/core/model/lineshape.pyx +++ b/cherab/core/model/lineshape.pyx @@ -148,37 +148,22 @@ cdef class LineShapeModel: :param float wavelength: The rest wavelength for this emission line. :param Species target_species: The target plasma species that is emitting. :param Plasma plasma: The emitting plasma object. + :param Integrator1D integrator: Integrator1D instance to integrate the line shape + over the spectral bin. Default is None. """ - def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma): + def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, Integrator1D integrator=None): self.line = line self.wavelength = wavelength self.target_species = target_species self.plasma = plasma + self.integrator = integrator cpdef Spectrum add_line(self, double radiance, Point3D point, Vector3D direction, Spectrum spectrum): raise NotImplementedError('Child lineshape class must implement this method.') -cdef class NumericallyIntegrableLineShapeModel(LineShapeModel): - """ - Line shape model to be numerically integrated over the spectral bin. - - :param Line line: The emission line object for this line shape. - :param float wavelength: The rest wavelength for this emission line. - :param Species target_species: The target plasma species that is emitting. - :param Plasma plasma: The emitting plasma object. - :param Integrator1D integrator: Integrator1D instance to integrate the line shape - over the spectral bin. Default is `GaussianQuadrature()`. - """ - - def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, Integrator1D integrator=None): - - super().__init__(line, wavelength, target_species, plasma) - self.integrator = integrator or GaussianQuadrature() - - cdef class GaussianLine(LineShapeModel): """ Produces Gaussian line shape. @@ -323,7 +308,7 @@ cdef class StarkFunction(Function1D): return 1. / ((fabs(x - self._x0))**2.5 + self._a) -cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): +cdef class StarkBroadenedLine(LineShapeModel): """ Parametrised Stark broadened line shape based on the Model Microfield Method (MMM). Contains embedded atomic data in the form of fits to MMM. @@ -342,6 +327,9 @@ cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): :param dict stark_model_coefficients: Alternative model coefficients in the form {line_ij: (c_ij, a_ij, b_ij), ...}. If None, the default model parameters will be used. + :param Integrator1D integrator: Integrator1D instance to integrate the line shape + over the spectral bin. Default is `GaussianQuadrature()`. + """ STARK_MODEL_COEFFICIENTS_DEFAULT = { @@ -386,8 +374,8 @@ cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): Line(tritium, 0, (9, 3)): (5.588e-15, 0.7165, 0.033) } - def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, Integrator1D integrator=None, - dict stark_model_coefficients=None): + def __init__(self, Line line, double wavelength, Species target_species, Plasma plasma, + dict stark_model_coefficients=None, integrator=GaussianQuadrature()): stark_model_coefficients = stark_model_coefficients or self.STARK_MODEL_COEFFICIENTS_DEFAULT @@ -426,7 +414,6 @@ cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): double bin_integral int start, end, i Spectrum raw_lineshape - StarkFunction stark_funcion ne = self.plasma.get_electron_distribution().density(point.x, point.y, point.z) if ne <= 0.0: @@ -438,7 +425,7 @@ cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): lambda_1_2 = self._cij * ne**self._aij / (te**self._bij) - stark_funcion = StarkFunction(self.wavelength, lambda_1_2) + self.integrator.function = StarkFunction(self.wavelength, lambda_1_2) # calculate and check end of limits cutoff_lower_wavelength = self.wavelength - LORENZIAN_CUTOFF_GAMMA * lambda_1_2 @@ -461,7 +448,7 @@ cdef class StarkBroadenedLine(NumericallyIntegrableLineShapeModel): for i in range(start, end): upper_wavelength = raw_lineshape.min_wavelength + raw_lineshape.delta_wavelength * (i + 1) - bin_integral, _ = self.integrator.integrate(stark_funcion, lower_wavelength, upper_wavelength) + bin_integral = self.integrator.evaluate(lower_wavelength, upper_wavelength) raw_lineshape.samples_mv[i] += bin_integral lower_wavelength = upper_wavelength From 6a915f9edc1c584b3c89856efabbea0da400cec3 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 17 Oct 2022 18:59:44 +0300 Subject: [PATCH 29/81] Remove Function2D inheritance for Integrator1D. Forbid setting the integrand to None. --- .../core/math/integrators/integrators1d.pxd | 6 ++- .../core/math/integrators/integrators1d.pyx | 42 ++++++++++++------- cherab/core/math/tests/test_integrators.py | 4 -- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/cherab/core/math/integrators/integrators1d.pxd b/cherab/core/math/integrators/integrators1d.pxd index 8109e6d7..c451285f 100644 --- a/cherab/core/math/integrators/integrators1d.pxd +++ b/cherab/core/math/integrators/integrators1d.pxd @@ -20,11 +20,13 @@ from numpy cimport ndarray from raysect.core.math.function.float cimport Function1D, Function2D -cdef class Integrator1D(Function2D): +cdef class Integrator1D: cdef: Function1D function + cdef double evaluate(self, double a, double b) except? -1e999 + cdef class GaussianQuadrature(Integrator1D): @@ -34,4 +36,4 @@ cdef class GaussianQuadrature(Integrator1D): ndarray _roots, _weights double[:] _roots_mv, _weights_mv - cdef _build_cash(self) + cdef _build_cache(self) diff --git a/cherab/core/math/integrators/integrators1d.pyx b/cherab/core/math/integrators/integrators1d.pyx index 1e69efd4..54ec4059 100644 --- a/cherab/core/math/integrators/integrators1d.pyx +++ b/cherab/core/math/integrators/integrators1d.pyx @@ -21,13 +21,13 @@ import numpy as np from scipy.special import roots_legendre -from raysect.core.math.function.float cimport autowrap_function1d +from raysect.core.math.function.float cimport autowrap_function1d, Constant1D from libc.math cimport INFINITY cimport cython -cdef class Integrator1D(Function2D): +cdef class Integrator1D: """ Compute a definite integral of a one-dimensional function. @@ -44,12 +44,25 @@ cdef class Integrator1D(Function2D): return self.function @integrand.setter - def integrand(self, object func): + def integrand(self, object func not None): - if func is None: - self.function = None - else: - self.function = autowrap_function1d(func) + self.function = autowrap_function1d(func) + + cdef double evaluate(self, double a, double b) except? -1e999: + + raise NotImplementedError("The evaluate() method has not been implemented.") + + def __call__(self, double a, double b): + """ + Integrates a one-dimensional function over a finite interval. + + :param double a: Lower limit of integration. + :param double b: Upper limit of integration. + + :returns: Definite integral of a one-dimensional function. + """ + + return self.evaluate(a, b) cdef class GaussianQuadrature(Integrator1D): @@ -58,7 +71,7 @@ cdef class GaussianQuadrature(Integrator1D): using fixed-tolerance Gaussian quadrature. (see Scipy `quadrature `). - :param object integrand: A 1D function to integrate. + :param object integrand: A 1D function to integrate. Default is Constant1D(0). :param double relative_tolerance: Iteration stops when relative error between last two iterates is less than this value. Default is 1.e-5. :param int max_order: Maximum order on Gaussian quadrature. Default is 50. @@ -71,7 +84,7 @@ cdef class GaussianQuadrature(Integrator1D): :ivar int min_order: Minimum order on Gaussian quadrature. """ - def __init__(self, object integrand=None, double relative_tolerance=1.e-5, int max_order=50, int min_order=1): + def __init__(self, object integrand=Constant1D(0), double relative_tolerance=1.e-5, int max_order=50, int min_order=1): if min_order < 1 or max_order < 1: raise ValueError("Order of Gaussian quadrature must be >= 1.") @@ -81,7 +94,7 @@ cdef class GaussianQuadrature(Integrator1D): self._min_order = min_order self._max_order = max_order - self._build_cash() + self._build_cache() self.integrand = integrand @@ -107,7 +120,7 @@ cdef class GaussianQuadrature(Integrator1D): self._min_order = value - self._build_cash() + self._build_cache() @property def max_order(self): @@ -129,7 +142,7 @@ cdef class GaussianQuadrature(Integrator1D): self._max_order = value - self._build_cash() + self._build_cache() @property def relative_tolerance(self): @@ -148,7 +161,7 @@ cdef class GaussianQuadrature(Integrator1D): self._rtol = value - cdef _build_cash(self): + cdef _build_cache(self): """ Caches the roots and weights of the Gauss-Legendre quadrature. """ @@ -187,9 +200,6 @@ cdef class GaussianQuadrature(Integrator1D): int order, i, ibegin double newval, oldval, error, x, c, d - if self.function is None: - raise AttributeError("Integrand is not set.") - oldval = INFINITY ibegin = 0 c = 0.5 * (a + b) diff --git a/cherab/core/math/tests/test_integrators.py b/cherab/core/math/tests/test_integrators.py index a62ffafd..fa967165 100644 --- a/cherab/core/math/tests/test_integrators.py +++ b/cherab/core/math/tests/test_integrators.py @@ -70,10 +70,6 @@ def test_integrate(self): quadrature = GaussianQuadrature(relative_tolerance=1.e-8) a = -0.5 b = 3. - - with self.assertRaises(AttributeError): # integrand is not set - quadrature(a, b) - quadrature.integrand = (2 / sqrt(pi)) * Exp1D(- Arg1D() * Arg1D()) exact_integral = erf(b) - erf(a) From e62f0adde3eae62cdf949a2db8013f352c5167ea Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 17 Oct 2022 21:52:05 +0300 Subject: [PATCH 30/81] Add initialisation checks to StarkFunction and make it return a normalised line shape. --- cherab/core/model/lineshape.pyx | 41 +++++++++++++++++----------- cherab/core/tests/test_lineshapes.py | 32 +++++++++++++--------- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/cherab/core/model/lineshape.pyx b/cherab/core/model/lineshape.pyx index 96c36495..69278560 100644 --- a/cherab/core/model/lineshape.pyx +++ b/cherab/core/model/lineshape.pyx @@ -19,6 +19,8 @@ # under the Licence. import numpy as np +from scipy.special import hyp2f1 + cimport numpy as np from libc.math cimport sqrt, erf, M_SQRT2, floor, ceil, fabs from raysect.optical.spectrum cimport new_spectrum @@ -80,8 +82,6 @@ cpdef double thermal_broadening(double wavelength, double temperature, double at # the number of standard deviations outside the rest wavelength the line is considered to add negligible value (including a margin for safety) DEF GAUSSIAN_CUTOFF_SIGMA = 10.0 -DEF LORENZIAN_CUTOFF_GAMMA = 50.0 - @cython.cdivision(True) @cython.initializedcheck(False) @@ -294,18 +294,36 @@ cdef class MultipletLineShape(LineShapeModel): return spectrum +DEF LORENZIAN_CUTOFF_GAMMA = 50.0 + + cdef class StarkFunction(Function1D): + """ + Normalised Stark function for the StarkBroadenedLine line shape. + """ - cdef double _a, _x0 + cdef double _a, _x0, _norm + + STARK_NORM_COEFFICIENT = 4 * LORENZIAN_CUTOFF_GAMMA * hyp2f1(0.4, 1, 1.4, -(2 * LORENZIAN_CUTOFF_GAMMA)**2.5) def __init__(self, double wavelength, double lambda_1_2): + + if wavelength <= 0: + raise ValueError("Argument 'wavelength' must be positive.") + + if lambda_1_2 <= 0: + raise ValueError("Argument 'lambda_1_2' must be positive.") + self._x0 = wavelength self._a = (0.5 * lambda_1_2)**2.5 + # normalise, so the integral over x is equal to 1 in the limits + # (_x0 - LORENZIAN_CUTOFF_GAMMA * lambda_1_2, _x0 + LORENZIAN_CUTOFF_GAMMA * lambda_1_2) + self._norm = (0.5 * lambda_1_2)**1.5 / self.STARK_NORM_COEFFICIENT @cython.cdivision(True) cdef double evaluate(self, double x) except? -1e999: - return 1. / ((fabs(x - self._x0))**2.5 + self._a) + return self._norm / ((fabs(x - self._x0))**2.5 + self._a) cdef class StarkBroadenedLine(LineShapeModel): @@ -441,25 +459,16 @@ cdef class StarkBroadenedLine(LineShapeModel): end = min(spectrum.bins, ceil((cutoff_upper_wavelength - spectrum.min_wavelength) / spectrum.delta_wavelength)) # add line to spectrum - raw_lineshape = spectrum.new_spectrum() - - lower_wavelength = raw_lineshape.min_wavelength + start * raw_lineshape.delta_wavelength + lower_wavelength = spectrum.min_wavelength + start * spectrum.delta_wavelength for i in range(start, end): - upper_wavelength = raw_lineshape.min_wavelength + raw_lineshape.delta_wavelength * (i + 1) + upper_wavelength = spectrum.min_wavelength + spectrum.delta_wavelength * (i + 1) bin_integral = self.integrator.evaluate(lower_wavelength, upper_wavelength) - raw_lineshape.samples_mv[i] += bin_integral + spectrum.samples_mv[i] += radiance * bin_integral / spectrum.delta_wavelength lower_wavelength = upper_wavelength - # perform normalisation - raw_lineshape.div_scalar(raw_lineshape.total()) - - for i in range(start, end): - # Radiance ??? - spectrum.samples_mv[i] += radiance * raw_lineshape.samples_mv[i] - return spectrum diff --git a/cherab/core/tests/test_lineshapes.py b/cherab/core/tests/test_lineshapes.py index c29f1f2e..da4dc41d 100644 --- a/cherab/core/tests/test_lineshapes.py +++ b/cherab/core/tests/test_lineshapes.py @@ -18,17 +18,17 @@ import unittest -import os import numpy as np -from scipy.special import erf +from scipy.special import erf, hyp2f1 +from scipy.integrate import quadrature from raysect.core import Point3D, Vector3D from raysect.core.math.function.float import Arg1D, Constant1D from raysect.optical import Spectrum from cherab.core import Line +from cherab.core.math.integrators import GaussianQuadrature from cherab.core.atomic import deuterium, nitrogen, ZeemanStructure -from cherab.openadas import OpenADAS from cherab.tools.plasmas.slab import build_constant_slab_plasma from cherab.core.model import GaussianLine, MultipletLineShape, StarkBroadenedLine, ZeemanTriplet, ParametrisedZeemanTriplet, ZeemanMultiplet @@ -116,7 +116,7 @@ def test_multiplet_line_shape(self): for i in range(bins): self.assertAlmostEqual(multi_gaussian[i], spectrum.samples[i], delta=1e-10, - msg='GaussianLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) + msg='MultipletLineShape.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) def test_zeeman_triplet(self): # setting up a line shape model @@ -167,7 +167,7 @@ def test_zeeman_triplet(self): for pol in ('no', 'pi', 'sigma'): for i in range(bins): self.assertAlmostEqual(tri_gaussian[pol][i], spectrum[pol].samples[i], delta=1e-10, - msg='GaussianLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) + msg='ZeemanTriplet.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) def test_parametrised_zeeman_triplet(self): # setting up a line shape model @@ -219,7 +219,7 @@ def test_parametrised_zeeman_triplet(self): for pol in ('no', 'pi', 'sigma'): for i in range(bins): self.assertAlmostEqual(tri_gaussian[pol][i], spectrum[pol].samples[i], delta=1e-10, - msg='GaussianLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) + msg='ParametrisedZeemanTriplet.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) def test_zeeman_multiplet(self): # setting up a line shape model @@ -277,14 +277,15 @@ def test_zeeman_multiplet(self): for pol in ('no', 'pi', 'sigma'): for i in range(bins): self.assertAlmostEqual(tri_gaussian[pol][i], spectrum[pol].samples[i], delta=1e-10, - msg='GaussianLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) + msg='ZeemanMultiplet.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) def test_stark_broadened_line(self): # setting up a line shape model line = Line(deuterium, 0, (6, 2)) # D-delta line target_species = self.plasma.composition.get(line.element, line.charge) wavelength = 656.104 - stark_line = StarkBroadenedLine(line, wavelength, target_species, self.plasma) + integrator = GaussianQuadrature(relative_tolerance=1.e-5) + stark_line = StarkBroadenedLine(line, wavelength, target_species, self.plasma, integrator=integrator) # spectrum parameters min_wavelength = wavelength - 0.2 @@ -304,14 +305,19 @@ def test_stark_broadened_line(self): te = self.plasma.electron_distribution.effective_temperature(point.x, point.y, point.z) lambda_1_2 = cij * ne**aij / (te**bij) + lorenzian_cutoff_gamma = 50 + stark_norm_coeff = 4 * lorenzian_cutoff_gamma * hyp2f1(0.4, 1, 1.4, -(2 * lorenzian_cutoff_gamma)**2.5) + norm = (0.5 * lambda_1_2)**1.5 / stark_norm_coeff + wavelengths, delta = np.linspace(min_wavelength, max_wavelength, bins + 1, retstep=True) - stark_lineshape = 1 / ((np.abs(wavelengths - wavelength))**2.5 + (0.5 * lambda_1_2)**2.5) - stark_lineshape = 0.5 * (stark_lineshape[1:] + stark_lineshape[:-1]) - stark_lineshape /= stark_lineshape.sum() * delta + + def stark_lineshape(x): + return norm / ((np.abs(x - wavelength))**2.5 + (0.5 * lambda_1_2)**2.5) for i in range(bins): - self.assertAlmostEqual(stark_lineshape[i], spectrum.samples[i], delta=1e-10, - msg='GaussianLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) + stark_bin = quadrature(stark_lineshape, wavelengths[i], wavelengths[i + 1], rtol=integrator.relative_tolerance)[0] / delta + self.assertAlmostEqual(stark_bin, spectrum.samples[i], delta=1e-9, + msg='StarkBroadenedLine.add_line() method gives a wrong value at {} nm.'.format(wavelengths[i])) if __name__ == '__main__': From 308208ceccfa8af6cfbab4c8aa308234696a6137 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 18 Oct 2022 23:14:03 +0300 Subject: [PATCH 31/81] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dfaac01..edc760b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ New: * Add Generomak core plasma profiles. (#360) * Add toroidal_mesh_from_polygon for making mesh for not fully-360 degrees axisymmetric elements. (#365) * Add GaussianQuadrature integration method for Function1D. (#366) -* Add NumericallyIntegrableLineShapeModel for lineshapes that cannot be analytically integrated over a spectral bin. (#366) +* Add integrator attribute to LineShapeModel to use with lineshapes that cannot be analytically integrated over a spectral bin. (#366) * Add a numerical integration of StarkBroadenedLine over the spectral bin. (#366) Bug Fixes: From f69b74c8784f6bfda988b71ec27be161e74ade85 Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 23 Nov 2022 22:01:12 +0300 Subject: [PATCH 32/81] Add cylindrical and periodic mappers. --- cherab/core/math/__init__.py | 13 +- cherab/core/math/mappers.pxd | 81 +++++-- cherab/core/math/mappers.pyx | 447 ++++++++++++++++++++++++++++++++++- 3 files changed, 514 insertions(+), 27 deletions(-) diff --git a/cherab/core/math/__init__.py b/cherab/core/math/__init__.py index b3e9a031..4f821332 100644 --- a/cherab/core/math/__init__.py +++ b/cherab/core/math/__init__.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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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,6 +31,11 @@ from .caching import Caching1D, Caching2D, Caching3D from .clamp import ClampOutput1D, ClampOutput2D, ClampOutput3D from .clamp import ClampInput1D, ClampInput2D, ClampInput3D -from .mappers import IsoMapper2D, IsoMapper3D, Swizzle2D, Swizzle3D, AxisymmetricMapper, VectorAxisymmetricMapper +from .mappers import IsoMapper2D, IsoMapper3D +from .mappers import Swizzle2D, Swizzle3D +from .mappers import AxisymmetricMapper, VectorAxisymmetricMapper +from .mappers import CylindricalMapper, VectorCylindricalMapper +from .mappers import PeriodicMapper1D, PeriodicMapper2D, PeriodicMapper3D +from .mappers import VectorPeriodicMapper1D, VectorPeriodicMapper2D, VectorPeriodicMapper3D from .mask import PolygonMask2D from .slice import Slice2D, Slice3D diff --git a/cherab/core/math/mappers.pxd b/cherab/core/math/mappers.pxd index 5b455d9d..4fee0cbf 100644 --- a/cherab/core/math/mappers.pxd +++ b/cherab/core/math/mappers.pxd @@ -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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -16,7 +16,11 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. -from cherab.core.math.function cimport Function1D, Function2D, Function3D, VectorFunction2D, VectorFunction3D +from libc.math cimport fmod +from raysect.core.math.function.float cimport Function1D, Function2D, Function3D +from raysect.core.math.function.vector3d cimport Function1D as VectorFunction1D +from raysect.core.math.function.vector3d cimport Function2D as VectorFunction2D +from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D from raysect.core cimport Vector3D @@ -26,8 +30,6 @@ cdef class IsoMapper2D(Function2D): readonly Function1D function1d readonly Function2D function2d - cdef double evaluate(self, double x, double y) except? -1e999 - cdef class IsoMapper3D(Function3D): @@ -35,15 +37,11 @@ cdef class IsoMapper3D(Function3D): readonly Function3D function3d readonly Function1D function1d - cdef double evaluate(self, double x, double y, double z) except? -1e999 - cdef class Swizzle2D(Function2D): cdef readonly Function2D function2d - cdef double evaluate(self, double x, double y) except? -1e999 - cdef class Swizzle3D(Function3D): @@ -51,18 +49,71 @@ cdef class Swizzle3D(Function3D): readonly Function3D function3d int shape[3] - cdef double evaluate(self, double x, double y, double z) except? -1e999 - cdef class AxisymmetricMapper(Function3D): cdef readonly Function2D function2d - cdef double evaluate(self, double x, double y, double z) except? -1e999 - cdef class VectorAxisymmetricMapper(VectorFunction3D): cdef readonly VectorFunction2D function2d - cdef Vector3D evaluate(self, double x, double y, double z) \ No newline at end of file + +cdef class CylindricalMapper(Function3D): + + cdef readonly Function3D function3d + + +cdef class VectorCylindricalMapper(VectorFunction3D): + + cdef readonly VectorFunction3D function3d + + +cdef inline double remainder(double x1, double x2) nogil: + if x2 == 0: + return x1 + x1 = fmod(x1, x2) + return x1 + x2 if (x1 < 0) else x1 + + +cdef class PeriodicMapper1D(Function1D): + + cdef: + readonly Function1D function1d + readonly double period + + +cdef class PeriodicMapper2D(Function2D): + + cdef: + readonly Function2D function2d + double period_x, period_y + + +cdef class PeriodicMapper3D(Function3D): + + cdef: + readonly Function3D function3d + readonly double period_x, period_y, period_z + + +cdef class VectorPeriodicMapper1D(VectorFunction1D): + + cdef: + readonly VectorFunction1D function1d + readonly double period + + +cdef class VectorPeriodicMapper2D(VectorFunction2D): + + cdef: + readonly VectorFunction2D function2d + readonly double period_x, period_y + + +cdef class VectorPeriodicMapper3D(VectorFunction3D): + + cdef: + readonly VectorFunction3D function3d + readonly double period_x, period_y, period_z diff --git a/cherab/core/math/mappers.pyx b/cherab/core/math/mappers.pyx index 5ff224a3..63f868a9 100644 --- a/cherab/core/math/mappers.pyx +++ b/cherab/core/math/mappers.pyx @@ -20,7 +20,10 @@ from libc.math cimport sqrt, atan2, M_PI -from cherab.core.math.function cimport autowrap_function1d, autowrap_function2d, autowrap_function3d, autowrap_vectorfunction2d +from raysect.core.math.function.float cimport autowrap_function1d, autowrap_function2d, autowrap_function3d +from raysect.core.math.function.vector3d cimport autowrap_function1d as autowrap_vectorfunction1d +from raysect.core.math.function.vector3d cimport autowrap_function2d as autowrap_vectorfunction2d +from raysect.core.math.function.vector3d cimport autowrap_function3d as autowrap_vectorfunction3d from raysect.core cimport rotate_z cimport cython @@ -251,13 +254,10 @@ cdef class AxisymmetricMapper(Function3D): def __init__(self, object function2d): if not callable(function2d): - raise TypeError("Function3D is not callable.") + raise TypeError("Function2D is not callable.") self.function2d = autowrap_function2d(function2d) - def __call__(self, double x, double y, double z): - return self.evaluate(x, y, z) - cdef double evaluate(self, double x, double y, double z) except? -1e999: """Return the value of function2d when it is y-axis symmetrically extended to the 3D space.""" @@ -299,13 +299,11 @@ cdef class VectorAxisymmetricMapper(VectorFunction3D): self.function2d = autowrap_vectorfunction2d(vectorfunction2d) - def __call__(self, double x, double y, double z): - return self.evaluate(x, y, z) - @cython.cdivision(True) cdef Vector3D evaluate(self, double x, double y, double z): """Return the value of function2d when it is y-axis symmetrically extended to the 3D space.""" + cdef double r, phi # convert to cylindrical coordinates phi = atan2(y, x) / M_PI * 180 @@ -313,3 +311,436 @@ cdef class VectorAxisymmetricMapper(VectorFunction3D): # perform axisymmetric rotation return self.function2d.evaluate(r, z).transform(rotate_z(phi)) + + +cdef class CylindricalMapper(Function3D): + """ + Converts Cartesian coordinates to cylindrical coordinates and calls a 3D function + defined in cylindrical coordinates, f(r, :math:`\\phi`, z). + + The angular coordinate is given in radians. + + Positive angular coordinate is measured counterclockwise from the xz plane. + + :param Function3D function3d: The function to be mapped. Must be defined + in the interval (:math:`-\\pi`, :math:`\\pi`] + on the angular axis. + + .. code-block:: pycon + + >>> from math import sqrt, cos + >>> from cherab.core.math import CylindricalMapper + >>> + >>> def my_func(r, phi, z): + >>> return r * cos(phi) + >>> + >>> f = CylindricalMapper(my_func) + >>> + >>> f(1, 0, 0) + 1.0 + >>> f(0.5 * sqrt(3), 0.5, 0) + 0.8660254037844385 + """ + + def __init__(self, object function3d): + + if not callable(function3d): + raise TypeError("Function3D is not callable.") + + self.function3d = autowrap_function3d(function3d) + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + """ + Converts to cylindrical coordinates and evaluates the function + defined in cylindrical coordinates. + """ + cdef double r, phi + + r = sqrt(x * x + y * y) + phi = atan2(y, x) + + return self.function3d.evaluate(r, phi, z) + + +cdef class VectorCylindricalMapper(VectorFunction3D): + """ + Converts Cartesian coordinates to cylindrical coordinates, calls + a 3D vector function defined in cylindrical coordinates, f(r, :math:`\\phi`, z), + then converts the returned 3D vector to Cartesian coordinates. + + The angular coordinate is given in radians. + + Positive angular coordinate is measured counterclockwise from the xz plane. + + :param VectorFunction3D function3d: The function to be mapped. Must be defined + in the interval (:math:`-\\pi`, :math:`\\pi`] + on the angular axis. + + .. code-block:: pycon + + >>> from math import sqrt, cos + >>> from raysect.core.math import Vector3D + >>> from cherab.core.math import VectorCylindricalMapper + >>> + >>> def my_vec_func(r, phi, z): + >>> v = Vector3D(0, 1, 0) + >>> v.length = r * abs(cos(phi)) + >>> return v + >>> + >>> f = VectorCylindricalMapper(my_vec_func) + >>> + >>> f(1, 0, 0) + Vector3D(0.0, 1.0, 0.0) + >>> f(1/sqrt(2), 1/sqrt(2), 0) + Vector3D(-0.5, 0.5, 0.0) + """ + + def __init__(self, object function3d): + + if not callable(function3d): + raise TypeError("Function3D is not callable.") + + self.function3d = autowrap_vectorfunction3d(function3d) + + @cython.cdivision(True) + cdef Vector3D evaluate(self, double x, double y, double z): + """ + Converts to cylindrical coordinates, evaluates the vector function + defined in cylindrical coordinates and rotates the resulting vector + around z-axis. + """ + cdef double r, phi + + r = sqrt(x * x + y * y) + phi = atan2(y, x) + + return self.function3d.evaluate(r, phi, z).transform(rotate_z(phi / M_PI * 180)) + + +cdef class PeriodicMapper1D(Function1D): + """ + Maps a periodic 1D function into 1D space. + + :param Function1D function1d: The periodic 1D function to map defined + in the [0, period) interval. + :param double period: The period of the function. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicMapper1D + >>> + >>> def f1(x): + >>> return x + >>> + >>> f2 = PeriodicMapper1D(f1, 1.) + >>> + >>> f2(1.5) + 0.5 + >>> f2(-0.3) + 0.7 + """ + + def __init__(self, object function1d, double period): + + if not callable(function1d): + raise TypeError("function1d is not callable.") + + self.function1d = autowrap_function1d(function1d) + + if period <= 0: + raise ValueError("Argument period must be positive.") + + self.period = period + + cdef double evaluate(self, double x) except? -1e999: + """Return the value of periodic function.""" + + return self.function1d.evaluate(remainder(x, self.period)) + + +cdef class PeriodicMapper2D(Function2D): + """ + Maps a periodic 2D function into 2D space. + + Set period_x/period_y to 0 if the function is not periodic along x/y axis. + + :param Function2D function2d: The periodic 2D function to map defined + in the ([0, period_x), [0, period_y)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicMapper2D + >>> + >>> def f1(x, y): + >>> return x * y + >>> + >>> f2 = PeriodicMapper2D(f1, 1., 1.) + >>> + >>> f2(1.5, 1.5) + 0.25 + >>> f2(-0.3, -1.3) + 0.49 + >>> + >>> f3 = PeriodicMapper2D(f1, 1., 0) + >>> + >>> f3(1.5, 1.5) + 0.75 + >>> f3(-0.3, -1.3) + -0.91 + """ + + def __init__(self, object function2d, double period_x, double period_y): + + if not callable(function2d): + raise TypeError("function2d is not callable.") + + self.function2d = autowrap_function2d(function2d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + + cdef double evaluate(self, double x, double y) except? -1e999: + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + + return self.function2d.evaluate(x, y) + + +cdef class PeriodicMapper3D(Function3D): + """ + Maps a periodic 3D function into 3D space. + + Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. + + :param Function3D function3d: The periodic 3D function to map defined in the + ([0, period_x), [0, period_y), [0, period_z)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + :param double period_z: The period of the function along z-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicMapper3D + >>> + >>> def f1(x, y, z): + >>> return x * y * z + >>> + >>> f2 = PeriodicMapper3D(f1, 1., 1., 1.) + >>> + >>> f2(1.5, 1.5, 1.5) + 0.125 + >>> f2(-0.3, -1.3, -2.3) + 0.343 + >>> + >>> f3 = PeriodicMapper3D(f1, 0, 1., 0) + >>> + >>> f3(1.5, 1.5, 1.5) + 1.125 + >>> f3(-0.3, -1.3, -0.3) + 0.063 + """ + + def __init__(self, object function3d, double period_x, double period_y, double period_z): + + if not callable(function3d): + raise TypeError("function2d is not callable.") + + self.function3d = autowrap_function3d(function3d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + if period_z < 0: + raise ValueError("Argument period_z must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + self.period_z = period_z + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + z = remainder(z, self.period_z) + + return self.function3d.evaluate(x, y, z) + + +cdef class VectorPeriodicMapper1D(VectorFunction1D): + """ + Maps a periodic 1D vector function into 1D space. + + :param VectorFunction1D function1d: The periodic 1D vector function to map + defined in the [0, period) interval. + :param double period: The period of the function. + + .. code-block:: pycon + + >>> from raysect.core.math import Vector3D + >>> from cherab.core.math import VectorPeriodicMapper1D + >>> + >>> def f1(x): + >>> return Vector3D(x, 0, 0) + >>> + >>> f2 = VectorPeriodicMapper1D(f1, 1.) + >>> + >>> f2(1.5) + Vector3D(0.5, 0, 0) + >>> f2(-0.3) + Vector3D(0.7, 0, 0) + """ + + def __init__(self, object function1d, double period): + + if not callable(function1d): + raise TypeError("function1d is not callable.") + + self.function1d = autowrap_vectorfunction1d(function1d) + + if period <= 0: + raise ValueError("Argument period must be positive.") + + self.period = period + + cdef Vector3D evaluate(self, double x): + """Return the value of periodic function.""" + + return self.function1d.evaluate(remainder(x, self.period)) + + +cdef class VectorPeriodicMapper2D(VectorFunction2D): + """ + Maps a periodic 2D vector function into 2D space. + + Set period_x/period_y to 0 if the function is not periodic along x/y axis. + + :param VectorFunction2D function2d: The periodic 2D vector function to map defined in + the ([0, period_x), [0, period_y)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import VectorPeriodicMapper2D + >>> + >>> def f1(x, y): + >>> return Vector3D(x, y, 0) + >>> + >>> f2 = VectorPeriodicMapper2D(f1, 1., 1.) + >>> + >>> f2(1.5, 1.5) + Vector3D(0.5, 0.5, 0) + >>> f2(-0.3, -1.3) + Vector3D(0.7, 0.7, 0) + >>> + >>> f3 = VectorPeriodicMapper2D(f1, 1., 0) + >>> + >>> f3(1.5, 1.5) + Vector3D(0.5, 1.5, 0) + >>> f3(-0.3, -1.3) + Vector3D(0.7, -1.3, 0) + """ + + def __init__(self, object function2d, double period_x, double period_y): + + if not callable(function2d): + raise TypeError("function2d is not callable.") + + self.function2d = autowrap_vectorfunction2d(function2d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + + cdef Vector3D evaluate(self, double x, double y): + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + + return self.function2d.evaluate(x, y) + + +cdef class VectorPeriodicMapper3D(VectorFunction3D): + """ + Maps a periodic 3D vector function into 3D space. + + Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. + + :param VectorFunction3D function3d: The periodic 3D vector function to map defined in the + ([0, period_x), [0, period_y), [0, period_z)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + :param double period_z: The period of the function along z-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicMapper3D + >>> + >>> def f1(x, y, z): + >>> return Vector3D(x, y, z) + >>> + >>> f2 = VectorPeriodicMapper3D(f1, 1., 1., 1.) + >>> + >>> f2(1.5, 1.5, 1.5) + Vector3D(0.5, 0.5, 0.5) + >>> f2(-0.3, -1.3, -2.3) + Vector3D(0.7, 0.7, 0.7) + >>> + >>> f3 = VectorPeriodicMapper3D(f1, 0, 1., 0) + >>> + >>> f3(1.5, 0.5, 1.5) + Vector3D(1.5, 0.5, 1.5) + """ + + def __init__(self, object function3d, double period_x, double period_y, double period_z): + + if not callable(function3d): + raise TypeError("function2d is not callable.") + + self.function3d = autowrap_vectorfunction3d(function3d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + if period_z < 0: + raise ValueError("Argument period_z must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + self.period_z = period_z + + cdef Vector3D evaluate(self, double x, double y, double z): + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + z = remainder(z, self.period_z) + + return self.function3d.evaluate(x, y, z) From 251b11b457cb1daa9cd5c82017a9bfd6c41aa94d Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 25 Nov 2022 22:50:35 +0300 Subject: [PATCH 33/81] Add tests for periodic and cylindrical mappers. --- cherab/core/math/tests/test_mappers.py | 114 ++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/cherab/core/math/tests/test_mappers.py b/cherab/core/math/tests/test_mappers.py index 777a6a85..69a5f771 100644 --- a/cherab/core/math/tests/test_mappers.py +++ b/cherab/core/math/tests/test_mappers.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-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); @@ -16,6 +16,7 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. +from raysect.core.math import Vector3D from cherab.core.math import mappers import numpy as np import unittest @@ -142,5 +143,112 @@ def test_axisymmetric_mapper_invalid_arg(self): """An error must be raised if the given argument is not callable.""" self.assertRaises(TypeError, mappers.AxisymmetricMapper, "blah") + def test_cylindrical_mapper(self): + """Cylindrical mapper.""" + def f3d(r, phi, z): return r * np.cos(phi) + z + cyl_func = mappers.CylindricalMapper(f3d) + self.assertAlmostEqual(cyl_func(1., 1., 0.5), + f3d(np.sqrt(2.), 0.25 * np.pi, 0.5), + places=10) + + def test_cylindrical_mapper_invalid_arg(self): + """An error must be raised if the given argument is not callable.""" + self.assertRaises(TypeError, mappers.CylindricalMapper, "blah") + + def test_vector_cylindrical_mapper(self): + """Cylindrical mapper.""" + def f3d(r, phi, z): return Vector3D(np.sin(phi), r * z, np.cos(phi)) + cyl_func = mappers.VectorCylindricalMapper(f3d) + vec1 = cyl_func(1., 1., 1.) + vec2 = Vector3D(-0.5, 1.5, 1 / np.sqrt(2)) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + def test_vector_cylindrical_mapper_invalid_arg(self): + """An error must be raised if the given argument is not callable.""" + self.assertRaises(TypeError, mappers.VectorCylindricalMapper, "blah") + + def test_periodic_mapper_1d(self): + """1D periodic mapper""" + period_func = mappers.PeriodicMapper1D(self.function1d, np.pi) + self.assertAlmostEqual(period_func(1.4 * np.pi), + self.function1d(0.4 * np.pi), + places=10) + self.assertAlmostEqual(period_func(-0.4 * np.pi), + self.function1d(0.6 * np.pi), + places=10) + + def test_periodic_mapper_1d_invalid_arg(self): + """1D periodic mapper. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, mappers.PeriodicMapper1D, "blah", np.pi) + # period is not a number + self.assertRaises(TypeError, mappers.PeriodicMapper1D, self.function1d, "blah") + # period is negative + self.assertRaises(ValueError, mappers.PeriodicMapper1D, self.function1d, -1) + + def test_periodic_mapper_2d(self): + """2D periodic mapper""" + period_func = mappers.PeriodicMapper2D(self.function2d, 1, np.pi) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(0.6, 0.4 * np.pi), + places=10) + # Periodic only along x + period_func = mappers.PeriodicMapper2D(self.function2d, 1., 0) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(0.6, 1.4 * np.pi), + places=10) + # Periodic only along y + period_func = mappers.PeriodicMapper2D(self.function2d, 0, np.pi) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(-0.4, 0.4 * np.pi), + places=10) + + def test_periodic_mapper_2d_invalid_arg(self): + """2D periodic mapper. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, mappers.PeriodicMapper2D, "blah", np.pi, np.pi) + # period is not a number + self.assertRaises(TypeError, mappers.PeriodicMapper2D, self.function2d, "blah", np.pi) + self.assertRaises(TypeError, mappers.PeriodicMapper2D, self.function2d, np.pi, "blah") + # period is negative + self.assertRaises(ValueError, mappers.PeriodicMapper2D, self.function2d, -1, np.pi) + self.assertRaises(ValueError, mappers.PeriodicMapper2D, self.function2d, np.pi, -1) + + def test_periodic_mapper_3d(self): + """3D periodic mapper""" + period_func = mappers.PeriodicMapper3D(self.function3d, 1, 1, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 0.4, 0.1), + places=10) + # Periodic only along y and z + period_func = mappers.PeriodicMapper3D(self.function3d, 0, 1, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(-0.4, 0.4, 0.1), + places=10) + # Periodic only along x and z + period_func = mappers.PeriodicMapper3D(self.function3d, 1, 0, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 1.4, 0.1), + places=10) + # Periodic only along x and y + period_func = mappers.PeriodicMapper3D(self.function3d, 1, 1, 0) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 0.4, 2.1), + places=10) + + def test_periodic_mapper_3d_invalid_arg(self): + """2D periodic mapper. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, mappers.PeriodicMapper3D, "blah", np.pi, np.pi, np.pi) + # period is not a number + self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, "blah", np.pi, np.pi) + self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, np.pi, "blah", np.pi) + self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, np.pi, np.pi, "blah") + # period is negative + self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, -1, np.pi, np.pi) + self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, np.pi, -1, np.pi) + self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, np.pi, np.pi, -1) + + if __name__ == '__main__': unittest.main() \ No newline at end of file From c0a60eeda1d7c64921767aae9cc4c4ca449a9fcf Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 25 Nov 2022 23:14:16 +0300 Subject: [PATCH 34/81] Update CHANGELOG. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe69a21..b8a3bc5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ New: * Add verbose parameter to SartOpencl solver (default is False). (#358) * Add Generomak core plasma profiles. (#360) * Add toroidal_mesh_from_polygon for making mesh for not fully-360 degrees axisymmetric elements. (#365) +* Add PeriodicMapperXD and VectorPeriodicMapperXD to support the data simulated with periodic boundary conditions. (#387) +* Add CylindricalMapper and VectorCylindricalMapper to map functions from cylindrical to Cartesian coordinates. (#387) Bug Fixes: ---------- From d9fcd2c934804395e335bd6c7af3cd5557a2f334 Mon Sep 17 00:00:00 2001 From: vsnever Date: Sat, 3 Dec 2022 00:18:15 +0300 Subject: [PATCH 35/81] Use ionisation balance for core profiles to fulfill plasma neutrality. Tweak core profile parameters. --- cherab/generomak/plasma/plasma.py | 117 ++++++++++++------------------ 1 file changed, 47 insertions(+), 70 deletions(-) diff --git a/cherab/generomak/plasma/plasma.py b/cherab/generomak/plasma/plasma.py index 65fef528..ab7ef95d 100644 --- a/cherab/generomak/plasma/plasma.py +++ b/cherab/generomak/plasma/plasma.py @@ -34,6 +34,8 @@ from cherab.core.math.mappers import AxisymmetricMapper, VectorAxisymmetricMapper from cherab.core.math.clamp import ClampInput1D +from cherab.tools.plasmas.ionisation_balance import interpolators1d_from_elementdensity, interpolators1d_match_plasma_neutrality + from cherab.openadas import OpenADAS from cherab.generomak.equilibrium import load_equilibrium @@ -318,21 +320,16 @@ def get_core_profiles_arguments(**kwargs): te_core core: (default 3e3) electron temperature te_convexity: (default 2.35) convexity of the electron temperature profile te_concavity: (default 1.26) concavity of the electron temperature profile - nh_core: (default 5e19) density of H1+ - nh_convexity: (default 1.09) convexity of H1+ density profile - nh_concavity: (default 0.24) concavity of H1+ density profile th_core: (default 2.8e3) H1+ temperature - th_convexity: (default 1) convexity of H1+ temperature profile - th_concavity: (default 0.82) concavity of H1+ temperature profile + th_convexity: (default 2) convexity of H1+ temperature profile + th_concavity: (default 1.26) concavity of H1+ temperature profile th0_fraction: (default 0.8) H0 temperature factor - nh0_decay decay: (default 20) rate of H0 density profile - timp_core: (default 2.7e3) core impurity temperature - timp_convexity: (default 1) convexity of impurity temperature profile - timp_concavity: (default 0.82) concavity of impurity temperature profile + timp_core: (default 2.8e3) core impurity temperature + timp_convexity: (default 2) convexity of impurity temperature profile + timp_concavity: (default 1.26) concavity of impurity temperature profile nimp_core: (default 5e17) impurity density nimp_convexity: (default 1.09) convexity of impurity density profile nimp_concavity: (default 0.24) concavity of impurity density profile - nimp_decay: (default 30) decay rate of impurity density profile (except bare nuclei) vtor_core: (default 1e5) toroidal rotation velocity m/s vtor_edge: (default 1e4) toroidal rotation velocity at the edge m/s vtor_convexity: (default 2) convexity of the toroidal rotation profile @@ -343,19 +340,13 @@ def get_core_profiles_arguments(**kwargs): :return: dictionary of profile arguments """ - core_args = {"ne_core": 5e19, "ne_convexity": 1.09, - "ne_concavity": 0.24, "te_core": 3e3, - "te_convexity": 2.35, "te_concavity": 1.26, - "nh_core": 5e19, "nh_convexity": 1.09, - "nh_concavity": 0.24, "th_core": 2.8e3, - "th_convexity": 1, "th_concavity": 0.82, - "th0_fraction": 0.8, "nh0_decay": 20, - "timp_core": 2.7e3, "timp_convexity": 1, - "timp_concavity": 0.82, "nimp_core": 5e17, - "nimp_convexity": 1.09, "nimp_concavity": 0.24, - "nimp_decay": 30, - "vtor_core": 1e5, "vtor_edge": 1e4, - "vtor_convexity": 2, "vtor_concavity": 4, + core_args = {"ne_core": 5e19, "ne_convexity": 1.09, "ne_concavity": 0.24, + "te_core": 3e3, "te_convexity": 2.35, "te_concavity": 1.26, + "th_core": 2.8e3, "th_convexity": 2, "th_concavity": 1.26, + "th0_fraction": 0.8, + "timp_core": 2.8e3, "timp_convexity": 2, "timp_concavity": 1.26, + "nimp_core": 5e17, "nimp_convexity": 1.09, "nimp_concavity": 0.24, + "vtor_core": 1e5, "vtor_edge": 1e4, "vtor_convexity": 2, "vtor_concavity": 4, "vpol_lcfs": 2e4, "vpol_decay": 0.08} if not kwargs: @@ -390,13 +381,8 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): z = 0 lcfs_values = get_edge_profile_values(r, z) - # manually correcting the LCFS densities for neutral species and low ionised carbon - # to better match the edge profiles - lcfs_values["composition"]["hydrogen"][0]["density"] = 1.e15 - lcfs_values["composition"]["carbon"][0]["density"] = 1.e5 - lcfs_values["composition"]["carbon"][1]["density"] = 1.5e5 - lcfs_values["composition"]["carbon"][2]["density"] = 1.e9 - lcfs_values["composition"]["carbon"][3]["density"] = 1.e13 + # total carbon impurity density at lcfs + nimp_lcfs = sum([value["density"] for _, value in lcfs_values["composition"]["carbon"].items()]) if core_args is None: core_args = get_core_profiles_arguments() @@ -425,47 +411,38 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): profiles["electron"]["f1d_vpol"] = Constant1D(0) profiles["electron"]["f1d_vnorm"] = Constant1D(0) - # Setup H1+ profiles with double parabola shapes - profiles["composition"]["hydrogen"][1]["f1d_temperature"] = get_double_parabola(lcfs_values["composition"]["hydrogen"][1]["temperature"], - core_args["th_core"], core_args["th_convexity"], core_args["th_concavity"], - xmin=1, xmax=0) - profiles["composition"]["hydrogen"][1]["f1d_density"] = get_double_parabola(lcfs_values["composition"]["hydrogen"][1]["density"], - core_args["nh_core"], core_args["nh_convexity"], - core_args["nh_concavity"], xmin=1, xmax=0) - profiles["composition"]["hydrogen"][1]["f1d_vtor"] = f1d_vtor - profiles["composition"]["hydrogen"][1]["f1d_vpol"] = f1d_vpol - profiles["composition"]["hydrogen"][1]["f1d_vnorm"] = f1d_vnorm - - # setup H0+ profile shapes with temperature as a fraction of H1+ and density with decaying exponential - profiles["composition"]["hydrogen"][0]["f1d_temperature"] = core_args["th0_fraction"] * get_double_parabola(lcfs_values["composition"]["hydrogen"][0]["temperature"], - core_args["th_core"], core_args["th_convexity"], - core_args["th_concavity"], xmin=1, xmax=0) - profiles["composition"]["hydrogen"][0]["f1d_density"] = get_exponential_growth( - lcfs_values["composition"]["hydrogen"][0]["density"], core_args["nh0_decay"]) - profiles["composition"]["hydrogen"][0]["f1d_vtor"] = f1d_vtor - profiles["composition"]["hydrogen"][0]["f1d_vpol"] = f1d_vpol - profiles["composition"]["hydrogen"][0]["f1d_vnorm"] = f1d_vnorm - - # setup C6+ profile shapes with double parabolas - profiles["composition"]["carbon"][6]["f1d_temperature"] = get_double_parabola(lcfs_values["composition"]["carbon"][6]["temperature"], - core_args["timp_core"], core_args["timp_convexity"], core_args["timp_concavity"], - xmin=1, xmax=0) - profiles["composition"]["carbon"][6]["f1d_density"] = get_double_parabola(lcfs_values["composition"]["carbon"][6]["density"], core_args["nimp_core"], - core_args["nimp_convexity"], core_args["nimp_concavity"], xmin=1, xmax=0) - profiles["composition"]["carbon"][6]["f1d_vtor"] = f1d_vtor - profiles["composition"]["carbon"][6]["f1d_vpol"] = f1d_vpol - profiles["composition"]["carbon"][6]["f1d_vnorm"] = f1d_vnorm - - # setup CX+ profile shapes with temperature as double parabolas and density with decaying exponentials - for chrg in range(6): - profiles["composition"]["carbon"][chrg]["f1d_temperature"] = get_double_parabola(lcfs_values["composition"]["carbon"][chrg]["temperature"], - core_args["timp_core"], core_args["timp_convexity"], core_args["timp_concavity"], + # total carbon density + carbon_total_density = get_double_parabola(nimp_lcfs, core_args["nimp_core"], + core_args["nimp_convexity"], core_args["nimp_concavity"], xmin=1, xmax=0) + + # solve ionisation balance + openadas = OpenADAS(permit_extrapolation=True) + psin_1d = np.linspace(0, 1, 256) + density_profiles = {} + density_profiles["carbon"] = interpolators1d_from_elementdensity(openadas, carbon, psin_1d, carbon_total_density, + profiles["electron"]["f1d_density"], + profiles["electron"]["f1d_temperature"]) + + density_profiles["hydrogen"] = interpolators1d_match_plasma_neutrality(openadas, hydrogen, psin_1d, [density_profiles["carbon"]], + profiles["electron"]["f1d_density"], + profiles["electron"]["f1d_temperature"]) + + # Setup ion profiles + for element, prefix in ((hydrogen, "h"), (carbon, "imp")): + name = element.name + for chrg in range(element.atomic_number + 1): + profiles["composition"][name][chrg]["f1d_temperature"] = get_double_parabola(lcfs_values["composition"][name][chrg]["temperature"], + core_args["t{}_core".format(prefix)], + core_args["t{}_convexity".format(prefix)], + core_args["t{}_concavity".format(prefix)], xmin=1, xmax=0) - profiles["composition"]["carbon"][chrg]["f1d_density"] = get_exponential_growth( - lcfs_values["composition"]["carbon"][chrg]["density"], core_args["nimp_decay"]) - profiles["composition"]["carbon"][chrg]["f1d_vtor"] = f1d_vtor - profiles["composition"]["carbon"][chrg]["f1d_vpol"] = f1d_vpol - profiles["composition"]["carbon"][chrg]["f1d_vnorm"] = f1d_vnorm + profiles["composition"][name][chrg]["f1d_density"] = density_profiles[name][chrg] + profiles["composition"][name][chrg]["f1d_vtor"] = f1d_vtor + profiles["composition"][name][chrg]["f1d_vpol"] = f1d_vpol + profiles["composition"][name][chrg]["f1d_vnorm"] = f1d_vnorm + + # multiply H0 temperature by th0_fraction + profiles["composition"]["hydrogen"][0]["f1d_temperature"] *= core_args["th0_fraction"] return profiles.freeze() From 65b545b01e83dd9f6a8411c477c1dd86b8534f91 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 22 Dec 2022 17:17:09 +0300 Subject: [PATCH 36/81] Added pre-calculated core profiles and the functions to load them. Switched to use pre-calculated core profiles by default. --- .../generomak/plasma/data/core/carbon0.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon1.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon2.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon3.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon4.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon5.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/carbon6.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/electrons.json | 1292 ++++++++++++++++ .../generomak/plasma/data/core/hydrogen0.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/hydrogen1.json | 1294 +++++++++++++++++ .../generomak/plasma/data/core/psi_norm.json | 260 ++++ cherab/generomak/plasma/plasma.py | 99 +- demos/generomak/plasma/plot_2d_plasma.py | 2 +- demos/generomak/plasma/plot_2d_profiles.py | 4 +- demos/generomak/plasma/plot_core_profiles.py | 7 +- 15 files changed, 13294 insertions(+), 16 deletions(-) create mode 100644 cherab/generomak/plasma/data/core/carbon0.json create mode 100644 cherab/generomak/plasma/data/core/carbon1.json create mode 100644 cherab/generomak/plasma/data/core/carbon2.json create mode 100644 cherab/generomak/plasma/data/core/carbon3.json create mode 100644 cherab/generomak/plasma/data/core/carbon4.json create mode 100644 cherab/generomak/plasma/data/core/carbon5.json create mode 100644 cherab/generomak/plasma/data/core/carbon6.json create mode 100644 cherab/generomak/plasma/data/core/electrons.json create mode 100644 cherab/generomak/plasma/data/core/hydrogen0.json create mode 100644 cherab/generomak/plasma/data/core/hydrogen1.json create mode 100644 cherab/generomak/plasma/data/core/psi_norm.json diff --git a/cherab/generomak/plasma/data/core/carbon0.json b/cherab/generomak/plasma/data/core/carbon0.json new file mode 100644 index 00000000..d8763cf4 --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon0.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.5297458338687, + 2782.7582301214393, + 2762.5950477966007, + 2735.8851983639343, + 2703.411010968356, + 2665.8945476185836, + 2624.0003243064125, + 2578.338228519893, + 2529.466541110544, + 2477.8949930363638, + 2424.08780488189, + 2368.4666705053005, + 2311.4136566031007, + 2253.2739981035534, + 2194.3587756195216, + 2134.9474661044947, + 2075.290361665309, + 2015.6108544256936, + 1956.107587588782, + 1896.9564745570865, + 1838.3125892477842, + 1780.3119316786645, + 1723.0730735666177, + 1666.6986891326694, + 1611.2769765905086, + 1556.8829759454748, + 1503.5797887772371, + 1451.4197056453777, + 1400.4452466615378, + 1350.6901206300427, + 1302.1801079829825, + 1254.9338725355856, + 1208.9637068710047, + 1164.2762159367799, + 1120.8729432030323, + 1078.7509434988951, + 1037.903306411775, + 998.3196339061595, + 959.986475596583, + 922.8877248943963, + 887.004979041061, + 852.3178658425425, + 818.8043397302939, + 786.4409495946626, + 755.2030806662577, + 725.0651725599275, + 696.0009154442936, + 667.9834261571025, + 640.9854059526704, + 614.9792814421413, + 589.9373301697594, + 565.8317921585761, + 542.6349686565285, + 520.3193092183391, + 498.8574881697798, + 478.22247141812255, + 458.3875744958107, + 439.3265126530432, + 421.0134437488174, + 403.4230046287076, + 386.5303416208766, + 370.3111357293156, + 354.74162305475744, + 339.79861092883743, + 325.4594902056625, + 311.70224411672444, + 298.5054540598485, + 285.84830266038824, + 273.71057441296176, + 262.0726541844933, + 250.91552383399323, + 240.22075718122792, + 229.97051353503508, + 220.14752997240066, + 210.73511254139078, + 201.7171265444924, + 193.07798604378416, + 184.80264271546582, + 176.8765741685898, + 169.28577183121658, + 162.01672849659778, + 155.05642561229888, + 148.39232038631826, + 142.01233277619647, + 135.90483241974619, + 130.05862555934604, + 124.46294200564746, + 119.10742218101434, + 113.98210427798426, + 109.07741156349235, + 104.38413985546642, + 99.89344519467129, + 95.59683173130277, + 91.48613984279793, + 87.55353449656745, + 83.79149386891429, + 80.19279822915814, + 76.7505190960298, + 73.4580086716009, + 70.30888955644176, + 67.29704474828924, + 64.41660792525342, + 61.66195401348148, + 59.027690038231896, + 56.508646256439604, + 54.09986756812256, + 51.79660520330721, + 49.59430868060964, + 47.488618033112196, + 45.4753562967661, + 43.55052225621492, + 41.710283442635344, + 39.95096937796647, + 38.26906505970934, + 36.66120468032837, + 35.12416557519362, + 33.65486239291572, + 32.25034148188933, + 30.907775486848166, + 29.624458149229337, + 28.39779930519129, + 27.225320075155384, + 26.104648238820975, + 25.033513789664312, + 24.009744663032187, + 23.03126263202616, + 22.09607936549286, + 21.20229264253159, + 20.348082718071975, + 19.531708834175102, + 18.751505871858317, + 18.005881138361524, + 17.29331128491523, + 16.612339350196027, + 15.961571924800158, + 15.339676432189938, + 14.745378521713246, + 14.17745956942282, + 13.634754282558198, + 13.116148403687774, + 12.62057651063149, + 12.147019908417766, + 11.694504609655857, + 11.262099399819382, + 10.848913984069997, + 10.454097212357015, + 10.076835379651857, + 9.716350598285864, + 9.37189923947122, + 9.042770441189758, + 8.728284679739293, + 8.427792402331782, + 8.140672718228085, + 7.866332145997564, + 7.604203414576368, + 7.353744315892651, + 7.114436606910324, + 6.88578495902669, + 6.66731595284398, + 6.458577116405904, + 6.259136005074808, + 6.068579321290205, + 5.886512072521773, + 5.712556765802551, + 5.546352637286773, + 5.387554915341459, + 5.235834115747535, + 5.09087536763343, + 4.952377768832103, + 4.820053769398764, + 4.693628582080498, + 4.572839618581702, + 4.457435950513924, + 4.347177793965752, + 4.241836016675181, + 4.1411916668281155, + 4.045035522543728, + 3.953167661156071, + 3.8653970474291826, + 3.7815411398866017, + 3.701425514464914, + 3.624883504742671, + 3.5517558580176334, + 3.4818904065449097, + 3.4151417532737645, + 3.3513709714494597, + 3.2904453174754256, + 3.23223795645469, + 3.176627699856822, + 3.1234987547774122, + 3.0727404842841777, + 3.0242471783623297, + 2.9779178349937, + 2.933655950925356, + 2.8913693217009238, + 2.850969850548094, + 2.8123733657334666, + 2.7754994460091185, + 2.7402712537980722, + 2.706615375774928, + 2.6744616705174318, + 2.6437431229153345, + 2.6143957050402027, + 2.586358243189803, + 2.5595722908346312, + 2.5339820072055117, + 2.509534041273594, + 2.4861774208836924, + 2.4638634468137517, + 2.442545591541203, + 2.4221794025087373, + 2.4027224096911914, + 2.384134037270308, + 2.366375519239019, + 2.3494098187571737, + 2.3332015510957254, + 2.3177169100087984, + 2.302923597380779, + 2.288790756005567, + 2.2752889053561534, + 2.2623898802136084, + 2.250066772028685, + 2.23829387289304, + 2.2270466220056035, + 2.21630155452372, + 2.2060362526908253, + 2.196229299141507, + 2.1868602322873785, + 2.1779095036891287, + 2.1693584373282744, + 2.1611891906943277, + 2.1533847176048013, + 2.145928732682899, + 2.1388056774176825, + 2.1320006877379507, + 2.125499563030551, + 2.1192887365398065, + 2.113355247087553, + 2.1076867120526006, + 2.1022713015558105, + 2.0970977137961215, + 2.092155151486069, + 2.0874332993384708, + 2.082922302556797, + 2.0786127462849016, + 2.0744956359735283, + 2.070562378622614, + 2.0668047648594987, + 2.0632149518174363, + 2.059785446777764, + 2.0565090915410997, + 2.05337904749653, + 2.050388781356637, + 2.0475320515291053, + 1.9864209304153415 + ], + "density": [ + 0.04048744608721366, + 0.040991967564575016, + 0.041600133540233744, + 0.04226815318206501, + 0.04300976853695856, + 0.04382292413886765, + 0.044710990818178135, + 0.04566084382265294, + 0.04668132671587653, + 0.04778384269676666, + 0.04894347040181093, + 0.050217658359466025, + 0.05155120707621356, + 0.05298459045905281, + 0.05451328150461624, + 0.05613579339020678, + 0.05786886344594796, + 0.05971555622426197, + 0.06168940973780461, + 0.06379299848100341, + 0.06604924274633829, + 0.06845688699486069, + 0.07104012824009528, + 0.07381877203820006, + 0.07680888578177371, + 0.07999015982750216, + 0.0834079665219863, + 0.08705720329088246, + 0.09096350307186839, + 0.09519183101684933, + 0.09977767252368747, + 0.10473300929035899, + 0.1101772697322425, + 0.11612224522135849, + 0.12263233516381865, + 0.12965535501683825, + 0.13730843623793318, + 0.1456718556947092, + 0.15482815214674314, + 0.1649193448672138, + 0.17609578865161815, + 0.18843317970688814, + 0.20225092445258935, + 0.21769147208669645, + 0.235057725643753, + 0.25450284419119984, + 0.27607481059071376, + 0.3001968017285936, + 0.32721833903790154, + 0.35788158051591024, + 0.3927201787927346, + 0.3419825951457436, + 4.4007276393775686e-05, + 2.118242147089871e-06, + 9.990808414127548e-06, + 2.1760842922898868e-05, + 1.0701015086025121e-05, + 2.0686100893291997e-05, + 1.4102252243972512e-05, + 1.6341843536751136e-05, + 5.920055478903454e-05, + 3.1202822019714874e-05, + 7.006577902969221e-06, + 3.0485999375746203e-110, + 1.351046152877299e-05, + 3.723317857953726e-05, + 1.4621524348837632e-05, + 8.234384469567877e-05, + 4.724949485563587e-07, + 1.3234130610459686e-05, + 1.1250023529740069e-06, + 3.40650350246754e-05, + 8.61113675417637e-05, + 3.4544273659392032e-06, + 1.115441842931324e-05, + 6.750427753043206e-05, + 0.000101851956735232, + 4.1417751607125216e-07, + 1.733113479346441e-05, + 0.00014160026465313052, + 0.00017297702950056632, + 0.00026253696716014923, + 0.0003314571871220419, + 0.0006750813370322345, + 0.0011644314857210615, + 0.0019017827396563996, + 0.0032704725357429448, + 0.006078302645905549, + 0.010855190117619993, + 0.01953392347223397, + 1.8680620540029122e-05, + 7.144970850284283e-05, + 5.542912364767046e-06, + 7.435691322796886e-05, + 0.00016143391343427039, + 0.00020306133691749687, + 0.00028544558695254034, + 0.0008743656306073129, + 0.0024050292905490136, + 0.005775071597051694, + 0.0005348662947240205, + 0.0006539565495507168, + 0.0010281871631532197, + 0.0013522734276574968, + 0.0018752787770719434, + 0.0022794719905617836, + 0.0032833530457091267, + 0.001990519405536644, + 0.005452626266015973, + 0.00677493232228747, + 0.008864117251803522, + 0.011092803666997013, + 0.013852370395545835, + 0.0172470165417693, + 0.020371187929570215, + 0.025505315179375047, + 0.031074048340423287, + 0.037995782307585234, + 0.0465310460856086, + 0.05631424807984447, + 0.06745275939537863, + 0.08017572144032707, + 0.09451365752132886, + 0.11074564103118154, + 0.12885395814665107, + 0.1495571109436204, + 0.17305975617364092, + 0.19900124477774955, + 0.22795492765149622, + 0.26016815091843437, + 0.29558301290421074, + 0.335098447301964, + 0.3787529583978551, + 0.42680395334454346, + 0.47905611444170587, + 0.5362824136346813, + 0.5985500572439016, + 0.6662418422094794, + 0.7392810015960789, + 0.8192667858555257, + 0.9041791387661262, + 0.9967330727340975, + 1.0961554182560838, + 1.202232925311796, + 1.3149305765995665, + 1.435581443569537, + 1.5641755524988206, + 1.6995539260866523, + 1.8438087576258209, + 1.9952089389535912, + 2.1548842155881163, + 2.3225752489437097, + 2.497782026083675, + 2.6799685020901842, + 2.8702102138142576, + 3.067718277784516, + 3.272652118255717, + 3.4841842881068805, + 3.70264957750554, + 3.9265053166806303, + 4.157418486084073, + 4.391689392465598, + 4.632972611931735, + 4.8774029454280745, + 5.12689907629093, + 5.380601479886791, + 5.635293049863927, + 5.894617217838846, + 6.15540931208811, + 6.41854607357553, + 6.681319307917702, + 6.9455701730729045, + 7.20987457968002, + 7.475425480246554, + 7.738667122716035, + 8.00131956130091, + 8.26244637126789, + 8.522348348950743, + 8.779348920756686, + 9.032914882475161, + 9.284651592551567, + 9.532433301321392, + 9.777230760031252, + 10.0174789157339, + 10.254100706292657, + 10.487234177305957, + 10.71545840617981, + 10.939496800352414, + 11.158697017879582, + 11.37314606319091, + 11.58237151830138, + 11.786714430857282, + 11.98677813625825, + 12.1808353928344, + 12.369922844931047, + 12.55375159835506, + 12.733137363800198, + 12.905822998243242, + 13.074456274693999, + 13.237236622767275, + 13.396079440071818, + 13.55086631379442, + 13.69892325592837, + 13.84289554141327, + 13.981971275333507, + 14.117407405854768, + 14.246818740400403, + 14.37203389084361, + 14.493587620099008, + 14.609735497673544, + 14.723242173478098, + 14.831297504428605, + 14.935912532356166, + 15.037379352591227, + 15.133755168376675, + 15.226465373590704, + 15.31670960797513, + 15.402724885287265, + 15.486363892362997, + 15.566439939250113, + 15.642186731562068, + 15.717136638192025, + 15.787527775619653, + 15.85536956371587, + 15.919950135878985, + 15.982642593928864, + 16.043113366621782, + 16.09989366562893, + 16.15516174675919, + 16.207812578733854, + 16.259269128589985, + 16.308251288450823, + 16.354604739329357, + 16.39882478129081, + 16.441254777863826, + 16.482492572267855, + 16.52136186970244, + 16.559074281078065, + 16.594586374436723, + 16.62951333749602, + 16.662596876693172, + 16.693809896725444, + 16.723989679209343, + 16.75356267510578, + 16.779924132332624, + 16.807121709533483, + 16.831205414235242, + 16.856245388846574, + 16.878685435533402, + 16.901672493576328, + 16.92253181927624, + 16.94316073854124, + 16.9612022642688, + 16.979916247897123, + 16.997137492131074, + 17.325004601219867 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 0 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon1.json b/cherab/generomak/plasma/data/core/carbon1.json new file mode 100644 index 00000000..b2d5c389 --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon1.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 0.48421585057396443, + 0.4902687240676583, + 0.49744711278943604, + 0.5051954006896824, + 0.5136620119549894, + 0.5228114951520789, + 0.5326752171258001, + 0.5430889205581807, + 0.5541504144444251, + 0.5659869467934964, + 0.5782948447729008, + 0.5917437089789345, + 0.6056712485911827, + 0.620542945043669, + 0.6362922713807064, + 0.6528879784388633, + 0.670509736386118, + 0.6891758543862906, + 0.7090235821831914, + 0.7300618223316414, + 0.7525298929070332, + 0.7763877953370656, + 0.8018826318051548, + 0.8292062565837163, + 0.8585038018336258, + 0.889508177208562, + 0.9226832625401263, + 0.9579291559694979, + 0.9954837795225133, + 1.0360065994185788, + 1.0798223982450068, + 1.1269947674435963, + 1.1787338800321392, + 1.2350760742733788, + 1.2966027474529238, + 1.3626536962098275, + 1.4343556208152823, + 1.5124235977441491, + 1.597576238405414, + 1.691121912675909, + 1.7944189321292177, + 1.9080331127816117, + 2.0349641993946186, + 2.176361663537031, + 2.3349380858639535, + 2.5118452848013555, + 2.707159678115966, + 2.9246174853883784, + 3.1671420854781687, + 3.4413506012389776, + 3.751694445122891, + 3.2477798067270536, + 0.006362863907386773, + 0.007372973669191416, + 0.009216593289128903, + 0.011548156028595503, + 0.014242714795831715, + 0.01786146488055299, + 0.022262162510133958, + 0.027939765134883766, + 0.03551634957985896, + 0.04443958387088995, + 0.055958579944039195, + 0.07088116012661974, + 0.09018659935564127, + 0.11496387559603737, + 0.14633834787935424, + 0.1875802388118898, + 0.23936517945868985, + 0.30754162306911564, + 0.3958068353549918, + 0.5112101892350656, + 0.6620966618289457, + 0.858660078735121, + 1.1181241421419907, + 1.46073435693994, + 1.911282430745415, + 2.5029504245674246, + 3.2846111449205577, + 4.318608003844665, + 5.687666141161567, + 7.506630045311503, + 9.92851137619441, + 13.163696880564427, + 17.493477080108423, + 23.303174917833566, + 31.091974173382223, + 41.45633739453835, + 55.267703371244075, + 73.72690488904475, + 98.20863422520927, + 131.2870853869013, + 175.83683138019174, + 235.99204766064628, + 316.38571854740593, + 421.7539328588253, + 559.4357994437013, + 738.9164751802173, + 972.3391869076578, + 1275.153777920394, + 1666.7711728749346, + 2171.6699589645095, + 2819.988751814856, + 3648.7031646271603, + 4702.668366138428, + 6035.779233963542, + 7686.47757537614, + 9663.067856260159, + 12007.31337433541, + 14768.024487039194, + 18001.483822967057, + 21772.849505706734, + 26157.550424254878, + 31242.376433647383, + 37126.23247711799, + 43920.55849586252, + 51749.31820504792, + 60748.85541615466, + 71036.10519259654, + 82505.25321944867, + 95172.6035262625, + 109100.32854050657, + 124351.58313892053, + 140991.89397504224, + 159090.80831541793, + 178723.66872728983, + 199973.32015148445, + 222931.63069035482, + 247704.87774357302, + 274402.6314683522, + 303149.57485778275, + 334081.81511881127, + 367346.4298088521, + 403095.30458799424, + 441271.5467435238, + 481872.1263701006, + 525005.3743482265, + 570775.3503247264, + 619280.1323497095, + 670610.2296256337, + 724847.0330594878, + 782061.4947899283, + 842312.7805629332, + 905647.1583655913, + 972096.9884098681, + 1041679.8789890977, + 1114397.9704522684, + 1190237.4178496636, + 1269168.0928057458, + 1351143.3680309465, + 1436100.2152481882, + 1523959.3923222842, + 1614625.8637893011, + 1707989.3899476596, + 1803925.2961875116, + 1902295.3488111356, + 2002948.8264528697, + 2105723.6679099784, + 2210447.758156687, + 2316940.2461408074, + 2425012.996869253, + 2534471.9531783885, + 2645118.713026125, + 2756751.8441781844, + 2869168.440277809, + 2982165.4309753384, + 3095540.9198091724, + 3209095.535627261, + 3322633.485232032, + 3435963.746723633, + 3548904.406828813, + 3661274.607561598, + 3772901.237685582, + 3883621.082668308, + 3993279.51143659, + 4101731.027144971, + 4208839.542291893, + 4314478.668059076, + 4418531.841795906, + 4520892.427679443, + 4621463.716299819, + 4720158.78415636, + 4816900.409340878, + 4911620.80796254, + 5004261.422094195, + 5094772.583239676, + 5183113.162616801, + 5269250.234491738, + 5353158.645119106, + 5434820.618175021, + 5514225.314109624, + 5591368.407651634, + 5666251.643182443, + 5738882.3707925305, + 5809273.161495088, + 5877441.340120579, + 5943408.591682677, + 6007200.515329759, + 6068846.311127089, + 6128378.312740362, + 6185831.708189282, + 6241244.1418844825, + 6294655.385905712, + 6346107.111966662, + 6395642.518902035, + 6443306.118805427, + 6489143.4314059075, + 6533200.829506674, + 6575525.270986898, + 6616164.092233446, + 6655164.89427008, + 6692575.279163696, + 6728442.694407392, + 6762814.329286974, + 6795737.335340715, + 6827258.228432123, + 6857422.965645077, + 6886276.833068685, + 6913864.435669005, + 6940229.566958312, + 6965415.187144678, + 6989463.413916613, + 7012415.368759321, + 7034311.272954711, + 7055190.338080873, + 7075090.793272931, + 7094049.833290375, + 7112103.614543278, + 7129287.29681578, + 7145634.973864277, + 7161179.732926623, + 7175953.608746651, + 7189987.629596161, + 7203311.823403726, + 7215955.222910218, + 7227945.884573181, + 7239310.885176149, + 7250076.380752132, + 7260267.580029734, + 7269908.81296078, + 7279023.497225329, + 7287634.200202345, + 7295762.6574449, + 7303429.782592609, + 7310655.664301383, + 7317459.684297547, + 7323860.396159016, + 7329875.705663031, + 7335522.739642086, + 7340818.009363841, + 7345777.309661405, + 7350415.843108907, + 7354748.154845227, + 7358788.250898356, + 7362549.51046329, + 7180737.62151424 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 1 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon2.json b/cherab/generomak/plasma/data/core/carbon2.json new file mode 100644 index 00000000..c7f6d89a --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon2.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 51.7269475194356, + 51.746952820624216, + 52.12388596214026, + 52.940163304633074, + 54.24294247848471, + 56.07509778838055, + 58.48625229633952, + 61.5368349714206, + 65.3030344598767, + 69.8785578386221, + 75.37529754084595, + 81.93078413627545, + 89.70164187223259, + 98.87428659903192, + 109.65942092421292, + 122.2933234051085, + 137.035367139739, + 154.16006793143808, + 173.94684809895617, + 196.66154529962796, + 222.53238297052988, + 251.7134046195229, + 284.2420121677726, + 319.983444861121, + 358.5598123137554, + 398.9683223412675, + 440.76433555850025, + 484.2490374594113, + 530.1044415099693, + 579.4915040302302, + 634.1713927433501, + 696.6820796978036, + 770.6142544227597, + 860.9672258522206, + 970.0620403589148, + 1099.2314423795724, + 1252.1185630618302, + 1432.9887166910512, + 1646.7948934705498, + 1899.2398766520157, + 2196.8166107464817, + 2546.8186480837194, + 2957.3244606006606, + 3437.1830720402863, + 3995.651317855098, + 4645.819288446255, + 5408.159661965817, + 6304.394233890673, + 7360.988631169922, + 8610.408235852314, + 10092.612861174073, + 11853.166711872651, + 13944.655327903243, + 16470.555060218794, + 19507.094824911295, + 23149.859879749787, + 27528.59209934883, + 32805.44146433598, + 39181.431974834195, + 46906.5301364389, + 56292.49024857901, + 67729.29859868562, + 81704.69552439438, + 98758.342767045, + 119563.79546648111, + 145008.98972599223, + 176209.22723183295, + 214569.82314126665, + 261867.1097143878, + 320353.5889126574, + 392894.6330259606, + 483146.86838287814, + 595791.405155585, + 736839.602081546, + 914034.8394921427, + 1137314.4676054649, + 1417795.5431438887, + 1770046.1195692741, + 2213501.0254945313, + 2773182.8952475805, + 3481388.8206957136, + 4379900.14495483, + 5522876.267226655, + 6980639.120267879, + 8844609.797864616, + 11234098.954064578, + 14292249.250883874, + 18171268.57400767, + 23102344.070654884, + 29391183.874651648, + 37439200.11924598, + 47773938.07168198, + 61088401.78943633, + 78290898.38971062, + 100252654.95122445, + 127678619.24781525, + 161848156.43389606, + 204348916.72694722, + 257122494.6832895, + 322522738.08793396, + 403373666.46606535, + 503023672.34567523, + 625393056.5647471, + 775013474.5069699, + 957060449.3713105, + 1177383070.8421464, + 1437802639.9565027, + 1734246225.369133, + 2068654420.0998182, + 2443569577.2558446, + 2862029131.1002626, + 3327664301.685319, + 3844746919.3145304, + 4418179733.538788, + 5053433114.860162, + 5756438161.127043, + 6533452755.5666065, + 7390922881.304381, + 8331837423.650323, + 9334354678.472628, + 10392166684.043266, + 11504279057.327274, + 12669790141.968946, + 13888035317.62539, + 15158729343.112686, + 16482091274.303825, + 17858939920.92599, + 19290752420.740105, + 20779851078.546913, + 22328898303.12378, + 23941318873.556976, + 25621068937.484055, + 27372541721.972637, + 29200132814.888065, + 31095452170.414516, + 33054347498.016705, + 35079589851.19578, + 37173581351.618835, + 39338307423.93913, + 41575301929.46964, + 43885622896.80891, + 46269837046.91366, + 48728011738.553474, + 51259713312.86814, + 53864011077.12315, + 56539486357.443695, + 59284246173.27229, + 62095941159.639656, + 64971787396.43695, + 67908591808.401474, + 70902780790.1204, + 73950431683.65508, + 77047306712.3454, + 80188888946.12115, + 83370419851.9303, + 86586937966.57417, + 89833318223.03227, + 93104311461.33716, + 96394583667.15906, + 99698754499.39764, + 103011434697.43271, + 106327261990.32256, + 109640935175.03737, + 112947246068.6951, + 116241109095.60986, + 119517588310.54092, + 122771921715.4813, + 125999542772.99667, + 129196099063.11314, + 132357468080.74841, + 135479838062.1428, + 138559536495.15198, + 141593161723.4288, + 144577614224.11197, + 147510062820.63623, + 150387945085.9323, + 153208965707.6481, + 155971093006.19897, + 158672553796.7852, + 161311826790.89548, + 163887634728.62924, + 166398935429.4681, + 168844911944.07657, + 171224961977.36823, + 173538686747.2005, + 175785879428.2105, + 177966513320.9635, + 180080729873.50775, + 182128826668.6315, + 184111245479.87717, + 186028560485.09735, + 187881466715.82117, + 189670768808.52518, + 191397370113.5591, + 193062262208.28482, + 194666514849.56927, + 196211266395.00525, + 197697714711.99057, + 199127108590.06726, + 200500739660.8907, + 201819934831.14236, + 203086049222.54807, + 204300459614.14108, + 205464558376.57272, + 206579747883.16934, + 207647435385.08353, + 208669028330.83698, + 209645930113.7524, + 210579536224.9345, + 211471230792.85892, + 212322383488.85797, + 213134346775.05908, + 213908449029.64093, + 214645996841.59247, + 215348286616.73877, + 216016580696.22003, + 216652114874.8826, + 217256097283.5322, + 217829707477.1932, + 218374095710.14105, + 218890382383.57236, + 219379657649.66318, + 219842981155.79706, + 220281381919.172, + 220695858314.53354, + 221087378166.2643, + 221456878931.67258, + 221805267966.18643, + 222133422860.92596, + 222442191842.04816, + 222732394226.20602, + 223004820922.12497, + 223260234973.31854, + 223499372134.43323, + 223722941475.72876, + 223931626010.58966, + 224126083341.021, + 224306946317.5971, + 224474823708.58456, + 224630300876.42337, + 224773940456.65158, + 224906283038.34857, + 225027847842.1965, + 225139133394.53152, + 225240618195.1795, + 225332761378.8069, + 225416003364.91315, + 225490766500.28265, + 225557455686.99042, + 225616459000.8862, + 225668148294.455, + 225712879788.01535, + 225750994644.923, + 225782819533.8887, + 225808667174.40283, + 214533479339.8047 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 2 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon3.json b/cherab/generomak/plasma/data/core/carbon3.json new file mode 100644 index 00000000..d561f286 --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon3.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 1696833.2929320585, + 1695585.5346261703, + 1703034.1483737943, + 1721256.0083039757, + 1751174.826856844, + 1793462.9777274628, + 1848789.2681748066, + 1917932.0502929946, + 2001843.1487110062, + 2101691.8507644087, + 2218901.8049322264, + 2355187.4339219616, + 2512593.5720948935, + 2693541.143056974, + 2900880.7853058777, + 3137956.567619743, + 3408681.8389850566, + 3717629.590246343, + 4070140.147236769, + 4472449.503360834, + 4931842.339843194, + 5456834.574082767, + 6057391.4069654485, + 6745188.043835769, + 7533894.08882723, + 8438040.68619504, + 9474927.617135428, + 10666144.076443244, + 12037269.181392074, + 13618691.263185747, + 15446615.360481534, + 17564303.70763869, + 20023607.824385516, + 22886777.35580498, + 26222719.857324515, + 30112198.083528586, + 34654282.723995, + 39966924.52730038, + 46190732.40796578, + 53493550.959011845, + 62076004.239125356, + 72178217.79676005, + 84087979.04679102, + 98153684.12489405, + 114790268.27579233, + 134480496.8088131, + 157796732.52584448, + 185454477.7662331, + 218321063.70239368, + 257449759.17177022, + 304122403.0477343, + 359902414.63618606, + 426700895.5275371, + 506859421.1661952, + 603150803.3245813, + 718665327.1439896, + 857491337.6972063, + 1024713797.2305741, + 1226629970.51637, + 1471064146.446006, + 1767770494.5111785, + 2128950440.3712964, + 2569871178.013945, + 3107483535.2911277, + 3762666980.8892303, + 4562658718.166039, + 5541407710.59275, + 6741327176.803194, + 8215528044.0905075, + 10030670665.17434, + 12270612334.574423, + 15041080240.00464, + 18475666848.57919, + 22743531642.40487, + 28059304890.69837, + 34694130667.19102, + 42949504729.17792, + 53215803474.32276, + 66005843073.27365, + 81970232639.91074, + 101935947429.07399, + 126955857114.0498, + 158372211099.3084, + 197897781357.9156, + 247719125699.63535, + 310636487052.79944, + 389922612130.1703, + 488927829361.61676, + 612743572971.3516, + 767966754305.5444, + 963061978933.3938, + 1208880863704.0518, + 1519300911417.147, + 1911986213718.501, + 2402412088320.5693, + 3001219151011.2773, + 3730120534876.667, + 4615158784849.36, + 5686907738665.593, + 6980763900484.745, + 8537026859965.436, + 10400699753349.402, + 12620966467453.045, + 15250350343992.717, + 18343622207917.098, + 21956583495935.363, + 26064693092269.617, + 30544136400340.87, + 35377753295293.17, + 40555945070609.02, + 46074045244408.83, + 51933029405493.94, + 58139222942210.87, + 64703130552471.7, + 71637626192466.19, + 78955815493426.89, + 86668917902746.72, + 94784516303177.33, + 103263931645205.48, + 111787224185099.47, + 120246770335232.78, + 128605747496359.89, + 136833759942592.23, + 144907844298562.9, + 152813152835414.7, + 160543211765841.1, + 168099722187906.75, + 175491935454603.38, + 182735876734993.4, + 189852619551918.88, + 196867432542592.47, + 203808284935431.44, + 210704581917170.66, + 217583961405604.62, + 224394192250872.2, + 231116082117766.88, + 237773792771364.6, + 244387675489041.34, + 250974441603543.8, + 257547405498000.12, + 264116767501773.88, + 270689913774420.62, + 277271717683311.97, + 283864832683560.44, + 290469970659869.75, + 297086162435741.6, + 303710998999869.2, + 310340853188191.1, + 316971082286105.75, + 323596212423999.56, + 330210105837718.44, + 336806112130098.3, + 343377204653890.2, + 349916103076979.94, + 356415383111422.3, + 362867574303987.75, + 369265246706052.7, + 375601087170428.94, + 381867965963014.5, + 388058994328742.4, + 394167573613298.7, + 400187436512475.75, + 406112680998405.06, + 411937797455005.75, + 417657689540276.8, + 423267689282113.25, + 428763566902546.94, + 434141535854502.4, + 439398253542820.25, + 444530818187850.8, + 449536811414876.2, + 454414150553507.06, + 459161179124996.75, + 463776666728802.44, + 468259765082445.1, + 472609990374218.7, + 476827204446105.7, + 480911595099409.4, + 484863655789798.3, + 488684164954596.6, + 492374165189189.6, + 495934942466422.6, + 499368005568998.6, + 502675065882530.7, + 505858017676230.6, + 508918918977704.56, + 511859973130526.25, + 514683511105241.2, + 517391974619713.7, + 519987900109775.94, + 522473903578741.44, + 524852666342586.44, + 527126921677870.1, + 529299442370347.3, + 531373029154628.2, + 533350500028981.56, + 535234680423608.1, + 537028394196253.75, + 538734455425684.3, + 540355660970247.06, + 541894783756889.0, + 543354566764333.56, + 544737717663353.94, + 546046904076213.9, + 547284749417582.06, + 548453829279530.9, + 549556668323423.5, + 550595737642856.25, + 551573452562394.7, + 552492170838372.0, + 553354191229003.4, + 554161752403094.4, + 554917020632621.5, + 555622101348608.25, + 556279072705655.25, + 556889927902278.8, + 557456598671095.75, + 557980955650210.25, + 558464808917578.9, + 558909908669404.6, + 559317946024909.9, + 559690553941324.56, + 560029308223890.9, + 560335728617201.25, + 560611279965183.6, + 560857373428226.7, + 561075367746842.94, + 561266570542317.8, + 561432239645791.94, + 561573584447694.25, + 561691767260778.06, + 561787904690278.2, + 561863069005538.4, + 561918289508186.7, + 561954553892423.7, + 561972809593324.8, + 561973965120028.06, + 561958891370560.56, + 561928422925964.1, + 561883359321281.1, + 561824466291756.2, + 561752476992557.2, + 561668093190769.7, + 561571986428726.75, + 561464799157707.44, + 561347145841483.9, + 561219614029419.6, + 561082765398626.2, + 560937136765227.25, + 560783241064650.5, + 560621568301310.75, + 560452586467449.8, + 560276742431891.2, + 560094462798939.7, + 559906154737711.9, + 519569650787351.1 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 3 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon4.json b/cherab/generomak/plasma/data/core/carbon4.json new file mode 100644 index 00000000..47ad77e9 --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon4.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 46350405566.4054, + 46284237625.31838, + 46377376549.137474, + 46670924446.71948, + 47180482713.78791, + 47915138259.74194, + 48882300889.21657, + 50089810565.15369, + 51547022732.33509, + 53265438570.25678, + 55259122012.65607, + 57545021624.12109, + 60143260320.84436, + 63077429051.469345, + 66374906777.00613, + 70067221925.64133, + 74190466880.22955, + 78785775449.38242, + 83899872865.75154, + 89585708209.65178, + 95903180036.86243, + 102919967269.99362, + 110712479034.47878, + 119366939061.52307, + 128980381012.53004, + 139650356255.3698, + 151493758818.3758, + 164655600080.99313, + 179302730877.29105, + 195627523788.2097, + 213852271426.5203, + 234234433172.45392, + 257072908865.32074, + 282714170388.7059, + 311476125733.1768, + 343728268938.59607, + 379948809932.3586, + 420690633544.8943, + 466594150949.36475, + 518402716039.77686, + 576981020112.0531, + 643337087885.5581, + 718648637928.0991, + 804309566656.8345, + 901936517731.6887, + 1013174699432.6936, + 1139774935542.7197, + 1284159542010.1714, + 1449192365214.294, + 1638263013716.838, + 1855394300765.4873, + 2105373695410.4524, + 2393914584397.565, + 2727854650178.9463, + 3114672632419.614, + 3561244443333.942, + 4078057118720.018, + 4678093148887.286, + 5377140773975.816, + 6194475953440.215, + 7153727019705.466, + 8283975395893.132, + 9620926371866.709, + 11198091896859.557, + 13056165093226.484, + 15251094943219.5, + 17851237199403.375, + 20940359891494.133, + 24621431200712.773, + 29021405474548.914, + 34297285209370.332, + 40643817115878.99, + 48303284204591.195, + 57577989916903.66, + 68846203133507.68, + 82575863200086.94, + 99191653487398.58, + 119279439872784.33, + 143654027332428.78, + 173346839323390.3, + 209668709470650.44, + 254291921482299.34, + 309357550616115.0, + 377616004551139.75, + 462610980484455.0, + 568935169243997.1, + 701805790886232.4, + 865973256198488.8, + 1069469897938848.2, + 1322843184955839.5, + 1639752367136081.5, + 2037895759219286.5, + 2540187857311035.5, + 3176220966949160.5, + 3974318084294743.5, + 4957628931592609.0, + 6166621547030046.0, + 7649980316205009.0, + 9465032414640132.0, + 1.167815021201937e+16, + 1.4364618692277636e+16, + 1.760776889672942e+16, + 2.149721890418564e+16, + 2.612615968793039e+16, + 3.158776631002165e+16, + 3.7970969353840856e+16, + 4.52687863954724e+16, + 5.335944463086585e+16, + 6.2229908295669816e+16, + 7.186462354298768e+16, + 8.224162698271402e+16, + 9.333233640328437e+16, + 1.051001076547748e+17, + 1.1749765655473509e+17, + 1.3046371799766349e+17, + 1.4391954758695259e+17, + 1.5776602862745238e+17, + 1.7188219580417078e+17, + 1.860924287861691e+17, + 2.0000578021076806e+17, + 2.1344414086257683e+17, + 2.2629718005560486e+17, + 2.384692421863735e+17, + 2.498824535514498e+17, + 2.604788577222335e+17, + 2.7022136553746403e+17, + 2.7909348028404227e+17, + 2.8709791375615872e+17, + 2.942534901122749e+17, + 3.005948389926677e+17, + 3.061667080728738e+17, + 3.1102163520002963e+17, + 3.1521700349012704e+17, + 3.188116802063171e+17, + 3.2183961044985395e+17, + 3.2435828220173325e+17, + 3.264375086754881e+17, + 3.2813887595373184e+17, + 3.295162754327499e+17, + 3.306165604397081e+17, + 3.3148025418647725e+17, + 3.321422598062225e+17, + 3.326325410056661e+17, + 3.32976754800993e+17, + 3.3319682689075654e+17, + 3.333114663703342e+17, + 3.333366204791668e+17, + 3.332858725073262e+17, + 3.331707873420125e+17, + 3.3300120975678624e+17, + 3.3278552069020934e+17, + 3.325308566056332e+17, + 3.322432966946062e+17, + 3.319280222669887e+17, + 3.315894522167183e+17, + 3.31231357998432e+17, + 3.308569611179469e+17, + 3.304690157406602e+17, + 3.300698786616609e+17, + 3.296615685611911e+17, + 3.2924581618800666e+17, + 3.288241068686598e+17, + 3.2839771652957235e+17, + 3.2796774223744435e+17, + 3.275351281085987e+17, + 3.271006873058874e+17, + 3.2666512072974803e+17, + 3.2622903291511296e+17, + 3.2579294556561664e+17, + 3.2535730908884525e+17, + 3.249224982684324e+17, + 3.244888569206653e+17, + 3.2405668223940326e+17, + 3.236262244858278e+17, + 3.2319769953504006e+17, + 3.227712934116456e+17, + 3.22347166191095e+17, + 3.219254553603287e+17, + 3.2150627871695424e+17, + 3.210897368740363e+17, + 3.2067591542741376e+17, + 3.202648868338333e+17, + 3.198567120409589e+17, + 3.19451441904167e+17, + 3.190491184198753e+17, + 3.186497758007563e+17, + 3.1825344141450534e+17, + 3.178601366046735e+17, + 3.174698774094042e+17, + 3.1708267519167014e+17, + 3.166985371926715e+17, + 3.1631746701840864e+17, + 3.1593946506808256e+17, + 3.1556452891173523e+17, + 3.151926536235753e+17, + 3.1482383207651834e+17, + 3.1445805520277523e+17, + 3.140953122246476e+17, + 3.1373559085913184e+17, + 3.1337887749952186e+17, + 3.130251573767114e+17, + 3.126744147026179e+17, + 3.123266327978007e+17, + 3.119817942051087e+17, + 3.1163988079097114e+17, + 3.113008738357073e+17, + 3.109647541141207e+17, + 3.106315019674411e+17, + 3.103010973675901e+17, + 3.099735199746016e+17, + 3.096487491879422e+17, + 3.0932676419239776e+17, + 3.0900753972786e+17, + 3.0869105054967526e+17, + 3.083772840437199e+17, + 3.080662189016621e+17, + 3.0775783376675834e+17, + 3.074521072573213e+17, + 3.071490179876445e+17, + 3.068485445867482e+17, + 3.0655066571506963e+17, + 3.0625536007936736e+17, + 3.0596260644602336e+17, + 3.056723836528408e+17, + 3.0538467061958035e+17, + 3.050994463572906e+17, + 3.048166899765865e+17, + 3.0453638069496154e+17, + 3.042584978432657e+17, + 3.039830208713851e+17, + 3.0370992935322266e+17, + 3.0343920299108154e+17, + 3.0317082161944416e+17, + 3.029047652082736e+17, + 3.0264101386582874e+17, + 3.0237954784109037e+17, + 3.021203475258075e+17, + 3.018633934561758e+17, + 3.0160866631429037e+17, + 3.013561469292451e+17, + 3.011058162780258e+17, + 3.0085765548619405e+17, + 3.0061164582834656e+17, + 3.003677687284272e+17, + 3.0012600575984256e+17, + 2.9988633864545626e+17, + 2.996487492574651e+17, + 2.994132196171548e+17, + 2.991797318945194e+17, + 2.989482684078314e+17, + 2.98718811623132e+17, + 2.9849134415361574e+17, + 2.982658487589408e+17, + 2.980423083445655e+17, + 2.9782070596092915e+17, + 2.7247030199525245e+17 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 4 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon5.json b/cherab/generomak/plasma/data/core/carbon5.json new file mode 100644 index 00000000..b62ee60a --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon5.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 161024132134966.47, + 160653503219502.1, + 160507242359572.56, + 160667836607887.75, + 161159174288638.38, + 161989547325367.2, + 163160868851305.97, + 164672538431461.94, + 166523370342109.3, + 168712636114736.53, + 171240653439960.9, + 174109128869520.62, + 177321363766464.66, + 180882384938404.34, + 184799035962934.97, + 189080051019599.56, + 193736124830517.1, + 198779987453727.56, + 204226489773322.7, + 210092703809260.47, + 216398040979350.88, + 223164390920621.16, + 230416283256009.7, + 238181074678749.84, + 246488677361616.25, + 255347696083510.9, + 264777740351847.78, + 274822297666057.56, + 285530597548920.0, + 296958209680815.56, + 309167755802187.0, + 322229722682802.0, + 336223391977405.75, + 351237037130031.44, + 367316468989557.44, + 384512645316222.44, + 402912558128665.9, + 422611765562034.25, + 443715236374775.9, + 466338364535512.5, + 490608107464424.5, + 516664263896114.6, + 544660909569018.25, + 574771346195028.4, + 607182200712998.2, + 641993775762799.1, + 679285757098039.9, + 719329437626251.1, + 762435817884073.2, + 808959351131308.6, + 859304387830781.4, + 913932717589034.6, + 973372418549912.6, + 1038228266498749.4, + 1108965758582219.4, + 1185530665811968.8, + 1268623485069471.2, + 1359148843563016.0, + 1458160473424394.8, + 1566887347887052.8, + 1686765177753372.5, + 1819474480244125.5, + 1966944277299036.2, + 2129644809721581.0, + 2308435409989728.5, + 2505507727432574.0, + 2723405054905318.5, + 2965083298551671.5, + 3233983555918746.0, + 3534118624816150.5, + 3870176221435777.5, + 4247642221714308.5, + 4672947861350066.0, + 5153645539587730.0, + 5698618664034045.0, + 6317959266999076.0, + 7015040256490839.0, + 7797878657778269.0, + 8680238046734384.0, + 9678419565046922.0, + 1.0811736328238992e+16, + 1.2103072275208854e+16, + 1.35795351531977e+16, + 1.5273210653384718e+16, + 1.7222019001933152e+16, + 1.9470878411506988e+16, + 2.206058988419503e+16, + 2.5010246550634016e+16, + 2.8374503295553108e+16, + 3.221862128793027e+16, + 3.6616618204665976e+16, + 4.1651074122496936e+16, + 4.74120543092295e+16, + 5.399462249641901e+16, + 6.143726358298171e+16, + 6.9713794415034904e+16, + 7.88602209992365e+16, + 8.889182371626213e+16, + 9.979072697762856e+16, + 1.1149427025010378e+17, + 1.2388317531927544e+17, + 1.3677125579435957e+17, + 1.4989901351691597e+17, + 1.6293374324877622e+17, + 1.7547842758551754e+17, + 1.8709055180135395e+17, + 1.9727096976715142e+17, + 2.055969980363844e+17, + 2.1184190259838147e+17, + 2.1585866802009814e+17, + 2.175780909076306e+17, + 2.1700505602378323e+17, + 2.142110900199348e+17, + 2.0932504552875306e+17, + 2.02523454416483e+17, + 1.940214986495018e+17, + 1.8406488653204474e+17, + 1.7292237180532278e+17, + 1.609070270228471e+17, + 1.485192170274923e+17, + 1.3607450007252114e+17, + 1.2380272018238762e+17, + 1.1189501743619742e+17, + 1.0050487014189278e+17, + 8.974958274849342e+16, + 7.971243093411478e+16, + 7.04455417952653e+16, + 6.197344649530697e+16, + 5.42978817655598e+16, + 4.7399830330996056e+16, + 4.124606771225955e+16, + 3.579255597379613e+16, + 3.098812762090215e+16, + 2.677841934624266e+16, + 2.313267459153055e+16, + 1.9995837148790244e+16, + 1.7299828713764886e+16, + 1.498424019897001e+16, + 1.2995976233140328e+16, + 1.1288719115750174e+16, + 9822303083643866.0, + 8562060401319240.0, + 7478179071658524.0, + 6545096357996279.0, + 5740941409601873.0, + 5047032901085019.0, + 4447432774883569.5, + 3928554174161130.5, + 3478819914604156.5, + 3088366959685935.5, + 2748792041830096.0, + 2452933605216769.0, + 2194685492053311.5, + 1968838156523490.2, + 1770943605623496.8, + 1597200692861872.5, + 1444357804385388.5, + 1309630363135666.2, + 1190630927952283.8, + 1085309978444810.6, + 991905753181653.0, + 908901750211121.1, + 834990707915531.6, + 769044064015345.5, + 710086044389402.1, + 657271664609963.1, + 609868038549173.2, + 567238482949368.1, + 528828986803599.75, + 494156681915552.7, + 462801819568105.44, + 434394305887636.3, + 408610314143343.06, + 385166603830043.2, + 363814226223222.2, + 344334005110715.2, + 326532652735273.4, + 310239427130823.75, + 295303251427072.06, + 281590227809429.2, + 268981489039979.28, + 257371339064654.56, + 246665641500495.62, + 236780420950391.28, + 227640647282167.97, + 219179177413892.6, + 211335832859303.44, + 204056594461261.25, + 197292898404320.6, + 191001019886732.9, + 185141532760857.62, + 179678835102545.62, + 174580732073686.62, + 169818068643664.22, + 165364405752635.5, + 161195734386968.4, + 157290222775333.8, + 153627992565845.03, + 150190920391755.9, + 146962461710962.6, + 143927494208912.38, + 141072178412878.78, + 138383833459875.8, + 135850826229914.27, + 133462472282759.86, + 131208947226407.88, + 129081207321019.44, + 127070918269517.56, + 125170391272622.27, + 123372525535675.33, + 121670756518192.75, + 120059009296409.5, + 118531668753453.81, + 117083525311571.0, + 115709710318728.34, + 114405725785893.33, + 113167389473178.39, + 111990809312097.34, + 110872360170072.14, + 109808662725540.33, + 108796564236592.3, + 107833121017659.64, + 106915582459347.52, + 106041376431703.06, + 105208095947617.9, + 104413486959420.16, + 103655437183194.61, + 102931965854681.19, + 102241214329040.6, + 101581437448067.73, + 100950995603730.38, + 100348347436377.56, + 99772043108404.7, + 99220718105874.52, + 98693087518270.73, + 98187940757455.16, + 97704136675393.52, + 97240599050432.17, + 96796312405593.72, + 96370318136411.11, + 95961710919354.02, + 95569635379466.4, + 95193282993472.34, + 94831889213877.6, + 94484730792535.0, + 94151123288018.19, + 93830418746832.02, + 93522003537859.14, + 93225296336143.55, + 92939746236089.92, + 92664830994011.1, + 92400055380555.25, + 92144949643312.14, + 91899068064388.0, + 91661987613690.53, + 80088749700966.69 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 5 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/carbon6.json b/cherab/generomak/plasma/data/core/carbon6.json new file mode 100644 index 00000000..4c824909 --- /dev/null +++ b/cherab/generomak/plasma/data/core/carbon6.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 4.9983892951576294e+17, + 4.983879497133105e+17, + 4.967755866140605e+17, + 4.9510985466990605e+17, + 4.9341581359634624e+17, + 4.9170556331941075e+17, + 4.89986255096533e+17, + 4.8826259422505344e+17, + 4.86537891784407e+17, + 4.848145870922532e+17, + 4.8309453749605005e+17, + 4.8137919232444864e+17, + 4.796697037214771e+17, + 4.7796700064309997e+17, + 4.762718401528628e+17, + 4.745848440962568e+17, + 4.7290652600562976e+17, + 4.71237311271517e+17, + 4.695775525472951e+17, + 4.6792754170000864e+17, + 4.6628751920653805e+17, + 4.646576816249229e+17, + 4.63038187590711e+17, + 4.6142916266522874e+17, + 4.598307037636062e+17, + 4.582429064892481e+17, + 4.5666583570714464e+17, + 4.5509951511611744e+17, + 4.535439474786944e+17, + 4.519991158057632e+17, + 4.504649841775356e+17, + 4.4894149825499296e+17, + 4.474285854993411e+17, + 4.4592615597774957e+17, + 4.4443415477814e+17, + 4.42952515097652e+17, + 4.414811279853572e+17, + 4.400198704534008e+17, + 4.3856860516097184e+17, + 4.3712717986695616e+17, + 4.356954267048369e+17, + 4.3427316126968966e+17, + 4.3286018150378886e+17, + 4.314562255858729e+17, + 4.3006107253038886e+17, + 4.28674584595776e+17, + 4.272966235432586e+17, + 4.259268569438572e+17, + 4.2456491049926803e+17, + 4.23210364386893e+17, + 4.218627468670139e+17, + 4.205215267547799e+17, + 4.191861045425703e+17, + 4.178558019143855e+17, + 4.165300783172122e+17, + 4.152089127552762e+17, + 4.138915252178627e+17, + 4.1257692847745683e+17, + 4.112639828847147e+17, + 4.099513696238169e+17, + 4.0863755841905824e+17, + 4.0732076842764634e+17, + 4.059989634281084e+17, + 4.046715679784462e+17, + 4.0333761021624723e+17, + 4.0199477060236544e+17, + 4.006403654855438e+17, + 3.992712831648083e+17, + 3.978839075577596e+17, + 3.9647402693668077e+17, + 3.950367246761433e+17, + 3.935662483399666e+17, + 3.920558527100581e+17, + 3.9049761151576006e+17, + 3.888821916572605e+17, + 3.871989618946227e+17, + 3.854440535692542e+17, + 3.83608792883725e+17, + 3.816785306952975e+17, + 3.7963586382173274e+17, + 3.774600978175744e+17, + 3.751266060486219e+17, + 3.726060693144332e+17, + 3.69863581102174e+17, + 3.668576069457651e+17, + 3.635385522314936e+17, + 3.5986031537030906e+17, + 3.557990082407581e+17, + 3.5129187163841626e+17, + 3.462630238193415e+17, + 3.406247132754573e+17, + 3.342765850451636e+17, + 3.2710558017180826e+17, + 3.189869600468432e+17, + 3.098538368048117e+17, + 2.997091691578431e+17, + 2.884763976878227e+17, + 2.7609146834775462e+17, + 2.6251483616307402e+17, + 2.4774269151380362e+17, + 2.318189253723286e+17, + 2.1484628655656454e+17, + 1.9699454486519517e+17, + 1.7850310137509254e+17, + 1.596756834262952e+17, + 1.4086575956198934e+17, + 1.2257942351734243e+17, + 1.0536119643932915e+17, + 8.945080677375304e+16, + 7.501077534396101e+16, + 6.213221597889738e+16, + 5.083876796328754e+16, + 4.109548571419219e+16, + 3.282073395211112e+16, + 2.58991771483556e+16, + 2.0194309163133372e+16, + 1.5559472132032808e+16, + 1.1846815437393852e+16, + 8918871356669974.0, + 6666488619767974.0, + 4952272490160231.0, + 3656693545661167.5, + 2684245219410593.0, + 1959293800683820.2, + 1422454462508854.5, + 1027495920737416.9, + 738735260847582.1, + 528869852835632.25, + 377246151542587.9, + 268208188769288.22, + 190158286219365.4, + 134519749871650.16, + 94999138095081.17, + 67016838139886.77, + 47388925728580.2, + 33655594842202.37, + 24010931117580.105, + 17211131680797.598, + 12397388136261.445, + 8975069389548.232, + 6531215810353.063, + 4778109970512.45, + 3514609743151.2197, + 2599594904029.761, + 1933687843450.649, + 1446636619284.179, + 1088581422766.1594, + 823990834577.6648, + 627438327748.4506, + 480650770721.95197, + 370438747494.49036, + 287240088062.0348, + 224091191132.38284, + 175897776716.16806, + 138915940488.82767, + 110381427410.77623, + 88243745695.27124, + 70974708829.00201, + 57430010951.75191, + 46748736133.543, + 38280102857.815254, + 31529840224.19217, + 26120769367.413773, + 21763705170.207542, + 18235884795.813892, + 15364908451.932526, + 13016733283.730207, + 11086658506.895058, + 9492528928.261642, + 8169588216.710768, + 7066704039.21469, + 6142970302.393482, + 5365759572.048553, + 4708966109.732259, + 4151558497.112541, + 3676522729.535672, + 3270038222.3734403, + 2920833184.218933, + 2619678032.075184, + 2358985990.8214483, + 2132496850.038897, + 1935025513.2003684, + 1762261779.2242439, + 1610609664.5842507, + 1477058481.0535715, + 1359078978.4888785, + 1254538959.6238554, + 1161635237.9576263, + 1078837828.5027132, + 1004844373.7736144, + 938543019.4518695, + 878981608.3420769, + 825342214.7196075, + 776920444.1419855, + 733107745.1355531, + 693376953.2984082, + 657270432.3485224, + 624389409.1422876, + 594385987.3914045, + 566955686.755834, + 541831025.8088642, + 518777281.941817, + 497587285.0481517, + 478077997.69254464, + 460087497.62123114, + 443471967.2421416, + 428103642.58286554, + 413868620.92078733, + 400665191.04849786, + 388402498.0855996, + 376998969.9038688, + 366381412.1133349, + 356484284.95387477, + 347248113.25952405, + 338619246.9022559, + 330549123.4969663, + 322993975.0574306, + 315913999.852501, + 309273169.99934995, + 303038445.91674054, + 297179891.09289044, + 291670181.76515394, + 286484267.6975641, + 281599400.4746377, + 276994518.5718484, + 272650410.9427122, + 268549411.96215296, + 264675181.73834926, + 261012759.79181898, + 257548445.94359872, + 254269423.21526513, + 251163844.2373063, + 248220801.75397795, + 245430340.81520307, + 242782931.8616595, + 240269948.92623258, + 237883261.9877548, + 235615478.3775228, + 233459505.95959592, + 231408820.5941001, + 229457393.87108496, + 227599572.65190783, + 225830024.39467406, + 224143772.6216756, + 222536269.81091282, + 221003094.60468093, + 219540278.05436647, + 218143888.0390999, + 216810518.66811267, + 215536728.0802908, + 214319215.59609443, + 213155316.59152457, + 212042071.98700914, + 210976871.09200314, + 209957208.5307115, + 173744949.17023906 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "carbon", + "charge": 6 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/electrons.json b/cherab/generomak/plasma/data/core/electrons.json new file mode 100644 index 00000000..7b5452e3 --- /dev/null +++ b/cherab/generomak/plasma/data/core/electrons.json @@ -0,0 +1,1292 @@ +{ + "temperature": [ + 3000.0, + 2998.52312403888, + 2992.7832506358122, + 2982.0621888623136, + 2966.1918094687762, + 2945.2429393424018, + 2919.419338214869, + 2889.003692058303, + 2854.3254277348515, + 2815.7398455505386, + 2773.6139136215174, + 2728.3163262527637, + 2680.2104553864137, + 2629.6493480144745, + 2576.972213977541, + 2522.5020223843676, + 2466.5439345047307, + 2409.3843734189736, + 2351.2905804738834, + 2292.5105439306594, + 2233.273210983751, + 2173.788913597856, + 2114.249953285668, + 2054.8313013065413, + 1995.6913796728331, + 1936.972895410661, + 1878.803706166504, + 1821.2976997951666, + 1764.5556742417446, + 1708.6662070172113, + 1653.7065059997449, + 1599.7432352775288, + 1546.8333113667693, + 1495.024666457186, + 1444.3569764096046, + 1394.8623520995304, + 1346.5659934019332, + 1299.4868056747446, + 1253.6379790455755, + 1209.0275311576331, + 1165.6588143030472, + 1123.5309880785605, + 1082.6394588511619, + 1042.9762874292182, + 1004.5305664061173, + 967.2887686849466, + 931.2350687100197, + 896.351637928748, + 862.6189159894875, + 830.0158591507654, + 798.5201673375811, + 768.1084912334692, + 738.7566207447438, + 710.4396561172668, + 683.1321629276453, + 656.8083121109125, + 631.4420061264298, + 607.0069923036725, + 583.4769643502522, + 560.8256529464521, + 539.0269062941003, + 518.0547614329445, + 497.88350708511757, + 478.4877387378806, + 459.84240662666764, + 441.9228572346464, + 424.7048688815144, + 408.16468193306855, + 392.2790241242251, + 377.0251314515118, + 362.3807650566294, + 348.3242244903237, + 334.83435771552126, + 321.890568180333, + 309.4728192650518, + 297.56163638257, + 286.1381069886319, + 275.1838787369333, + 264.68115599418036, + 254.6126949117557, + 244.96179723353092, + 235.71230300348657, + 226.84858232216044, + 218.35552628735832, + 210.21853724207088, + 202.42351844097678, + 194.95686323627902, + 187.8054438738336, + 180.95659998151527, + 174.3981268234994, + 168.11826338653523, + 162.10568035733561, + 156.34946804381812, + 150.8391242871043, + 145.56454240585458, + 140.51599920963352, + 135.6841431135791, + 131.0599823825858, + 126.63487352955082, + 122.40050988887697, + 118.3489103834026, + 114.47240850017948, + 110.76364148803557, + 107.21553978761827, + 103.82131670259133, + 100.57445831884021, + 97.46871367691406, + 94.49808520145595, + 91.65681939008829, + 88.93939776303986, + 86.34052807377111, + 83.8551357799498, + 81.47835577330721, + 79.20552436620889, + 77.03217153215161, + 74.95401339685759, + 72.9669449761771, + 71.06703315661875, + 69.25050991397345, + 67.51376576524152, + 65.85334344881281, + 64.26593182768406, + 62.74836001033597, + 61.2975916837819, + 59.91071965322365, + 58.58496058269206, + 57.31764993102628, + 56.10623707754045, + 54.948280631735244, + 53.84144392146098, + 52.78349065396557, + 51.77228074433782, + 50.805766305924465, + 49.88198779737891, + 48.999070321097264, + 48.15522006789341, + 47.348720902865914, + 46.57793108752631, + 45.841280133367995, + 45.137265782168555, + 44.46445110844881, + 43.82146173961798, + 43.206983189469376, + 42.61975830080557, + 42.05858479309852, + 41.522312911211856, + 41.00984317133116, + 40.520124200373346, + 40.05215066526151, + 39.604961288570934, + 39.17763694716649, + 38.7692988505653, + 38.379106795872445, + 38.00625749624137, + 37.64998297992401, + 37.30954905707338, + 36.98425385156884, + 36.67342639522852, + 36.37642528187246, + 36.09263737879576, + 35.82147659329382, + 35.56238269198415, + 35.314820170740816, + 35.07827717314717, + 34.852264455457785, + 34.63631439612891, + 34.42998004805659, + 34.23283423173999, + 34.044468667644786, + 33.864493146125206, + 33.69253473331596, + 33.52823701147538, + 33.371259352322355, + 33.221276221963834, + 33.07797651607301, + 32.94106292402577, + 32.81025132076462, + 32.685270185198156, + 32.56586004400546, + 32.45177293975274, + 32.34277192227911, + 32.23863056234819, + 32.13913248661057, + 32.04407093295307, + 31.953248325357347, + 31.866475867422928, + 31.783573153745696, + 31.704367798379554, + 31.62869507963904, + 31.556397600531596, + 31.48732496414222, + 31.421333463316515, + 31.3582857840232, + 31.298050721795224, + 31.24050291068117, + 31.18552256415908, + 31.132995227490305, + 31.082811541013847, + 31.034867013898335, + 30.98906180789872, + 30.94530053067335, + 30.903492038247204, + 30.863549246214866, + 30.82538894930257, + 30.788931648920514, + 30.754101388354496, + 30.720825595258578, + 30.68903493113094, + 30.658663147461834, + 30.62964694826175, + 30.60192585868675, + 30.575442099493, + 30.550140467063347, + 30.52596821875878, + 30.502874963360853, + 30.480812556378506, + 30.459735000005395, + 30.439598347523223, + 30.420360611949583, + 30.401981678749532, + 30.384423222424292, + 30.36764862680968, + 30.35162290891837, + 30.336312646168288, + 30.321685906848675, + 30.307712183679225, + 30.294362330325363, + 30.28160850073722, + 30.26942409119068, + 30.257783684906165, + 30.246662999132866, + 30.23603883458999, + 30.225889027158132, + 30.21619240172184, + 30.206928728068068, + 30.19807867874907, + 30.18962378882196, + 30.181546417381178, + 30.17382971080637, + 30.16645756764611, + 30.159414605066953, + 30.15268612679821, + 30.146258092504468, + 30.1401170885238, + 30.13425029990965, + 30.128645483719644, + 30.123290943494364, + 30.118175504875328, + 30.113288492308037, + 30.108619706785408, + 30.104159404583456, + 30.09989827694405, + 30.095827430664894, + 30.091938369554885, + 30.08822297671646, + 30.00874190034343 + ], + "density": [ + 5e+19, + 4.981243417835291e+19, + 4.960402826870333e+19, + 4.938876378646617e+19, + 4.916988294636239e+19, + 4.894895073575541e+19, + 4.872689168534975e+19, + 4.850431386174099e+19, + 4.82816450569505e+19, + 4.8059200450545025e+19, + 4.783722014076859e+19, + 4.761589167152264e+19, + 4.739536438387333e+19, + 4.7175758996665205e+19, + 4.6957174248046666e+19, + 4.673969164500353e+19, + 4.65233789497414e+19, + 4.630829279642529e+19, + 4.609448069324508e+19, + 4.588198258002084e+19, + 4.567083205796747e+19, + 4.546105737335663e+19, + 4.5252682213529305e+19, + 4.504572635781684e+19, + 4.484020621485682e+19, + 4.463613526993922e+19, + 4.443352446035942e+19, + 4.423238249261527e+19, + 4.403271611221671e+19, + 4.383453033457265e+19, + 4.3637828643671245e+19, + 4.34426131639279e+19, + 4.324888480953614e+19, + 4.305664341484428e+19, + 4.286588784864013e+19, + 4.2676616114717884e+19, + 4.248882544069383e+19, + 4.230251235670968e+19, + 4.2117672765396435e+19, + 4.193430200425467e+19, + 4.175239490142886e+19, + 4.157194582570674e+19, + 4.1392948731452695e+19, + 4.121539719908261e+19, + 4.103928447160288e+19, + 4.0864603487664456e+19, + 4.069134691152288e+19, + 4.051950716024378e+19, + 4.034907642845002e+19, + 4.018004671086943e+19, + 4.0012409822910185e+19, + 3.984615741946379e+19, + 3.968128101211149e+19, + 3.951777198489014e+19, + 3.935562160875532e+19, + 3.919482105486449e+19, + 3.903536140678914e+19, + 3.887723367175341e+19, + 3.872042879098642e+19, + 3.856493764926597e+19, + 3.841075108372399e+19, + 3.82578598919766e+19, + 3.810625483963539e+19, + 3.795592666725145e+19, + 3.780686609673816e+19, + 3.765906383731481e+19, + 3.751251059100921e+19, + 3.736719705775351e+19, + 3.7223113940105036e+19, + 3.708025194762049e+19, + 3.6938601800909865e+19, + 3.6798154235393765e+19, + 3.665890000478603e+19, + 3.652082988432173e+19, + 3.638393467374876e+19, + 3.6248205200099906e+19, + 3.611363232026088e+19, + 3.5980206923348574e+19, + 3.584791993291257e+19, + 3.5716762308972077e+19, + 3.55867250498995e+19, + 3.545779919416078e+19, + 3.532997582192232e+19, + 3.5203246056533017e+19, + 3.5077601065889927e+19, + 3.495303206369484e+19, + 3.4829530310609023e+19, + 3.470708711531262e+19, + 3.4585693835474727e+19, + 3.446534187864e+19, + 3.434602270303676e+19, + 3.422772781831188e+19, + 3.4110448786196742e+19, + 3.3994177221108638e+19, + 3.3878904790691725e+19, + 3.376462321630112e+19, + 3.3651324273433653e+19, + 3.3538999792108577e+19, + 3.3427641657201336e+19, + 3.331724180873318e+19, + 3.320779224211924e+19, + 3.3099285008377905e+19, + 3.299171221430335e+19, + 3.288506602260401e+19, + 3.277933865200853e+19, + 3.2674522377341583e+19, + 3.257060952957118e+19, + 3.246759249582918e+19, + 3.236546371940678e+19, + 3.22642156997264e+19, + 3.21638409922914e+19, + 3.2064332208615055e+19, + 3.1965682016130003e+19, + 3.1867883138079457e+19, + 3.1770928353391223e+19, + 3.1674810496535667e+19, + 3.157952245736852e+19, + 3.1485057180959785e+19, + 3.1391407667409125e+19, + 3.129856697164928e+19, + 3.1206528203237556e+19, + 3.1115284526136713e+19, + 3.1024829158485823e+19, + 3.093515537236158e+19, + 3.0846256493530964e+19, + 3.0758125901195686e+19, + 3.0670757027729146e+19, + 3.058414335840632e+19, + 3.049827843112693e+19, + 3.0413155836133044e+19, + 3.032876921572053e+19, + 3.0245112263945794e+19, + 3.016217872632765e+19, + 3.0079962399544726e+19, + 2.9998457131129012e+19, + 2.9917656819155902e+19, + 2.9837555411930575e+19, + 2.9758146907671814e+19, + 2.9679425354192785e+19, + 2.9601384848579527e+19, + 2.9524019536867484e+19, + 2.9447323613715747e+19, + 2.937129132207994e+19, + 2.9295916952883618e+19, + 2.922119484468826e+19, + 2.9147119383362347e+19, + 2.907368500174985e+19, + 2.9000886179337527e+19, + 2.8928717441922073e+19, + 2.885717336127708e+19, + 2.878624855481938e+19, + 2.8715937685275652e+19, + 2.8646235460349194e+19, + 2.857713663238656e+19, + 2.850863599804493e+19, + 2.844072839795962e+19, + 2.83734087164125e+19, + 2.830667188100075e+19, + 2.8240512862306402e+19, + 2.8174926673567138e+19, + 2.8109908370347393e+19, + 2.8045453050210898e+19, + 2.798155585239442e+19, + 2.7918211957482054e+19, + 2.7855416587081368e+19, + 2.779316500350069e+19, + 2.773145250942718e+19, + 2.7670274447607374e+19, + 2.7609626200527954e+19, + 2.7549503190099005e+19, + 2.748990087733828e+19, + 2.7430814762057028e+19, + 2.7372240382547927e+19, + 2.7314173315273884e+19, + 2.725660917455944e+19, + 2.719954361228283e+19, + 2.714297231757104e+19, + 2.7086891016495333e+19, + 2.7031295471769723e+19, + 2.697618148245014e+19, + 2.692154488363691e+19, + 2.686738154617714e+19, + 2.6813687376370782e+19, + 2.6760458315677737e+19, + 2.67076903404267e+19, + 2.665537946152642e+19, + 2.660352172417858e+19, + 2.65521132075925e+19, + 2.65011500247021e+19, + 2.645062832188477e+19, + 2.6400544278682247e+19, + 2.6350894107522163e+19, + 2.6301674053443994e+19, + 2.625288039382521e+19, + 2.620450943810967e+19, + 2.6156557527538237e+19, + 2.610902103488069e+19, + 2.6061896364171543e+19, + 2.6015179950445117e+19, + 2.5968868259474686e+19, + 2.5922957787512246e+19, + 2.5877445061031244e+19, + 2.5832326636470903e+19, + 2.578759909998139e+19, + 2.57432590671733e+19, + 2.5699303182867214e+19, + 2.5655728120845242e+19, + 2.561253058360556e+19, + 2.5569707302117368e+19, + 2.5527255035580244e+19, + 2.5485170571182055e+19, + 2.544345072386111e+19, + 2.54020923360703e+19, + 2.5361092277541216e+19, + 2.5320447445052424e+19, + 2.5280154762197893e+19, + 2.5240211179157164e+19, + 2.520061367247062e+19, + 2.5161359244810146e+19, + 2.5122444924759847e+19, + 2.5083867766590497e+19, + 2.5045624850041692e+19, + 2.500771328010387e+19, + 2.4970130186799833e+19, + 2.493287272497215e+19, + 2.489593807406909e+19, + 2.485932343793488e+19, + 2.482302604459721e+19, + 2.478704314606391e+19, + 2.475137201811416e+19, + 2.471600996009324e+19, + 2.4680954294713426e+19, + 2.464620236785044e+19, + 2.4611751548345704e+19, + 2.45775992278063e+19, + 2.4543742820412535e+19, + 2.451017976272195e+19, + 2.447690751347609e+19, + 2.444392355341035e+19, + 2.4411225385064636e+19, + 2.4378810532594893e+19, + 2.434667654158714e+19, + 2.4314820978872984e+19, + 2.4283241432347005e+19, + 2.42519355107831e+19, + 2.422090084365806e+19, + 2.419013508096743e+19, + 2.415963589305566e+19, + 2.4129400970434146e+19, + 2.4099428023610917e+19, + 2.406971478291697e+19, + 2.4040258998335894e+19, + 2.4011058439331717e+19, + 2.3982110894683005e+19, + 2.395341417231851e+19, + 2.0670269989725e+19 + ], + "vtor": [ + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10, + 1e-10 + ], + "vpol": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/hydrogen0.json b/cherab/generomak/plasma/data/core/hydrogen0.json new file mode 100644 index 00000000..754940c0 --- /dev/null +++ b/cherab/generomak/plasma/data/core/hydrogen0.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2240.0, + 2236.4504489807964, + 2226.309382068473, + 2210.299052071184, + 2189.0904205810994, + 2163.3046865525707, + 2133.515194552534, + 2100.249595432215, + 2063.992162943028, + 2025.1861932135298, + 1984.2364319190758, + 1941.5114877758033, + 1897.3462016693657, + 1852.0439490190533, + 1805.87885942599, + 1759.0979426720367, + 1711.9231140372276, + 1664.5531149286294, + 1617.1653271484834, + 1569.917480919263, + 1522.949258141365, + 1476.3837933749978, + 1430.3290757822574, + 1384.8792557946174, + 1340.1158606300705, + 1296.1089230088292, + 1252.9180275356005, + 1210.5932792532092, + 1169.1761988453034, + 1128.7005488900284, + 1089.193095453988, + 1050.674309176122, + 1013.1590098321976, + 976.6569581985458, + 941.1733988535289, + 906.7095573708474, + 873.2630951733505, + 840.828525131861, + 809.3975908125881, + 778.9596121003383, + 749.5017997540461, + 721.0095412868372, + 693.4666604055054, + 666.8556520941395, + 641.1578952839868, + 616.3538449164151, + 592.4232050780837, + 569.3450847669792, + 547.0981377346717, + 525.6606877437563, + 505.0108404797533, + 485.1265832634224, + 465.9858736222754, + 447.56671769870127, + 429.8472393962903, + 412.8057410953542, + 396.4207567029529, + 380.6710977417666, + 365.53589312550383, + 350.9946232160131, + 337.02714870861604, + 323.61373484709463, + 310.7350714280776, + 298.37228901601867, + 286.50697175433055, + 275.12116712535635, + 264.1973929815059, + 253.7186421419, + 243.66838482307517, + 234.0305691485461, + 224.78961996016457, + 215.93043613409628, + 207.4383865857546, + 199.29930513103795, + 191.4994843556246, + 184.02566862976738, + 176.86504639289873, + 170.00524182033894, + 163.43430597337053, + 157.14070752386905, + 151.113323135452, + 145.34142757467652, + 139.81468361812196, + 134.52313181416025, + 129.457180151816, + 124.60759368327163, + 119.96548414126156, + 115.52229958776202, + 111.26981412599169, + 107.20011770374389, + 103.30560603245968, + 99.57897064317038, + 96.01318909747529, + 92.60151536903889, + 89.33747040868218, + 86.21483290395201, + 83.22763024211139, + 80.37012968371364, + 77.63682975236918, + 75.02245184488561, + 72.52193206471382, + 70.13041328051168, + 67.84323741064236, + 65.6559379335423, + 63.564232623128014, + 61.56401650771693, + 59.65135505035933, + 57.82247754794227, + 56.07377074599886, + 54.40177266575983, + 52.80316663966101, + 51.27477555125246, + 49.81355627521912, + 48.416594313043035, + 47.081098619687594, + 45.80439661656459, + 44.5839293859712, + 43.417247042115314, + 42.302004273818525, + 41.23595605397633, + 40.216953510850516, + 39.24293995630613, + 38.311947066125406, + 37.422091207594626, + 36.571569909608, + 35.75865847061232, + 34.98170669978367, + 34.23913578692253, + 33.52943529662951, + 32.85116028243641, + 32.20292851664732, + 31.583417831760713, + 30.99136356943732, + 30.425556133091256, + 29.88483864028179, + 29.36810467119799, + 28.87429610962729, + 28.40240107291426, + 27.951451927516537, + 27.52052338687281, + 27.108730688404705, + 26.715227846572123, + 26.33920597900726, + 25.979891702853777, + 25.636545598528727, + 25.30846073823038, + 24.994961276600144, + 24.69540110104437, + 24.409162539308983, + 24.13565512198808, + 23.874314397731172, + 23.624600798996898, + 23.385998556284218, + 23.15801465884384, + 22.940177859954957, + 22.73203772492011, + 22.533163720006204, + 22.343144340625674, + 22.161586277118445, + 21.988113616562465, + 21.822367079097155, + 21.664003287311004, + 21.51269406729655, + 21.36812578003317, + 21.229998681815967, + 21.098026312495502, + 20.971934910344643, + 20.851462852421577, + 20.736360119335554, + 20.626387783375975, + 20.521317519002128, + 20.420931134733753, + 20.32502012552446, + 20.233385244735498, + 20.145836094864723, + 20.06219073622283, + 19.982275312781507, + 19.90592369444775, + 19.832977135057188, + 19.763283945401255, + 19.696699180637957, + 19.633084341458513, + 19.572307088415513, + 19.51424096883524, + 19.45876515576827, + 19.40576419845266, + 19.355127783786383, + 19.30675050832906, + 19.26053166037145, + 19.21637501163307, + 19.174188618164745, + 19.133884630054332, + 19.09537910954868, + 19.05859185722216, + 19.023446245839033, + 18.989869061570744, + 18.957790352245382, + 18.927143282320497, + 18.897863994281074, + 18.86989147618248, + 18.843167435065453, + 18.817636175985687, + 18.79324448640893, + 18.769941525736378, + 18.747678719732868, + 18.726409659641607, + 18.706090005778155, + 18.686677395406114, + 18.668131354704837, + 18.650413214648612, + 18.633486030623327, + 18.617314505615823, + 18.60186491681852, + 18.587105045495814, + 18.573004109970697, + 18.55953270159014, + 18.546662723539878, + 18.53436733238102, + 18.522620882187194, + 18.51139887116874, + 18.500677890671284, + 18.49043557644487, + 18.480650562082833, + 18.471302434532834, + 18.46237169158913, + 18.453839701278447, + 18.445688663053495, + 18.437901570715436, + 18.430462176988556, + 18.423354959672093, + 18.416565089300423, + 18.41007839824483, + 18.403881351191185, + 18.39796101693386, + 18.392305041426237, + 18.386901622033136, + 18.381739482930183, + 18.376807851599832, + 18.372096436376008, + 18.367595404988766, + 18.36329536406628, + 18.359187339550697, + 18.355262757987074, + 18.351513428646914, + 18.34793152644875, + 18.344509575640426, + 18.341240434209354, + 18.338117278988225, + 18.335133591424395, + 18.3322831439848, + 18.329559987167194, + 18.326958437090312, + 18.324473063638234, + 18.32209867913344, + 18.319830327515373, + 18.271305784128668 + ], + "density": [ + 204620001816.96503, + 203995340626.48117, + 203580415549.07077, + 203478214247.57297, + 203715877183.5095, + 204301348415.06805, + 205234420738.4918, + 206511241598.7883, + 208126529002.83133, + 210074752469.19244, + 212350782448.41467, + 214950246524.57938, + 217869717181.2876, + 221106800859.7011, + 224660168985.34265, + 228529555375.00076, + 232715734933.54498, + 237220492826.1153, + 242046589785.09818, + 247197727005.0989, + 252678512684.92447, + 258494431389.8997, + 264651816845.81558, + 271157828420.81525, + 278020413999.39655, + 285247320715.9104, + 292847439717.963, + 300831346075.9571, + 309210473286.05414, + 317997118815.822, + 327204455041.3841, + 336846543548.0578, + 346938352650.2804, + 357495722378.11005, + 368531748603.2294, + 380060992884.0296, + 392101369277.8834, + 404671758538.71185, + 417792030624.14746, + 431483075722.2703, + 445766837408.0821, + 460666347857.28577, + 476205765045.6582, + 492411668158.4271, + 509310082743.527, + 526922958785.0509, + 545270668436.08124, + 564382532826.562, + 584289351347.6514, + 605023347803.2103, + 626618224577.489, + 649109218441.2275, + 672533157882.3363, + 696928521829.5643, + 722330392907.0331, + 748761752833.0225, + 776263316106.7876, + 804879690534.3215, + 834657513313.9681, + 865645526272.6191, + 897894651906.1387, + 931458069962.6783, + 966390478339.3801, + 1002713570323.5283, + 1040458926521.3761, + 1079684516540.4954, + 1120450776084.2368, + 1162820677057.6262, + 1206859796754.8408, + 1252636384433.044, + 1300221424799.789, + 1349688697963.7998, + 1401114835449.2217, + 1454579371952.6218, + 1510164792644.5955, + 1567952481060.059, + 1627931114636.4526, + 1690139925687.1553, + 1754669353636.4456, + 1821613533247.6384, + 1891070371220.4712, + 1963141624989.376, + 2037932986753.0464, + 2115554176680.7764, + 2196119050183.666, + 2279748776152.387, + 2366500641895.066, + 2456287369484.3516, + 2549234395774.7485, + 2645490036768.047, + 2745210502439.3457, + 2848560231576.2715, + 2955712221053.107, + 3066848216768.975, + 3181983423138.0234, + 3300978418418.4097, + 3423964172116.361, + 3551081532136.3022, + 3682471863828.1035, + 3818274934361.4946, + 3958626240909.5186, + 4103653876103.972, + 4253475165354.2246, + 4408193462719.133, + 4567895603650.418, + 4732650517791.943, + 4902247847002.056, + 5076233402000.4795, + 5254598646625.475, + 5437349446630.464, + 5624489405383.76, + 5816019959574.812, + 6011939258098.727, + 6212239938237.438, + 6416906050351.422, + 6625909469387.242, + 6839206174537.927, + 7056732786183.625, + 7278311975421.752, + 7503119857298.018, + 7730869714380.9375, + 7961427820158.273, + 8194643345174.029, + 8430349935940.838, + 8668367358140.194, + 8908503068344.902, + 9150553621597.744, + 9394305867677.299, + 9639552766370.97, + 9886049104086.564, + 10133557734495.324, + 10381834826485.693, + 10630630439847.912, + 10879678469431.771, + 11128195788042.75, + 11375596059217.254, + 11621622648260.379, + 11866019968617.504, + 12108534650895.979, + 12348916749575.322, + 12586920956579.773, + 12822307795224.22, + 13054844772251.508, + 13284307469611.012, + 13510480561149.14, + 13733158742539.867, + 13952147565575.44, + 14167264170431.275, + 14378337911729.918, + 14585210876204.7, + 14787738291529.992, + 14985788827443.982, + 15179244791671.332, + 15368002224351.652, + 15551970895709.932, + 15731074212570.957, + 15905249040010.746, + 16074445444998.629, + 16238626369271.07, + 16397767238935.273, + 16551855518444.57, + 16700890216574.428, + 16844881351954.912, + 16983849385509.26, + 17117824626881.824, + 17246846621603.266, + 17370963525334.229, + 17490231471110.625, + 17604713935017.176, + 17714481105258.8, + 17819608453161.367, + 17920177950565.527, + 18016276628873.59, + 18107995459063.83, + 18195429156535.652, + 18278675646852.23, + 18357835555954.918, + 18433011726092.445, + 18504308758387.65, + 18571832582598.63, + 18635690054375.332, + 18695988580024.676, + 18752835768579.754, + 18806339110761.88, + 18856605684254.773, + 18903741884561.38, + 18947853180595.484, + 18989043894059.926, + 19027417001587.02, + 19063073958565.055, + 19096114543521.96, + 19126636721924.43, + 19154736528236.87, + 19180507965077.684, + 19204042918329.66, + 19225431087078.62, + 19244759927277.656, + 19262114608067.395, + 19277577979726.01, + 19291230552256.516, + 19303150483665.746, + 19313413577033.516, + 19322093285526.824, + 19329260724543.79, + 19334984690237.266, + 19339331683709.87, + 19342365940211.094, + 19344149462728.09, + 19344742059393.53, + 19344201384180.91, + 19342582980399.023, + 19339940326544.8, + 19336324363046.41, + 19331784091828.13, + 19326368145671.793, + 19320122234851.223, + 19313090256097.117, + 19305314345120.19, + 19296834929279.25, + 19287690780209.77, + 19277919066210.582, + 19267555404250.375, + 19256633911438.43, + 19245187255846.457, + 19233246706569.15, + 19220842182934.86, + 19208002302790.24, + 19194754429784.965, + 19181124719614.805, + 19167138165162.6, + 19152818640516.805, + 19138188943830.562, + 19123270839007.04, + 19108085096194.83, + 19092651531087.504, + 19076989043026.625, + 19061115651909.043, + 19045048533903.996, + 19028804056001.64, + 19012397809386.355, + 18995844641670.94, + 18979158687998.574, + 18962353401040.9, + 18945441579905.883, + 18928435397987.637, + 18911346429777.703, + 18894185676666.883, + 18876963591763.613, + 18859690103748.47, + 18842374639807.22, + 18825026147656.855, + 18807653116696.703, + 18790263598309.477, + 18772865225350.633, + 18755465230832.047, + 16384843817946.543 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "hydrogen", + "charge": 0 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/hydrogen1.json b/cherab/generomak/plasma/data/core/hydrogen1.json new file mode 100644 index 00000000..a23d3c11 --- /dev/null +++ b/cherab/generomak/plasma/data/core/hydrogen1.json @@ -0,0 +1,1294 @@ +{ + "temperature": [ + 2800.0, + 2795.6140361201715, + 2783.083337747409, + 2763.3003486616526, + 2737.094135213008, + 2705.2322750926364, + 2668.4232152414806, + 2627.3189416606197, + 2582.5178419123567, + 2534.5676700076638, + 2483.96854551181, + 2431.1759357517954, + 2376.6035832043513, + 2320.6263503869714, + 2263.5829625419237, + 2205.7786346035323, + 2147.4875737595085, + 2088.955352654985, + 2030.4011511730957, + 1972.019866937452, + 1913.9840963599631, + 1856.4459893126868, + 1799.5389814222144, + 1743.3794086390585, + 1688.0680091781107, + 1633.691318203845, + 1580.3229607811295, + 1528.0248486579108, + 1476.8482864126447, + 1426.8349924056063, + 1378.018039834137, + 1330.4227230192646, + 1284.0673538547676, + 1238.963993137122, + 1195.1191212721988, + 1152.5342526267314, + 1111.2064975634503, + 1071.1290759712253, + 1032.291785877979, + 994.6814305162284, + 958.2822070001829, + 923.0760595703174, + 889.0430001669228, + 856.1613989086177, + 824.4082468755387, + 793.759393429837, + 764.1897601482588, + 735.6735332927431, + 708.1843366049751, + 681.6953860793737, + 656.1796282458071, + 631.6098633780208, + 607.9588549360606, + 585.1994264504128, + 563.3045469619041, + 542.2474060441687, + 522.0014793543342, + 502.5405855822321, + 483.8389355984452, + 465.8711745366052, + 448.61241748523827, + 432.0382794087496, + 416.124899865624, + 400.8489630442867, + 386.1877135930409, + 372.11896867986945, + 358.6211266803817, + 345.67317285760663, + 333.2546823654665, + 321.34582087841227, + 309.927343122692, + 298.9805895598673, + 288.4874814503533, + 278.4305145037626, + 268.79275130356683, + 259.5578126759042, + 250.7098681561356, + 242.23362569190442, + 234.11432070782254, + 226.33770464446184, + 218.89003307292606, + 211.75805347586066, + 204.92899277624957, + 198.39054468665884, + 192.13085694367678, + 186.13851848507585, + 180.40254662065936, + 174.91237424177845, + 169.65783710907806, + 164.62916125309604, + 159.8169505178761, + 155.21217427370195, + 150.80615532139907, + 146.59055800733688, + 142.55737656528729, + 138.69892369858735, + 135.00781941365733, + 131.47698011372418, + 128.09960795968092, + 124.86918050324817, + 121.77944059606116, + 118.82438657692074, + 115.99826273821829, + 113.29555007145385, + 110.71095729082082, + 108.23941213297381, + 105.87605293038021, + 103.6162204549953, + 101.45545002847112, + 99.38946389462029, + 97.41416384945612, + 95.52562412379939, + 93.72008451315051, + 91.99394374930452, + 90.34375310799985, + 88.7662102467457, + 87.25815326688075, + 85.81655499383113, + 84.43851746950027, + 83.12126665071017, + 81.86214730760918, + 80.65861811600642, + 79.5082469376184, + 78.408706282292, + 77.35776894632689, + 76.35330382111951, + 75.39327186643368, + 74.47572224272074, + 73.59878859700572, + 72.76068549699494, + 71.95970500815942, + 71.19421340869229, + 70.46264803735373, + 69.7635142693571, + 69.0953826155724, + 68.45688594046604, + 67.84671679431725, + 67.26362485539421, + 66.70641447789761, + 66.17394234161189, + 65.6651151993376, + 65.1788877182984, + 64.7142604118468, + 64.27027765791827, + 63.84602580079542, + 63.440631332874815, + 63.05325915323381, + 62.68311089991544, + 62.32942335295714, + 61.9914669052981, + 61.66854409880293, + 61.359988222742814, + 61.065161972176995, + 60.78345616376737, + 60.51428850665944, + 60.2571024261477, + 60.01136593793548, + 59.776570570881596, + 59.55223033620793, + 59.33788074122536, + 59.13307784570519, + 58.937397359105915, + 58.75043377692946, + 58.571799554551646, + 58.40112431694312, + 58.23805410275451, + 58.08225064130303, + 57.93339066106313, + 57.7911652283102, + 57.65527911463285, + 57.525450192074885, + 57.40140885472106, + 57.28289746559213, + 57.16966982775895, + 57.06149067863122, + 56.95813520642253, + 56.85938858783372, + 56.765045546033065, + 56.674909928059456, + 56.588794300802036, + 56.50651956475268, + 56.427914584755875, + 56.35281583702141, + 56.281067071686564, + 56.21251899025332, + 56.14702893725086, + 56.08446060550164, + 56.02468375439783, + 55.96757394061782, + 55.91301226073971, + 55.8608851052287, + 55.81108392330204, + 55.76350499819346, + 55.718049232360165, + 55.67462194219673, + 55.63313266183696, + 55.593494955645, + 55.55562623901411, + 55.51944760710454, + 55.484883671174465, + 55.45186240216659, + 55.42031498123234, + 55.390175656886, + 55.361381608497936, + 55.333872815845915, + 55.307591934457406, + 55.282484176486456, + 55.258497196881336, + 55.23558098460842, + 55.21368775870917, + 55.19277186897538, + 55.17278970103895, + 55.153699585681665, + 55.13546171217539, + 55.11803804547773, + 55.101392247108336, + 55.08548959954608, + 55.070296933989404, + 55.05578256132999, + 55.04191620619953, + 55.028668943950365, + 55.01601314044173, + 55.003922394507015, + 54.99237148298145, + 54.98133630817787, + 54.970793847702375, + 54.96072210650347, + 54.951100071057624, + 54.941907665596375, + 54.93312571028218, + 54.9247358812481, + 54.91672067241873, + 54.90906335903125, + 54.90174796278291, + 54.8947592185312, + 54.888082542479076, + 54.881704001777535, + 54.87561028548313, + 54.869788676811275, + 54.86422702662521, + 54.858913728107794, + 54.85383769256265, + 54.84898832629396, + 54.8443555085177, + 54.83992957025756, + 54.83570127418218, + 54.83166179534185, + 54.82780270276455, + 54.824115941872016, + 54.82059381768116, + 54.81722897875463, + 54.81401440186672, + 54.81094337735412, + 54.80800949511986, + 54.80520663126194, + 54.7452478101525 + ], + "density": [ + 4.7000161116838035e+19, + 4.682128787215119e+19, + 4.662255270837901e+19, + 4.6417278208422126e+19, + 4.620855584730208e+19, + 4.5997877921630495e+19, + 4.5786126032580125e+19, + 4.557388001473378e+19, + 4.536154779862328e+19, + 4.514942993087138e+19, + 4.4937755363011396e+19, + 4.472670293288807e+19, + 4.451641505013135e+19, + 4.430700683219043e+19, + 4.409857243769369e+19, + 4.38911895956297e+19, + 4.368492293000609e+19, + 4.347982645523464e+19, + 4.327594548538098e+19, + 4.3073318119596106e+19, + 4.287197641493933e+19, + 4.267194732453969e+19, + 4.247325345683865e+19, + 4.227591369649927e+19, + 4.207994371652285e+19, + 4.18853563809563e+19, + 4.169216213518003e+19, + 4.150036932127918e+19, + 4.130998441718659e+19, + 4.1121012257462985e+19, + 4.093345622347993e+19, + 4.074731840811801e+19, + 4.056259975913072e+19, + 4.037930020368103e+19, + 4.019741870571682e+19, + 4.001695340964126e+19, + 3.983790175600905e+19, + 3.966026052904146e+19, + 3.948402592421399e+19, + 3.930919360878721e+19, + 3.91357587761679e+19, + 3.896371619490987e+19, + 3.879306025305037e+19, + 3.862378038885082e+19, + 3.8455872756913046e+19, + 3.828933304946574e+19, + 3.812415434913541e+19, + 3.796032969592534e+19, + 3.779785195844539e+19, + 3.763671385931872e+19, + 3.747690800145458e+19, + 3.731842689377711e+19, + 3.716126297679983e+19, + 3.700540864846064e+19, + 3.6850856060966724e+19, + 3.6697596750521393e+19, + 3.6545622931847754e+19, + 3.63949269560757e+19, + 3.624550126620646e+19, + 3.6097338433711747e+19, + 3.5950431200155054e+19, + 3.580477252521384e+19, + 3.5660355599881843e+19, + 3.551717212816437e+19, + 3.5375214199829737e+19, + 3.523447525545721e+19, + 3.509494910531205e+19, + 3.4956630001189454e+19, + 3.4819512721075306e+19, + 3.4683592669405524e+19, + 3.4548865996283527e+19, + 3.44153297397094e+19, + 3.4282981995701944e+19, + 3.4151822122170814e+19, + 3.402185098353278e+19, + 3.389307085841355e+19, + 3.3765477248415257e+19, + 3.36390706526775e+19, + 3.3513857808022893e+19, + 3.3389848457318638e+19, + 3.326705595137885e+19, + 3.3145497973701267e+19, + 3.3025197409857077e+19, + 3.2906183384364196e+19, + 3.27884924868037e+19, + 3.2672168857369743e+19, + 3.2557253870071173e+19, + 3.2443771047542505e+19, + 3.233178288004695e+19, + 3.222136754653978e+19, + 3.2112618260038386e+19, + 3.2005644930339512e+19, + 3.190057544359449e+19, + 3.179755610169293e+19, + 3.169667413331649e+19, + 3.1597941789312086e+19, + 3.1501468231219503e+19, + 3.1407358392679612e+19, + 3.1315701402899493e+19, + 3.122655976363501e+19, + 3.113995725177193e+19, + 3.1055866895317287e+19, + 3.0974201050364137e+19, + 3.0894806075100783e+19, + 3.0817464043937587e+19, + 3.074190310163784e+19, + 3.0667602748084875e+19, + 3.059388912084078e+19, + 3.0520502154565943e+19, + 3.0447256542588035e+19, + 3.0374032039505535e+19, + 3.0300769320810455e+19, + 3.0227459649422733e+19, + 3.0154130399978762e+19, + 3.0080828724751536e+19, + 3.00076055212318e+19, + 2.9934501515846365e+19, + 2.986153682499915e+19, + 2.9788666487587082e+19, + 2.9715601389175697e+19, + 2.9642293974170833e+19, + 2.9568746794147893e+19, + 2.9494953117879144e+19, + 2.942090418993194e+19, + 2.9346594991144505e+19, + 2.927202828423032e+19, + 2.919721694348071e+19, + 2.912218473740004e+19, + 2.9046961655055204e+19, + 2.897159522535346e+19, + 2.889613573005297e+19, + 2.8820638275299803e+19, + 2.8745160581640344e+19, + 2.866976018562403e+19, + 2.859446819509753e+19, + 2.8519338651384783e+19, + 2.8444437402203193e+19, + 2.8369821546424705e+19, + 2.8295540143670977e+19, + 2.822163499192403e+19, + 2.8148141418240123e+19, + 2.8075089045501837e+19, + 2.800250251202477e+19, + 2.7930402131116364e+19, + 2.785880448496708e+19, + 2.7787722952184242e+19, + 2.7717168171436e+19, + 2.764714844554494e+19, + 2.757767009134292e+19, + 2.750873774095989e+19, + 2.744035460018579e+19, + 2.7372522669268402e+19, + 2.730524293109751e+19, + 2.7238515511248703e+19, + 2.7172339813867467e+19, + 2.710671463689212e+19, + 2.704163826966439e+19, + 2.697710857556336e+19, + 2.6913123061929193e+19, + 2.684967893921741e+19, + 2.678677317103723e+19, + 2.6724402516482183e+19, + 2.666256356594527e+19, + 2.6601252771429528e+19, + 2.6540466472208925e+19, + 2.648020091656107e+19, + 2.642045228018025e+19, + 2.6361216681785897e+19, + 2.6302490196357964e+19, + 2.6244268866366194e+19, + 2.6186547167773954e+19, + 2.6129321911080337e+19, + 2.607258987087877e+19, + 2.6016347040942785e+19, + 2.596058941784374e+19, + 2.5905313005155705e+19, + 2.585051381702677e+19, + 2.5796187881207525e+19, + 2.5742331241620062e+19, + 2.568893996053235e+19, + 2.563601012039743e+19, + 2.5583537825404264e+19, + 2.5531519202783388e+19, + 2.5479950403901665e+19, + 2.5428827605176574e+19, + 2.5378147008834527e+19, + 2.5327904843536536e+19, + 2.5278097364889854e+19, + 2.522872085586001e+19, + 2.5179771627098292e+19, + 2.5131246017196376e+19, + 2.5083140392876634e+19, + 2.5035451149129798e+19, + 2.498817470930402e+19, + 2.4941307525154173e+19, + 2.4894846076854927e+19, + 2.484878687298473e+19, + 2.4803126450483405e+19, + 2.475786137458537e+19, + 2.4712988238736052e+19, + 2.466850366448876e+19, + 2.462440430138878e+19, + 2.4580686826843484e+19, + 2.4537347945982157e+19, + 2.4494384391507644e+19, + 2.445179292353768e+19, + 2.4409570329441386e+19, + 2.4367713423668306e+19, + 2.432621904757395e+19, + 2.428508406924054e+19, + 2.4244305383293637e+19, + 2.420387991071655e+19, + 2.4163804063775474e+19, + 2.4124074299375776e+19, + 2.4084688695258206e+19, + 2.4045644275574723e+19, + 2.4006938089881907e+19, + 2.3968567212948713e+19, + 2.393052874455778e+19, + 2.3892819809314083e+19, + 2.3855437556447207e+19, + 2.3818379159616664e+19, + 2.378164181671946e+19, + 2.374522274969222e+19, + 2.3709119204319965e+19, + 2.3673328450042348e+19, + 2.3637847779761213e+19, + 2.3602674509648167e+19, + 2.3567805978955555e+19, + 2.3533239549825778e+19, + 2.349897260710105e+19, + 2.346500255813818e+19, + 2.3431326832619577e+19, + 2.3397942882369196e+19, + 2.3364848181166285e+19, + 2.333204022456342e+19, + 2.3299516529704546e+19, + 2.326727463514042e+19, + 2.3235312100654547e+19, + 2.320362650708015e+19, + 2.3172215456123494e+19, + 2.3141076570189193e+19, + 2.3110207492203815e+19, + 2.3079605885444526e+19, + 2.3049269433364124e+19, + 2.3019195839420236e+19, + 2.2989382826907095e+19, + 2.295982813878743e+19, + 2.293052953752237e+19, + 2.290148480490682e+19, + 2.287269174190705e+19, + 2.2844148168495403e+19, + 2.2815851923484787e+19, + 2.278780086437519e+19, + 2.2759992867188072e+19, + 1.9578429198926516e+19 + ], + "vtor": [ + 100000.0, + 99544.32023364124, + 98251.15453696062, + 96235.68685722632, + 93614.68356191639, + 90502.18847954353, + 87006.32501749854, + 83227.06508922808, + 79254.813872946, + 75169.66123127713, + 71041.16042746486, + 66928.50919629741, + 62881.02482158773, + 58938.821939433255, + 55133.61820859918, + 51489.60808192722, + 48024.35830839606, + 44749.69035052268, + 41672.524623402256, + 38795.66945343124, + 36118.54407642795, + 33637.83003375026, + 31348.04917610031, + 29242.06933764292, + 27311.54077408969, + 25547.26782590489, + 23939.521110407513, + 22478.295982958116, + 21153.523137258686, + 19955.237120191036, + 18873.708284120235, + 17899.54334214529, + 17023.759270761642, + 16237.834851443324, + 15533.743681380842, + 14903.972031120154, + 14341.524495030524, + 13839.919977172622, + 13393.180184865832, + 12995.812467288095, + 12642.788537234375, + 12329.520349892675, + 12051.83418147994, + 11805.94375056095, + 11588.423053275488, + 11396.179437797053, + 11226.42732039882, + 11076.662842842592, + 10944.639685904545, + 10828.34618435543, + 10725.983832469563, + 10635.94722420132, + 10556.805436804136, + 10487.284839339893, + 10426.253286892172, + 10372.705646187464, + 10325.750587737686, + 10284.598572685094, + 10248.550958525679, + 10216.990146193662, + 10189.370691092356, + 10165.211302127113, + 10144.087655281786, + 10125.625951492917, + 10109.49715228246, + 10095.411830623676, + 10083.115578687914, + 10072.384918337477, + 10063.023664403154, + 10054.85969484832, + 10047.742085826912, + 10041.538573356505, + 10036.133306828673, + 10031.424862854412, + 10027.3244909875, + 10023.75456568367, + 10020.647221443161, + 10017.943150456194, + 10015.59054423511, + 10013.544162684711, + 10011.764515845945, + 10010.217145160046, + 10008.871992553453, + 10007.702846950711, + 10006.686858995241, + 10005.804115808194, + 10005.037268554323, + 10004.371206421612, + 10003.792771367725, + 10003.29050865027, + 10002.85444874773, + 10002.475916801126, + 10002.14736617021, + 10001.86223310832, + 10001.614809922945, + 10001.400134309408, + 10001.213892828007, + 10001.052336744104, + 10000.912208670363, + 10000.790678643563, + 10000.68528843837, + 10000.593903069897, + 10000.514668568, + 10000.445975221452, + 10000.386425591105, + 10000.334806679686, + 10000.290065723417, + 10000.25128913859, + 10000.217684215675, + 10000.188563205464, + 10000.16332948734, + 10000.141465549392, + 10000.122522544827, + 10000.106111219531, + 10000.091894031972, + 10000.079578309811, + 10000.068910307727, + 10000.05967004848, + 10000.051666844598, + 10000.044735411424, + 10000.038732493818, + 10000.033533939033, + 10000.029032157028, + 10000.02513391718, + 10000.021758437058, + 10000.018835724715, + 10000.016305140998, + 10000.01411415281, + 10000.012217252064, + 10000.010575018385, + 10000.009153306504, + 10000.007922541854, + 10000.00685710995, + 10000.005934827166, + 10000.005136482061, + 10000.004445437868, + 10000.003847288048, + 10000.003329557814, + 10000.002881445527, + 10000.00249359863, + 10000.002157919536, + 10000.001867397486, + 10000.001615962863, + 10000.001398361033, + 10000.001210043049, + 10000.001047070993, + 10000.000906036008, + 10000.000783987294, + 10000.000678370623, + 10000.000586975104, + 10000.000507887078, + 10000.000439450198, + 10000.000380230858, + 10000.000328988277, + 10000.000284648579, + 10000.000246282361, + 10000.000213085277, + 10000.00018436122, + 10000.000159507772, + 10000.000138003594, + 10000.000119397531, + 10000.000103299173, + 10000.000089370667, + 10000.000077319659, + 10000.000066893168, + 10000.000057872281, + 10000.000050067574, + 10000.00004331514, + 10000.00003747315, + 10000.000032418886, + 10000.000028046165, + 10000.00002426311, + 10000.000020990228, + 10000.000018158735, + 10000.00001570912, + 10000.000013589894, + 10000.000011756505, + 10000.00001017041, + 10000.00000879826, + 10000.000007611205, + 10000.00000658428, + 10000.000005695889, + 10000.000004927346, + 10000.000004262487, + 10000.000003687326, + 10000.000003189763, + 10000.000002759334, + 10000.000002386978, + 10000.000002064864, + 10000.000001786213, + 10000.00000154516, + 10000.000001336637, + 10000.00000115625, + 10000.000001000204, + 10000.000000865217, + 10000.000000748445, + 10000.000000647431, + 10000.00000056005, + 10000.000000484462, + 10000.000000419075, + 10000.000000362512, + 10000.000000313583, + 10000.000000271257, + 10000.000000234644, + 10000.000000202972, + 10000.000000175574, + 10000.000000151877, + 10000.000000131377, + 10000.000000113641, + 10000.000000098302, + 10000.000000085032, + 10000.000000073554, + 10000.000000063626, + 10000.000000055037, + 10000.000000047608, + 10000.000000041182, + 10000.000000035621, + 10000.000000030814, + 10000.000000026654, + 10000.000000023056, + 10000.000000019943, + 10000.000000017251, + 10000.000000014923, + 10000.000000012908, + 10000.000000011165, + 10000.000000009659, + 10000.000000008355, + 10000.000000007227, + 10000.00000000625, + 10000.000000005406, + 10000.000000004677, + 10000.000000004045, + 10000.0000000035, + 10000.000000003027, + 10000.000000002618, + 10000.000000002265, + 10000.000000001959, + 10000.000000001695, + 10000.000000001466, + 10000.000000001268, + 10000.000000001097, + 10000.00000000095, + 10000.00000000082, + 10000.00000000071, + 10000.000000000615, + 10000.000000000531, + 10000.00000000046, + 10000.000000000397, + 10000.000000000344, + 10000.000000000296, + 10000.000000000256, + 10000.000000000222, + 10000.000000000193, + 10000.000000000167, + 10000.000000000144, + 10000.0 + ], + "vpol": [ + 18462.326927732716, + 18514.99979366994, + 18565.939231880784, + 18615.197379613106, + 18662.8251518226, + 18708.87224398403, + 18753.38713728863, + 18796.417106004, + 18838.008226787257, + 18878.20538975573, + 18917.052311132516, + 18954.591547296637, + 18990.864510079347, + 19025.91148315922, + 19059.7716394193, + 19092.483059139577, + 19124.08274890752, + 19154.60666113828, + 19184.089714104663, + 19212.565812384706, + 19240.067867642374, + 19266.627819663598, + 19292.27665757659, + 19317.044441191432, + 19340.960322399642, + 19364.052566579816, + 19386.34857396039, + 19407.874900895215, + 19428.65728101207, + 19448.720646198086, + 19468.08914739, + 19486.78617514046, + 19504.834379934928, + 19522.2556922367, + 19539.07134224024, + 19555.301879315663, + 19570.96719112952, + 19586.08652242914, + 19600.678493479918, + 19614.761118146518, + 19628.351821610984, + 19641.467457721887, + 19654.124325970388, + 19666.33818809011, + 19678.124284279074, + 19689.497349042842, + 19700.47162665909, + 19711.060886264648, + 19721.278436566783, + 19731.137140181316, + 19740.649427600623, + 19749.827310795343, + 19758.68239645382, + 19767.225898864108, + 19775.4686524434, + 19783.421123920307, + 19791.093424175622, + 19798.49531974744, + 19805.63624400677, + 19812.52530800986, + 19819.171311033715, + 19825.582750801284, + 19831.76783340299, + 19837.73448292125, + 19843.49035076469, + 19849.042824718887, + 19854.399037720275, + 19859.565876360022, + 19864.549989124593, + 19869.357794379575, + 19873.99548810352, + 19878.469051378208, + 19882.78425764191, + 19886.946679712015, + 19890.961696583312, + 19894.83450000816, + 19898.570100864654, + 19902.173335318803, + 19905.64887078662, + 19909.00121170188, + 19912.234705095303, + 19915.353545990587, + 19918.361782622906, + 19921.263321485007, + 19924.061932206263, + 19926.76125226966, + 19929.36479157172, + 19931.875936830187, + 19934.297955844206, + 19936.634001611572, + 19938.887116307546, + 19941.060235129582, + 19943.156190012254, + 19945.17771321644, + 19947.12744079687, + 19949.00791595186, + 19950.821592259108, + 19952.570836801166, + 19954.25793318425, + 19955.885084453774, + 19957.454415910102, + 19958.967977827684, + 19960.427748080827, + 19961.835634679162, + 19963.193478215824, + 19964.503054231183, + 19965.76607549503, + 19966.984194209857, + 19968.159004137942, + 19969.292042654735, + 19970.384792731096, + 19971.438684846682, + 19972.455098836952, + 19973.435365675872, + 19974.380769196654, + 19975.29254775252, + 19976.1718958196, + 19977.019965543906, + 19977.83786823432, + 19978.6266758034, + 19979.38742215782, + 19980.121104540183, + 19980.828684823875, + 19981.511090762506, + 19982.169217195635, + 19982.80392721215, + 19983.41605327286, + 19984.006398293674, + 19984.575736690727, + 19985.124815388765, + 19985.654354794107, + 19986.165049733347, + 19986.657570359053, + 19987.132563023555, + 19987.590651121973, + 19988.03243590553, + 19988.458497266216, + 19988.869394493737, + 19989.265667005842, + 19989.647835052798, + 19990.01640039704, + 19990.371846968832, + 19990.714641498744, + 19991.045234127785, + 19991.36405899601, + 19991.67153481026, + 19991.968065391884, + 19992.254040205054, + 19992.52983486641, + 19992.795811636643, + 19993.05231989471, + 19993.299696595244, + 19993.538266709777, + 19993.768343652326, + 19993.9902296899, + 19994.2042163385, + 19994.410584745023, + 19994.60960605568, + 19994.801541771343, + 19994.986644090288, + 19995.165156238767, + 19995.33731278991, + 19995.503339971237, + 19995.66345596134, + 19995.817871175987, + 19995.96678854407, + 19996.110403773815, + 19996.248905609486, + 19996.38247607898, + 19996.511290732687, + 19996.6355188738, + 19996.75532378048, + 19996.870862920143, + 19996.98228815611, + 19997.089745946923, + 19997.1933775386, + 19997.29331915003, + 19997.389702151813, + 19997.482653238705, + 19997.572294595982, + 19997.65874405985, + 19997.74211527218, + 19997.822517829743, + 19997.90005742811, + 19997.974836000485, + 19998.046951851553, + 19998.11649978661, + 19998.183571236077, + 19998.248254375594, + 19998.31063424184, + 19998.370792844253, + 19998.42880927274, + 19998.4847598016, + 19998.538717989708, + 19998.590754777182, + 19998.64093857857, + 19998.68933537273, + 19998.736008789543, + 19998.78102019351, + 19998.824428764387, + 19998.866291574945, + 19998.906663665974, + 19998.945598118597, + 19998.983146124054, + 19999.019357050955, + 19999.054278510157, + 19999.087956417356, + 19999.120435053414, + 19999.151757122556, + 19999.181963808518, + 19999.21109482865, + 19999.239188486128, + 19999.26628172031, + 19999.292410155274, + 19999.317608146655, + 19999.34190882679, + 19999.36534414829, + 19999.387944926013, + 19999.409740877607, + 19999.430760662537, + 19999.451031919776, + 19999.470581304155, + 19999.489434521372, + 19999.5076163618, + 19999.525150733072, + 19999.54206069153, + 19999.558368472495, + 19999.57409551955, + 19999.58926251268, + 19999.603889395497, + 19999.61799540144, + 19999.63159907907, + 19999.644718316464, + 19999.657370364694, + 19999.669571860562, + 19999.681338848437, + 19999.69268680136, + 19999.703630641383, + 19999.7141847592, + 19999.72436303305, + 19999.73417884697, + 19999.743645108418, + 19999.752774265195, + 19999.76157832185, + 19999.770068855447, + 19999.778257030794, + 19999.78615361512, + 19999.793768992236, + 19999.801113176174, + 19999.808195824375, + 19999.815026250366, + 19999.82161343603, + 19999.827966043387, + 19999.834092426012, + 19999.84000064, + 20000.0 + ], + "vnorm": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "element": "hydrogen", + "charge": 1 +} \ No newline at end of file diff --git a/cherab/generomak/plasma/data/core/psi_norm.json b/cherab/generomak/plasma/data/core/psi_norm.json new file mode 100644 index 00000000..01760ebf --- /dev/null +++ b/cherab/generomak/plasma/data/core/psi_norm.json @@ -0,0 +1,260 @@ +{ + "psi_norm": [ + 0.0, + 0.03561162084555414, + 0.06995505415186065, + 0.10307546213272856, + 0.13501639870233162, + 0.1658198667493661, + 0.19552637337158152, + 0.2241749831433214, + 0.25180336948611703, + 0.27844786420989853, + 0.3041435052899555, + 0.3289240829424859, + 0.35282218405932053, + 0.3758692350602538, + 0.3980955432193337, + 0.41953033651945604, + 0.44020180208767157, + 0.4601371232617498, + 0.47936251533674257, + 0.49790326003855345, + 0.5157837387698492, + 0.5330274646720292, + 0.5496571135454165, + 0.5656945536683295, + 0.581160874554252, + 0.5960764146849096, + 0.6104607882557274, + 0.6243329109688405, + 0.637711024907571, + 0.6506127225250871, + 0.663054969778784, + 0.6750541284408158, + 0.6866259776141095, + 0.6977857344821621, + 0.7085480743199009, + 0.7189271497919272, + 0.7289366095635164, + 0.7385896162488508, + 0.7478988637200875, + 0.7568765938000214, + 0.7655346123602946, + 0.7738843048463258, + 0.7819366512493673, + 0.7897022405453866, + 0.7971912846197539, + 0.8044136316960491, + 0.8113787792866483, + 0.8180958866821177, + 0.8245737869958408, + 0.8308209987797164, + 0.8368457372262026, + 0.842655924971439, + 0.8482592025136506, + 0.8536629382605364, + 0.8588742382188548, + 0.8638999553389449, + 0.8687466985264773, + 0.8734208413332797, + 0.8779285303386681, + 0.882275693232307, + 0.8864680466092238, + 0.8905111034872313, + 0.8944101805566421, + 0.8981704051718096, + 0.9017967220936874, + 0.9052938999922776, + 0.9086665377175137, + 0.9119190703468294, + 0.915055775017362, + 0.9180807765504632, + 0.9209980528759103, + 0.9238114402629539, + 0.9265246383650785, + 0.9291412150851113, + 0.931664611267077, + 0.9340981452209673, + 0.9364450170863771, + 0.9387083130407426, + 0.9408910093577201, + 0.9429959763210364, + 0.9450259819989626, + 0.9469836958843723, + 0.9488716924051706, + 0.9506924543097125, + 0.9524483759316599, + 0.954141766338572, + 0.9557748523683696, + 0.9573497815576658, + 0.9588686249658143, + 0.960333379898388, + 0.9617459725336712, + 0.9631082604556176, + 0.9644220350966051, + 0.9656890240932012, + 0.9669108935580351, + 0.9680892502707645, + 0.9692256437910194, + 0.9703215684960996, + 0.9713784655461073, + 0.9723977247790973, + 0.9733806865387387, + 0.9743286434368901, + 0.9752428420534066, + 0.9761244845754142, + 0.9769747303782067, + 0.9777946975498447, + 0.9785854643614604, + 0.9793480706852037, + 0.9800835193616915, + 0.9807927775187607, + 0.9814767778432588, + 0.9821364198075426, + 0.9827725708523005, + 0.9833860675272521, + 0.9839777165912252, + 0.9845482960730585, + 0.9850985562947225, + 0.9856292208580062, + 0.9861409875960662, + 0.9866345294910889, + 0.9871104955592747, + 0.9875695117043048, + 0.9880121815404163, + 0.9884390871861642, + 0.988850790029919, + 0.989247831468101, + 0.9896307336171266, + 0.99, + 0.9903561162084555, + 0.9906995505415186, + 0.9910307546213273, + 0.9913501639870234, + 0.9916581986674937, + 0.9919552637337158, + 0.9922417498314332, + 0.9925180336948611, + 0.992784478642099, + 0.9930414350528995, + 0.9932892408294248, + 0.9935282218405932, + 0.9937586923506025, + 0.9939809554321933, + 0.9941953033651946, + 0.9944020180208767, + 0.9946013712326175, + 0.9947936251533674, + 0.9949790326003856, + 0.9951578373876985, + 0.9953302746467203, + 0.9954965711354542, + 0.9956569455366833, + 0.9958116087455425, + 0.9959607641468491, + 0.9961046078825573, + 0.9962433291096884, + 0.9963771102490757, + 0.9965061272252509, + 0.9966305496977879, + 0.9967505412844082, + 0.9968662597761411, + 0.9969778573448216, + 0.997085480743199, + 0.9971892714979192, + 0.9972893660956351, + 0.9973858961624885, + 0.9974789886372009, + 0.9975687659380003, + 0.997655346123603, + 0.9977388430484633, + 0.9978193665124937, + 0.9978970224054539, + 0.9979719128461976, + 0.9980441363169605, + 0.9981137877928665, + 0.9981809588668211, + 0.9982457378699584, + 0.9983082099877971, + 0.998368457372262, + 0.9984265592497144, + 0.9984825920251366, + 0.9985366293826053, + 0.9985887423821885, + 0.9986389995533894, + 0.9986874669852648, + 0.9987342084133328, + 0.9987792853033867, + 0.998822756932323, + 0.9988646804660922, + 0.9989051110348723, + 0.9989441018055665, + 0.998981704051718, + 0.9990179672209368, + 0.9990529389999228, + 0.9990866653771752, + 0.9991191907034683, + 0.9991505577501736, + 0.9991808077655047, + 0.9992099805287591, + 0.9992381144026296, + 0.9992652463836508, + 0.9992914121508512, + 0.9993166461126708, + 0.9993409814522096, + 0.9993644501708637, + 0.9993870831304075, + 0.9994089100935772, + 0.9994299597632104, + 0.9994502598199896, + 0.9994698369588437, + 0.9994887169240517, + 0.9995069245430971, + 0.9995244837593166, + 0.9995414176633857, + 0.9995577485236837, + 0.9995734978155767, + 0.9995886862496581, + 0.9996033337989839, + 0.9996174597253367, + 0.9996310826045561, + 0.999644220350966, + 0.999656890240932, + 0.9996691089355804, + 0.9996808925027076, + 0.9996922564379102, + 0.999703215684961, + 0.9997137846554611, + 0.9997239772477909, + 0.9997338068653874, + 0.9997432864343689, + 0.999752428420534, + 0.9997612448457541, + 0.9997697473037821, + 0.9997779469754985, + 0.9997858546436146, + 0.999793480706852, + 0.999800835193617, + 0.9998079277751876, + 0.9998147677784326, + 0.9998213641980754, + 0.999827725708523, + 0.9998338606752725, + 0.9998397771659122, + 0.9998454829607306, + 0.9998509855629473, + 0.9998562922085801, + 0.9998614098759606, + 0.9998663452949109, + 0.9998711049555927, + 0.999875695117043, + 0.9998801218154042, + 0.9998843908718617, + 0.9998885079002992, + 0.999892478314681, + 0.9998963073361713, + 0.9999, + 1.0 + ] +} \ No newline at end of file diff --git a/cherab/generomak/plasma/plasma.py b/cherab/generomak/plasma/plasma.py index ab7ef95d..45c5ed3e 100644 --- a/cherab/generomak/plasma/plasma.py +++ b/cherab/generomak/plasma/plasma.py @@ -125,7 +125,6 @@ def get_edge_interpolators(): mesh_interp["composition"][elem_name][stage]["temperature"] = t mesh_interp["composition"][elem_name][stage]["density"] = n mesh_interp["composition"][elem_name][stage]["velocity"] = v - mesh_interp["composition"][elem_name][stage]["element"] = stage_data["element"] return mesh_interp.freeze() @@ -195,6 +194,84 @@ def get_edge_plasma(atomic_data=None, parent=None, name="Generomak edge plasma") parent=parent, name=name) +def load_core_profiles(): + """ + Loads Generomak default core plasma profiles. + + Return a single dictionary with available core plasma species temperature and + density profiles on a magnetic surface coordinate grid. + + :return: dictionary with electron and plasma composition profiles + """ + profiles_dir = os.path.join(os.path.dirname(__file__), "data/core") + + core_data = RecursiveDict() + path = os.path.join(profiles_dir, "psi_norm.json") + with open(path, "r") as fhl: + core_data["psi_norm"] = json.load(fhl)["psi_norm"] + + path = os.path.join(profiles_dir, "electrons.json") + with open(path, "r") as fhl: + core_data["electron"] = json.load(fhl) + + saved_elements = (hydrogen, carbon) + + for element in saved_elements: + for chrg in range(element.atomic_number + 1): + path = os.path.join(profiles_dir, "{}{:d}.json".format(element.name, chrg)) + + with open(path, "r") as fhl: + file_data = json.load(fhl) + element_name = file_data["element"] + charge = file_data["charge"] + + core_data["composition"][element_name][charge] = file_data + + return core_data.freeze() + + +def get_core_interpolators(): + """ + Provides 1d interpolators for Generomak default core profiles. + + :return: dictionary holding 1D interpolators of density, + temperature and velocity for plasma species + """ + + profiles = load_core_profiles() + + core_interp = RecursiveDict() + + te = Interpolator1DArray(profiles["psi_norm"], profiles["electron"]["temperature"], 'cubic', 'nearest', 1.e-5) + ne = Interpolator1DArray(profiles["psi_norm"], profiles["electron"]["density"], 'cubic', 'nearest', 1.e-5) + ve_tor = Interpolator1DArray(profiles["psi_norm"], profiles["electron"]["vtor"], 'cubic', 'nearest', 1.e-5) + ve_pol = Interpolator1DArray(profiles["psi_norm"], profiles["electron"]["vpol"], 'cubic', 'nearest', 1.e-5) + ve_norm = Interpolator1DArray(profiles["psi_norm"], profiles["electron"]["vnorm"], 'cubic', 'nearest', 1.e-5) + + core_interp["electron"]["f1d_temperature"] = te + core_interp["electron"]["f1d_density"] = ne + core_interp["electron"]["f1d_vtor"] = ve_tor + core_interp["electron"]["f1d_vpol"] = ve_pol + core_interp["electron"]["f1d_vnorm"] = ve_norm + + for elem_name, elem_data in profiles["composition"].items(): + for stage, stage_data in elem_data.items(): + + t = Interpolator1DArray(profiles["psi_norm"], stage_data["temperature"], 'cubic', 'nearest', 1.e-5) + n = Interpolator1DArray(profiles["psi_norm"], stage_data["density"], 'cubic', 'nearest', 1.e-5) + vtor = Interpolator1DArray(profiles["psi_norm"], stage_data["vtor"], 'cubic', 'nearest', 1.e-5) + vpol = Interpolator1DArray(profiles["psi_norm"], stage_data["vpol"], 'cubic', 'nearest', 1.e-5) + vnorm = Interpolator1DArray(profiles["psi_norm"], stage_data["vnorm"], 'cubic', 'nearest', 1.e-5) + + core_interp["composition"][elem_name][stage]["f1d_temperature"] = t + core_interp["composition"][elem_name][stage]["f1d_density"] = n + core_interp["composition"][elem_name][stage]["f1d_vtor"] = vtor + core_interp["composition"][elem_name][stage]["f1d_vpol"] = vpol + core_interp["composition"][elem_name][stage]["f1d_vnorm"] = vnorm + + return core_interp.freeze() + + def get_double_parabola(v_min, v_max, convexity, concavity, xmin=0, xmax=1): """ Returns a 1d double-quadratic Function1D @@ -417,7 +494,7 @@ def get_core_profiles_description(lcfs_values=None, core_args=None): # solve ionisation balance openadas = OpenADAS(permit_extrapolation=True) - psin_1d = np.linspace(0, 1, 256) + psin_1d = np.append(1. - np.geomspace(1.e-4, 1, 1023)[::-1], [1.]) # density profiles are sharp near psin=1 density_profiles = {} density_profiles["carbon"] = interpolators1d_from_elementdensity(openadas, carbon, psin_1d, carbon_total_density, profiles["electron"]["f1d_density"], @@ -451,15 +528,17 @@ def get_core_distributions(profiles=None, equilibrium=None): """ Returns a dictionary of core plasma species Maxwellian distributions. - :param profiles: Dictionary of core particle profiles. The dictionary has to have the same form - as the one returned by the function get_core_profiles_description. - The default value is the value returned by the call get_core_profiles_description(). + :param profiles: Dictionary with core interpolators. The dictionary has to have + the same form as the one returned by the function + get_core_profiles_description or get_core_interpolators. + The default value is the value returned by the call + get_core_interpolators(). :param equilibrium: an instance of EFITEquilibrium. :return: dictionary of core plasma species with Maxwellian distribution """ # get core profile data if not passed sa argument if profiles is None: - profiles = get_core_profiles_description() + profiles = get_core_interpolators() # load plasma equilibrium if not passed as argument if equilibrium is None: @@ -504,11 +583,11 @@ def get_full_profiles(equilibrium=None, core_profiles=None, edge_profiles=None, :param equilibrium: an instance of EFITEquilibrium. The default value is the value returned by load_equilibrium(). - :param core_profiles: Dictionary of core particle profiles. The dictionary has to have + :param core_profiles: Dictionary with core interpolators. The dictionary has to have the same form as the one returned by the function - get_core_profiles_description. + get_core_profiles_description or get_core_interpolators. The default value is the value returned by the call - get_core_profiles_description(). + get_core_interpolators(). :param edge_profiles: Dictionary with edge interpolators in the shape returned by the get_edge_interpolators function. If not specified, will use the value returned by @@ -524,7 +603,7 @@ def get_full_profiles(equilibrium=None, core_profiles=None, edge_profiles=None, equilibrium = equilibrium or load_equilibrium() - core_profiles = core_profiles or get_core_profiles_description() + core_profiles = core_profiles or get_core_interpolators() edge_profiles = edge_profiles or get_edge_interpolators() diff --git a/demos/generomak/plasma/plot_2d_plasma.py b/demos/generomak/plasma/plot_2d_plasma.py index 24750242..12f58866 100755 --- a/demos/generomak/plasma/plot_2d_plasma.py +++ b/demos/generomak/plasma/plot_2d_plasma.py @@ -28,7 +28,7 @@ from cherab.core.math import sample3d from cherab.core.atomic.elements import hydrogen, carbon -from cherab.generomak.plasma.plasma import get_core_plasma, get_edge_plasma, get_plasma +from cherab.generomak.plasma import get_core_plasma, get_edge_plasma, get_plasma def plot_profiles(core_profile, edge_profile, full_profile, r_range, z_range, label): diff --git a/demos/generomak/plasma/plot_2d_profiles.py b/demos/generomak/plasma/plot_2d_profiles.py index 34daa025..07fb7683 100755 --- a/demos/generomak/plasma/plot_2d_profiles.py +++ b/demos/generomak/plasma/plot_2d_profiles.py @@ -30,7 +30,7 @@ from cherab.core.utility import RecursiveDict from cherab.generomak.equilibrium import load_equilibrium -from cherab.generomak.plasma.plasma import get_core_profiles_description, load_edge_profiles, get_full_profiles +from cherab.generomak.plasma.plasma import get_core_interpolators, load_edge_profiles, get_full_profiles def plot_profiles(core_profile, edge_mesh, edge_data, full_profile, label): @@ -90,7 +90,7 @@ def plot_profiles(core_profile, edge_mesh, edge_data, full_profile, label): equilibrium = load_equilibrium() # load 1D core profiles, f(psi_norm) -core_profiles_1d = get_core_profiles_description() +core_profiles_1d = get_core_interpolators() # load 2D edge profiles defined on a quadrilateral mesh edge_data = load_edge_profiles() diff --git a/demos/generomak/plasma/plot_core_profiles.py b/demos/generomak/plasma/plot_core_profiles.py index c12f0d5a..23fd4486 100644 --- a/demos/generomak/plasma/plot_core_profiles.py +++ b/demos/generomak/plasma/plot_core_profiles.py @@ -22,9 +22,9 @@ import matplotlib.pyplot as plt from cherab.core.math.samplers import sample1d_points -from cherab.generomak.plasma.plasma import get_core_profiles_description +from cherab.generomak.plasma.plasma import get_core_interpolators -profiles = get_core_profiles_description() +profiles = get_core_interpolators() # setup temperature plot _, ax_t = plt.subplots() @@ -35,11 +35,12 @@ # setup density plot _, ax_n = plt.subplots() ax_n.set_yscale("log") +ax_n.set_ylim(1.e-1, 1.e21) ax_n.set_title("Species Core Density Profiles") ax_n.set_xlabel("psin") ax_n.set_ylabel("m^-3") -psin = np.linspace(0, 1, 30) +psin = np.append(1. - np.geomspace(1.e-4, 1, 127)[::-1], [1.]) # add hydrogen curves for chrg, desc in profiles["composition"]["hydrogen"].items(): vals = sample1d_points(desc["f1d_temperature"], psin) From d7fa6380c8338647846b534128c431a6d5ac9977 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Thu, 22 Dec 2022 16:36:59 +0000 Subject: [PATCH 37/81] Update CI with new python and numpy versions (#391) * Update python and numpy versions in CI - Remove Python 3.6 - Only test oldest and newest supported numpy versions * Update pyopencl version in CI v2022.2.4 fixes POCL library not found issue. * Use newest pre-built numpy in CI Add --prefer-binary flag when installing dependencies, to avoid trying to build newer numpy versions from source on older Pythons. --- .github/workflows/ci.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56bc565f..a1350bf7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,11 +11,8 @@ jobs: strategy: fail-fast: false matrix: - numpy-version: ["1.15.0", "1.16.6", "1.19.2"] - python-version: ["3.6", "3.7", "3.8"] - exclude: - - python-version: "3.8" - numpy-version: "1.15.0" + numpy-version: ["oldest-supported-numpy", "numpy"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - name: Checkout code uses: actions/checkout@v2 @@ -26,9 +23,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: Install Python dependencies - run: python -m pip install cython>=0.28 numpy==${{ matrix.numpy-version }} scipy matplotlib pyopencl[pocl]==2022.1 - - name: Work around PyOpenCL issue 537 - run: echo OCL_ICD_VENDORS=$(python -c 'import os, pyopencl; print(os.path.join(*pyopencl.__path__, ".libs"))') >> $GITHUB_ENV + run: python -m pip install --prefer-binary cython>=0.28 ${{ matrix.numpy-version }} scipy matplotlib "pyopencl[pocl]>=2022.2.4" - name: Install Raysect from pypi run: pip install raysect==0.7.1 - name: Build cherab From a7caca2e0f2593017c7085a32bd8446c7c10b977 Mon Sep 17 00:00:00 2001 From: Matej Tomes Date: Thu, 22 Dec 2022 17:42:05 +0100 Subject: [PATCH 38/81] Rewritten TS model with segmented laser geometry (#219) I decided to do new PR, because at the end there were many changes: laser geometry is now segmented cylinder as suggested by @mattngc. This propagated into handling of information between plasma, laser node, laser model and scattering model. This was neccessary to simplify handling of notifications, deletions and etc. laser model and spectrum hold no plasma and laser reference. Their methods return requested properties (e.g. laser power) in laser node frame. Laser material now obtains all the information from plasma, laser spectrum and laser model needed by the scattering model. Scattering model works in the frame of reference of the laser node. Method for scattered spectrum calcullation must now get all the neccessary plasma and laser variables (e.g. Te, ne, directions, etc.) laser models were rewritten and new added (uniform, bivariate and trivariate normal spatial distributions, Gaussian beam model). Lasers are now described by pulse energy and pulse temporal lengh, this is transformed to spatial power densities using given distributions. laser spectrum power spectral density was corrected. Unittests checking the following were added: laser node initialisation propagation of notifications between laser model, laser spectrum, scattering model, laser geometry and laser material position of the laser segments compared to the expected one laser spectrum initialisation and changes normalisation of models laser models initialisation polarisation direction correct values of power for spatial points integration of laser power over pulse spatial extent is compared to expected pulse energy scattering model scaterred spectrum traced by a ray is compared to expected values calculated by semi-analytical approach. --- CHANGELOG.md | 1 + cherab/core/laser/__init__.pxd | 4 + cherab/core/laser/__init__.py | 4 + cherab/core/laser/laserspectrum.pxd | 47 ++ cherab/core/laser/laserspectrum.pyx | 192 +++++ cherab/core/laser/material.pxd | 31 + cherab/core/laser/material.pyx | 66 ++ cherab/core/laser/model.pxd | 37 + cherab/core/laser/model.pyx | 78 ++ cherab/core/laser/node.pxd | 55 ++ cherab/core/laser/node.pyx | 261 ++++++ cherab/core/laser/profile.pxd | 41 + cherab/core/laser/profile.pyx | 163 ++++ cherab/core/laser/tests/__init__.py | 0 cherab/core/laser/tests/test_laser.py | 110 +++ cherab/core/laser/tests/test_laserspectrum.py | 62 ++ cherab/core/model/laser/__init__.pxd | 4 + cherab/core/model/laser/__init__.py | 4 + cherab/core/model/laser/laserspectrum.pxd | 34 + cherab/core/model/laser/laserspectrum.pyx | 133 +++ cherab/core/model/laser/math_functions.pxd | 48 ++ cherab/core/model/laser/math_functions.pyx | 304 +++++++ cherab/core/model/laser/model.pxd | 40 + cherab/core/model/laser/model.pyx | 220 +++++ cherab/core/model/laser/profile.pxd | 57 ++ cherab/core/model/laser/profile.pyx | 765 ++++++++++++++++++ cherab/core/model/laser/tests/__init__.py | 0 .../model/laser/tests/test_laserspectrum.py | 46 ++ cherab/core/model/laser/tests/test_model.py | 104 +++ .../core/model/laser/tests/test_profiles.py | 198 +++++ demos/laser/laser_profile.py | 86 ++ demos/laser/laser_spectrum.py | 34 + demos/laser/model_seldenmatoba.py | 72 ++ demos/laser/thomson_scattering.py | 61 ++ docs/source/models/emission_models.rst | 1 + docs/source/models/laser/laser.rst | 28 + docs/source/plasmas/laser.rst | 20 + docs/source/plasmas/plasmas.rst | 1 + 38 files changed, 3412 insertions(+) create mode 100644 cherab/core/laser/__init__.pxd create mode 100644 cherab/core/laser/__init__.py create mode 100644 cherab/core/laser/laserspectrum.pxd create mode 100644 cherab/core/laser/laserspectrum.pyx create mode 100644 cherab/core/laser/material.pxd create mode 100644 cherab/core/laser/material.pyx create mode 100644 cherab/core/laser/model.pxd create mode 100644 cherab/core/laser/model.pyx create mode 100644 cherab/core/laser/node.pxd create mode 100644 cherab/core/laser/node.pyx create mode 100644 cherab/core/laser/profile.pxd create mode 100644 cherab/core/laser/profile.pyx create mode 100644 cherab/core/laser/tests/__init__.py create mode 100644 cherab/core/laser/tests/test_laser.py create mode 100644 cherab/core/laser/tests/test_laserspectrum.py create mode 100644 cherab/core/model/laser/__init__.pxd create mode 100644 cherab/core/model/laser/__init__.py create mode 100644 cherab/core/model/laser/laserspectrum.pxd create mode 100644 cherab/core/model/laser/laserspectrum.pyx create mode 100644 cherab/core/model/laser/math_functions.pxd create mode 100644 cherab/core/model/laser/math_functions.pyx create mode 100644 cherab/core/model/laser/model.pxd create mode 100644 cherab/core/model/laser/model.pyx create mode 100644 cherab/core/model/laser/profile.pxd create mode 100644 cherab/core/model/laser/profile.pyx create mode 100644 cherab/core/model/laser/tests/__init__.py create mode 100644 cherab/core/model/laser/tests/test_laserspectrum.py create mode 100644 cherab/core/model/laser/tests/test_model.py create mode 100644 cherab/core/model/laser/tests/test_profiles.py create mode 100644 demos/laser/laser_profile.py create mode 100644 demos/laser/laser_spectrum.py create mode 100644 demos/laser/model_seldenmatoba.py create mode 100644 demos/laser/thomson_scattering.py create mode 100644 docs/source/models/laser/laser.rst create mode 100644 docs/source/plasmas/laser.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index dbe69a21..d6d704ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ New: * Add group observer class for each of Raysect's 0D observers. (#332) * Add a demo for observer group handling and plotting. * Add verbose parameter to SartOpencl solver (default is False). (#358) +* Add Thomson Scattering model. (#97) * Add Generomak core plasma profiles. (#360) * Add toroidal_mesh_from_polygon for making mesh for not fully-360 degrees axisymmetric elements. (#365) diff --git a/cherab/core/laser/__init__.pxd b/cherab/core/laser/__init__.pxd new file mode 100644 index 00000000..2760a2ea --- /dev/null +++ b/cherab/core/laser/__init__.pxd @@ -0,0 +1,4 @@ +from cherab.core.laser.node cimport Laser +from cherab.core.laser.model cimport LaserModel +from cherab.core.laser.laserspectrum cimport LaserSpectrum +from cherab.core.laser.profile cimport LaserProfile \ No newline at end of file diff --git a/cherab/core/laser/__init__.py b/cherab/core/laser/__init__.py new file mode 100644 index 00000000..911a64b1 --- /dev/null +++ b/cherab/core/laser/__init__.py @@ -0,0 +1,4 @@ +from .node import Laser +from .model import LaserModel +from .laserspectrum import LaserSpectrum +from .profile import LaserProfile \ No newline at end of file diff --git a/cherab/core/laser/laserspectrum.pxd b/cherab/core/laser/laserspectrum.pxd new file mode 100644 index 00000000..a00945eb --- /dev/null +++ b/cherab/core/laser/laserspectrum.pxd @@ -0,0 +1,47 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function1D + +from cherab.core.utility.constants cimport SPEED_OF_LIGHT, PLANCK_CONSTANT + +from numpy cimport ndarray + + +cdef class LaserSpectrum(Function1D): + + cdef: + double _min_wavelength, _max_wavelength, _delta_wavelength + int _bins + ndarray _power, _power_spectral_density, _wavelengths # power_spectral_density [w/nm] + double[::1] power_mv, power_spectral_density_mv, wavelengths_mv + + cpdef double evaluate_integral(self, double lower_limit, double upper_limit) + + cpdef void _update_cache(self) + + cpdef double get_min_wavelenth(self) + + cpdef double get_max_wavelenth(self) + + cpdef int get_spectral_bins(self) + + cpdef double get_delta_wavelength(self) + + cpdef double _get_bin_power_spectral_density(self, double wavelength_lower, double wavelength_upper) \ No newline at end of file diff --git a/cherab/core/laser/laserspectrum.pyx b/cherab/core/laser/laserspectrum.pyx new file mode 100644 index 00000000..e196fba1 --- /dev/null +++ b/cherab/core/laser/laserspectrum.pyx @@ -0,0 +1,192 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function1D +from raysect.optical cimport Point3D, Vector3D + +from cherab.core.utility import Notifier +from cherab.core.utility.constants cimport SPEED_OF_LIGHT, PLANCK_CONSTANT + +import numpy as np +cimport numpy as np + + +cdef class LaserSpectrum(Function1D): + """ + Laser spectrum base class. + + This is an abstract class and cannot be used for observing. + + A 1D function holding information about the spectral properties + of a laser. The scattered spectrum is calculated as an iteration + over the laser spectrum. + + + .. warning:: + When adding a LaserSpectrum, a special care should be given + to the integral power of the laser spectrum. During the + scattering calculation, the spectral power can be multiplied + by the power spatial distribution [W * m ** -3] of the laser + power from the LaserProfile. If the integral power + of the LaserSpectrum is not 1, unexpected values + might be obtained. + + .. note:: + It is expected that majority of the fusion applications can + neglect the influence of the spectral shape of the + laser and can use laser spectrum with a single + bin, which approximates an infinitely narrow laser spectrum. + + :param float min_wavelength: The minimum wavelength of the laser + spectrum in nm. + :param float max_wavelength: The maximum wavelength of the laser + spectrum in nm. + :param int bins: The number of spectral bins of the laser spectrum. + :ivar float min_wavelength: The minimum wavelength of the laser + spectrum in nm. + :ivar float max_wavelength: The maximum wavelength of the laser + spectrum in nm. + :ivar int bins: The number of specral bins of the laser spectrum + :ivar ndarray wavelengths: The wavelengt coordinate vector in nm. + :ivar ndarray power_spectral_density: The values of the power + spectral density in W / nm. + :ivar float delta_wavelength: Spectral width of the bins in nm. + """ + + def __init__(self, double min_wavelength, double max_wavelength, int bins): + + super().__init__() + + self._check_wavelength_validity(min_wavelength, max_wavelength) + + self._min_wavelength = min_wavelength + self._max_wavelength = max_wavelength + + self.bins = bins + + @property + def min_wavelength(self): + return self._min_wavelength + + @min_wavelength.setter + def min_wavelength(self, double value): + + self._check_wavelength_validity(value, self.max_wavelength) + self._min_wavelength = value + self._update_cache() + + @property + def max_wavelength(self): + return self._max_wavelength + + @max_wavelength.setter + def max_wavelength(self, double value): + + self._check_wavelength_validity(self.min_wavelength, value) + self._max_wavelength = value + self._update_cache() + + @property + def bins(self): + return self._bins + + @bins.setter + def bins(self, int value): + if value <= 0: + raise ValueError("Value has to be larger than 0") + + self._bins = value + self._update_cache() + + @property + def wavelengths(self): + return self._wavelengths + + @property + def power_spectral_density(self): + return self._power_spectral_density + + @property + def delta_wavelength(self): + return self._delta_wavelength + + def _check_wavelength_validity(self, min_wavelength, max_wavelength): + + if min_wavelength <= 0: + raise ValueError("min_wavelength has to be larger than 0, but {} passed.".format(min_wavelength)) + if max_wavelength <= 0: + raise ValueError("min_wavelength has to be larger than 0, but {} passed.".format(max_wavelength)) + + if min_wavelength >= max_wavelength: + raise ValueError("min_wavelength has to be smaller than max_wavelength: min_wavelength={} > max_wavelength={}".format(min_wavelength, max_wavelength)) + + cpdef double get_min_wavelenth(self): + return self._min_wavelength + + cpdef double get_max_wavelenth(self): + return self._min_wavelength + + cpdef int get_spectral_bins(self): + return self._bins + + cpdef double get_delta_wavelength(self): + return self._delta_wavelength + + cpdef void _update_cache(self): + + cdef: + Py_ssize_t index + double delta_wvl_half, wvl_lower, wvl_upper, wvl + + self._delta_wavelength = (self._max_wavelength - self._min_wavelength) / self._bins + self._wavelengths = np.zeros(self.bins, dtype=np.double) + self.wavelengths_mv = self._wavelengths + + for index in range(self._bins): + self._wavelengths[index] = self._min_wavelength + (0.5 + index) * self._delta_wavelength + + self._power_spectral_density = np.zeros(self._bins, dtype=np.double) # power spectral density (PSD) + self.power_spectral_density_mv = self._power_spectral_density + + self._power = np.zeros(self._bins, dtype=np.double) # power in a spectral bin (PSD * delta wavelength) + self.power_mv = self._power + + delta_wvl_half = self._delta_wavelength * 0.5 + wvl_lower = self.wavelengths_mv[0] - delta_wvl_half + + for index in range(self._bins): + wvl = wvl_lower + delta_wvl_half + wvl_upper = wvl_lower + self._delta_wavelength + + self.power_spectral_density_mv[index] = self._get_bin_power_spectral_density(wvl_lower, wvl_upper) + self.power_mv[index] = self.power_spectral_density_mv[index] * self._delta_wavelength # power in the spectral bin for scattering calculations + + wvl_lower = wvl_upper + + cpdef double evaluate_integral(self, double lower_limit, double upper_limit): + raise NotImplementedError('Virtual method must be implemented in a sub-class.') + + cpdef double _get_bin_power_spectral_density(self, double wavelength_lower, double wavelength_upper): + """ + Returns the power spectral density in a bin. + + This method can be overidden if a better precision is needed. + For example for distributions with known cumulative distribution function. + """ + return 0.5 * (self.evaluate(wavelength_lower) + self.evaluate(wavelength_upper)) diff --git a/cherab/core/laser/material.pxd b/cherab/core/laser/material.pxd new file mode 100644 index 00000000..c91fa416 --- /dev/null +++ b/cherab/core/laser/material.pxd @@ -0,0 +1,31 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.scenegraph._nodebase cimport _NodeBase +from raysect.core.math cimport AffineMatrix3D +from raysect.optical.material.emitter cimport InhomogeneousVolumeEmitter + +from cherab.core.laser.node cimport Laser + + +cdef class LaserMaterial(InhomogeneousVolumeEmitter): + + cdef: + AffineMatrix3D _laser_to_plasma, _laser_segment_to_laser_node + list _models diff --git a/cherab/core/laser/material.pyx b/cherab/core/laser/material.pyx new file mode 100644 index 00000000..4732e01a --- /dev/null +++ b/cherab/core/laser/material.pyx @@ -0,0 +1,66 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.scenegraph._nodebase cimport _NodeBase +from raysect.optical cimport World, Primitive, Ray, Spectrum, Point3D, Vector3D, AffineMatrix3D +from raysect.optical.material.emitter cimport InhomogeneousVolumeEmitter +from raysect.optical.material.emitter.inhomogeneous cimport VolumeIntegrator + +from cherab.core.laser.node cimport Laser +from cherab.core.laser.model cimport LaserModel + + +cdef class LaserMaterial(InhomogeneousVolumeEmitter): + + def __init__(self, Laser laser not None, _NodeBase laser_segment not None, list models, VolumeIntegrator integrator not None): + + super().__init__(integrator) + + self._laser_segment_to_laser_node = laser_segment.to(laser) + self._laser_to_plasma = laser_segment.to(laser.plasma) + self.importance = laser.importance + + #validate and set models + for model in models: + if not isinstance(model, LaserModel): + raise TypeError("Model supplied to laser are not LaserMaterial is not LaserModel") + model.plasma = laser.plasma + model.laser_profile = laser.laser_profile + model.laser_spectrum = laser.laser_spectrum + + self._models = models + + cpdef Spectrum emission_function(self, Point3D point, Vector3D direction, Spectrum spectrum, + World world, Ray ray, Primitive primitive, + AffineMatrix3D to_local, AffineMatrix3D to_world): + + cdef: + Point3D point_plasma, point_laser + Vector3D direction_plasma, direction_laser + LaserModel model + + point_laser = point.transform(self._laser_segment_to_laser_node) + direction_laser = direction.transform(self._laser_segment_to_laser_node) # observation vector in the laser frame + point_plasma = point.transform(self._laser_to_plasma) + direction_plasma = direction.transform(self._laser_to_plasma) + + for model in self._models: + spectrum = model.emission(point_plasma, direction_plasma, point_laser, direction_laser, spectrum) + + return spectrum diff --git a/cherab/core/laser/model.pxd b/cherab/core/laser/model.pxd new file mode 100644 index 00000000..71cdf9a8 --- /dev/null +++ b/cherab/core/laser/model.pxd @@ -0,0 +1,37 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.optical cimport Vector3D, Point3D +from raysect.optical.spectrum cimport Spectrum + +from cherab.core cimport Plasma +from cherab.core.laser.profile cimport LaserProfile +from cherab.core.laser.laserspectrum cimport LaserSpectrum + + +cdef class LaserModel: + cdef: + Plasma _plasma + LaserSpectrum _laser_spectrum + LaserProfile _laser_profile + + cpdef Spectrum emission(self, Point3D point_plasma, Vector3D observation_plasma, Point3D point_laser, + Vector3D observation_laser, Spectrum spectrum) + + cdef object __weakref__ diff --git a/cherab/core/laser/model.pyx b/cherab/core/laser/model.pyx new file mode 100644 index 00000000..c7d76cae --- /dev/null +++ b/cherab/core/laser/model.pyx @@ -0,0 +1,78 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.optical cimport Vector3D, Point3D +from raysect.optical.spectrum cimport Spectrum + +from cherab.core cimport Plasma +from cherab.core.laser.profile cimport LaserProfile +from cherab.core.laser.laserspectrum cimport LaserSpectrum + + +cdef class LaserModel: + """ + Laser spectrum base class. + + This is an abstract class and cannot be used for observing. + + Calculates the contribution to a spectrum caused by a laser. + + :param laser_profile: LaserProfile object + :param plasma: Plasma object + :param laser_spectrum: LaserSpectrum object + + :ivar laser_profile: LaserProfile object + :ivar plasma: Plasma object + :ivar laser_spectrum: LaserSpectrum object + """ + def __init__(self, LaserProfile laser_profile=None, LaserSpectrum laser_spectrum=None, Plasma plasma=None): + + self._laser_profile = laser_profile + self._laser_spectrum = laser_spectrum + self._plasma = plasma + + cpdef Spectrum emission(self, Point3D point_plasma, Vector3D observation_plasma, Point3D point_laser, Vector3D observation_laser, + Spectrum spectrum): + + raise NotImplementedError('Virtual method must be implemented in a sub-class.') + + @property + def laser_profile(self): + return self._laser_profile + + @laser_profile.setter + def laser_profile(self, LaserProfile value): + self._laser_profile = value + + @property + def plasma(self): + return self._plasma + + @plasma.setter + def plasma(self, Plasma value): + self._plasma = value + + @property + def laser_spectrum(self): + return self._laser_spectrum + + @laser_spectrum.setter + def laser_spectrum(self, LaserSpectrum value): + + self._laser_spectrum = value diff --git a/cherab/core/laser/node.pxd b/cherab/core/laser/node.pxd new file mode 100644 index 00000000..6045fb4a --- /dev/null +++ b/cherab/core/laser/node.pxd @@ -0,0 +1,55 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.optical cimport Point3D, Vector3D, Node, Spectrum, Primitive +from raysect.optical.material.emitter.inhomogeneous cimport VolumeIntegrator +from raysect.primitive cimport Cylinder + +from cherab.core.plasma cimport Plasma +from cherab.core.laser.profile cimport LaserProfile +from cherab.core.laser.laserspectrum cimport LaserSpectrum +from cherab.core.laser.model cimport LaserModel + + +cdef class ModelManager: + + cdef: + list _models + readonly object notifier + + cpdef object set(self, object models) + + cpdef object add(self, LaserModel model) + + cpdef object clear(self) + + +cdef class Laser(Node): + + cdef: + readonly object notifier + double _importance + Plasma _plasma + ModelManager _models + LaserProfile _laser_profile + LaserSpectrum _laser_spectrum + list _geometry + VolumeIntegrator _integrator + + cdef object __weakref__ \ No newline at end of file diff --git a/cherab/core/laser/node.pyx b/cherab/core/laser/node.pyx new file mode 100644 index 00000000..b0b821b5 --- /dev/null +++ b/cherab/core/laser/node.pyx @@ -0,0 +1,261 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.primitive cimport Cylinder +from raysect.optical cimport World, AffineMatrix3D, Primitive, Ray +from raysect.optical.material.emitter.inhomogeneous cimport NumericalIntegrator +from raysect.core cimport translate, Material + +from cherab.core.laser.material cimport LaserMaterial +from cherab.core.laser.model cimport LaserModel +from cherab.core.laser.profile import LaserProfile +from cherab.core.laser.laserspectrum import LaserSpectrum +from cherab.core.utility import Notifier +from libc.math cimport M_PI + +from math import ceil + +cdef double DEGREES_TO_RADIANS = (M_PI / 180) + + +cdef class ModelManager: + + def __init__(self): + self._models = [] + self.notifier = Notifier() + + def __iter__(self): + return iter(self._models) + + cpdef object set(self, object models): + + # copy models and test it is an iterable + models = list(models) + + # check contents of list are laser models + for model in models: + if not isinstance(model, LaserModel): + raise TypeError('The model list must consist of only LaserModel objects.') + + self._models = models + self.notifier.notify() + + cpdef object add(self, LaserModel model): + + if not model: + raise ValueError('Model must not be None type.') + + self._models.append(model) + self.notifier.notify() + + cpdef object clear(self): + self._models = [] + self.notifier.notify() + + +cdef class Laser(Node): + """ + A scene-graph object representing a laser of laser light. + + The Cherab laser object holds basic information about the laser and connects + the components which are needed for the laser description. With specified + emission models it can contribute to observed radiation. + + The Laser object is a Raysect scene-graph node and lives in it's own + coordinate space. This coordinate space is defined relative to it's parent + scene-graph object by an AffineTransform. The beam parameters are defined + in the Laser object coordinate space. Models using the beam object must + convert any spatial coordinates into beam space before requesting values + from the Laser object. + + The main physical properties of the laser are defined by the three + attributes laser_spectrum, laser_profile and models. The laser_spectrum + has to be an instance of LaserSpectrum and defines the spectral properties + of the laser light. The laser_profile has to be an instance of LaserProfile + and it holds all the space related definitions as volumetric distribution + of laser light energy polarisation direction. In the models a list of LaserModels + can be stored, which calculate the contribution of the laser ligth to the observed + radiation. The models can cover various applications as for example + Thomson scattering. Please see the documentation of individual classes + for more detail. + + The shape of the laser (e.g. cylinder) and its parameters (e.g. radius) + is controled by the LaserProfile. + + The plasma reference has to be specified to attach the any models. + + :param Node parent: The parent node in the Raysect scene-graph. + See the Raysect documentation for more guidance. + :param AffineMatrix3D transform: The transform defining the spatial position + and orientation of this laser. See the Raysect documentation if you need + guidance on how to use AffineMatrix3D transforms. + :param str name: The name for this laser object. + :ivar Plasma plasma: The plasma instance with which this laser interacts. + :ivar float importance: The importance sampling factor. + :ivar LaserSpectrum laser_spectrum: The LaserSpectrum instance with which this laser interacts. + :ivar LaserProfile laser_profile: The LaserProfile instance with which this laser interacts. + :ivar ModelManager models: The manager class that sets and provides access to the + emission models for this laser. + :ivar VolumeIntegrator integrator: The configurable method for doing + volumetric integration through the laser along a Ray's path. Defaults to + a numerical integrator with 1mm step size, NumericalIntegrator(step=0.001). + """ + + def __init__(self, object parent=None, AffineMatrix3D transform=None, str name=None): + + super().__init__(parent, transform, name) + + self._set_init_values() + + self.notifier = Notifier() + + self._models = ModelManager() + + self._integrator = NumericalIntegrator(step=1e-3) + + self._importance = 1. + + def _set_init_values(self): + """ + Sets initial values of the laser shape to avoid errors. + """ + self._importance = 0. + self._geometry = [] + + @property + def plasma(self): + return self._plasma + + @plasma.setter + def plasma(self, Plasma value not None): + + #unregister from old plasma notifier + if self._plasma is not None: + self._plasma.notifier.remove(self._plasma_changed) + + self._plasma = value + self._plasma.notifier.add(self._plasma_changed) + + self._configure_materials() + + @property + def importance(self): + return self._importance + + @importance.setter + def importance(self, double value): + + self._importance = value + self._configure_materials() + + @property + def laser_spectrum(self): + return self._laser_spectrum + + @laser_spectrum.setter + def laser_spectrum(self, LaserSpectrum value): + self._laser_spectrum = value + self._configure_materials() + + @property + def laser_profile(self): + return self._laser_profile + + @laser_profile.setter + def laser_profile(self, LaserProfile value): + + if self._laser_profile is not None: + self._laser_profile.notifier.remove(self.configure_geometry) + + self._laser_profile = value + self._laser_profile.notifier.add(self.configure_geometry) + + self.configure_geometry() + + @property + def models(self): + return list(self._models) + + @models.setter + def models(self, value): + + # check necessary data is available + if not all([self._plasma, self._laser_profile, self._laser_spectrum]): + raise ValueError("The plasma, laser_profile and laser_spectrum must be set before before specifying any models.") + + self._models.set(value) + self._configure_materials() + + @property + def integrator(self): + return self._integrator + + @integrator.setter + def integrator(self, VolumeIntegrator value): + self._integrator = value + + for i in self._geometry: + i.material.integrator = value + + def configure_geometry(self): + """ + Reconfigure the laser primitives and materials. + """ + + self._build_geometry() + self._configure_materials() + + def _build_geometry(self): + """ + Delete and build new laser segments + """ + # remove old laser segments in any case + for i in self._geometry: + i.parent = None + self._geometry = [] + + # no point in adding segments if there is no model and profile + if self._laser_profile is None: + return + + # rebuild geometry + self._geometry = self._laser_profile.generate_geometry() + + for i in self._geometry: + i.parent = self + + def _configure_materials(self): + """ + Configure laser segment materials + """ + if not list(self._models) or self._plasma is None or self._laser_spectrum is None: + return + + for i in self._geometry: + i.material = LaserMaterial(self, i, list(self._models), self._integrator) + + def get_geometry(self): + return self._geometry + + def _plasma_changed(self): + """React to change of plasma and propagate the information.""" + self._configure_materials() + + def _modified(self): + self._configure_materials() diff --git a/cherab/core/laser/profile.pxd b/cherab/core/laser/profile.pxd new file mode 100644 index 00000000..c634a2f8 --- /dev/null +++ b/cherab/core/laser/profile.pxd @@ -0,0 +1,41 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function3D +from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D + +from raysect.optical cimport Spectrum, Point3D, Vector3D + +from cherab.core.laser.node cimport Laser + + +cdef class LaserProfile: + + cdef: + VectorFunction3D _polarization3d, _pointing3d + Function3D _energy_density3d + readonly object notifier + + cpdef Vector3D get_pointing(self, double x, double y, double z) + + cpdef Vector3D get_polarization(self, double x, double y, double z) + + cpdef double get_energy_density(self, double x, double y, double z) + + cpdef list generate_geometry(self) \ No newline at end of file diff --git a/cherab/core/laser/profile.pyx b/cherab/core/laser/profile.pyx new file mode 100644 index 00000000..6356d1cb --- /dev/null +++ b/cherab/core/laser/profile.pyx @@ -0,0 +1,163 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function3D +from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D + +from raysect.optical cimport SpectralFunction, Spectrum, InterpolatedSF, Point3D, Vector3D + +from cherab.core.laser.node cimport Laser +from cherab.core.utility import Notifier + + +cdef class LaserProfile: + """ + LaserProfile base class. + + This is an abstract class and cannot be used for observing. + + Provides information about spatial properties of the laser beam: + direction of the laser propagation (direction + of the Poynting vector), polarisation of the ligth as the direction + of the electric component vector and volumetric energy density of + the laser light. + + All the laser properties are evaluated in the frame of reference of + the laser. + + .. warning:: + When combining a LaserProfile with a LaserSpectrum for a laser, + a special care has to be given to obtain the correct power + of the scattered spectrum. Scattering models can multiply + both the spectral power density given by the LaserProfile and + the volumetric energy density given by the LaserProfile. + Combination of incompatible cases may yield incorrect + values of scattered power. + + :ivar Laser laser: The Laser scenegraph node the LaserProfile + is connected to. + """ + + def __init__(self): + + self.notifier = Notifier() + + def set_polarization_function(self, VectorFunction3D function): + """ + Assigns the 3D vector function describing the polarisation vector. + + The polarisation is given as the direction of the electric + component of the electromagnetic wave. + + The function is specified in the laser space. + + :param VectorFunction3D function: A 3D vector function describing + the polarisation vector. + """ + self._polarization3d = function + + def set_pointing_function(self, VectorFunction3D function): + """ + Assings the 3D vector function describing the direction of the laser propagation. + + The direction of the laser light propagation is the direction + of the Poynting vector. + + :param VectorFunction3D function: A 3D vector function describing + the laser light propagation direction + """ + self._pointing3d = function + + def set_energy_density_function(self, Function3D function): + """ + Assigns the 3D scalar function describing the laser energy distribution. + + The laser power distribution is the value of the volumetric + energy density of the laser light. + """ + self._energy_density3d = function + + cpdef Vector3D get_pointing(self, double x, double y, double z): + """ + Returns the laser light propagation direction. + + At the point (x, y, z) in the laser space. + + :param x: x coordinate in meters. + :param y: y coordinate in meters. + :param z: z coordinate in meters. + :return: Intensity in m^-3. + """ + + return self._pointing3d.evaluate(x, y, z) + + cpdef Vector3D get_polarization(self, double x, double y, double z): + """ + Returns a vector denoting the laser polarisation. + + The polarisation direction is the direction of the electric + component of the electromagnetic wave for the point (x, y, z) + in the laser space. + + :param x: x coordinate in meters. + :param y: y coordinate in meters. + :param z: z coordinate in meters. + :return: power density in Wm^-3. + """ + + return self._polarization3d(x, y, z) + + cpdef double get_energy_density(self, double x, double y, double z): + """ + Returns the volumetric energy density of the laser light in W*m^-3. + + At the point (x, y, z) in the laser space. + + :param x: x coordinate in meters in the laser frame. + :param y: y coordinate in meters in the laser frame. + :param z: z coordinate in meters in the laser frame. + :return: power density in W*m^-3. + """ + + return self._energy_density3d.evaluate(x, y, z) + + cpdef list generate_geometry(self): + """ + returns list of raysect primitives composing the laser geometry + + This method is called from the Laser instance to which the instance + of Profile is attached to. The Laser instance will be assigned as + the parent to the returned primitives in the Laser._configure method. + The Laser._configure method does not change any transforms. This is + why the returned primitives have to have their transforms already + initialised in the frame of the laser, when returned. + """ + + raise NotImplementedError("Virtual function density not defined.") + + def _change(self): + """ + Called if the laser properties change. + + If the model caches calculation data that would be invalidated if its + source data changes then this method may be overridden to clear the + cache. + """ + + pass diff --git a/cherab/core/laser/tests/__init__.py b/cherab/core/laser/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cherab/core/laser/tests/test_laser.py b/cherab/core/laser/tests/test_laser.py new file mode 100644 index 00000000..f9f85732 --- /dev/null +++ b/cherab/core/laser/tests/test_laser.py @@ -0,0 +1,110 @@ +import unittest + +from raysect.optical import World +from raysect.optical.material.emitter.inhomogeneous import NumericalIntegrator + +from cherab.core import Plasma +from cherab.core.laser.node import Laser +from cherab.core.model.laser.laserspectrum import ConstantSpectrum +from cherab.core.model.laser.model import SeldenMatobaThomsonSpectrum +from cherab.core.model.laser.profile import UniformEnergyDensity + + +class TestLaser(unittest.TestCase): + + def test_laser_init(self): + """ + Test correct initialisation of a laser instance. + """ + + world = World() + laser = Laser(parent=world) + + with self.assertRaises(ValueError, msg="Model was attached before Plasma, Profile and LaserSpectrum were specified."): + laser.models = [SeldenMatobaThomsonSpectrum()] + + laser.laser_profile = UniformEnergyDensity() + with self.assertRaises(ValueError, msg="Model was attached before Plasma, Profile and LaserSpectrum were specified."): + laser.models = [SeldenMatobaThomsonSpectrum()] + + laser.laser_spectrum = ConstantSpectrum(min_wavelength=1059, max_wavelength=1061, bins=10) + with self.assertRaises(ValueError, msg="Model was attached before Plasma, Profile and LaserSpectrum were specified."): + laser.models = [SeldenMatobaThomsonSpectrum()] + + laser.plasma = Plasma(parent=world) + laser.models = [SeldenMatobaThomsonSpectrum()] + + def test_reference_change(self): + + world = World() + + laser_profile = UniformEnergyDensity(laser_length=1, laser_radius=0.1) + laser_spectrum = ConstantSpectrum(min_wavelength=1059, max_wavelength=1061, bins=10) + plasma = Plasma(parent=world) + models = [SeldenMatobaThomsonSpectrum()] + + laser_profile2 = UniformEnergyDensity() + laser_spectrum2 = ConstantSpectrum(min_wavelength=1059, max_wavelength=1061, bins=10) + plasma2 = Plasma(parent=world) + models2 = [SeldenMatobaThomsonSpectrum()] + + laser = Laser(parent=world) + + laser.laser_spectrum = laser_spectrum + laser.plasma = plasma + laser.laser_profile = laser_profile + laser.models = models + + for mod in list(laser.models): + self.assertIs(mod.laser_profile, laser_profile, msg="laser_profile reference in emission model" + "is not set correctly.") + self.assertIs(mod.plasma, plasma, msg="plasma reference in emission model" + "is not set correctly.") + self.assertIs(mod.laser_spectrum, laser_spectrum, msg="laser_spectrum reference in emission model" + "is not set correctly.") + + laser.laser_spectrum = laser_spectrum2 + laser.plasma = plasma2 + laser.laser_profile = laser_profile2 + + for mod in list(laser.models): + self.assertIs(mod.laser_profile, laser_profile2, msg="laser_profile reference in emission model" + "is not set correctly.") + self.assertIs(mod.plasma, plasma2, msg="plasma reference in emission model" + "is not set correctly.") + self.assertIs(mod.laser_spectrum, laser_spectrum2, msg="laser_spectrum reference in emission model" + "is not set correctly.") + + laser.models = models + models2 + + for mod in list(laser.models): + self.assertIs(mod.laser_profile, laser_profile2, msg="laser_profile reference in emission model" + "is not set correctly.") + self.assertIs(mod.plasma, plasma2, msg="plasma reference in emission model" + "is not set correctly.") + self.assertIs(mod.laser_spectrum, laser_spectrum2, msg="laser_spectrum reference in emission model" + "is not set correctly.") + + def test_integrator_change(self): + + world = World() + + laser_profile = UniformEnergyDensity(laser_length=1, laser_radius=0.1) + laser_spectrum = ConstantSpectrum(min_wavelength=1059, max_wavelength=1061, bins=10) + plasma = Plasma(parent=world) + models = [SeldenMatobaThomsonSpectrum()] + + laser = Laser(parent=world) + + laser.laser_spectrum = laser_spectrum + laser.plasma = plasma + laser.laser_profile = laser_profile + laser.models = models + + integrator = NumericalIntegrator(1e-4) + + laser.integrator = integrator + + for i in laser.get_geometry(): + self.assertIs(i.material.integrator, integrator, msg="Integrator not updated properly") + diff --git a/cherab/core/laser/tests/test_laserspectrum.py b/cherab/core/laser/tests/test_laserspectrum.py new file mode 100644 index 00000000..9473e43d --- /dev/null +++ b/cherab/core/laser/tests/test_laserspectrum.py @@ -0,0 +1,62 @@ +import unittest +import numpy as np + +from cherab.core.laser.laserspectrum import LaserSpectrum +from raysect.optical.spectrum import Spectrum + +class TestLaserSpectrum(unittest.TestCase): + + def test_laserspectrum_init(self): + # test min_wavelength boundaries + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise a ValueError with min_wavelength being zero."): + LaserSpectrum(0., 100, 200) + LaserSpectrum(-1, 100, 200) + + # test max_wavelength boundaries + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise a ValueError with max_wavelength being zero."): + LaserSpectrum(10, 0, 200) + LaserSpectrum(10, -1, 200) + + # test min_wavelength >= max_wavelength + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise a ValueError with max_wavelength < min_wavelength."): + LaserSpectrum(40, 30, 200) + LaserSpectrum(30, 30, 200) + + # test bins > 0 + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise a ValueError with max_wavelength < min_wavelength."): + LaserSpectrum(30, 30, 0) + LaserSpectrum(30, 30, -1) + + def test_laserspectrum_changes(self): + laser_spectrum = LaserSpectrum(100, 200, 100) + + # change min_wavelength to be larger or equal to max_wavelength + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise ValueError for min_wavelength change " + "with min_wavelength >= max_wavelength."): + laser_spectrum.min_wavelength = 300 + laser_spectrum.min_wavelength = 200 + + # change max_wavelength to be smaller than max_wavelength + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise ValueError for max_wavelength change " + "with min_wavelength > max_wavelength."): + laser_spectrum.max_wavelength = 50 + laser_spectrum.max_wavelength = 100 + + with self.assertRaises(ValueError, + msg="LaserSpectrum did not raise a ValueError with max_wavelength < min_wavelength."): + laser_spectrum.bins = -1 + laser_spectrum.bins = 0 + + # laser spectrum should have same behaviour as Spectrum from raysect.optical + spectrum = Spectrum(laser_spectrum.min_wavelength, laser_spectrum.max_wavelength, laser_spectrum.bins) + + # test caching of spectrum data, behaviour should be consistent with raysect.optical.spectrum.Spectrum + self.assertTrue(np.array_equal(laser_spectrum.wavelengths, spectrum.wavelengths), + "LaserSpectrum.wavelengths values are not equal to Spectrum.wavelengths " + "with same boundaries and number of bins") \ No newline at end of file diff --git a/cherab/core/model/laser/__init__.pxd b/cherab/core/model/laser/__init__.pxd new file mode 100644 index 00000000..3b0e3818 --- /dev/null +++ b/cherab/core/model/laser/__init__.pxd @@ -0,0 +1,4 @@ +from cherab.core.model.laser.laserspectrum import ConstantSpectrum, GaussianSpectrum +from cherab.core.model.laser.profile import UniformEnergyDensity, ConstantAxisymmetricGaussian +from cherab.core.model.laser.profile import ConstantBivariateGaussian, TrivariateGaussian, GaussianBeamAxisymmetric +from cherab.core.model.laser.model import SeldenMatobaThomsonSpectrum \ No newline at end of file diff --git a/cherab/core/model/laser/__init__.py b/cherab/core/model/laser/__init__.py new file mode 100644 index 00000000..930b55a7 --- /dev/null +++ b/cherab/core/model/laser/__init__.py @@ -0,0 +1,4 @@ +from .laserspectrum import ConstantSpectrum, GaussianSpectrum +from .profile import UniformEnergyDensity, ConstantAxisymmetricGaussian +from .profile import ConstantBivariateGaussian, TrivariateGaussian, GaussianBeamAxisymmetric +from .model import SeldenMatobaThomsonSpectrum diff --git a/cherab/core/model/laser/laserspectrum.pxd b/cherab/core/model/laser/laserspectrum.pxd new file mode 100644 index 00000000..e21d36fb --- /dev/null +++ b/cherab/core/model/laser/laserspectrum.pxd @@ -0,0 +1,34 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from cherab.core.laser cimport LaserSpectrum + + +cdef class ConstantSpectrum(LaserSpectrum): + + cdef double evaluate(self, double x) except? -1e999 + + +cdef class GaussianSpectrum(LaserSpectrum): + + cdef: + double _stddev, _recip_stddev, _normalisation, _mean + double _norm_cdf + + cdef double evaluate(self, double x) except? -1e999 diff --git a/cherab/core/model/laser/laserspectrum.pyx b/cherab/core/model/laser/laserspectrum.pyx new file mode 100644 index 00000000..58c1cada --- /dev/null +++ b/cherab/core/model/laser/laserspectrum.pyx @@ -0,0 +1,133 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from cherab.core.laser cimport LaserSpectrum +from libc.math cimport sqrt, exp, M_PI, erf, M_SQRT2 + + +cdef class ConstantSpectrum(LaserSpectrum): + """ + A laser spectrum with constant power. + + Has a constant, non-zero distribution of power spectral density + between the min_wavelength and max_wavelength. The integral value + of the power is 1 W. + + .. note:: + The ConstantSpectrum class is suitable for approximation + of an infinitely thin laser spectrum, e.g.: + ConstantSpectrum(1063.9, 1064.1, 1) + """ + + def __init__(self, double min_wavelength, double max_wavelength, int bins): + + super().__init__(min_wavelength, max_wavelength, bins) + + cdef double evaluate(self, double x) except? -1e999: + """ + Returns the spectral power density for the given wavelength. + + :param float x: Wavelength in nm. + + :return: Power spectral density in W/nm. + """ + + cdef: + double spectrum_width + int index + + if self._min_wavelength <= x <= self._max_wavelength: + return 1.0 / (self._max_wavelength - self._min_wavelength) + else: + return 0 + + +cdef class GaussianSpectrum(LaserSpectrum): + """ + A laser spectrum with a normally distributed power spectral density. + + Has a Gaussian-like spectral shape. The inegral value of power is 1 W. + + :param float mean: The mean value of the Gaussian distribution + of the laser spectrum in nm, can be thought of as the central + wavelength of the laser. + :param float stddev: Standard deviation of the Gaussian + distribution of the laser spectrum. + + :ivar float stddev: Standard deviation of the Gaussian + distribution of the laser spectrum. + :ivar float mean: The mean value of the Gaussian distribution + of the laser spectrum in nm, can be thought of as the central + wavelength of the laser. + """ + + def __init__(self, double min_wavelength, double max_wavelength, int bins, double mean, double stddev): + + self.stddev = stddev + self.mean = mean + super().__init__(min_wavelength, max_wavelength, bins) + + @property + def stddev(self): + return self._stddev + + @stddev.setter + def stddev(self, value): + if value <= 0: + raise ValueError("Value has to be larger than 0") + + self._stddev = value + self._recip_stddev = 1 / value + self._normalisation = 1 / (value * sqrt(2 * M_PI)) + self._norm_cdf = 1 / (value * M_SQRT2) + + @property + def mean(self): + return self._mean + + @mean.setter + def mean(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0") + + self._mean = value + + cdef double evaluate(self, double x) except? -1e999: + """ + Returns the spectral power density for the given wavelength. + + :param float x: Wavelength in nm. + + :return: Power spectral density in W/nm. + """ + return self._normalisation * exp(-0.5 * ((x - self._mean) * self._recip_stddev) ** 2) + + cpdef double _get_bin_power_spectral_density(self, double wavelength_lower, double wavelength_upper): + """ + Returns the power spectral density in a bin. + + Overrides the parent method to deliver better precision. + """ + + cdef: + double val_lower, val_upper + + val_lower = erf((wavelength_lower - self._mean) * self._norm_cdf) + val_upper = erf((wavelength_upper - self._mean) * self._norm_cdf) + return 0.5 * (val_upper - val_lower) / self._delta_wavelength \ No newline at end of file diff --git a/cherab/core/model/laser/math_functions.pxd b/cherab/core/model/laser/math_functions.pxd new file mode 100644 index 00000000..08827094 --- /dev/null +++ b/cherab/core/model/laser/math_functions.pxd @@ -0,0 +1,48 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function3D + +cdef class ConstantAxisymmetricGaussian3D(Function3D): + + cdef: + double _stddev, _normalisation, _kr + + cdef double evaluate(self, double x, double y, double z) except? -1e999 + + +cdef class ConstantBivariateGaussian3D(Function3D): + + cdef: + double _stddev_x, _stddev_y, _kx, _ky, _normalisation + + +cdef class TrivariateGaussian3D(Function3D): + + cdef: + double _mean_z, _stddev_x, _stddev_y, _stddev_z, _kx, _ky + double _kz, _normalisation + + +cdef class GaussianBeamModel(Function3D): + + cdef: + double _waist_z, _stddev_waist, _stddev_waist2, _wavelength, _rayleigh_range + + cdef double evaluate(self, double x, double y, double z) except? -1e999 diff --git a/cherab/core/model/laser/math_functions.pyx b/cherab/core/model/laser/math_functions.pyx new file mode 100644 index 00000000..1ed73a61 --- /dev/null +++ b/cherab/core/model/laser/math_functions.pyx @@ -0,0 +1,304 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +cimport cython + +from raysect.core.math.function.float cimport Function3D +from raysect.core.math.cython.utility cimport find_index + +from libc.math cimport sqrt, exp, pi + + +cdef class ConstantAxisymmetricGaussian3D(Function3D): + """ + A function with a 2D Gaussian in the x-y plane and equal standard deviations in x and y directions. + + .. math:: + F(x, y, z) = \\frac{1}{2 * \\pi \\sigma^2} exp\\left(-\\frac{x^2 + y^2}{2 * \\sigma^2}\\right) + + The function value has a Gaussian shape in the x-y plane with the standard deviations in + x and y direction being equal. The integral over an x-y plane is equal to 1 + and the mean values in x and y directions are equal to 0. + + :param float stddev: The standard deviation in both the x and y directions. + """ + + def __init__(self, stddev): + + super().__init__() + + self.stddev = stddev + + @property + def stddev(self): + + return self._stddev + + @stddev.setter + def stddev(self, value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev = value + self._kr = -1 / (2 * value ** 2) + self._normalisation = 1 / (2 * pi * value ** 2) + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + cdef: + double r2 + r2 = x ** 2 + y ** 2 + return self._normalisation * exp(r2 * self._kr) + + +cdef class ConstantBivariateGaussian3D(Function3D): + """ + A function with a 2D Gaussian in the x-y plane. + + .. math:: + F(x, y, z) = \\frac{1}{2 * \\pi \\sigma_x \\sigma_y} exp\\left(-\\frac{x^2 + y^2}{2 * \\sigma_x \\sigma_y}\\right) + + The function value has a Gaussian shape in the x-y plane. The integral over an x-y plane is equal to 1 + and the mean values in x and y directions are equal to 0. + The correlation between the standard deviations in x and y directions is equal to 0. + + :param float stddev_x: The standard deviation in the x directions. + :param float stddev_y: The standard deviation in the y directions. + """ + + def __init__(self, stddev_x, stddev_y): + + super().__init__() + self._init_params() + + self.stddev_x = stddev_x + self.stddev_y = stddev_y + + def _init_params(self): + self._stddev_x = 1 + self._stddev_y = 1 + + @property + def stddev_x(self): + return self._stddev_x + + @stddev_x.setter + def stddev_x(self, value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev_x = value + + self._cache_constants() + + @property + def stddev_y(self): + return self._stddev_y + + @stddev_y.setter + def stddev_y(self, value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev_y = value + + self._cache_constants() + + def _cache_constants(self): + self._kx = -1 / (2 * self._stddev_x ** 2) + self._ky = -1 / (2 * self._stddev_y ** 2) + self._normalisation = 1 / (2 * pi * self._stddev_x * self._stddev_y) + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + return self._normalisation * exp(x ** 2 * self._kx + + y ** 2 * self._ky) + + +cdef class TrivariateGaussian3D(Function3D): + """ + A function with a 3D Gaussian shape. + + .. math:: + F(x, y, z) = \\frac{1}{\\sqrt{2 \\pi^3} \\sigma_x \\sigma_y \\sigma_z} exp\\left(-\\frac{x^2}{2 \\sigma_x^2} -\\frac{y^2}{2 \\sigma_y^2} - \\frac{(z - \\mu_z)^2}{2 \\sigma_z^2}\\right) + + The integral over the whole 3D space is equal to 1.The correlation between the standard deviations in x and y directions is equal to 0. The mean value in the + x and y directions are equal to 0. + + :param float mean_z: Mean value in the z direction. + :param float stddev_x: The standard deviation in the x directions. + :param float stddev_y: The standard deviation in the y directions. + :param float stddev_z: The standard deviation in the z directions. + """ + + def __init__(self, mean_z, stddev_x, stddev_y, stddev_z): + + super().__init__() + self._init_params() + + self.stddev_x = stddev_x + self.stddev_y = stddev_y + self.stddev_z = stddev_z + self.mean_z = mean_z + + def _init_params(self): + self._mean_z = 1 + self._stddev_x = 1 + self._stddev_y = 1 + self._stddev_z = 1 + + @property + def stddev_x(self): + return self._stddev_x + + @stddev_x.setter + def stddev_x(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev_x = value + + self._cache_constants() + + @property + def stddev_y(self): + return self._stddev_y + + @stddev_y.setter + def stddev_y(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev_y = value + + self._cache_constants() + + @property + def stddev_z(self): + return self._stddev_z + + @stddev_z.setter + def stddev_z(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._stddev_z = value + + self._cache_constants() + + @property + def mean_z(self): + return self._mean_z + + @mean_z.setter + def mean_z(self, double value): + self._mean_z = value + + def _cache_constants(self): + self._kx = -1 / (2 * self._stddev_x ** 2) + self._ky = -1 / (2 * self._stddev_y ** 2) + self._kz = -1 / (2 * self._stddev_z ** 2) + self._normalisation = 1 / (sqrt((2 * pi) ** 3) * self._stddev_x * self._stddev_y * self._stddev_z) + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + return self._normalisation * exp(x ** 2 * self._kx + + y ** 2 * self._ky + + (z - self._mean_z) ** 2 * self._kz) + + +cdef class GaussianBeamModel(Function3D): + """ + A Gaussian beam function (https://en.wikipedia.org/wiki/Gaussian_beam) + + .. math:: + F(x, y, z) = \\frac{1}{2 \\pi \\sigma^2_z} exp\\left( -\\frac{x^2 + y^2}{2 \\sigma_z(z)^2 }\\right) + + where the standard deviation in the z direction + + .. math:: + \\sigma_z(z) = \\sigma_0 \\sqrt{1 + \\left(\\frac{z - z_0}{z_R}\\right)^2} + + is a function of position and the + + .. math:: + z_R = \\frac{\\pi \\omega_0^2 n}{\\lambda_l} + + is the Rayleigh range. + """ + + def __init__(self, double wavelength, double waist_z, double stddev_waist): + + # preset default values + self._wavelength = 1e3 + self._waist_z = 0 + self._stddev_waist = 1e-3 + + self.wavelength = wavelength + self.waist_z = waist_z + self.stddev_waist = stddev_waist + + @property + def wavelength(self): + return self._wavelength + + @wavelength.setter + def wavelength(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0, but {0} passed.".format(value)) + + self._wavelength = value + self._cache_constants() + + @property + def waist_z(self): + return self._waist_z + + @waist_z.setter + def waist_z(self, double value): + self._waist_z = value + + @property + def stddev_waist(self): + return self._stddev_waist + + @stddev_waist.setter + def stddev_waist(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0, but {0} passed.".format(value)) + + self._stddev_waist = value + self._stddev_waist2 = self._stddev_waist ** 2 + self._cache_constants() + + def _cache_constants(self): + + n = 1 # refractive index of vacuum + self._rayleigh_range = 2 * pi * n * self._stddev_waist2 / self._wavelength / 1e-9 + + @cython.cdivision(True) + cdef double evaluate(self, double x, double y, double z) except? -1e999: + + cdef: + double r2, stddev_z2, z_prime + + # shift to correct gaussiam beam model coords, it works with waist at z=0 + z_prime = z - self._waist_z + + r2 = x ** 2 + y ** 2 + stddev_z2 = self._stddev_waist2 * (1 + ((z_prime) / self._rayleigh_range) ** 2) + + return 1 / (2 * pi * stddev_z2) * exp(r2 / (-2 * stddev_z2)) diff --git a/cherab/core/model/laser/model.pxd b/cherab/core/model/laser/model.pxd new file mode 100644 index 00000000..27e0230f --- /dev/null +++ b/cherab/core/model/laser/model.pxd @@ -0,0 +1,40 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.optical cimport Vector3D, Point3D +from raysect.optical.spectrum cimport Spectrum + +from cherab.core.laser cimport Laser, LaserModel, LaserSpectrum, LaserProfile + + +cdef class SeldenMatobaThomsonSpectrum(LaserModel): + + cdef: + double _CONST_ALPHA, _RATE_TS, _RECIP_M_PI + + cpdef Spectrum emission(self, Point3D point_plasma, Vector3D observation_plasma, Point3D point_laser, + Vector3D observation_laser, Spectrum spectrum) + + cdef double seldenmatoba_spectral_shape(self, double epsilon, double cos_theta, double alpha) + + cdef Spectrum _add_spectral_contribution(self, double ne, double te, double laser_energy, double angle_pointing, + double angle_polarization, double laser_wavelength, Spectrum spectrum) + + cpdef Spectrum calculate_spectrum(self, double ne, double te, double laser_energy_density, double laser_wavelength, + double observation_angle, double angle_polarization, Spectrum spectrum) \ No newline at end of file diff --git a/cherab/core/model/laser/model.pyx b/cherab/core/model/laser/model.pyx new file mode 100644 index 00000000..dbab8803 --- /dev/null +++ b/cherab/core/model/laser/model.pyx @@ -0,0 +1,220 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from libc.math cimport exp, sqrt, cos, M_PI, sin +cimport cython + +from raysect.optical cimport Vector3D, Point3D +from raysect.optical.spectrum cimport Spectrum + +from cherab.core cimport Plasma +from cherab.core.laser cimport LaserModel, LaserProfile, LaserSpectrum +from cherab.core.utility.constants cimport DEGREES_TO_RADIANS +from cherab.core.utility.constants cimport SPEED_OF_LIGHT, ELECTRON_CLASSICAL_RADIUS, ELECTRON_REST_MASS, ELEMENTARY_CHARGE + + +cdef class SeldenMatobaThomsonSpectrum(LaserModel): + """ + Thomson Scattering based on Selden-Matoba. + + The class calculates Thomson scattering of the laser to the spectrum. The model of the scattered spectrum used is based on + the semi-empirical model by Selden and the Thomson scattering cross-section is taken from Matoba articles. The spectral contribution + of the scattered laser light c is calculated as a sum of contributions of all laser wavelengths + + .. math:: + c(\lambda) = c r_e^2 n_e cos^2\\theta \\sum_{\\lambda_L} \\frac{E_L(\\lambda_l) S(\\frac{\\lambda}{\\lambda_L} - 1, \\varphi, T_e)}{\\lambda_L}, + + + where :math:`\\lambda` is the spectrum's wavelength, :math:`r_e` is the classical electron radius, :math:`n_e` is the electron delsity, + :math:`\\theta` is the angle between the laser polarisation and scattering vectors, :math:`c` is the vacuum speed of light + :math:`\\lambda_L` is the laser wavelength, :math:`E_L` is the laser energy density, :math:`\\varphi` is the scattering angle and :math:`T_e` is the electron + temperature. The scattering function S is taken from the Matoba article. The multiplication by the speed of light is added to transfer the Thomson scattering + cross section into a reaction rate. + + .. seealso:: + The Prunty article provides a thorough introduction into the phyiscs of Thomson scattering. The articles by Selden and Matoba were used to build + this model. + + :Selden: `Selden, A.C., 1980. Simple analytic form of the relativistic Thomson scattering spectrum. Physics Letters A, 79(5-6), pp.405-406.` + :Matoba: `Matoba, T., et al., 1979. Analytical approximations in the theory of relativistic Thomson scattering for high temperature fusion plasma. + Japanese Journal of Applied Physics, 18(6), p.1127.` + :Prunty: `Prunty, S.L., 2014. A primer on the theory of Thomson scattering for high-temperature fusion plasmas. Physica Scripta, 89(12), p.128001.` + + """ + + def __init__(self, LaserProfile laser_profile=None, LaserSpectrum laser_spectrum=None, Plasma plasma=None): + + super().__init__(laser_profile, laser_spectrum, plasma) + + # Selden, A.C., 1980. Simple analytic form of the relativistic Thomson scattering spectrum. Physics Letters A, 79(5-6), pp.405-406. + self._CONST_ALPHA = ELECTRON_REST_MASS * SPEED_OF_LIGHT ** 2 / (2 * ELEMENTARY_CHARGE) #constant alpha, rewritten for Te in eV + + # from: Prunty, S. L. "A primer on the theory of Thomson scattering for high-temperature fusion plasmas." + # TS cross section equiation ~ 3.28 or + # Matoba, T., et al., 1979. Analytical approximations in the theory of relativistic Thomson scattering for high temperature fusion plasma. + # Japanese Journal of Applied Physics, 18(6), p.1127., TS cross section equiation 18 + # speed of light for correct normalisation of the scattered intensity calculation (from x-section to rate constant) + self._RATE_TS = ELECTRON_CLASSICAL_RADIUS ** 2 * SPEED_OF_LIGHT + + self._RECIP_M_PI = 1 / M_PI + + @cython.cdivision(True) + cdef double seldenmatoba_spectral_shape(self, double epsilon, double const_theta, double alpha): + + cdef: + double c, a, b + + # const_theta is 2 * (1 - cos(theta)) + + c = sqrt(alpha * self._RECIP_M_PI) * (1 - 15. / (16. * alpha) + 345. / (512. * alpha ** 2)) + a = (1 + epsilon) ** 3 * sqrt(const_theta * (1 + epsilon) + epsilon ** 2) + b = sqrt(1 + epsilon ** 2 / (const_theta * (1 + epsilon))) - 1 + + return c / a * exp(-2 * alpha * b) + + @cython.boundscheck(False) + @cython.wraparound(False) + cpdef Spectrum emission(self, Point3D point_plasma, Vector3D observation_plasma, Point3D point_laser, + Vector3D observation_laser, Spectrum spectrum): + cdef: + double angle_scattering, angle_pointing, angle_polarization + double te, ne, laser_energy_density, laser_energy + double plasma_x, plasma_y, plasma_z, laser_x, laser_y, laser_z + double[::1] laser_wavelength_mv, laser_spectrum_power_mv + int bins + Vector3D pointing_vector, polarisation_vector + Py_ssize_t index + + plasma_x = point_plasma.x + plasma_y = point_plasma.y + plasma_z = point_plasma.z + + # get electron parameters for the plasma point + te = self._plasma.get_electron_distribution().effective_temperature(plasma_x, plasma_y, plasma_z) + + #terminate early if electron temperature is 0 + if te <= 0: + return spectrum + + ne = self._plasma.get_electron_distribution().density(plasma_x, plasma_y, plasma_z) + + #terminate early if electron density is 0 + if ne <= 0: + return spectrum + + laser_x = point_laser.x + laser_y = point_laser.y + laser_z = point_laser.z + + #get laser volumetric power + laser_energy_density = self._laser_profile.get_energy_density(laser_x, laser_y, laser_z) + + #terminate early if laser power is 0 + if laser_energy_density == 0: + return spectrum + + pointing_vector = self._laser_profile.get_pointing(laser_x, laser_y, laser_z) + + #angle between observation and pointing vector + angle_pointing = observation_laser.angle(pointing_vector) # angle between observation and pointing vector of laser + + angle_scattering = (180. - angle_pointing) # scattering direction is the opposite to obervation direction + + # angle between polarisation and observation + polarisation_vector = self._laser_profile.get_polarization(laser_x, laser_y, laser_z) + angle_polarization = observation_laser.angle(polarisation_vector) # scattering direction is the opposite to obervation direction + + laser_wavelength_mv = self._laser_spectrum.wavelengths_mv + laser_spectrum_power_mv = self._laser_spectrum.power_mv # power in spectral bins (PSD * delta wavelength) + bins = self._laser_spectrum.get_spectral_bins() + + for index in range(bins): + laser_energy = laser_spectrum_power_mv[index] * laser_energy_density + if laser_energy > 0: + spectrum = self._add_spectral_contribution(ne, te, laser_energy, angle_scattering, + angle_polarization, laser_wavelength_mv[index], spectrum) + + return spectrum + + @cython.boundscheck(False) + @cython.wraparound(False) + @cython.cdivision(True) + cdef Spectrum _add_spectral_contribution(self, double ne, double te, double laser_energy, double angle_scattering, + double angle_polarization, double laser_wavelength, Spectrum spectrum): + + cdef: + int index, nbins + double alpha, epsilon, cos_anglescat, wavelength, min_wavelength, delta_wavelength + double const_theta, recip_laser_wavelength, scattered_power, spectrum_norm + double sin2_angle_pol + + alpha = self._CONST_ALPHA / te + # scattering angle of the photon = pi - observation_angle + cos_anglescat = cos(angle_scattering * DEGREES_TO_RADIANS) + + # pre-calculate constants for Selden-Matoba shape + const_theta = 2 * (1 - cos_anglescat) + + nbins = spectrum.bins + min_wavelength = spectrum.min_wavelength + delta_wavelength = spectrum.delta_wavelength + recip_laser_wavelength = 1 / laser_wavelength + + # dipole radiation has a cos ** 2 characteristic, here angle shifted by 90 deg + sin2_angle_pol = sin(angle_polarization * DEGREES_TO_RADIANS) ** 2 + + #from d_lambda to d_epsilon:d_epsilon = d_lambda / laser_wavelength + scattered_power = ne * self._RATE_TS * laser_energy * recip_laser_wavelength * sin2_angle_pol + for index in range(nbins): + wavelength = min_wavelength + (0.5 + index) * delta_wavelength + epsilon = (wavelength * recip_laser_wavelength) - 1 + spectrum_norm = self.seldenmatoba_spectral_shape(epsilon, const_theta, alpha) + spectrum.samples_mv[index] += spectrum_norm * scattered_power + + return spectrum + + cpdef Spectrum calculate_spectrum(self, double ne, double te, double laser_energy_density, double laser_wavelength, + double observation_angle, double angle_polarization, Spectrum spectrum): + """ + Calculates scattered spectrum for the given parameters. + + The method returns the Thomson scattered spectrum given the plasma parameters, without the need of specifying + plasma or laser. + + :param float ne: Plasma electron density in m**-3 + :param float te: Plasma electron temperature in eV + :param float laser_energy_density: Energy density of the laser light in J * m**-3 + :param float laser_wavelength: The laser light wavelength in nm + :param float observation_angle: The angle of observation is the angle between the observation direction and the direction + of the Poynting vector. + :param float angle_polarization: The angle between the observation direction and the polarisation direction of the laser light. + + :return: Spectrum + """ + # check for nonzero laser power, ne, te, wavelength + if ne <= 0 or te <= 0 or not laser_energy_density > 0: + return spectrum + if laser_wavelength <= 0: + raise ValueError("laser wavelength has to be larger than 0") + + angle_scattering = (180. - observation_angle) # scattering direction is the opposite to obervation direction + + return self._add_spectral_contribution(ne, te, laser_energy_density, angle_scattering, angle_polarization, laser_wavelength, spectrum) + + \ No newline at end of file diff --git a/cherab/core/model/laser/profile.pxd b/cherab/core/model/laser/profile.pxd new file mode 100644 index 00000000..12379335 --- /dev/null +++ b/cherab/core/model/laser/profile.pxd @@ -0,0 +1,57 @@ +# Copyright 2016-2021 Euratom +# Copyright 2016-2021 United Kingdom Atomic Energy Authority +# Copyright 2016-2021 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +from raysect.core.math.function.float cimport Function3D +from raysect.optical cimport Spectrum, Point3D, Vector3D + +from cherab.core.laser cimport LaserProfile + + +cdef class UniformEnergyDensity(LaserProfile): + + cdef: + double _energy_density, _laser_length, _laser_radius + + +cdef class ConstantAxisymmetricGaussian(LaserProfile): + + cdef: + double _stddev, _pulse_energy, _pulse_length, _laser_length, _laser_radius + Function3D _distribution + + +cdef class ConstantBivariateGaussian(LaserProfile): + + cdef: + double _stddev_x, _stddev_y, _pulse_energy, _pulse_length, _laser_length, _laser_radius + Function3D _distribution + + +cdef class TrivariateGaussian(LaserProfile): + + cdef: + double _stddev_x, _stddev_y, _stddev_z, _mean_z, _pulse_energy, _pulse_length, _laser_length, _laser_radius + Function3D _distribution + + +cdef class GaussianBeamAxisymmetric(LaserProfile): + + cdef: + double _pulse_energy, _pulse_length, _stddev_waist, _waist_z, _laser_wavelength, _laser_length, _laser_radius + Function3D _distribution diff --git a/cherab/core/model/laser/profile.pyx b/cherab/core/model/laser/profile.pyx new file mode 100644 index 00000000..82376980 --- /dev/null +++ b/cherab/core/model/laser/profile.pyx @@ -0,0 +1,765 @@ +from raysect.core.math.function.float import Constant3D +from raysect.core.math.function.vector3d cimport Constant3D as ConstantVector3D +from raysect.primitive import Cylinder +from raysect.optical cimport Spectrum, Vector3D, translate + +from cherab.core.laser cimport Laser, LaserProfile +from cherab.core.model.laser.math_functions cimport ConstantAxisymmetricGaussian3D, ConstantBivariateGaussian3D, TrivariateGaussian3D, GaussianBeamModel + +from cherab.core.utility.constants cimport SPEED_OF_LIGHT + +from libc.math cimport M_PI, sqrt, exp + + +cdef class UniformEnergyDensity(LaserProfile): + """ + LaserProfile with a constant volumetric energy density. + + Returns a laser with a cylindrical shape within which the laser volumentric energy density is constant. + The laser starts at z=0 and extends in the positive z direction. + + .. note: + The methods get_pointing, get_polarization and get_energy_density are not limited to the inside + of the laser cylinder. If called alone for position (x, y, z) outisde the laser cylinder, + they will still return non-zero values. + + In the following example, a laser of length of 2 m (extending from z=0 to z=2 m) with a radius of 3 cm + and volumetric energy density of 5 J*m^-3 and polarisation in the y direction is created: + + .. code-block:: pycon + + >>> from raysect.core import Vector3D + >>> from cherab.core.model.laser import UniformEnergyDensity + + >>> energy = 5 # energy density in J + >>> radius = 3e-2 # laser radius in m + >>> length = 2 # laser length in m + >>> polarisation = Vector3D(0, 1, 0) # polarisation direction + + # create the laser profile + >>> laser_profile = UniformEnergyDensity(energy, radius, length, polarisation) + + :param float energy_density: The volumetric energy density of the laser light. + :param float laser_length: The length of the laser cylinder. + :param float laser_radius: The radius of the laser cylinder. + :param Vector3D polarization: The direction of the laser polarization: + + :ivar float energy_density: The volumetric energy density of the laser light. + :ivar float laser_radius: The radius of the laser cylinder. + :ivar float laser_length: The length of the laser cylinder. + """ + + def __init__(self, double energy_density=1., double laser_length=1., double laser_radius=0.05, Vector3D polarization=Vector3D(0, 1, 0)): + super().__init__() + + self.set_polarization(polarization) + self.set_pointing_function(ConstantVector3D(Vector3D(0, 0, 1))) + self.energy_density = energy_density + + self._laser_radius = 0.05 + self._laser_length = 1. + + self.laser_radius = laser_radius + self.laser_length = laser_length + + def set_polarization(self, Vector3D value): + value = value.normalise() + self.set_polarization_function(ConstantVector3D(value)) + + @property + def laser_length(self): + return self._laser_length + + @laser_length.setter + def laser_length(self, value): + + if value <= 0: + raise ValueError("Laser length has to be larger than 0.") + + self._laser_length = value + self.notifier.notify() + + @property + def laser_radius(self): + return self._laser_radius + + @laser_radius.setter + def laser_radius(self, value): + + if value <= 0: + raise ValueError("Laser radius has to be larger than 0.") + + self._laser_radius = value + self.notifier.notify() + + @property + def energy_density(self): + return self._energy_density + + @energy_density.setter + def energy_density(self, value): + if value <= 0: + raise ValueError("Laser power density has to be larger than 0.") + + self._energy_density = value + funct = Constant3D(value) + self.set_energy_density_function(funct) + + cpdef list generate_geometry(self): + + return generate_segmented_cylinder(self.laser_radius, self.laser_length) + + +cdef class ConstantBivariateGaussian(LaserProfile): + """ + LaserProfile with a Gaussian-shaped volumetric energy density distribution in the xy plane + and constant pulse intensity. + + Returns a laser with a cylindrical shape and the propagation of the laser light in the positive z direction. + + The model imitates a laser beam with a uniform power output within a single pulse. This results + in the distribution of the energy density along the propagation direction of the laser (z-axis) to be also + uniform. The integral value of laser energy Exy in an x-y plane is given by + + .. math:: + E_{xy} = \\frac{E_p}{(c * \\tau)}, + + where Ep is the energy of the laser pulse, tau is the temporal pulse length and c is the speed of light in vacuum. + In an x-y plane, the volumetric energy density follows a bivariate Gaussian with a zero correlation: + + .. math:: + E(x, y) = \\frac{E_{xy}}{2 \\pi \\sigma_x \\sigma_y} exp\\left(-\\frac{x^2 + y^2}{2 \\sigma_x \\sigma_y}\\right). + + The sigma_x and sigma_y are standard deviations in x and y directions, respectively. + + .. note:: + The height of the cylinder, forming the laser beam, is given by the laser_length and is independent from the + temporal length of the laser pulse given by pulse_length. This gives the possibility to independently control + the size of the laser primitive and the value of the volumetric energy density. + + The methods get_pointing, get_polarization and get_energy_density are not limited to the inside + of the laser cylinder. If called for position (x, y, z) outisde the laser cylinder, they can still + return non-zero values. + + + The following example shows how to create a laser with sigma_x= 1 cm and sigma_y=2 cm, which makes the laser + profile in x-y plane to be elliptical. The pulse energy is 5 J and the laser temporal pulse length is 10 ns: + + .. code-block:: pycon + + >>> from raysect.core import Vector3D + >>> from cherab.core.model.laser import ConstantBivariateGaussian + + >>> radius = 3e-2 # laser radius in m + >>> length = 2 # laser length in m + >>> polarisation = Vector3D(0, 1, 0) # polarisation direction + >>> pulse_energy = 5 # energy in a laser pulse in J + >>> pulse_length = 1e-8 # pulse length in s + >>> width_x = 1e-2 # standard deviation in x direction in m + >>> width_y = 2e-2 # standard deviation in y direction in m + + # create the laser profile + >>> laser_profile = ConstantBivariateGaussian(pulse_energy, pulse_length, radius, length, width_x, width_y, polarisation) + + :param float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :param float pulse_length: The temporal length of the laser pulse in seconds. + :param float laser_length: The length of the laser cylinder. + :param float laser_radius: The radius of the laser cylinder. + :param float stddev_x: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the x axis in meters. + :param float stddev_y: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the y axis in meters. + :param Vector3D polarization: The direction of the laser polarization: + + :ivar float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :ivar float pulse_length: The temporal length of the laser pulse in seconds. + :ivar float laser_radius: The radius of the laser cylinder. + :ivar float laser_length: The length of the laser cylinder. + :ivar float stddev_x: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the x axis in meters. + :ivar float stddev_y: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the y axis in meters. + """ + def __init__(self, double pulse_energy=1, double pulse_length=1, double laser_radius=0.05, double laser_length=1., + double stddev_x=0.01, double stddev_y=0.01, Vector3D polarization=Vector3D(0, 1, 0)): + + super().__init__() + # set initial values + self._pulse_energy = 1 + self._pulse_length = 1 + self._stddev_x = 0.1 + self._stddev_y = 0.1 + + self._laser_radius = 0.05 + self._laser_length = 1 + + self.laser_radius = laser_radius + self.laser_length = laser_length + + self.set_polarization(polarization) + self.set_pointing_function(ConstantVector3D(Vector3D(0, 0, 1))) + + self.stddev_x = stddev_x + self.stddev_y = stddev_y + + self.pulse_energy = pulse_energy + self.pulse_length = pulse_length + + # set laser constants + self.set_polarization(polarization) + + def set_polarization(self, Vector3D value): + value = value.normalise() + self.set_polarization_function(ConstantVector3D(value)) + + @property + def laser_length(self): + return self._laser_length + + @laser_length.setter + def laser_length(self, value): + + if value <= 0: + raise ValueError("Laser length has to be larger than 0.") + + self._laser_length = value + self.notifier.notify() + + @property + def laser_radius(self): + return self._laser_radius + + @laser_radius.setter + def laser_radius(self, value): + + if value <= 0: + raise ValueError("Laser radius has to be larger than 0.") + + self._laser_radius = value + self.notifier.notify() + + @property + def pulse_energy(self): + return self._pulse_energy + + @pulse_energy.setter + def pulse_energy(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_energy = value + self.notifier.notify() + + @property + def pulse_length(self): + return self._pulse_length + + @pulse_length.setter + def pulse_length(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_length = value + self._function_changed() + + @property + def stddev_x(self): + return self._stddev_x + + @stddev_x.setter + def stddev_x(self, value): + if value <= 0: + raise ValueError("Standard deviation of the laser power has to be larger than 0.") + + self._stddev_x = value + self._function_changed() + + @property + def stddev_y(self): + return self._stddev_y + + @stddev_y.setter + def stddev_y(self, value): + if value <= 0: + raise ValueError("Standard deviation of the laser power has to be larger than 0.") + + self._stddev_y = value + self._function_changed() + + def _function_changed(self): + """ + Energy density should be returned in units [J/m ** 3]. Energy shape in xy + plane is defined by normal distribution (integral over xy plane for + constant z is 1). The units of such distribution are [m ** -2]. + In the z axis direction (direction of laser propagation), + the laser_energy is spread along the z axis using the velocity + of light SPEED_OF_LIGHT and the temporal duration of the pulse: + length = SPEED_OF_LIGTH * pulse_length. Combining the normal distribution with the normalisation + pulse_energy / length gives the units [J / m ** 3]. + """ + self._distribution = ConstantBivariateGaussian3D(self._stddev_x, self._stddev_y) + + length = SPEED_OF_LIGHT * self._pulse_length # convert from temporal to spatial length of pulse + normalisation = self._pulse_energy / length # normalisation to have correct spatial energy density [J / m**3] + + function = normalisation * self._distribution + self.set_energy_density_function(function) + + cpdef list generate_geometry(self): + + return generate_segmented_cylinder(self.laser_radius, self.laser_length) + + +cdef class TrivariateGaussian(LaserProfile): + """ + LaserProfile with a trivariate Gaussian-shaped volumetric energy density. + + Returns a laser with a cylindrical shape and the propagation of the laser light in the positive z direction. + This model imitates a laser beam with a Gaussian distribution of power output within a single pulse frozen in time: + + .. math:: + E(x, y, z) = \\frac{E_p}{\\sqrt{2 \\pi^3} \\sigma_x \\sigma_y \\sigma_z} exp\\left(-\\frac{x^2}{2 \\sigma_x^2} -\\frac{y^2}{2 \\sigma_y^2} -\\frac{(z - \\mu_z)^2}{2 \\sigma_z^2}\\right). + + + The sigma_x and sigma_y are standard deviations in x and y directions, respectively, and E_p is the energy deliverd by laser in a + single laser pulse. The mu_z is the mean of the distribution in the z direction and controls th position of the laser pulse along the z direction. + The standard deviation in z direction sigma_z is calculated from the pulse length tau_p, which is the + standard deviation of the Gaussian distributed ouput power of the laser within a single pulse: + + .. math:: + \\sigma_z = \\tau_p c. + + The c stands for the speed of light in vacuum. + + .. note:: + The height of the cylinder, forming the laser beam, is given by the laser_length and is independent from the + temporal length of the laser pulse given by pulse_length. This gives the possibility to independently control + the size of the laser primitive and the value of the volumetric energy density. + + The methods get_pointing, get_polarization and get_energy_density are not limited to the inside + of the laser cylinder. If called alone for position (x, y, z) outisde the laser cylinder, they can still + return non-zero values. + + + The following example shows how to create a laser with sigma_x = 1 cm and sigma_y = 2 cm, which makes the laser + profile in an x-y plane to be elliptical. The pulse energy is 5 J and the laser temporal pulse length is 10 ns. + The position of the laser pulse maximum mean_z is set to 0.5: + + .. code-block:: pycon + + >>> from raysect.core import Vector3D + >>> from cherab.core.model.laser import ConstantBivariateGaussian + + >>> radius = 3e-2 # laser radius in m + >>> length = 2 # laser length in m + >>> polarisation = Vector3D(0, 1, 0) # polarisation direction + >>> pulse_energy = 5 # energy in a laser pulse in J + >>> pulse_length = 1e-8 # pulse length in s + >>> pulse_z = 0.5 # position of the pulse mean + >>> width_x = 1e-2 # standard deviation in x direction in m + >>> width_y = 2e-2 # standard deviation in y direction in m + + # create the laser profile + >>> laser_profile = ConstantBivariateGaussian(pulse_energy, pulse_length, pulse_z, radius, length, width_x, width_y, polarisation) + + + :param float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :param float pulse_length: The standard deviation of the laser pulse length in the temporal domain. + :param float mean_z: Position of the mean value of the laser pulse in the z direction. Can be used to control the + position of the laser pulse along the laser propagation. + :param float laser_length: The length of the laser cylinder. + :param float laser_radius: The radius of the laser cylinder. + :param float stddev_x: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the x axis in meters. + :param float stddev_y: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the y axis in meters. + :param Vector3D polarization: The direction of the laser polarization. + + :ivar float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :ivar float pulse_length: The standard deviation of the laser pulse length in the temporal domain. + :ivar float mean_z: Position of the mean value of the laser pulse in the z direction. + Can be used to control the position of the laser pulse along the laser propagation. + :ivar float laser_radius: The radius of the laser cylinder. + :ivar float laser_length: The length of the laser cylinder. + :ivar float stddev_x: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the x axis in meters. + :ivar float stddev_y: The standard deviation of the bivariate Gaussian distribution of the volumetric energy + density distribution of the laser light in the y axis in meters. + """ + def __init__(self, double pulse_energy=1, double pulse_length=1, double mean_z=0, + double laser_length=1., double laser_radius=0.05, + double stddev_x=0.01, double stddev_y=0.01, + Vector3D polarization=Vector3D(0, 1, 0)): + + super().__init__() + # set initial values + self._pulse_energy = 1 + self._pulse_length = 1 + self._stddev_x = 0.1 + self._stddev_y = 0.1 + self._stddev_z = 1 + self._laser_radius = 0.05 + self._laser_length = 1 + self._mean_z = mean_z + + + self.laser_radius = laser_radius + self.laser_length = laser_length + self.stddev_x = stddev_x + self.stddev_y = stddev_y + self.mean_z = mean_z + + self.pulse_energy = pulse_energy + self.pulse_length = pulse_length + + self.set_polarization(polarization) + self.set_pointing_function(ConstantVector3D(Vector3D(0, 0, 1))) + + def set_polarization(self, Vector3D value): + value = value.normalise() + self.set_polarization_function(ConstantVector3D(value)) + + @property + def laser_length(self): + return self._laser_length + + @laser_length.setter + def laser_length(self, value): + + if value <= 0: + raise ValueError("Laser length has to be larger than 0.") + + self._laser_length = value + self.notifier.notify() + + @property + def laser_radius(self): + return self._laser_radius + + @laser_radius.setter + def laser_radius(self, value): + + if value <= 0: + raise ValueError("Laser radius has to be larger than 0.") + + self._laser_radius = value + self.notifier.notify() + + @property + def pulse_energy(self): + return self._pulse_energy + + @pulse_energy.setter + def pulse_energy(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_energy = value + self._function_changed() + + @property + def pulse_length(self): + return self._pulse_length + + @pulse_length.setter + def pulse_length(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_length = value + self._stddev_z = self._pulse_length * SPEED_OF_LIGHT + self._function_changed() + + @property + def stddev_x(self): + return self._stddev_x + + @stddev_x.setter + def stddev_x(self, value): + if value <= 0: + raise ValueError("Standard deviation of the laser power has to be larger than 0.") + + self._stddev_x = value + self._function_changed() + + @property + def stddev_y(self): + return self._stddev_y + + @stddev_y.setter + def stddev_y(self, value): + if value <= 0: + raise ValueError("Standard deviation of the laser power has to be larger than 0.") + + self._stddev_y = value + self._function_changed() + + @property + def mean_z(self): + return self._mean_z + + @mean_z.setter + def mean_z(self, double value): + self._mean_z = value + self._function_changed() + + def _function_changed(self): + """ + Energy density should be returned in units [J/m ** 3]. The integral value of the _distribution + is 1, thus multiplying _distribution by _pulse_energy gives correct values. + """ + + self._distribution = TrivariateGaussian3D(self._mean_z, self._stddev_x, self._stddev_y, + self._stddev_z) + + normalisation = self._pulse_energy + + function = normalisation * self._distribution + self.set_energy_density_function(function) + + cpdef list generate_geometry(self): + + return generate_segmented_cylinder(self.laser_radius, self.laser_length) + +cdef class GaussianBeamAxisymmetric(LaserProfile): + """ + LaserProfile with volumetric energy density following the Gaussian beam model. + + Returns a laser with a cylindrical shape and the propagation of the laser light in the positive z direction. This model implements + the axisymmetrical Gaussian beam model. It immitates a focused axis symmetrical laser beam with a uniform power ouput in a laser pulse. + The volumetric energy density is given by + + .. math:: + E(x, y, z) = \\frac{E_{xy}}{2 \\pi \\sigma^2(z)} exp\\left( -\\frac{x^2 + y^2}{2 \\sigma^2(z) }\\right) \\\\ + + where the sigma is the standard deviation of the Gaussian shape in the xy plane and is given by + + .. math:: + sigma(z) = \\sigma_0 \\sqrt{1 + \\left(\\frac{z - z_0}{z_R}\\right)^2}. + + The z_0 is the position of the beam focus and z_R is the Rayleigh length + + .. math:: + z_R = \\frac{\\pi \\omega_0^2 n}{\\lambda_l} + + where the omega_0 is the standard deviation in the xy plane in the focal point (beam waist) and lambda_l is the central wavelength of + the laser. The E_xy stand for the laser energy in an xy plane and is calculated as: + + .. math:: + E_{xy} = \\frac{E_p}{(c * \\tau)}, + + where the E_p is the energy in a single laser pulse and tau is the temporal pulse length. + + .. note:: + For more information about the Gaussian beam model see https://en.wikipedia.org/wiki/Gaussian_beam + + The methods get_pointing, get_polarization and get_energy_density are not limited to the inside + of the laser cylinder. If called alone for position (x, y, z) outisde the laser cylinder, they can still + return non-zero values. + + The following example shows how to create a laser with pulse energy 5J, pulse length 10 ns and with the laser cylinder primitive + being 2m long with 5 cm in diameter. The the standard deviation of the beam in the focal point (waist) is 5mm and the position of the + waist is z=50 cm. The laser wavelength is 1060 nm. + + .. code-block:: pycon + + >>> from raysect.core import Vector3D + >>> from cherab.core.model.laser import GaussianBeamAxisymmetric + + >>> radius = 5e-2 # laser radius in m + >>> length = 2 # laser length in m + >>> polarisation = Vector3D(0, 1, 0) # polarisation direction + >>> pulse_energy = 5 # energy in a laser pulse in J + >>> pulse_length = 1e-8 # pulse length in s + >>> waist_width = 5e-3 # standard deviation in the waist + >>> waist_z = 0.5 # position of the pulse mean + >>> width_x = 1e-2 # standard deviation in x direction in m + >>> width_y = 2e-2 # standard deviation in y direction in m + >>> laser_wlen = 1060 # laser wavelength in nm + + # create the laser profile + >>> laser_profile = GaussianBeamAxisymmetric(pulse_energy, pulse_length, length, radius, waist_z, waist_width, laser_wlen) + + :param float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :param float pulse_length: The temporal length of the laser pulse in seconds. + :param float laser_length: The length of the laser cylinder in meters. + :param float laser_radius: The radius of the laser cylinder in meters. + :param float waist_z: Position of the laser waist along the z axis in m. + :param float stddev_waist: The standard deviation of the laser width in the focal point (waist) in m. + :param float laser_wavelength: The central wavelength of the laser light in nanometers. + :param Vector3D polarization: The direction of the laser polarization. + + :ivar float pulse_energy: The energy of the laser in Joules delivered in a single laser pulse. + :ivar float pulse_length: The temporal length of the laser pulse in seconds. + :ivar float laser_length: The length of the laser cylinder in meters. + :ivar float laser_radius: The radius of the laser cylinder in meters. + :ivar float waist_z: Position of the laser waist along the z axis in m. + :ivar float stddev_waist: The standard deviation of the laser width in the focal point (waist) in m. + :ivar float laser_wavelength: The central wavelength of the laser light in nanometers. + :ivar Vector3D polarization: The direction of the laser polarization. + """ + + def __init__(self, double pulse_energy=1, double pulse_length=1, + double laser_length=1., double laser_radius=0.05, + double waist_z=0, double stddev_waist=0.01, + double laser_wavelength=1e3, Vector3D polarization=Vector3D(0, 1, 0)): + + super().__init__() + # set initial values + self._pulse_energy = 1 + self._pulse_length = 1 + self._stddev_waist = 0.1 + self._waist_z = waist_z + self._laser_wavelength = 1e3 + self._laser_radius = 0.05 + self._laser_length = 1 + + self.laser_length = laser_length + self.laser_radius = laser_radius + + self.set_polarization(polarization) + self.set_pointing_function(ConstantVector3D(Vector3D(0, 0, 1))) + + self.stddev_waist = stddev_waist + self.waist_z = waist_z + + self.pulse_energy = pulse_energy + self.pulse_length = pulse_length + self.laser_wavelength = laser_wavelength + + def set_polarization(self, Vector3D value): + value = value.normalise() + self.set_polarization_function(ConstantVector3D(value)) + + @property + def laser_length(self): + return self._laser_length + + @laser_length.setter + def laser_length(self, value): + + if value <= 0: + raise ValueError("Laser length has to be larger than 0.") + + self._laser_length = value + self.notifier.notify() + + @property + def laser_radius(self): + return self._laser_radius + + @laser_radius.setter + def laser_radius(self, value): + + if value <= 0: + raise ValueError("Laser radius has to be larger than 0.") + + self._laser_radius = value + self.notifier.notify() + + @property + def pulse_energy(self): + return self._pulse_energy + + @pulse_energy.setter + def pulse_energy(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_energy = value + self._function_changed() + + @property + def pulse_length(self): + return self._pulse_length + + @pulse_length.setter + def pulse_length(self, double value): + if value <= 0: + raise ValueError("Value has to be larger than 0.") + + self._pulse_length = value + self._function_changed() + + @property + def waist_z(self): + return self._waist_z + + @waist_z.setter + def waist_z(self, double value): + self._waist_z = value + self._function_changed() + + @property + def stddev_waist(self): + return self._stddev_waist + + @stddev_waist.setter + def stddev_waist(self, double value): + self._stddev_waist = value + self._function_changed() + + @property + def laser_wavelength(self): + return self._laser_wavelength + + @laser_wavelength.setter + def laser_wavelength(self, double value): + self._laser_wavelength = value + self._function_changed() + + def _function_changed(self): + """ + Energy density should be returned in units [J/m ** 3]. Energy shape in xy + plane is defined by normal distribution (integral over xy plane for + constant z is 1). The units of such distribution are [m ** -2]. + In the z axis direction (direction of laser propagation), + the laser_energy is spread along the z axis using the velocity + of light SPEED_OF_LIGHT and the temporal duration of the pulse: + length = SPEED_OF_LIGTH * pulse_length. Combining the normal distribution with the normalisation + pulse_energy / length gives the units [J / m ** 3]. + """ + + self._distribution = GaussianBeamModel(self._laser_wavelength, self._waist_z, self._stddev_waist) + # calculate volumetric power dentiy + length = SPEED_OF_LIGHT * self._pulse_length # convert from temporal to spatial length of pulse + normalisation = self._pulse_energy / length # normalisation to have correct spatial energy density [J / m**3] + + function = normalisation * self._distribution + self.set_energy_density_function(function) + + cpdef list generate_geometry(self): + + return generate_segmented_cylinder(self.laser_radius, self.laser_length) + + +def generate_segmented_cylinder(radius, length): + """ + Generates a segmented cylindrical laser geometry + + Approximates a long cylinder with a cylindrical segments to optimize + targetted and importance sampling. The height of a cylinder segments is roughly + 2 * cylinder radius. + + :return: List of cylinders + """ + + n_segments = int(length // (2 * radius)) # number of segments + geometry = [] + + #length of segment is either length / n_segments if length > radius or length if length < radius + if n_segments > 1: + segment_length = length / n_segments + for i in range(n_segments): + segment = Cylinder(name="Laser segment {0:d}".format(i), radius=radius, height=segment_length, + transform=translate(0, 0, i * segment_length)) + + geometry.append(segment) + elif 0 <= n_segments < 2: + segment = Cylinder(name="Laser segment {0:d}".format(0), radius=radius, height=length) + + geometry.append(segment) + else: + raise ValueError("Incorrect number of segments calculated.") + + return geometry \ No newline at end of file diff --git a/cherab/core/model/laser/tests/__init__.py b/cherab/core/model/laser/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cherab/core/model/laser/tests/test_laserspectrum.py b/cherab/core/model/laser/tests/test_laserspectrum.py new file mode 100644 index 00000000..1f72e666 --- /dev/null +++ b/cherab/core/model/laser/tests/test_laserspectrum.py @@ -0,0 +1,46 @@ +import unittest +from scipy.integrate import nquad + +from cherab.core.model.laser.laserspectrum import GaussianSpectrum, ConstantSpectrum + +class TestLaserSpectrum(unittest.TestCase): + + def test_constantspectrum(self): + """ + Laser spectrum should be normalized, i.e. integral from minuns inf. to inf. should be one. + :return: + """ + min_wavelength = 1039.9 + max_wavelength = 1040.1 + bins = 10 + + spectrum = ConstantSpectrum(min_wavelength, max_wavelength, bins) + + # check if the power_spectral density is normalized + + integral = spectrum.power_spectral_density.sum() * spectrum.delta_wavelength + self.assertTrue(integral == 1, msg="Power spectral density is not normalised.") + + def test_gaussian_spectrum(self): + """ + Laser spectrum should be normalized, i.e. integral from minuns inf. to inf. should be one. + :return: + """ + min_wavelength = 1035 + max_wavelength = 1045 + bins = 100 + mean = 1040 + stddev = 0.5 + + spectrum = GaussianSpectrum(min_wavelength, max_wavelength, bins, mean, stddev) + integral = nquad(spectrum, [(min_wavelength, max_wavelength)])[0] + + # check if the power_spectral density is normalized + self.assertAlmostEqual(integral, 1., 8, msg="Power spectral density function is not normalised.") + + psd = spectrum.power_spectral_density + integral = 0 + for index in range(0, spectrum.bins - 1): + integral += (psd[index] + psd[index + 1]) / 2 * spectrum.delta_wavelength + + self.assertAlmostEqual(integral, 1, 8, msg="Power spectral density is not normalised.") diff --git a/cherab/core/model/laser/tests/test_model.py b/cherab/core/model/laser/tests/test_model.py new file mode 100644 index 00000000..992d5d52 --- /dev/null +++ b/cherab/core/model/laser/tests/test_model.py @@ -0,0 +1,104 @@ +import unittest +import numpy as np +from math import cos, sin, sqrt, radians, exp +from scipy.constants import pi, c, e, m_e, epsilon_0 + +from raysect.optical import World, Point3D, Vector3D, translate, Ray + +from cherab.core.laser import Laser +from cherab.core.model.laser import ConstantSpectrum, SeldenMatobaThomsonSpectrum, UniformEnergyDensity + +from cherab.tools.plasmas.slab import build_constant_slab_plasma + +class TestScatteringModel(unittest.TestCase): + laser_wavelength = 1040 + wavelength = np.linspace(600, 1200, 800) + scatangle = 45 + + def test_selden_matoba_scattered_spectrum(self): + + # calculate TS cross section and constants + r_e = e ** 2 / (4 * pi * epsilon_0 * m_e * c ** 2) # classical electron radius + + # re ** 2 is the cross section, c transforms xsection into rate constant + scat_const = r_e ** 2 * c + + ray_origin = Point3D(0, 0, 0) + + # angle of scattering + observation_angle = [45, 90, 135] + for obsangle in observation_angle: + + # pointing vector is in +z direction, angle of observation is 180 - obsangle + z = cos((obsangle) / 180 * pi) + x = sin((obsangle) / 180 * pi) + ray_direction = Vector3D(x, 0, z).normalise() + + # ray spectrum properties + min_wavelength = 600 + max_wavelength = 1200 + bins = 800 + + # plasma properties + e_density = 8e19 + t_e = [100, 1e3, 1e4] + + for vte in t_e: + # setup scene + world = World() + plasma = build_constant_slab_plasma(length=1, width=1, height=1, electron_density=e_density, + electron_temperature=vte, plasma_species=[], parent=world) + + # setup laser + laser_spectrum = ConstantSpectrum(1059, 1061, 1) + laser_profile = UniformEnergyDensity(laser_length=1, laser_radius=0.015) + scattering_model = SeldenMatobaThomsonSpectrum() + laser = Laser() + laser.parent = world + laser.transform = translate(0.05, 0, -0.5) + laser.laser_profile = laser_profile + laser.laser_spectrum = laser_spectrum + laser.plasma = plasma + laser.models = [scattering_model] + + # trace a single ray through the laser + ray = Ray(origin=ray_origin, direction=ray_direction, min_wavelength=min_wavelength, + max_wavelength=max_wavelength, bins=bins) + traced_spectrum = ray.trace(world) + + + # calculate spectrum ray-tracing should deliver + dl = 2 * laser_profile.laser_radius / sin((obsangle) / 180 * pi) # ray-laser cross section length + intensity_test = np.zeros_like(traced_spectrum.wavelengths) + + for vl in laser.laser_spectrum.wavelengths: + intensity_const = scat_const * e_density / vl * dl + for iwvl, vwvl in enumerate(traced_spectrum.wavelengths): + intensity_test[iwvl] += _selden_matoba_shape(vwvl, vte, obsangle, vl) * intensity_const + + for index, (vtest, vray) in enumerate(zip(intensity_test, traced_spectrum.samples)): + # skip the test for too low values of power spectral density, max is approx. 3e-5 + if vray > 1e-30: + rel_error = np.abs((vtest - vray) / vray) + self.assertLess(rel_error, 1e-7, + msg="Traced and test spectrum value do not match: " + "scattering angle = {0} deg, Te = {1} eV, wavelength = {2} nm." + .format(180 - obsangle, vte, traced_spectrum.wavelengths[index])) + + +def _selden_matoba_shape(wavelength, te, obsangle, laser_wavelength): + """ + Returns Selden-Matoba Spectral shape + """ + epsilon = wavelength / laser_wavelength - 1 + + alpha = m_e * c ** 2 / (2 * e * te) + + scat_angle = 180 - obsangle + cos_scat = cos(radians(scat_angle)) + + const_c = sqrt(alpha / pi) * (1 - 15 / 16 / alpha + 345 / 512 / alpha ** 2) + const_a = (1 + epsilon) ** 3 * sqrt(2 * (1 - cos_scat) * (1 + epsilon) + epsilon ** 2) + const_b = sqrt(1 + epsilon ** 2 / (2 * (1 - cos_scat) * (1 + epsilon))) - 1 + + return const_c / const_a * exp(-2 * alpha * const_b) diff --git a/cherab/core/model/laser/tests/test_profiles.py b/cherab/core/model/laser/tests/test_profiles.py new file mode 100644 index 00000000..6f2c9fc3 --- /dev/null +++ b/cherab/core/model/laser/tests/test_profiles.py @@ -0,0 +1,198 @@ +import unittest +import numpy as np +from math import exp, sqrt + +from raysect.core import Vector3D + +from cherab.core.model.laser.profile import UniformEnergyDensity, ConstantBivariateGaussian +from cherab.core.model.laser.profile import TrivariateGaussian, GaussianBeamAxisymmetric, generate_segmented_cylinder + +from scipy.integrate import nquad +from scipy.constants import c, pi + +class TestSegmentedCylinder(unittest.TestCase): + + def test_number_of_primitives(self): + + # for r > l there should be 1 cylinder segment only + primitives = generate_segmented_cylinder(radius=1, length=0.5) + self.assertEqual(len(primitives), 1, msg="Wrong nuber of laser segments, expected 1.") + + # for r < l tehre should be length // (2 * radius) segments + primitives = generate_segmented_cylinder(radius=0.5, length=10) + self.assertEqual(len(primitives), 10, msg="Wrong nuber of laser segments, expected 20.") + + +class TestLaserProfile(unittest.TestCase): + + def test_uniform_energy_density(self): + polarisation = Vector3D(1, 3, 8).normalise() + energy_density = 2 + model = UniformEnergyDensity(energy_density=energy_density, polarization=polarisation) + + # test polarisation + pol_model = model.get_polarization(1, 1, 1) + self.assertEqual(pol_model.x, polarisation.x, + msg="Model polarization x vector component does not agreee with input value.") + self.assertEqual(pol_model.y, polarisation.y, + msg="Model polarization y vector component does not agreee with input value.") + self.assertEqual(pol_model.z, polarisation.z, + msg="Model polarization z vector component does not agreee with input value.") + + # test power + self.assertEqual(model.get_energy_density(3, 4, 1), energy_density, + msg="Model power density distribution does not agree with input.") + + def test_bivariate_gaussian(self): + + pulse_energy = 2 + pulse_length = 1e-8 + stddev_x = 0.03 + stddev_y = 0.06 + polarisation = Vector3D(2, 3, 4).normalise() + model = ConstantBivariateGaussian(pulse_energy=pulse_energy, pulse_length=pulse_length, stddev_x=stddev_x, + stddev_y=stddev_y, polarization=polarisation) + + # test polarisation + pol_model = model.get_polarization(1, 1, 1) + self.assertEqual(pol_model.x, polarisation.x, + msg="Model polarization x vector component does not agreee with input value.") + self.assertEqual(pol_model.y, polarisation.y, + msg="Model polarization y vector component does not agreee with input value.") + self.assertEqual(pol_model.z, polarisation.z, + msg="Model polarization z vector component does not agreee with input value.") + + # Integrate over laser volume to check energy + xlim = [-5 * stddev_x, 5 * stddev_x] + ylim = [-5 * stddev_y, 5 * stddev_y] + zlim = [0, pulse_length * c] + energy_integrated = nquad(model.get_energy_density, [xlim, ylim, zlim])[0] + self.assertTrue(np.isclose(energy_integrated / pulse_energy, 1, 1e-3), + msg="Integrated laser energy of the model does not give results close to input energy") + + # Check laser power density profile + x = np.linspace(-3 * stddev_x, 3 * stddev_x, 30) + y = np.linspace(-3 * stddev_y, 3 * stddev_y, 30) + for vx in x: + for vy in y: + tmp = _constant_bivariate_gaussian2d(vx, vy, pulse_energy, pulse_length, stddev_x, stddev_y) + tmp2 = model.get_energy_density(vx, vy, 0) + self.assertTrue(np.isclose(tmp, tmp2, 1e-9), + msg="Model power density distribution for ({},{},{}) does not agree with input.".format( + vx, vy, 0)) + + def test_trivariate_gaussian(self): + + pulse_energy = 2 + pulse_length = 1e-8 + mean_z = 0 + stddev_x = 0.03 + stddev_y = 0.06 + polarisation = Vector3D(2, 3, 4).normalise() + model = TrivariateGaussian(pulse_energy=pulse_energy, pulse_length=pulse_length, mean_z=mean_z, + stddev_x=stddev_x, stddev_y=stddev_y, polarization=polarisation) + + # test polarisation + pol_model = model.get_polarization(1, 1, 1) + self.assertEqual(pol_model.x, polarisation.x, + msg="Model polarization x vector component does not agreee with input value.") + self.assertEqual(pol_model.y, polarisation.y, + msg="Model polarization y vector component does not agreee with input value.") + self.assertEqual(pol_model.z, polarisation.z, + msg="Model polarization z vector component does not agreee with input value.") + + # Integrate over laser volume to check energy + xlim = [-5 * stddev_x, 5 * stddev_x] + ylim = [-5 * stddev_y, 5 * stddev_y] + zlim = [mean_z - 5 * pulse_length * c, mean_z + 5 * pulse_length * c] + energy_integrated = nquad(model.get_energy_density, [xlim, ylim, zlim])[0] + + self.assertTrue(np.isclose(energy_integrated / pulse_energy, 1, 1e-3), + msg="Integrated laser energy of the model does not give results close to input energy") + + # Check laser power density profile + x = np.linspace(-3 * stddev_x, 3 * stddev_x, 30) + y = np.linspace(-3 * stddev_y, 3 * stddev_y, 30) + z = np.linspace(-3 * pulse_length * c, 3 * pulse_length * c, 30) + + for vx in x: + for vy in y: + for vz in z: + tmp = _constant_trivariate_gaussian3d(vx, vy, vz, pulse_energy, pulse_length, mean_z, stddev_x, + stddev_y) + tmp2 = model.get_energy_density(vx, vy, vz) + self.assertTrue(np.isclose(tmp, tmp2, 1e-9), + msg="Model power density distribution for ({},{},{})" + " does not agree with input.".format(vx, vy, vz)) + + def test_gaussianbeam(self): + + pulse_energy = 2 + pulse_length = 1e-9 + waist_z = 0 + stddev_waist = 0.003 + laser_wavelength = 1040 + polarisation = Vector3D(2, 3, 4).normalise() + + model = GaussianBeamAxisymmetric(pulse_energy=pulse_energy, pulse_length=pulse_length, waist_z=waist_z, + stddev_waist=stddev_waist, laser_wavelength=laser_wavelength, + polarization=polarisation) + + # test polarisation + pol_model = model.get_polarization(1, 1, 1) + self.assertEqual(pol_model.x, polarisation.x, + msg="Model polarization x vector component does not agreee with input value.") + self.assertEqual(pol_model.y, polarisation.y, + msg="Model polarization y vector component does not agreee with input value.") + self.assertEqual(pol_model.z, polarisation.z, + msg="Model polarization z vector component does not agreee with input value.") + + # Integrate over laser volume to check energy + xlim = [-20 * stddev_waist, 20 * stddev_waist] + zlim = [-1 * pulse_length / 2 * c, pulse_length / 2 * c] + energy_integrated = nquad(model.get_energy_density, [xlim, xlim, zlim])[0] + + self.assertTrue(np.isclose(energy_integrated / pulse_energy, 1, 1e-3), + msg="Integrated laser energy of the model does not give results close to input energy") + + # Check laser power density profile + x = np.linspace(-3 * stddev_waist, 3 * stddev_waist, 30) + y = np.linspace(-3 * stddev_waist, 3 * stddev_waist, 30) + z = np.linspace(-3 * pulse_length * c, 3 * pulse_length * c, 30) + + for vx in x: + for vy in y: + for vz in z: + tmp = _gaussian_beam_model(vx, vy, vz, pulse_energy, pulse_length, waist_z, stddev_waist, + laser_wavelength * 1e-9) + tmp2 = model.get_energy_density(vx, vy, vz) + self.assertTrue(np.isclose(tmp, tmp2, 1e-9), + msg="Model power density distribution for ({},{},{}) " + "does not agree with input.".format(vx, vy, vz)) + + +def _gaussian_beam_model(x, y, z, pulse_energy, pulse_length, waist_z, stddev_waist, wavelength): + laser_power_axis = pulse_energy / (pulse_length * c) + + n = 1 # refractive index + rayleigh_distance = 2 * pi * stddev_waist ** 2 * n / wavelength + + z_prime = z - waist_z + + stddev_z2 = stddev_waist ** 2 * (1 + (z_prime / rayleigh_distance) ** 2) + + r2 = x ** 2 + y ** 2 + + return laser_power_axis / (2 * pi * stddev_z2) * exp(r2 / (-2 * stddev_z2)) + + +def _constant_trivariate_gaussian3d(x, y, z, pulse_energy, pulse_length, mean_z, stddev_x, stddev_y): + stddev_z = pulse_length * c + return (pulse_energy / (sqrt((2 * pi) ** 3) * stddev_x * stddev_y * stddev_z) * + exp(-1 / 2 * ((x / stddev_x) ** 2 + (y / stddev_y) ** 2 + ((z - mean_z) / stddev_z) ** 2))) + + +def _constant_bivariate_gaussian2d(x, y, pulse_energy, pulse_length, stddev_x, stddev_y): + length = pulse_length * c + normalisation = pulse_energy / length + return normalisation / (stddev_x * stddev_y * 2 * pi) * exp(-1 / 2 * ((x / stddev_x) ** 2 + (y / stddev_y) ** 2)) diff --git a/demos/laser/laser_profile.py b/demos/laser/laser_profile.py new file mode 100644 index 00000000..fd5a08ad --- /dev/null +++ b/demos/laser/laser_profile.py @@ -0,0 +1,86 @@ +from random import gauss +from raysect.core import Vector3D + +from cherab.core.math.samplers import sample3d_grid +from cherab.core.model.laser.profile import (UniformEnergyDensity, ConstantBivariateGaussian, + TrivariateGaussian, GaussianBeamAxisymmetric) + +import numpy as np +import matplotlib.pyplot as plt + +def plot_profiles(profile, title=""): + """Plot the laser profile + + Produces 2d energy density plot in the x-z plane at y=0. + Produces plots of energy density profiles along x, y and z + directions. + """ + + # set coordinate grid and zero indices + x = np.linspace(-0.01, 0.01, 31) + z = np.linspace(-1, 1, 101) + x_zero = np.abs(x).argmin() + z_zero = np.abs(z).argmin() + + e_xz_profile = sample3d_grid(profile.get_energy_density, x, [0], z)[:, 0, :] + e_y_profile = sample3d_grid(profile.get_energy_density, [0], x, [0])[0, :, 0] + + # plot + fig = plt.figure(constrained_layout=True) + fig.suptitle(title) + spec = fig.add_gridspec(4, 3) + + # profile along y at z=0 + axz = fig.add_subplot(spec[0, 0:2]) + axz.plot(x, e_y_profile, color="C2", ls="dashed") + axz.set_xlabel("y [m]") + axz.set_ylabel("Energy [J/m^3]") + + # x-y plane + ax2d = fig.add_subplot(spec[1:3, 0:2]) + im = ax2d.pcolormesh(x, z, e_xz_profile.T) + fig.colorbar(im, ax=ax2d, label="Energy [J/m^3]") + ax2d.axhline(z[z_zero], color="C0", ls="dashed") + ax2d.axvline(x[x_zero], color="C1", ls="dashed") + ax2d.plot([x[x_zero]], z[z_zero], marker="x", color="C2") + ax2d.set_xlabel("x [m]") + ax2d.set_ylabel("z [m]") + + # profile along z at x=0 + axz = fig.add_subplot(spec[1:3, -1]) + axz.plot(e_xz_profile[x_zero, :], z, color="C0", ls="dashed") + axz.set_ylabel("z [m]") + axz.set_xlabel("Energy [J/m^3]") + + # profile along x at z=0 + axz = fig.add_subplot(spec[-1, 0:2]) + axz.plot(x, e_xz_profile[:, z_zero].T, color="C1", ls="dashed") + axz.set_xlabel("x [m]") + axz.set_ylabel("Energy [J/m^3]") + +# UniformEnergyDensity profile has constant parameters in the whole x, y, z space +uniform = UniformEnergyDensity(energy_density=1e3, laser_length=2., laser_radius=0.005, + polarization=Vector3D(0, 1, 0)) +plot_profiles(uniform, "Uniform Energy Profile") + +# Example of ConstantBivariteGaussian. With energy 2J, pulse temporal length 5 ns +# and different standard deviations in the x and y plane. The mean value in both +# dimensions is equal to 0. There is no correlation between x and y. + +gauss2d = ConstantBivariateGaussian(pulse_energy=2, pulse_length=5e-9, + stddev_x=2e-3, stddev_y=4e-3) +plot_profiles(gauss2d, "ConstantBivariateGaussian Energy Profile") + +# Example of TrivariageGaussian profile. With the pulse mean at z=0.2 +gauss3d = TrivariateGaussian(pulse_energy=2, pulse_length=2e-9, + mean_z=0.2, stddev_x=2e-3, stddev_y=4e-3 ) +plot_profiles(gauss3d, "TrivariateGaussian Energy Profile") + +# Example of GaussianBeamModel with wavelength 1e4 nm and 1 mm standard deviation +# in the waist. The wavelength is too high +# but was selected to produce nice plots in the defined x, y, z dimensions. + +gaussbeam = GaussianBeamAxisymmetric(stddev_waist=1e-3, waist_z=0.2, laser_wavelength=1e4) +plot_profiles(gaussbeam, "GaussianBeam Energy Profile") + +plt.show() \ No newline at end of file diff --git a/demos/laser/laser_spectrum.py b/demos/laser/laser_spectrum.py new file mode 100644 index 00000000..7904bbdc --- /dev/null +++ b/demos/laser/laser_spectrum.py @@ -0,0 +1,34 @@ +from cherab.core.model.laser import ConstantSpectrum, GaussianSpectrum + +import matplotlib.pyplot as plt + + +# construct a ConstantSpectrum with 10 spectral bins +constant_wide = ConstantSpectrum(min_wavelength=1059.9, max_wavelength=1060.1, bins=10) + +# plot the power_spectral_density attribute of the laser +_, ax = plt.subplots() +ax.plot(constant_wide.wavelengths, constant_wide.power_spectral_density) + +ax.set_xlabel("Wavelength [nm]") +ax.set_ylabel("W / nm") + +ax.set_title("Energy Spectral Density") +plt.show() + +# construct a narrow laser spectrum +constant_narrow = ConstantSpectrum(min_wavelength=1059.999, max_wavelength=1060.001, bins=1) +print("narow spectrum wavelengths: {}, power spectral density: {}".format(constant_narrow.wavelengths, + constant_narrow.power_spectral_density)) + +# construct a GaussianSpectrum with 20 bins +gaussian = GaussianSpectrum(min_wavelength=1059, max_wavelength=1061, bins=30, + mean=1060, stddev=0.3) + +_, ax = plt.subplots() +ax.plot(gaussian.wavelengths, gaussian.power_spectral_density) +ax.set_xlabel("Wavelength [nm]") +ax.set_ylabel("W / nm") + +ax.set_title("Energy Spectral Density") +plt.show() diff --git a/demos/laser/model_seldenmatoba.py b/demos/laser/model_seldenmatoba.py new file mode 100644 index 00000000..0491cd66 --- /dev/null +++ b/demos/laser/model_seldenmatoba.py @@ -0,0 +1,72 @@ +import matplotlib.pyplot as plt + +from raysect.optical.spectrum import Spectrum + +from cherab.core.model.laser import SeldenMatobaThomsonSpectrum +from cherab.core.utility import RecursiveDict + + +density = 3e19 # electron density +temperatures = [100, 2.e3] # electron temperatures in eV +laser_wavelength = 1060 # wavelength of the laser light in nm +laser_energy = 1 # energy density of the laser light in J/m^3 + +# angle between observation direction and electric field +angles_pol = [90, 45] + +# angles between propagation direction and observation direction +angles_obs = [45, 90, 135, 120] + +# define spectrum of observed scattering +min_wavelength = 650 +max_wavelength = 1300 +bins = 1000 + + +# calculate Thomson scattered spectra for the specified combinations of el. properties and observation +model = SeldenMatobaThomsonSpectrum() +scattered = RecursiveDict() + +for te in temperatures: + for ap in angles_pol: + for ao in angles_obs: + spectrum = Spectrum(min_wavelength, max_wavelength, bins) + scattered[te][ap][ao] = model.calculate_spectrum(density, te, laser_energy, laser_wavelength, + ao, ap, spectrum).samples +scattered = scattered.freeze() + +wvls = spectrum.wavelengths + +# plot temperature influence on scattered spectra +ap, ao = 90, 90 +_, ax = plt.subplots() +ax.set_title("Scattered spectrum, pol. angl.={:d}, obs. angl = {:d}".format(ap, ao)) +for te in temperatures: + rad = scattered[te][ap][ao] + ax.plot(wvls, rad, label="Te = {:3.1f} eV".format(te)) +ax.set_xlabel("Wavelength [nm]") +ax.set_ylabel("Spectral Radiance [W/m^3/sr]") +ax.legend() + +# plot influence of angle between polarisation and observation on scattered spectra +te, ao = 100, 90 +_, ax = plt.subplots() +ax.set_title("Scattered spectrum, te = {:3.1f}, obs. angl = {:d}".format(te, ao)) +for ap in angles_pol: + rad = scattered[te][ap][ao] + ax.plot(wvls, rad, label="pol. angl. = {:d} deg".format(ap)) +ax.set_xlabel("Wavelength [nm]") +ax.set_ylabel("Spectral Radiance [W/m^3/sr]") +ax.legend() + +# plot influence of observation angle on scattered spectra +te, ap = 2e3, 90 +_, ax = plt.subplots() +ax.set_title("Scattered spectrum, te = {:3.1f}, obs. angl = {:d}".format(te, ao)) +for ao in angles_obs: + rad = scattered[te][ap][ao] + ax.plot(wvls, rad, label="obs. angl. = {:d} deg".format(ao)) +ax.set_xlabel("Wavelength [nm]") +ax.set_ylabel("Spectral Radiance [W/m^3/sr]") +ax.legend() +plt.show() diff --git a/demos/laser/thomson_scattering.py b/demos/laser/thomson_scattering.py new file mode 100644 index 00000000..f9198d8e --- /dev/null +++ b/demos/laser/thomson_scattering.py @@ -0,0 +1,61 @@ +import numpy as np + +from raysect.optical import World, translate, Point3D, rotate_basis, Vector3D +from raysect.optical.observer import FibreOptic + +from cherab.core.model.laser import ConstantBivariateGaussian, ConstantSpectrum, SeldenMatobaThomsonSpectrum +from cherab.core.laser import Laser + +from cherab.generomak.plasma import get_core_plasma +from cherab.generomak.equilibrium import load_equilibrium + +import matplotlib.pyplot as plt + +world = World() + +plasma = get_core_plasma(parent=world) +equilibrium = load_equilibrium() + +# set up the laser +laser = Laser(name="Thomson Scattering laser", parent=world) +laser.transform = translate(equilibrium.magnetic_axis[0], 0, -2) +laser.plasma = plasma +laser.laser_profile = ConstantBivariateGaussian(pulse_energy=2, pulse_length=1e-8, + laser_length=4, laser_radius=1e-2, + stddev_x=3e-3, stddev_y=2e-3) +laser.laser_spectrum = ConstantSpectrum(min_wavelength=1059.9, max_wavelength=1060.1, bins=1) +laser.models = [SeldenMatobaThomsonSpectrum()] + +# generate points on laser in world space to measure on +laser_points = [Point3D(0, 0, round(z, 2)).transform(laser.to_root()) for z in np.linspace(2, 2.8, 5)] +te = [plasma.electron_distribution.effective_temperature(*point) for point in laser_points] +ne = [plasma.electron_distribution.density(*point) for point in laser_points] + +# place fibres 0.1m outside sep on lfs +fibre_position = Point3D(equilibrium.psin_to_r(1) + 0.1, 0, 0) + +# generate fibres list and observe +fibres = {} +for point in laser_points: + + direction = fibre_position.vector_to(point) + transform = translate(*fibre_position) * rotate_basis(direction, Vector3D(0, 0, 1)) + + fibre = FibreOptic(radius=1e-3, acceptance_angle=0.25, + parent=world, transform=transform, + min_wavelength=800, max_wavelength=1200, + spectral_bins=1000, + pixel_samples=1000) + + fibre.pipelines[0].display_progress = False + fibre.observe() + fibres[point.z] = fibre + +_, ax = plt.subplots() +for z, fibre in fibres.items(): + pipeline = fibre.pipelines[0] + ax.plot(pipeline.wavelengths, pipeline.samples.mean, label="z={:1.2f}m".format(z)) +ax.set_xlabel("wavelength [nm]") +ax.set_ylabel("spectral power W/nm") +ax.legend() +plt.show() diff --git a/docs/source/models/emission_models.rst b/docs/source/models/emission_models.rst index 73f76cc2..3a2c3b9c 100644 --- a/docs/source/models/emission_models.rst +++ b/docs/source/models/emission_models.rst @@ -13,3 +13,4 @@ Cherab contains a number of independent physics models for spectroscopic emissio brem/bremsstrahlung basic_line/basic_line_emission line_shapes/spectral_line_shapes + laser/laser diff --git a/docs/source/models/laser/laser.rst b/docs/source/models/laser/laser.rst new file mode 100644 index 00000000..da9f7f79 --- /dev/null +++ b/docs/source/models/laser/laser.rst @@ -0,0 +1,28 @@ +Laser +====== + +Laser Spectrum +-------------- + +.. autoclass:: cherab.core.model.laser.laserspectrum.ConstantSpectrum + :members: +.. autoclass:: cherab.core.model.laser.laserspectrum.GaussianSpectrum + :members: + +Laser Profile +------------- + +.. autoclass:: cherab.core.model.laser.profile.UniformEnergyDensity + :members: +.. autoclass:: cherab.core.model.laser.profile.ConstantBivariateGaussian + :members: +.. autoclass:: cherab.core.model.laser.profile.TrivariateGaussian + :members: +.. autoclass:: cherab.core.model.laser.profile.GaussianBeamAxisymmetric + :members: + +Laser Model +------------- + +.. autoclass:: cherab.core.model.laser.model.SeldenMatobaThomsonSpectrum + :members: diff --git a/docs/source/plasmas/laser.rst b/docs/source/plasmas/laser.rst new file mode 100644 index 00000000..6c94c6d8 --- /dev/null +++ b/docs/source/plasmas/laser.rst @@ -0,0 +1,20 @@ +Laser +====== + +Laser Spectrum +-------------- + +.. autoclass:: cherab.core.laser.laserspectrum.LaserSpectrum + :members: + +Laser Profile +------------- + +.. autoclass:: cherab.core.laser.profile.LaserProfile + :members: + +Laser Model +------------- + +.. autoclass:: cherab.core.laser.model.LaserModel + :members: diff --git a/docs/source/plasmas/plasmas.rst b/docs/source/plasmas/plasmas.rst index 07198e71..98e3d9c8 100644 --- a/docs/source/plasmas/plasmas.rst +++ b/docs/source/plasmas/plasmas.rst @@ -7,3 +7,4 @@ Plasmas core_plasma_classes equilibrium particle_beams + laser From ab6df92d62e511582d508c7437a1134291de7c1e Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 23 Dec 2022 14:46:30 +0000 Subject: [PATCH 39/81] Fixup changelog --- CHANGELOG.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb38c25..d7bf7c6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,13 @@ Release 1.4.0 (TBD) API changes: * Spectroscopic observers and their groups are deprecated and replaced by groups based on Raysect's 0D observers. (#332) +* Support for Python 3.6 is dropped. It may still work, but is no longer actively tested. Bug fixes: * Fixed generomak plasma edge data paths. * Fix and improve OpenCL utility functions. (#358) -* Fix wavelength indexing in Bremsstrahlung emission model. (#352) +* Fixed Bremsstrahlung trapezium evaluation (#384). +* Fixed generomak plasma edge data paths. New: * Make f_profile (current flux) a read-only attribute of EFITEquilibrium. (#355) @@ -26,12 +28,8 @@ New: * Add integrator attribute to LineShapeModel to use with lineshapes that cannot be analytically integrated over a spectral bin. (#366) * Add a numerical integration of StarkBroadenedLine over the spectral bin. (#366) * Add Generomak full plasma profiles obtained by blending the core and edge profiles. (#372) - -Bug Fixes: ----------- -* Fixed Bremsstrahlung trapezium evaluation (#384). -* Fixed generomak plasma edge data paths. -* Fix and improve OpenCL utility functions. (#358) +* Clean up build/install dependencies. (#353) +* Test against Python 3.10 and latest released Numpy. Drop Python 3.6 and older Numpy from tests. (#391) Release 1.3.0 (8 Dec 2021) From f63dcda02509659409ef24588a794d4820c741ab Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 23 Dec 2022 15:35:11 +0000 Subject: [PATCH 40/81] Update version in docs and VERSION file --- cherab/core/VERSION | 2 +- docs/source/conf.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cherab/core/VERSION b/cherab/core/VERSION index f0bb29e7..40b48802 100644 --- a/cherab/core/VERSION +++ b/cherab/core/VERSION @@ -1 +1 @@ -1.3.0 +1.4.0rc1 diff --git a/docs/source/conf.py b/docs/source/conf.py index 7dfb5f04..60589037 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -55,16 +55,16 @@ # General information about the project. project = 'Cherab' -copyright = '2021, Cherab Team' +copyright = '2022, Cherab Team' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = '1.3' +version = '1.4' # The full version, including alpha/beta/rc tags. -release = '1.3.0' +release = '1.4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 365c211acc1a3bfc45b273ab52d03f593b1fc4e2 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 23 Dec 2022 19:08:17 +0000 Subject: [PATCH 41/81] Add some notes on how to build wheels for PyPI --- dev/pypi_notes.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 dev/pypi_notes.md diff --git a/dev/pypi_notes.md b/dev/pypi_notes.md new file mode 100644 index 00000000..c79e6fe8 --- /dev/null +++ b/dev/pypi_notes.md @@ -0,0 +1,80 @@ +Building wheels for publishing on PyPI +====================================== + +Linux wheels published on PyPI must be for one of the manylinux variants. +This means they should be built inside a manylinux Docker container. + +For Cherab versions 1.4 and earlier (which depend on raysect 0.7.1 or earlier), +the procedure varies slightly depending on whether there is a raysect wheel +available for the Python version or not. + +When Raysect wheels are available +--------------------------------- + +1. Retrieve the appropriate manylinux container (we'll use manylinux1 here as + an example, but any appropriate version works the same way). + ```bash + sudo docker run -ti -v :/cherab_core quay.io/pypa/manylinux1_x86_64 /bin/bash + ``` + Or, if using singularity instead of Docker (where sudo rights are not available): + ```bash + singularity pull docker://quay.io/pypa/manylinux1_x86_64 + singularity run -B :/cherab_core -W /tmp -c ./manylinux1_x86_64_latest.sif + ``` +2. Inside the container, change to the top level directory of this repository. + ```bash + cd /cherab_core + ``` +3. Configure pip to prefer older binary wheels over newer sdists. This is because + the manylinux images have very few libraries installed so fail to build many + packages. + ```bash + export PIP_PREFER_BINARY=1 + ``` +4. (Optional) Configure a cache directory for pip that doesn't have a small quota. + This will prevent `No space left on device` errors when collecting dependencies, + or when pip does have to build certain packages (Numpy for example does successfully + build on certain manylinux versions for certain Python versions). + ```bash + export PIP_CACHE_DIR=/tmp/pipcache + ``` +5. Use PyPA's `build` package to build the sdists and wheels, for each Python version + we're building the wheels for. For example, for Python 3.8: + ```bash + /opt/python/cp38-cp38/bin/python -m build . + ``` + Ensure you've done step 3 above before running this command! +6. Once the build has finished, repair the wheel to give it the correct manylinux tag. + Once again, using Python 3.8 as an example: + ```bash + auditwheel repair ./dist/cherab-1.4.0rc1-cp38-cp38-linux_x86_64.whl + ``` + This will produce a wheel in the `./wheelhouse` directory which can be uploaded to PyPI. + +When Raysect wheels aren't available +------------------------------------ + +For Raysect 0.8 and later, the same procedure applies as above. +For Raysect 0.7.1 and below, a couple of additional steps are required. + +1. Follow steps 1-4 above to set up the container environment. +2. Create a virtual environment for building the wheel. For example, for Python 3.10: + ```bash + /opt/python/cp310-cp310/bin/python -m venv /tmp/cp310 + . /tmp/cp310/bin/activate + ``` +3. Install build, wheel Cython and the oldest supported Numpy into this environment. + ```bash + pip install build wheel cython oldest-supported-numpy + ``` +4. Install the required Raysect version. + ```bash + pip install raysect==0.7.1 + ``` +5. Use PyPA's `build` to build the wheel, but tell it to use this virtual + environment rather than creating a new isolated one. + ```bash + python -m build -n . + ``` +6. Run the auditwheel command as given in step 6 above to produce wheels with + the correct tag for uploading to PyPI. From 73b87df644b09e8b536e14f60b95ab5976ba9f2f Mon Sep 17 00:00:00 2001 From: vsnever Date: Mon, 26 Dec 2022 14:06:40 +0300 Subject: [PATCH 42/81] Rename periodic/cylindrical mappers to periodic/cylindrical transforms and move them to cherab.core.math.transform module. --- cherab/core/math/__init__.pxd | 1 + cherab/core/math/__init__.py | 6 +- cherab/core/math/mappers.pxd | 62 --- cherab/core/math/mappers.pyx | 436 +-------------------- cherab/core/math/tests/test_mappers.py | 114 +----- cherab/core/math/tests/test_transform.py | 157 ++++++++ cherab/core/math/transform/__init__.pxd | 20 + cherab/core/math/transform/__init__.py | 21 + cherab/core/math/transform/cylindrical.pxd | 30 ++ cherab/core/math/transform/cylindrical.pyx | 128 ++++++ cherab/core/math/transform/periodic.pxd | 72 ++++ cherab/core/math/transform/periodic.pyx | 352 +++++++++++++++++ 12 files changed, 796 insertions(+), 603 deletions(-) create mode 100644 cherab/core/math/tests/test_transform.py create mode 100644 cherab/core/math/transform/__init__.pxd create mode 100644 cherab/core/math/transform/__init__.py create mode 100644 cherab/core/math/transform/cylindrical.pxd create mode 100644 cherab/core/math/transform/cylindrical.pyx create mode 100644 cherab/core/math/transform/periodic.pxd create mode 100644 cherab/core/math/transform/periodic.pyx diff --git a/cherab/core/math/__init__.pxd b/cherab/core/math/__init__.pxd index 99e92fbe..710ee381 100644 --- a/cherab/core/math/__init__.pxd +++ b/cherab/core/math/__init__.pxd @@ -25,3 +25,4 @@ from cherab.core.math.clamp cimport * from cherab.core.math.mappers cimport * from cherab.core.math.mask cimport * from cherab.core.math.slice cimport * +from cherab.core.math.transform cimport * diff --git a/cherab/core/math/__init__.py b/cherab/core/math/__init__.py index 4f821332..85336afa 100644 --- a/cherab/core/math/__init__.py +++ b/cherab/core/math/__init__.py @@ -34,8 +34,8 @@ from .mappers import IsoMapper2D, IsoMapper3D from .mappers import Swizzle2D, Swizzle3D from .mappers import AxisymmetricMapper, VectorAxisymmetricMapper -from .mappers import CylindricalMapper, VectorCylindricalMapper -from .mappers import PeriodicMapper1D, PeriodicMapper2D, PeriodicMapper3D -from .mappers import VectorPeriodicMapper1D, VectorPeriodicMapper2D, VectorPeriodicMapper3D from .mask import PolygonMask2D from .slice import Slice2D, Slice3D +from .transform import CylindricalTransform, VectorCylindricalTransform +from .transform import PeriodicTransform1D, PeriodicTransform2D, PeriodicTransform3D +from .transform import VectorPeriodicTransform1D, VectorPeriodicTransform2D, VectorPeriodicTransform3D diff --git a/cherab/core/math/mappers.pxd b/cherab/core/math/mappers.pxd index 4fee0cbf..3835e949 100644 --- a/cherab/core/math/mappers.pxd +++ b/cherab/core/math/mappers.pxd @@ -16,12 +16,9 @@ # See the Licence for the specific language governing permissions and limitations # under the Licence. -from libc.math cimport fmod from raysect.core.math.function.float cimport Function1D, Function2D, Function3D -from raysect.core.math.function.vector3d cimport Function1D as VectorFunction1D from raysect.core.math.function.vector3d cimport Function2D as VectorFunction2D from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D -from raysect.core cimport Vector3D cdef class IsoMapper2D(Function2D): @@ -58,62 +55,3 @@ cdef class AxisymmetricMapper(Function3D): cdef class VectorAxisymmetricMapper(VectorFunction3D): cdef readonly VectorFunction2D function2d - - -cdef class CylindricalMapper(Function3D): - - cdef readonly Function3D function3d - - -cdef class VectorCylindricalMapper(VectorFunction3D): - - cdef readonly VectorFunction3D function3d - - -cdef inline double remainder(double x1, double x2) nogil: - if x2 == 0: - return x1 - x1 = fmod(x1, x2) - return x1 + x2 if (x1 < 0) else x1 - - -cdef class PeriodicMapper1D(Function1D): - - cdef: - readonly Function1D function1d - readonly double period - - -cdef class PeriodicMapper2D(Function2D): - - cdef: - readonly Function2D function2d - double period_x, period_y - - -cdef class PeriodicMapper3D(Function3D): - - cdef: - readonly Function3D function3d - readonly double period_x, period_y, period_z - - -cdef class VectorPeriodicMapper1D(VectorFunction1D): - - cdef: - readonly VectorFunction1D function1d - readonly double period - - -cdef class VectorPeriodicMapper2D(VectorFunction2D): - - cdef: - readonly VectorFunction2D function2d - readonly double period_x, period_y - - -cdef class VectorPeriodicMapper3D(VectorFunction3D): - - cdef: - readonly VectorFunction3D function3d - readonly double period_x, period_y, period_z diff --git a/cherab/core/math/mappers.pyx b/cherab/core/math/mappers.pyx index 63f868a9..f1326f12 100644 --- a/cherab/core/math/mappers.pyx +++ b/cherab/core/math/mappers.pyx @@ -20,10 +20,9 @@ from libc.math cimport sqrt, atan2, M_PI +from raysect.core.math cimport Vector3D from raysect.core.math.function.float cimport autowrap_function1d, autowrap_function2d, autowrap_function3d -from raysect.core.math.function.vector3d cimport autowrap_function1d as autowrap_vectorfunction1d from raysect.core.math.function.vector3d cimport autowrap_function2d as autowrap_vectorfunction2d -from raysect.core.math.function.vector3d cimport autowrap_function3d as autowrap_vectorfunction3d from raysect.core cimport rotate_z cimport cython @@ -311,436 +310,3 @@ cdef class VectorAxisymmetricMapper(VectorFunction3D): # perform axisymmetric rotation return self.function2d.evaluate(r, z).transform(rotate_z(phi)) - - -cdef class CylindricalMapper(Function3D): - """ - Converts Cartesian coordinates to cylindrical coordinates and calls a 3D function - defined in cylindrical coordinates, f(r, :math:`\\phi`, z). - - The angular coordinate is given in radians. - - Positive angular coordinate is measured counterclockwise from the xz plane. - - :param Function3D function3d: The function to be mapped. Must be defined - in the interval (:math:`-\\pi`, :math:`\\pi`] - on the angular axis. - - .. code-block:: pycon - - >>> from math import sqrt, cos - >>> from cherab.core.math import CylindricalMapper - >>> - >>> def my_func(r, phi, z): - >>> return r * cos(phi) - >>> - >>> f = CylindricalMapper(my_func) - >>> - >>> f(1, 0, 0) - 1.0 - >>> f(0.5 * sqrt(3), 0.5, 0) - 0.8660254037844385 - """ - - def __init__(self, object function3d): - - if not callable(function3d): - raise TypeError("Function3D is not callable.") - - self.function3d = autowrap_function3d(function3d) - - cdef double evaluate(self, double x, double y, double z) except? -1e999: - """ - Converts to cylindrical coordinates and evaluates the function - defined in cylindrical coordinates. - """ - cdef double r, phi - - r = sqrt(x * x + y * y) - phi = atan2(y, x) - - return self.function3d.evaluate(r, phi, z) - - -cdef class VectorCylindricalMapper(VectorFunction3D): - """ - Converts Cartesian coordinates to cylindrical coordinates, calls - a 3D vector function defined in cylindrical coordinates, f(r, :math:`\\phi`, z), - then converts the returned 3D vector to Cartesian coordinates. - - The angular coordinate is given in radians. - - Positive angular coordinate is measured counterclockwise from the xz plane. - - :param VectorFunction3D function3d: The function to be mapped. Must be defined - in the interval (:math:`-\\pi`, :math:`\\pi`] - on the angular axis. - - .. code-block:: pycon - - >>> from math import sqrt, cos - >>> from raysect.core.math import Vector3D - >>> from cherab.core.math import VectorCylindricalMapper - >>> - >>> def my_vec_func(r, phi, z): - >>> v = Vector3D(0, 1, 0) - >>> v.length = r * abs(cos(phi)) - >>> return v - >>> - >>> f = VectorCylindricalMapper(my_vec_func) - >>> - >>> f(1, 0, 0) - Vector3D(0.0, 1.0, 0.0) - >>> f(1/sqrt(2), 1/sqrt(2), 0) - Vector3D(-0.5, 0.5, 0.0) - """ - - def __init__(self, object function3d): - - if not callable(function3d): - raise TypeError("Function3D is not callable.") - - self.function3d = autowrap_vectorfunction3d(function3d) - - @cython.cdivision(True) - cdef Vector3D evaluate(self, double x, double y, double z): - """ - Converts to cylindrical coordinates, evaluates the vector function - defined in cylindrical coordinates and rotates the resulting vector - around z-axis. - """ - cdef double r, phi - - r = sqrt(x * x + y * y) - phi = atan2(y, x) - - return self.function3d.evaluate(r, phi, z).transform(rotate_z(phi / M_PI * 180)) - - -cdef class PeriodicMapper1D(Function1D): - """ - Maps a periodic 1D function into 1D space. - - :param Function1D function1d: The periodic 1D function to map defined - in the [0, period) interval. - :param double period: The period of the function. - - .. code-block:: pycon - - >>> from cherab.core.math import PeriodicMapper1D - >>> - >>> def f1(x): - >>> return x - >>> - >>> f2 = PeriodicMapper1D(f1, 1.) - >>> - >>> f2(1.5) - 0.5 - >>> f2(-0.3) - 0.7 - """ - - def __init__(self, object function1d, double period): - - if not callable(function1d): - raise TypeError("function1d is not callable.") - - self.function1d = autowrap_function1d(function1d) - - if period <= 0: - raise ValueError("Argument period must be positive.") - - self.period = period - - cdef double evaluate(self, double x) except? -1e999: - """Return the value of periodic function.""" - - return self.function1d.evaluate(remainder(x, self.period)) - - -cdef class PeriodicMapper2D(Function2D): - """ - Maps a periodic 2D function into 2D space. - - Set period_x/period_y to 0 if the function is not periodic along x/y axis. - - :param Function2D function2d: The periodic 2D function to map defined - in the ([0, period_x), [0, period_y)) intervals. - :param double period_x: The period of the function along x-axis. - 0 if not periodic. - :param double period_y: The period of the function along y-axis. - 0 if not periodic. - - .. code-block:: pycon - - >>> from cherab.core.math import PeriodicMapper2D - >>> - >>> def f1(x, y): - >>> return x * y - >>> - >>> f2 = PeriodicMapper2D(f1, 1., 1.) - >>> - >>> f2(1.5, 1.5) - 0.25 - >>> f2(-0.3, -1.3) - 0.49 - >>> - >>> f3 = PeriodicMapper2D(f1, 1., 0) - >>> - >>> f3(1.5, 1.5) - 0.75 - >>> f3(-0.3, -1.3) - -0.91 - """ - - def __init__(self, object function2d, double period_x, double period_y): - - if not callable(function2d): - raise TypeError("function2d is not callable.") - - self.function2d = autowrap_function2d(function2d) - - if period_x < 0: - raise ValueError("Argument period_x must be >= 0.") - if period_y < 0: - raise ValueError("Argument period_y must be >= 0.") - - self.period_x = period_x - self.period_y = period_y - - cdef double evaluate(self, double x, double y) except? -1e999: - """Return the value of periodic function.""" - - x = remainder(x, self.period_x) - y = remainder(y, self.period_y) - - return self.function2d.evaluate(x, y) - - -cdef class PeriodicMapper3D(Function3D): - """ - Maps a periodic 3D function into 3D space. - - Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. - - :param Function3D function3d: The periodic 3D function to map defined in the - ([0, period_x), [0, period_y), [0, period_z)) intervals. - :param double period_x: The period of the function along x-axis. - 0 if not periodic. - :param double period_y: The period of the function along y-axis. - 0 if not periodic. - :param double period_z: The period of the function along z-axis. - 0 if not periodic. - - .. code-block:: pycon - - >>> from cherab.core.math import PeriodicMapper3D - >>> - >>> def f1(x, y, z): - >>> return x * y * z - >>> - >>> f2 = PeriodicMapper3D(f1, 1., 1., 1.) - >>> - >>> f2(1.5, 1.5, 1.5) - 0.125 - >>> f2(-0.3, -1.3, -2.3) - 0.343 - >>> - >>> f3 = PeriodicMapper3D(f1, 0, 1., 0) - >>> - >>> f3(1.5, 1.5, 1.5) - 1.125 - >>> f3(-0.3, -1.3, -0.3) - 0.063 - """ - - def __init__(self, object function3d, double period_x, double period_y, double period_z): - - if not callable(function3d): - raise TypeError("function2d is not callable.") - - self.function3d = autowrap_function3d(function3d) - - if period_x < 0: - raise ValueError("Argument period_x must be >= 0.") - if period_y < 0: - raise ValueError("Argument period_y must be >= 0.") - if period_z < 0: - raise ValueError("Argument period_z must be >= 0.") - - self.period_x = period_x - self.period_y = period_y - self.period_z = period_z - - cdef double evaluate(self, double x, double y, double z) except? -1e999: - """Return the value of periodic function.""" - - x = remainder(x, self.period_x) - y = remainder(y, self.period_y) - z = remainder(z, self.period_z) - - return self.function3d.evaluate(x, y, z) - - -cdef class VectorPeriodicMapper1D(VectorFunction1D): - """ - Maps a periodic 1D vector function into 1D space. - - :param VectorFunction1D function1d: The periodic 1D vector function to map - defined in the [0, period) interval. - :param double period: The period of the function. - - .. code-block:: pycon - - >>> from raysect.core.math import Vector3D - >>> from cherab.core.math import VectorPeriodicMapper1D - >>> - >>> def f1(x): - >>> return Vector3D(x, 0, 0) - >>> - >>> f2 = VectorPeriodicMapper1D(f1, 1.) - >>> - >>> f2(1.5) - Vector3D(0.5, 0, 0) - >>> f2(-0.3) - Vector3D(0.7, 0, 0) - """ - - def __init__(self, object function1d, double period): - - if not callable(function1d): - raise TypeError("function1d is not callable.") - - self.function1d = autowrap_vectorfunction1d(function1d) - - if period <= 0: - raise ValueError("Argument period must be positive.") - - self.period = period - - cdef Vector3D evaluate(self, double x): - """Return the value of periodic function.""" - - return self.function1d.evaluate(remainder(x, self.period)) - - -cdef class VectorPeriodicMapper2D(VectorFunction2D): - """ - Maps a periodic 2D vector function into 2D space. - - Set period_x/period_y to 0 if the function is not periodic along x/y axis. - - :param VectorFunction2D function2d: The periodic 2D vector function to map defined in - the ([0, period_x), [0, period_y)) intervals. - :param double period_x: The period of the function along x-axis. - 0 if not periodic. - :param double period_y: The period of the function along y-axis. - 0 if not periodic. - - .. code-block:: pycon - - >>> from cherab.core.math import VectorPeriodicMapper2D - >>> - >>> def f1(x, y): - >>> return Vector3D(x, y, 0) - >>> - >>> f2 = VectorPeriodicMapper2D(f1, 1., 1.) - >>> - >>> f2(1.5, 1.5) - Vector3D(0.5, 0.5, 0) - >>> f2(-0.3, -1.3) - Vector3D(0.7, 0.7, 0) - >>> - >>> f3 = VectorPeriodicMapper2D(f1, 1., 0) - >>> - >>> f3(1.5, 1.5) - Vector3D(0.5, 1.5, 0) - >>> f3(-0.3, -1.3) - Vector3D(0.7, -1.3, 0) - """ - - def __init__(self, object function2d, double period_x, double period_y): - - if not callable(function2d): - raise TypeError("function2d is not callable.") - - self.function2d = autowrap_vectorfunction2d(function2d) - - if period_x < 0: - raise ValueError("Argument period_x must be >= 0.") - if period_y < 0: - raise ValueError("Argument period_y must be >= 0.") - - self.period_x = period_x - self.period_y = period_y - - cdef Vector3D evaluate(self, double x, double y): - """Return the value of periodic function.""" - - x = remainder(x, self.period_x) - y = remainder(y, self.period_y) - - return self.function2d.evaluate(x, y) - - -cdef class VectorPeriodicMapper3D(VectorFunction3D): - """ - Maps a periodic 3D vector function into 3D space. - - Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. - - :param VectorFunction3D function3d: The periodic 3D vector function to map defined in the - ([0, period_x), [0, period_y), [0, period_z)) intervals. - :param double period_x: The period of the function along x-axis. - 0 if not periodic. - :param double period_y: The period of the function along y-axis. - 0 if not periodic. - :param double period_z: The period of the function along z-axis. - 0 if not periodic. - - .. code-block:: pycon - - >>> from cherab.core.math import PeriodicMapper3D - >>> - >>> def f1(x, y, z): - >>> return Vector3D(x, y, z) - >>> - >>> f2 = VectorPeriodicMapper3D(f1, 1., 1., 1.) - >>> - >>> f2(1.5, 1.5, 1.5) - Vector3D(0.5, 0.5, 0.5) - >>> f2(-0.3, -1.3, -2.3) - Vector3D(0.7, 0.7, 0.7) - >>> - >>> f3 = VectorPeriodicMapper3D(f1, 0, 1., 0) - >>> - >>> f3(1.5, 0.5, 1.5) - Vector3D(1.5, 0.5, 1.5) - """ - - def __init__(self, object function3d, double period_x, double period_y, double period_z): - - if not callable(function3d): - raise TypeError("function2d is not callable.") - - self.function3d = autowrap_vectorfunction3d(function3d) - - if period_x < 0: - raise ValueError("Argument period_x must be >= 0.") - if period_y < 0: - raise ValueError("Argument period_y must be >= 0.") - if period_z < 0: - raise ValueError("Argument period_z must be >= 0.") - - self.period_x = period_x - self.period_y = period_y - self.period_z = period_z - - cdef Vector3D evaluate(self, double x, double y, double z): - """Return the value of periodic function.""" - - x = remainder(x, self.period_x) - y = remainder(y, self.period_y) - z = remainder(z, self.period_z) - - return self.function3d.evaluate(x, y, z) diff --git a/cherab/core/math/tests/test_mappers.py b/cherab/core/math/tests/test_mappers.py index 69a5f771..a1d0eb73 100644 --- a/cherab/core/math/tests/test_mappers.py +++ b/cherab/core/math/tests/test_mappers.py @@ -36,6 +36,9 @@ def f2d(x, y): return x*np.sin(y) def f3d(x, y, z): return x*x*np.exp(y)-2*z*y self.function3d = f3d + def vecf2d(r, z): return Vector3D(0, r, z) + self.vectorfunction2d = vecf2d + def test_iso_mapper_2d(self): """Composition of a 1D and a 2D function.""" @@ -143,112 +146,17 @@ def test_axisymmetric_mapper_invalid_arg(self): """An error must be raised if the given argument is not callable.""" self.assertRaises(TypeError, mappers.AxisymmetricMapper, "blah") - def test_cylindrical_mapper(self): - """Cylindrical mapper.""" - def f3d(r, phi, z): return r * np.cos(phi) + z - cyl_func = mappers.CylindricalMapper(f3d) - self.assertAlmostEqual(cyl_func(1., 1., 0.5), - f3d(np.sqrt(2.), 0.25 * np.pi, 0.5), - places=10) - - def test_cylindrical_mapper_invalid_arg(self): - """An error must be raised if the given argument is not callable.""" - self.assertRaises(TypeError, mappers.CylindricalMapper, "blah") - - def test_vector_cylindrical_mapper(self): - """Cylindrical mapper.""" - def f3d(r, phi, z): return Vector3D(np.sin(phi), r * z, np.cos(phi)) - cyl_func = mappers.VectorCylindricalMapper(f3d) - vec1 = cyl_func(1., 1., 1.) - vec2 = Vector3D(-0.5, 1.5, 1 / np.sqrt(2)) + def test_vector_axisymmetric_mapper(self): + """Vector axisymmetric mapper.""" + symm_func = mappers.VectorAxisymmetricMapper(self.vectorfunction2d) + vec1 = symm_func(1., 1., 1.) + vec2 = Vector3D(-1., 1., 1.) np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) - def test_vector_cylindrical_mapper_invalid_arg(self): + def test_vector_axisymmetric_mapper_invalid_arg(self): """An error must be raised if the given argument is not callable.""" - self.assertRaises(TypeError, mappers.VectorCylindricalMapper, "blah") - - def test_periodic_mapper_1d(self): - """1D periodic mapper""" - period_func = mappers.PeriodicMapper1D(self.function1d, np.pi) - self.assertAlmostEqual(period_func(1.4 * np.pi), - self.function1d(0.4 * np.pi), - places=10) - self.assertAlmostEqual(period_func(-0.4 * np.pi), - self.function1d(0.6 * np.pi), - places=10) - - def test_periodic_mapper_1d_invalid_arg(self): - """1D periodic mapper. Invalid arguments.""" - # 1st argument is not callable - self.assertRaises(TypeError, mappers.PeriodicMapper1D, "blah", np.pi) - # period is not a number - self.assertRaises(TypeError, mappers.PeriodicMapper1D, self.function1d, "blah") - # period is negative - self.assertRaises(ValueError, mappers.PeriodicMapper1D, self.function1d, -1) - - def test_periodic_mapper_2d(self): - """2D periodic mapper""" - period_func = mappers.PeriodicMapper2D(self.function2d, 1, np.pi) - self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), - self.function2d(0.6, 0.4 * np.pi), - places=10) - # Periodic only along x - period_func = mappers.PeriodicMapper2D(self.function2d, 1., 0) - self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), - self.function2d(0.6, 1.4 * np.pi), - places=10) - # Periodic only along y - period_func = mappers.PeriodicMapper2D(self.function2d, 0, np.pi) - self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), - self.function2d(-0.4, 0.4 * np.pi), - places=10) - - def test_periodic_mapper_2d_invalid_arg(self): - """2D periodic mapper. Invalid arguments.""" - # 1st argument is not callable - self.assertRaises(TypeError, mappers.PeriodicMapper2D, "blah", np.pi, np.pi) - # period is not a number - self.assertRaises(TypeError, mappers.PeriodicMapper2D, self.function2d, "blah", np.pi) - self.assertRaises(TypeError, mappers.PeriodicMapper2D, self.function2d, np.pi, "blah") - # period is negative - self.assertRaises(ValueError, mappers.PeriodicMapper2D, self.function2d, -1, np.pi) - self.assertRaises(ValueError, mappers.PeriodicMapper2D, self.function2d, np.pi, -1) - - def test_periodic_mapper_3d(self): - """3D periodic mapper""" - period_func = mappers.PeriodicMapper3D(self.function3d, 1, 1, 1) - self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), - self.function3d(0.6, 0.4, 0.1), - places=10) - # Periodic only along y and z - period_func = mappers.PeriodicMapper3D(self.function3d, 0, 1, 1) - self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), - self.function3d(-0.4, 0.4, 0.1), - places=10) - # Periodic only along x and z - period_func = mappers.PeriodicMapper3D(self.function3d, 1, 0, 1) - self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), - self.function3d(0.6, 1.4, 0.1), - places=10) - # Periodic only along x and y - period_func = mappers.PeriodicMapper3D(self.function3d, 1, 1, 0) - self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), - self.function3d(0.6, 0.4, 2.1), - places=10) - - def test_periodic_mapper_3d_invalid_arg(self): - """2D periodic mapper. Invalid arguments.""" - # 1st argument is not callable - self.assertRaises(TypeError, mappers.PeriodicMapper3D, "blah", np.pi, np.pi, np.pi) - # period is not a number - self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, "blah", np.pi, np.pi) - self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, np.pi, "blah", np.pi) - self.assertRaises(TypeError, mappers.PeriodicMapper3D, self.function3d, np.pi, np.pi, "blah") - # period is negative - self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, -1, np.pi, np.pi) - self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, np.pi, -1, np.pi) - self.assertRaises(ValueError, mappers.PeriodicMapper3D, self.function3d, np.pi, np.pi, -1) + self.assertRaises(TypeError, mappers.VectorAxisymmetricMapper, "blah") if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/cherab/core/math/tests/test_transform.py b/cherab/core/math/tests/test_transform.py new file mode 100644 index 00000000..2ee4eefc --- /dev/null +++ b/cherab/core/math/tests/test_transform.py @@ -0,0 +1,157 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from raysect.core.math import Vector3D +from cherab.core.math import transform +import numpy as np +import unittest + + +class TestCylindricalTransform(unittest.TestCase): + """Cylindrical transform tests.""" + + def setUp(self): + """Initialisation with functions to map.""" + + def f3d(r, phi, z): return r * np.cos(phi) + z + self.function3d = f3d + + def vecf3d(r, phi, z): return Vector3D(np.sin(phi), r * z, np.cos(phi)) + self.vectorfunction3d = vecf3d + + def test_cylindrical_transform(self): + """Cylindrical transform.""" + cyl_func = transform.CylindricalTransform(self.function3d) + self.assertAlmostEqual(cyl_func(1., 1., 0.5), + self.function3d(np.sqrt(2.), 0.25 * np.pi, 0.5), + places=10) + + def test_cylindrical_transform_invalid_arg(self): + """An error must be raised if the given argument is not callable.""" + self.assertRaises(TypeError, transform.CylindricalTransform, "blah") + + def test_vector_cylindrical_transform(self): + """Cylindrical transform.""" + cyl_func = transform.VectorCylindricalTransform(self.vectorfunction3d) + vec1 = cyl_func(1., 1., 1.) + vec2 = Vector3D(-0.5, 1.5, 1 / np.sqrt(2)) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + def test_vector_cylindrical_transform_invalid_arg(self): + """An error must be raised if the given argument is not callable.""" + self.assertRaises(TypeError, transform.VectorCylindricalTransform, "blah") + + +class TestPeriodicTransform(unittest.TestCase): + """Periodic transform tests.""" + + def setUp(self): + """Initialisation with functions to map.""" + + def f1d(x): return x*np.cos(x-3) + self.function1d = f1d + def f2d(x, y): return x*np.sin(y) + self.function2d = f2d + def f3d(x, y, z): return x*x*np.exp(y)-2*z*y + self.function3d = f3d + + def test_periodic_transform_1d(self): + """1D periodic transform""" + period_func = transform.PeriodicTransform1D(self.function1d, np.pi) + self.assertAlmostEqual(period_func(1.4 * np.pi), + self.function1d(0.4 * np.pi), + places=10) + self.assertAlmostEqual(period_func(-0.4 * np.pi), + self.function1d(0.6 * np.pi), + places=10) + + def test_periodic_transform_1d_invalid_arg(self): + """1D periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.PeriodicTransform1D, "blah", np.pi) + # period is not a number + self.assertRaises(TypeError, transform.PeriodicTransform1D, self.function1d, "blah") + # period is negative + self.assertRaises(ValueError, transform.PeriodicTransform1D, self.function1d, -1) + + def test_periodic_transform_2d(self): + """2D periodic transform""" + period_func = transform.PeriodicTransform2D(self.function2d, 1, np.pi) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(0.6, 0.4 * np.pi), + places=10) + # Periodic only along x + period_func = transform.PeriodicTransform2D(self.function2d, 1., 0) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(0.6, 1.4 * np.pi), + places=10) + # Periodic only along y + period_func = transform.PeriodicTransform2D(self.function2d, 0, np.pi) + self.assertAlmostEqual(period_func(-0.4, 1.4 * np.pi), + self.function2d(-0.4, 0.4 * np.pi), + places=10) + + def test_periodic_transform_2d_invalid_arg(self): + """2D periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.PeriodicTransform2D, "blah", np.pi, np.pi) + # period is not a number + self.assertRaises(TypeError, transform.PeriodicTransform2D, self.function2d, "blah", np.pi) + self.assertRaises(TypeError, transform.PeriodicTransform2D, self.function2d, np.pi, "blah") + # period is negative + self.assertRaises(ValueError, transform.PeriodicTransform2D, self.function2d, -1, np.pi) + self.assertRaises(ValueError, transform.PeriodicTransform2D, self.function2d, np.pi, -1) + + def test_periodic_transform_3d(self): + """3D periodic transform""" + period_func = transform.PeriodicTransform3D(self.function3d, 1, 1, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 0.4, 0.1), + places=10) + # Periodic only along y and z + period_func = transform.PeriodicTransform3D(self.function3d, 0, 1, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(-0.4, 0.4, 0.1), + places=10) + # Periodic only along x and z + period_func = transform.PeriodicTransform3D(self.function3d, 1, 0, 1) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 1.4, 0.1), + places=10) + # Periodic only along x and y + period_func = transform.PeriodicTransform3D(self.function3d, 1, 1, 0) + self.assertAlmostEqual(period_func(-0.4, 1.4, 2.1), + self.function3d(0.6, 0.4, 2.1), + places=10) + + def test_periodic_transform_3d_invalid_arg(self): + """2D periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.PeriodicTransform3D, "blah", np.pi, np.pi, np.pi) + # period is not a number + self.assertRaises(TypeError, transform.PeriodicTransform3D, self.function3d, "blah", np.pi, np.pi) + self.assertRaises(TypeError, transform.PeriodicTransform3D, self.function3d, np.pi, "blah", np.pi) + self.assertRaises(TypeError, transform.PeriodicTransform3D, self.function3d, np.pi, np.pi, "blah") + # period is negative + self.assertRaises(ValueError, transform.PeriodicTransform3D, self.function3d, -1, np.pi, np.pi) + self.assertRaises(ValueError, transform.PeriodicTransform3D, self.function3d, np.pi, -1, np.pi) + self.assertRaises(ValueError, transform.PeriodicTransform3D, self.function3d, np.pi, np.pi, -1) + + +if __name__ == '__main__': + unittest.main() diff --git a/cherab/core/math/transform/__init__.pxd b/cherab/core/math/transform/__init__.pxd new file mode 100644 index 00000000..3ce39b6b --- /dev/null +++ b/cherab/core/math/transform/__init__.pxd @@ -0,0 +1,20 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from cherab.core.math.transform.periodic cimport * +from cherab.core.math.transform.cylindrical cimport * \ No newline at end of file diff --git a/cherab/core/math/transform/__init__.py b/cherab/core/math/transform/__init__.py new file mode 100644 index 00000000..168bb305 --- /dev/null +++ b/cherab/core/math/transform/__init__.py @@ -0,0 +1,21 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from .cylindrical import CylindricalTransform, VectorCylindricalTransform +from .periodic import PeriodicTransform1D, PeriodicTransform2D, PeriodicTransform3D +from .periodic import VectorPeriodicTransform1D, VectorPeriodicTransform2D, VectorPeriodicTransform3D diff --git a/cherab/core/math/transform/cylindrical.pxd b/cherab/core/math/transform/cylindrical.pxd new file mode 100644 index 00000000..504b2fd5 --- /dev/null +++ b/cherab/core/math/transform/cylindrical.pxd @@ -0,0 +1,30 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from raysect.core.math.function.float cimport Function3D +from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D + + +cdef class CylindricalTransform(Function3D): + + cdef readonly Function3D function3d + + +cdef class VectorCylindricalTransform(VectorFunction3D): + + cdef readonly VectorFunction3D function3d diff --git a/cherab/core/math/transform/cylindrical.pyx b/cherab/core/math/transform/cylindrical.pyx new file mode 100644 index 00000000..cd716cad --- /dev/null +++ b/cherab/core/math/transform/cylindrical.pyx @@ -0,0 +1,128 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from libc.math cimport sqrt, atan2, M_PI + +from raysect.core.math cimport Vector3D +from raysect.core.math.function.float cimport autowrap_function3d +from raysect.core.math.function.vector3d cimport autowrap_function3d as autowrap_vectorfunction3d +from raysect.core cimport rotate_z +cimport cython + +cdef class CylindricalTransform(Function3D): + """ + Converts Cartesian coordinates to cylindrical coordinates and calls a 3D function + defined in cylindrical coordinates, f(r, :math:`\\phi`, z). + + The angular coordinate is given in radians. + + Positive angular coordinate is measured counterclockwise from the xz plane. + + :param Function3D function3d: The function to be mapped. Must be defined + in the interval (:math:`-\\pi`, :math:`\\pi`] + on the angular axis. + + .. code-block:: pycon + + >>> from math import sqrt, cos + >>> from cherab.core.math import CylindricalTransform + >>> + >>> def my_func(r, phi, z): + >>> return r * cos(phi) + >>> + >>> f = CylindricalTransform(my_func) + >>> + >>> f(1, 0, 0) + 1.0 + >>> f(0.5 * sqrt(3), 0.5, 0) + 0.8660254037844385 + """ + + def __init__(self, object function3d): + + if not callable(function3d): + raise TypeError("Function3D is not callable.") + + self.function3d = autowrap_function3d(function3d) + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + """ + Converts to cylindrical coordinates and evaluates the function + defined in cylindrical coordinates. + """ + cdef double r, phi + + r = sqrt(x * x + y * y) + phi = atan2(y, x) + + return self.function3d.evaluate(r, phi, z) + + +cdef class VectorCylindricalTransform(VectorFunction3D): + """ + Converts Cartesian coordinates to cylindrical coordinates, calls + a 3D vector function defined in cylindrical coordinates, f(r, :math:`\\phi`, z), + then converts the returned 3D vector to Cartesian coordinates. + + The angular coordinate is given in radians. + + Positive angular coordinate is measured counterclockwise from the xz plane. + + :param VectorFunction3D function3d: The function to be mapped. Must be defined + in the interval (:math:`-\\pi`, :math:`\\pi`] + on the angular axis. + + .. code-block:: pycon + + >>> from math import sqrt, cos + >>> from raysect.core.math import Vector3D + >>> from cherab.core.math import VectorCylindricalTransform + >>> + >>> def my_vec_func(r, phi, z): + >>> v = Vector3D(0, 1, 0) + >>> v.length = r * abs(cos(phi)) + >>> return v + >>> + >>> f = VectorCylindricalTransform(my_vec_func) + >>> + >>> f(1, 0, 0) + Vector3D(0.0, 1.0, 0.0) + >>> f(1/sqrt(2), 1/sqrt(2), 0) + Vector3D(-0.5, 0.5, 0.0) + """ + + def __init__(self, object function3d): + + if not callable(function3d): + raise TypeError("Function3D is not callable.") + + self.function3d = autowrap_vectorfunction3d(function3d) + + @cython.cdivision(True) + cdef Vector3D evaluate(self, double x, double y, double z): + """ + Converts to cylindrical coordinates, evaluates the vector function + defined in cylindrical coordinates and rotates the resulting vector + around z-axis. + """ + cdef double r, phi + + r = sqrt(x * x + y * y) + phi = atan2(y, x) + + return self.function3d.evaluate(r, phi, z).transform(rotate_z(phi / M_PI * 180)) diff --git a/cherab/core/math/transform/periodic.pxd b/cherab/core/math/transform/periodic.pxd new file mode 100644 index 00000000..e97e4602 --- /dev/null +++ b/cherab/core/math/transform/periodic.pxd @@ -0,0 +1,72 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from libc.math cimport fmod +from raysect.core.math.function.float cimport Function1D, Function2D, Function3D +from raysect.core.math.function.vector3d cimport Function1D as VectorFunction1D +from raysect.core.math.function.vector3d cimport Function2D as VectorFunction2D +from raysect.core.math.function.vector3d cimport Function3D as VectorFunction3D + + +cdef inline double remainder(double x1, double x2) nogil: + if x2 == 0: + return x1 + x1 = fmod(x1, x2) + return x1 + x2 if (x1 < 0) else x1 + + +cdef class PeriodicTransform1D(Function1D): + + cdef: + readonly Function1D function1d + readonly double period + + +cdef class PeriodicTransform2D(Function2D): + + cdef: + readonly Function2D function2d + double period_x, period_y + + +cdef class PeriodicTransform3D(Function3D): + + cdef: + readonly Function3D function3d + readonly double period_x, period_y, period_z + + +cdef class VectorPeriodicTransform1D(VectorFunction1D): + + cdef: + readonly VectorFunction1D function1d + readonly double period + + +cdef class VectorPeriodicTransform2D(VectorFunction2D): + + cdef: + readonly VectorFunction2D function2d + readonly double period_x, period_y + + +cdef class VectorPeriodicTransform3D(VectorFunction3D): + + cdef: + readonly VectorFunction3D function3d + readonly double period_x, period_y, period_z diff --git a/cherab/core/math/transform/periodic.pyx b/cherab/core/math/transform/periodic.pyx new file mode 100644 index 00000000..13869458 --- /dev/null +++ b/cherab/core/math/transform/periodic.pyx @@ -0,0 +1,352 @@ +# Copyright 2016-2022 Euratom +# Copyright 2016-2022 United Kingdom Atomic Energy Authority +# Copyright 2016-2022 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +from raysect.core.math cimport Vector3D +from raysect.core.math.function.float cimport autowrap_function1d, autowrap_function2d, autowrap_function3d +from raysect.core.math.function.vector3d cimport autowrap_function1d as autowrap_vectorfunction1d +from raysect.core.math.function.vector3d cimport autowrap_function2d as autowrap_vectorfunction2d +from raysect.core.math.function.vector3d cimport autowrap_function3d as autowrap_vectorfunction3d + + +cdef class PeriodicTransform1D(Function1D): + """ + Extends a periodic 1D function to an infinite 1D space. + + :param Function1D function1d: The periodic 1D function defined + in the [0, period) interval. + :param double period: The period of the function. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicTransform1D + >>> + >>> def f1(x): + >>> return x + >>> + >>> f2 = PeriodicTransform1D(f1, 1.) + >>> + >>> f2(1.5) + 0.5 + >>> f2(-0.3) + 0.7 + """ + + def __init__(self, object function1d, double period): + + if not callable(function1d): + raise TypeError("function1d is not callable.") + + self.function1d = autowrap_function1d(function1d) + + if period <= 0: + raise ValueError("Argument period must be positive.") + + self.period = period + + cdef double evaluate(self, double x) except? -1e999: + """Return the value of periodic function.""" + + return self.function1d.evaluate(remainder(x, self.period)) + + +cdef class PeriodicTransform2D(Function2D): + """ + Extends a periodic 2D function to an infinite 2D space. + + Set period_x/period_y to 0 if the function is not periodic along x/y axis. + + :param Function2D function2d: The periodic 2D function defined + in the ([0, period_x), [0, period_y)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicTransform2D + >>> + >>> def f1(x, y): + >>> return x * y + >>> + >>> f2 = PeriodicTransform2D(f1, 1., 1.) + >>> + >>> f2(1.5, 1.5) + 0.25 + >>> f2(-0.3, -1.3) + 0.49 + >>> + >>> f3 = PeriodicTransform2D(f1, 1., 0) + >>> + >>> f3(1.5, 1.5) + 0.75 + >>> f3(-0.3, -1.3) + -0.91 + """ + + def __init__(self, object function2d, double period_x, double period_y): + + if not callable(function2d): + raise TypeError("function2d is not callable.") + + self.function2d = autowrap_function2d(function2d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + + cdef double evaluate(self, double x, double y) except? -1e999: + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + + return self.function2d.evaluate(x, y) + + +cdef class PeriodicTransform3D(Function3D): + """ + Extends a periodic 3D function to an infinite 3D space. + + Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. + + :param Function3D function3d: The periodic 3D function defined in the + ([0, period_x), [0, period_y), [0, period_z)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + :param double period_z: The period of the function along z-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicTransform3D + >>> + >>> def f1(x, y, z): + >>> return x * y * z + >>> + >>> f2 = PeriodicTransform3D(f1, 1., 1., 1.) + >>> + >>> f2(1.5, 1.5, 1.5) + 0.125 + >>> f2(-0.3, -1.3, -2.3) + 0.343 + >>> + >>> f3 = PeriodicTransform3D(f1, 0, 1., 0) + >>> + >>> f3(1.5, 1.5, 1.5) + 1.125 + >>> f3(-0.3, -1.3, -0.3) + 0.063 + """ + + def __init__(self, object function3d, double period_x, double period_y, double period_z): + + if not callable(function3d): + raise TypeError("function2d is not callable.") + + self.function3d = autowrap_function3d(function3d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + if period_z < 0: + raise ValueError("Argument period_z must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + self.period_z = period_z + + cdef double evaluate(self, double x, double y, double z) except? -1e999: + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + z = remainder(z, self.period_z) + + return self.function3d.evaluate(x, y, z) + + +cdef class VectorPeriodicTransform1D(VectorFunction1D): + """ + Extends a periodic 1D vector function to an infinite 1D space. + + :param VectorFunction1D function1d: The periodic 1D vector function + defined in the [0, period) interval. + :param double period: The period of the function. + + .. code-block:: pycon + + >>> from raysect.core.math import Vector3D + >>> from cherab.core.math import VectorPeriodicTransform1D + >>> + >>> def f1(x): + >>> return Vector3D(x, 0, 0) + >>> + >>> f2 = VectorPeriodicTransform1D(f1, 1.) + >>> + >>> f2(1.5) + Vector3D(0.5, 0, 0) + >>> f2(-0.3) + Vector3D(0.7, 0, 0) + """ + + def __init__(self, object function1d, double period): + + if not callable(function1d): + raise TypeError("function1d is not callable.") + + self.function1d = autowrap_vectorfunction1d(function1d) + + if period <= 0: + raise ValueError("Argument period must be positive.") + + self.period = period + + cdef Vector3D evaluate(self, double x): + """Return the value of periodic function.""" + + return self.function1d.evaluate(remainder(x, self.period)) + + +cdef class VectorPeriodicTransform2D(VectorFunction2D): + """ + Extends a periodic 2D vector function to an infinite 2D space. + + Set period_x/period_y to 0 if the function is not periodic along x/y axis. + + :param VectorFunction2D function2d: The periodic 2D vector function defined in + the ([0, period_x), [0, period_y)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import VectorPeriodicTransform2D + >>> + >>> def f1(x, y): + >>> return Vector3D(x, y, 0) + >>> + >>> f2 = VectorPeriodicTransform2D(f1, 1., 1.) + >>> + >>> f2(1.5, 1.5) + Vector3D(0.5, 0.5, 0) + >>> f2(-0.3, -1.3) + Vector3D(0.7, 0.7, 0) + >>> + >>> f3 = VectorPeriodicTransform2D(f1, 1., 0) + >>> + >>> f3(1.5, 1.5) + Vector3D(0.5, 1.5, 0) + >>> f3(-0.3, -1.3) + Vector3D(0.7, -1.3, 0) + """ + + def __init__(self, object function2d, double period_x, double period_y): + + if not callable(function2d): + raise TypeError("function2d is not callable.") + + self.function2d = autowrap_vectorfunction2d(function2d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + + cdef Vector3D evaluate(self, double x, double y): + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + + return self.function2d.evaluate(x, y) + + +cdef class VectorPeriodicTransform3D(VectorFunction3D): + """ + Extends a periodic 3D vector function to an infinite 3D space. + + Set period_x/period_y/period_z to 0 if the function is not periodic along x/y/z axis. + + :param VectorFunction3D function3d: The periodic 3D vector function defined in the + ([0, period_x), [0, period_y), [0, period_z)) intervals. + :param double period_x: The period of the function along x-axis. + 0 if not periodic. + :param double period_y: The period of the function along y-axis. + 0 if not periodic. + :param double period_z: The period of the function along z-axis. + 0 if not periodic. + + .. code-block:: pycon + + >>> from cherab.core.math import PeriodicTransform3D + >>> + >>> def f1(x, y, z): + >>> return Vector3D(x, y, z) + >>> + >>> f2 = VectorPeriodicTransform3D(f1, 1., 1., 1.) + >>> + >>> f2(1.5, 1.5, 1.5) + Vector3D(0.5, 0.5, 0.5) + >>> f2(-0.3, -1.3, -2.3) + Vector3D(0.7, 0.7, 0.7) + >>> + >>> f3 = VectorPeriodicTransform3D(f1, 0, 1., 0) + >>> + >>> f3(1.5, 0.5, 1.5) + Vector3D(1.5, 0.5, 1.5) + """ + + def __init__(self, object function3d, double period_x, double period_y, double period_z): + + if not callable(function3d): + raise TypeError("function2d is not callable.") + + self.function3d = autowrap_vectorfunction3d(function3d) + + if period_x < 0: + raise ValueError("Argument period_x must be >= 0.") + if period_y < 0: + raise ValueError("Argument period_y must be >= 0.") + if period_z < 0: + raise ValueError("Argument period_z must be >= 0.") + + self.period_x = period_x + self.period_y = period_y + self.period_z = period_z + + cdef Vector3D evaluate(self, double x, double y, double z): + """Return the value of periodic function.""" + + x = remainder(x, self.period_x) + y = remainder(y, self.period_y) + z = remainder(z, self.period_z) + + return self.function3d.evaluate(x, y, z) From 04b7813c82f577e5438cd985ebe6462cb86685ed Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 28 Dec 2022 11:59:45 +0300 Subject: [PATCH 43/81] Add docs for math.transfrom sub-module. --- docs/source/math/math.rst | 1 + docs/source/math/transform.rst | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 docs/source/math/transform.rst diff --git a/docs/source/math/math.rst b/docs/source/math/math.rst index eab9a1fa..836cbe84 100644 --- a/docs/source/math/math.rst +++ b/docs/source/math/math.rst @@ -18,6 +18,7 @@ utilities that Cherab provides for slicing, dicing and projecting these function function interpolators mappers + transform mask samplers slice diff --git a/docs/source/math/transform.rst b/docs/source/math/transform.rst new file mode 100644 index 00000000..f3d6cfa8 --- /dev/null +++ b/docs/source/math/transform.rst @@ -0,0 +1,11 @@ + +Transformations +--------------- + +These functions perform coordinate transformations as wrappers for other functions. Unlike mappers, these wrappers do not change the dimensionality of the wrapped functions. + +.. automodule:: cherab.core.math.transform.cylindrical + :members: + +.. automodule:: cherab.core.math.transform.periodic + :members: From 63e964be60e56e11d1f1b500ff1eee8befd18692 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Fri, 20 Jan 2023 15:52:46 +0300 Subject: [PATCH 44/81] Allow custom line shapes in BeamCXLine model. (#394) --- CHANGELOG.md | 6 ++ cherab/core/model/beam/charge_exchange.pxd | 3 + cherab/core/model/beam/charge_exchange.pyx | 84 +++++++++++++++------- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bf7c6d..e6483556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Project Changelog ================= +Release 1.5.0 (TBD) +------------------- + +New: +* Add custom line shape support to BeamCXLine model. (#394) + Release 1.4.0 (TBD) ------------------- diff --git a/cherab/core/model/beam/charge_exchange.pxd b/cherab/core/model/beam/charge_exchange.pxd index 4d9220e5..cd0b48db 100644 --- a/cherab/core/model/beam/charge_exchange.pxd +++ b/cherab/core/model/beam/charge_exchange.pxd @@ -21,6 +21,7 @@ from raysect.optical cimport Node, World, Primitive, Ray, Spectrum, SpectralFunc from cherab.core cimport Species, Plasma, Beam, Line, AtomicData, BeamCXPEC from cherab.core.beam cimport BeamModel +from cherab.core.model.lineshape cimport LineShapeModel cdef class BeamCXLine(BeamModel): @@ -31,6 +32,8 @@ cdef class BeamCXLine(BeamModel): double _wavelength BeamCXPEC _ground_beam_rate list _excited_beam_data + LineShapeModel _lineshape + 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 diff --git a/cherab/core/model/beam/charge_exchange.pyx b/cherab/core/model/beam/charge_exchange.pyx index 5cefa3d6..295d5f5f 100644 --- a/cherab/core/model/beam/charge_exchange.pyx +++ b/cherab/core/model/beam/charge_exchange.pyx @@ -1,8 +1,8 @@ # cython: language_level=3 -# 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-2023 Euratom +# Copyright 2016-2023 United Kingdom Atomic Energy Authority +# Copyright 2016-2023 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"); @@ -28,7 +28,7 @@ cimport cython from raysect.optical.material.emitter.inhomogeneous import NumericalIntegrator from cherab.core cimport Species, Plasma, Beam, Element, BeamPopulationRate -from cherab.core.model.lineshape cimport doppler_shift, thermal_broadening, add_gaussian_line +from cherab.core.model.lineshape cimport GaussianLine from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, ATOMIC_MASS cdef double RECIP_ELEMENTARY_CHARGE = 1 / ELEMENTARY_CHARGE @@ -44,24 +44,58 @@ cdef double ms_to_evamu(double x): cdef class BeamCXLine(BeamModel): - """Calculates CX emission for a beam. - - :param line: - :param step: integration step in meters - :return: + """ + Calculates emission produced by charge-exchange of plasma ions + with beam species. + + :param Line line: The emission line object. + :param Beam beam: The beam object. + :param Plasma plasma: The emitting plasma object. + :param AtomicData atomic_data: The atomic data provider. + :param object lineshape: The spectral line shape class. Must be a subclass of `LineShapeModel`. + Defaults to `GaussianLine`. + :param object lineshape_args: The arguments of spectral line shape class. Defaults is None. + :param object lineshape_kwargs: The keyword arguments of spectral line shape class. + Defaults is None. + + :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 + >>> + >>> cVI_8_7 = Line(carbon, 5, (8, 7)) # emission line + >>> # define plasma, beam and atomic data, plasma mast contain C6+ ions. + >>> ... + >>> # here we override default line shape class, GaussianLine, + >>> # with ParametrisedZeemanTriplet to take into account Zeeman splitting. + >>> beam_cx_line = BeamCXLine(cVI_8_7, lineshape=ParametrisedZeemanTriplet) + >>> beam.models = [beam_cx_line] """ - def __init__(self, Line line not None, Beam beam=None, Plasma plasma=None, AtomicData atomic_data=None): + def __init__(self, Line line not None, Beam beam=None, Plasma plasma=None, AtomicData atomic_data=None, + object lineshape=None, object lineshape_args=None, object lineshape_kwargs=None): super().__init__(beam, plasma, atomic_data) self._line = line - # initialise cache to empty - self._target_species = None - self._wavelength = 0.0 - self._ground_beam_rate = None - self._excited_beam_data = None + self._lineshape_class = lineshape or GaussianLine + if not issubclass(self._lineshape_class, LineShapeModel): + raise TypeError("The attribute lineshape must be a subclass of LineShapeModel.") + + if lineshape_args: + self._lineshape_args = lineshape_args + else: + self._lineshape_args = [] + if lineshape_kwargs: + self._lineshape_kwargs = lineshape_kwargs + else: + self._lineshape_kwargs = {} + + # ensure that cache is initialised + self._change() @property def line(self): @@ -85,9 +119,9 @@ cdef class BeamCXLine(BeamModel): cdef: double x, y, z double donor_density - double receiver_temperature, receiver_density, receiver_ion_mass, interaction_speed, interaction_energy, emission_rate + double receiver_temperature, receiver_density, interaction_speed, interaction_energy, emission_rate Vector3D receiver_velocity, donor_velocity, interaction_velocity - double natural_wavelength, central_wavelength, radiance, sigma + double radiance # cache data on first run if self._target_species is None: @@ -116,7 +150,6 @@ cdef class BeamCXLine(BeamModel): return spectrum receiver_velocity = self._target_species.distribution.bulk_velocity(x, y, z) - receiver_ion_mass = self._target_species.element.atomic_weight donor_velocity = beam_direction.normalise().mul(evamu_to_ms(self._beam.get_energy())) @@ -127,20 +160,16 @@ cdef class BeamCXLine(BeamModel): # calculate the composite charge-exchange emission coefficient emission_rate = self._composite_cx_rate(x, y, z, interaction_energy, donor_velocity, receiver_temperature, receiver_density) - # calculate emission line central wavelength, doppler shifted along observation direction - natural_wavelength = self._wavelength - central_wavelength = doppler_shift(natural_wavelength, observation_direction, receiver_velocity) - # spectral line emission in W/m^3/str radiance = RECIP_4_PI * donor_density * receiver_density * emission_rate - sigma = thermal_broadening(natural_wavelength, receiver_temperature, receiver_ion_mass) - return add_gaussian_line(radiance, central_wavelength, sigma, spectrum) + + return self._lineshape.add_line(radiance, plasma_point, observation_direction, spectrum) @cython.boundscheck(False) @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, double receiver_density) except? -1e999: """ Performs a beam population weighted average of the effective cx rates. @@ -328,6 +357,10 @@ cdef class BeamCXLine(BeamModel): # link each rate with its population data self._excited_beam_data.append((rate, population_data)) + # instance line shape renderer + self._lineshape = self._lineshape_class(self._line, self._wavelength, self._target_species, self._plasma, + *self._lineshape_args, **self._lineshape_kwargs) + def _change(self): # clear cache to force regeneration on first use @@ -335,4 +368,3 @@ cdef class BeamCXLine(BeamModel): self._wavelength = 0.0 self._ground_beam_rate = None self._excited_beam_data = None - From 394fe4cb205c23a5958b58d61164489c2f85f76a Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 24 Jan 2023 22:13:12 +0300 Subject: [PATCH 45/81] Add numerical integration to Bremsstrahlung plasma model. --- cherab/core/model/plasma/bremsstrahlung.pxd | 21 ++- cherab/core/model/plasma/bremsstrahlung.pyx | 149 +++++++++++++------- 2 files changed, 109 insertions(+), 61 deletions(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pxd b/cherab/core/model/plasma/bremsstrahlung.pxd index f8251b28..44025c8c 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pxd +++ b/cherab/core/model/plasma/bremsstrahlung.pxd @@ -19,20 +19,27 @@ # cython: language_level=3 from numpy cimport ndarray +from cherab.core.math cimport Function1D +from cherab.core.math.integrators cimport Integrator1D from cherab.core.atomic cimport FreeFreeGauntFactor from cherab.core.plasma cimport PlasmaModel -cdef class Bremsstrahlung(PlasmaModel): +cdef class BremsFunction(Function1D): cdef: - FreeFreeGauntFactor _gaunt_factor - bint _user_provided_gaunt_factor - ndarray _species_charge, _species_density - double[::1] _species_density_mv, _species_charge_mv + double ne, te + FreeFreeGauntFactor gaunt_factor + ndarray species_density, species_charge + double[::1] species_density_mv + double[::1] species_charge_mv - cdef double _bremsstrahlung(self, double wvl, double te, double ne) - cdef int _populate_cache(self) except -1 +cdef class Bremsstrahlung(PlasmaModel): + cdef: + BremsFunction _brems_func + bint _user_provided_gaunt_factor + Integrator1D _integrator + cdef int _populate_cache(self) except -1 diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 2ba7245b..e076478c 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -21,7 +21,7 @@ import numpy as np from raysect.optical cimport Spectrum, Point3D, Vector3D from cherab.core cimport Plasma, AtomicData -from cherab.core.atomic cimport FreeFreeGauntFactor +from cherab.core.math.integrators cimport GaussianQuadrature from cherab.core.species cimport Species from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, SPEED_OF_LIGHT, PLANCK_CONSTANT from libc.math cimport sqrt, log, exp @@ -33,6 +33,61 @@ cdef double PH_TO_J_FACTOR = PLANCK_CONSTANT * SPEED_OF_LIGHT * 1e9 cdef double EXP_FACTOR = PH_TO_J_FACTOR / ELEMENTARY_CHARGE +cdef class BremsFunction(Function1D): + """ + Calculates bremsstrahlung spectrum. + + :param FreeFreeGauntFactor gaunt_factor: Free-free Gaunt factor as a function of Z, Te and + wavelength. + :param object species_density: Array-like object wiyh ions' density in m-3. + :param object species_charge: Array-like object wiyh ions' charge. + :param double ne: Electron density in m-3. + :param double te: Electron temperature in eV. + """ + + def __init__(self, FreeFreeGauntFactor gaunt_factor, object species_density, object species_charge, double ne, double te): + + if ne <= 0: + raise ValueError("Argument ne must be positive.") + self.ne = ne + + if te <= 0: + raise ValueError("Argument te must be positive.") + self.te = te + + self.gaunt_factor = gaunt_factor + self.species_density = np.asarray(species_density, dtype=np.float64) # copied if type does not match + self.species_density_mv = self.species_density + self.species_charge = np.asarray(species_charge, dtype=np.float64) # copied if type does not match + self.species_charge_mv = self.species_charge + + @cython.cdivision(True) + @cython.boundscheck(False) + @cython.wraparound(False) + cdef double evaluate(self, double wvl) except? -1e999: + """ + :param double wvl: Wavelength in nm. + :return: + """ + + cdef double ni_gff_z2, radiance, pre_factor, ni, z + cdef int i + + ni_gff_z2 = 0 + for i in range(self.species_charge_mv.shape[0]): + z = self.species_charge_mv[i] + ni = self.species_density_mv[i] + if ni > 0: + ni_gff_z2 += ni * self.gaunt_factor.evaluate(z, self.te, wvl) * z * z + + # bremsstrahlung equation W/m^3/str/nm + pre_factor = 0.95e-19 * RECIP_4_PI * ni_gff_z2 * self.ne / (sqrt(self.te) * wvl) + radiance = pre_factor * exp(- EXP_FACTOR / (self.te * wvl)) * PH_TO_J_FACTOR + + # convert to W/m^3/str/nm + return radiance / wvl + + # todo: doppler shift? cdef class Bremsstrahlung(PlasmaModel): """ @@ -51,13 +106,17 @@ cdef class Bremsstrahlung(PlasmaModel): :ivar FreeFreeGauntFactor gaunt_factor: Free-free Gaunt factor as a function of Z, Te and wavelength. If not provided, the `atomic_data` is used. + :ivar Integrator1D integrator: Integrator1D instance to integrate Bremsstrahlung radiation + over the spectral bin. Default is `GaussianQuadrature`. """ - def __init__(self, Plasma plasma=None, AtomicData atomic_data=None, FreeFreeGauntFactor gaunt_factor=None): + def __init__(self, Plasma plasma=None, AtomicData atomic_data=None, FreeFreeGauntFactor gaunt_factor=None, Integrator1D integrator=GaussianQuadrature()): super().__init__(plasma, atomic_data) + self._brems_func = BremsFunction.__new__(BremsFunction) self.gaunt_factor = gaunt_factor + self.integrator = integrator # ensure that cache is initialised self._change() @@ -65,14 +124,24 @@ cdef class Bremsstrahlung(PlasmaModel): @property def gaunt_factor(self): - return self._gaunt_factor + return self._brems_func.gaunt_factor @gaunt_factor.setter def gaunt_factor(self, value): - self._gaunt_factor = value + self._brems_func.gaunt_factor = value self._user_provided_gaunt_factor = True if value else False + @property + def integrator(self): + + return self._integrator + + @integrator.setter + def integrator(self, Integrator1D value not None): + + self._integrator = value + def __repr__(self): return '' @@ -84,13 +153,12 @@ cdef class Bremsstrahlung(PlasmaModel): cdef: double ne, te - double lower_wavelength, upper_wavelength - double lower_sample, upper_sample + double lower_wavelength, upper_wavelength, bin_integral Species species int i # cache data on first run - if self._species_charge is None: + if self._brems_func.species_charge is None: self._populate_cache() ne = self._plasma.get_electron_distribution().density(point.x, point.y, point.z) @@ -100,57 +168,30 @@ cdef class Bremsstrahlung(PlasmaModel): if te <= 0: return spectrum + self._brems_func.ne = ne + self._brems_func.te = te + # collect densities of charged species i = 0 for species in self._plasma.get_composition(): if species.charge > 0: - self._species_density_mv[i] = species.distribution.density(point.x, point.y, point.z) + self._brems_func.species_density_mv[i] = species.distribution.density(point.x, point.y, point.z) i += 1 - # numerically integrate using trapezium rule - # todo: add sub-sampling to increase numerical accuracy + self._integrator.function = self._brems_func + + # add bremsstrahlung to spectrum lower_wavelength = spectrum.min_wavelength - lower_sample = self._bremsstrahlung(lower_wavelength, te, ne) for i in range(spectrum.bins): - upper_wavelength = spectrum.min_wavelength + spectrum.delta_wavelength * (i + 1) - upper_sample = self._bremsstrahlung(upper_wavelength, te, ne) - spectrum.samples_mv[i] += 0.5 * (lower_sample + upper_sample) + bin_integral = self._integrator.evaluate(lower_wavelength, upper_wavelength) + spectrum.samples_mv[i] += bin_integral / spectrum.delta_wavelength lower_wavelength = upper_wavelength - lower_sample = upper_sample return spectrum - @cython.cdivision(True) - @cython.boundscheck(False) - @cython.wraparound(False) - cdef double _bremsstrahlung(self, double wvl, double te, double ne): - """ - :param double wvl: Wavelength in nm. - :param double te: Electron temperature in eV - :param double ne: Electron dencity in m^-3 - :return: - """ - - cdef double ni_gff_z2, radiance, pre_factor, ni, z - cdef int i - - ni_gff_z2 = 0 - for i in range(self._species_charge_mv.shape[0]): - z = self._species_charge_mv[i] - ni = self._species_density_mv[i] - if ni > 0: - ni_gff_z2 += ni * self._gaunt_factor.evaluate(z, te, wvl) * z * z - - # bremsstrahlung equation W/m^3/str/nm - pre_factor = 0.95e-19 * RECIP_4_PI * ni_gff_z2 * ne / (sqrt(te) * wvl) - radiance = pre_factor * exp(- EXP_FACTOR / (te * wvl)) * PH_TO_J_FACTOR - - # convert to W/m^3/str/nm - return radiance / wvl - cdef int _populate_cache(self) except -1: cdef list species_charge @@ -159,12 +200,12 @@ cdef class Bremsstrahlung(PlasmaModel): if self._plasma is None: raise RuntimeError("The emission model is not connected to a plasma object.") - if self._gaunt_factor is None: + if self._brems_func.gaunt_factor is None: if self._atomic_data is None: raise RuntimeError("The emission model is not connected to an atomic data source.") # initialise Gaunt factor on first run using the atomic data - self._gaunt_factor = self._atomic_data.free_free_gaunt_factor() + self._brems_func.gaunt_factor = self._atomic_data.free_free_gaunt_factor() species_charge = [] for species in self._plasma.get_composition(): @@ -172,18 +213,18 @@ cdef class Bremsstrahlung(PlasmaModel): species_charge.append(species.charge) # Gaunt factor takes Z as double to support Zeff, so caching Z as float64 - self._species_charge = np.array(species_charge, dtype=np.float64) - self._species_charge_mv = self._species_charge + self._brems_func.species_charge = np.array(species_charge, dtype=np.float64) + self._brems_func.species_charge_mv = self._brems_func.species_charge - self._species_density = np.zeros_like(self._species_charge) - self._species_density_mv = self._species_density + self._brems_func.species_density = np.zeros_like(self._brems_func.species_charge) + self._brems_func.species_density_mv = self._brems_func.species_density def _change(self): # clear cache to force regeneration on first use if not self._user_provided_gaunt_factor: - self._gaunt_factor = None - self._species_charge = None - self._species_charge_mv = None - self._species_density = None - self._species_density_mv = None + self._brems_func.gaunt_factor = None + self._brems_func.species_charge = None + self._brems_func.species_charge_mv = None + self._brems_func.species_density = None + self._brems_func.species_density_mv = None From 0578c09dfd90b02a88a97b47baac58e088a6362d Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 24 Jan 2023 23:08:04 +0300 Subject: [PATCH 46/81] Update changelog. --- CHANGELOG.md | 7 +++++++ cherab/core/model/plasma/bremsstrahlung.pyx | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bf7c6d..276040eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Project Changelog ================= +Release 1.5.0 (TBD) +------------------- + +New: +* Add numerical integration of Bremsstrahlung spectrum over a spectral bin. (#395) + + Release 1.4.0 (TBD) ------------------- diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index e076478c..01e896a9 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -110,13 +110,13 @@ cdef class Bremsstrahlung(PlasmaModel): over the spectral bin. Default is `GaussianQuadrature`. """ - def __init__(self, Plasma plasma=None, AtomicData atomic_data=None, FreeFreeGauntFactor gaunt_factor=None, Integrator1D integrator=GaussianQuadrature()): + def __init__(self, Plasma plasma=None, AtomicData atomic_data=None, FreeFreeGauntFactor gaunt_factor=None, Integrator1D integrator=None): super().__init__(plasma, atomic_data) self._brems_func = BremsFunction.__new__(BremsFunction) self.gaunt_factor = gaunt_factor - self.integrator = integrator + self.integrator = integrator or GaussianQuadrature() # ensure that cache is initialised self._change() From bbcc03092350d3a3a316dfc7e30e70fe9ca61c09 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 26 Jan 2023 12:54:53 +0300 Subject: [PATCH 47/81] Set the integrand in Bremsstrahlung in integrator setter and not in emission(). --- cherab/core/model/plasma/bremsstrahlung.pyx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 01e896a9..fa761eae 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -141,6 +141,7 @@ cdef class Bremsstrahlung(PlasmaModel): def integrator(self, Integrator1D value not None): self._integrator = value + self._integrator.function = self._brems_func def __repr__(self): return '' @@ -178,8 +179,6 @@ cdef class Bremsstrahlung(PlasmaModel): self._brems_func.species_density_mv[i] = species.distribution.density(point.x, point.y, point.z) i += 1 - self._integrator.function = self._brems_func - # add bremsstrahlung to spectrum lower_wavelength = spectrum.min_wavelength for i in range(spectrum.bins): From 7711680667273edb895d313fc7968925d0897df0 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 3 Feb 2023 15:28:48 +0000 Subject: [PATCH 48/81] Remove duplicate changelog entry --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bf7c6d..1a9d87c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,6 @@ Bug fixes: * Fixed generomak plasma edge data paths. * Fix and improve OpenCL utility functions. (#358) * Fixed Bremsstrahlung trapezium evaluation (#384). -* Fixed generomak plasma edge data paths. New: * Make f_profile (current flux) a read-only attribute of EFITEquilibrium. (#355) From cf77c57f11b88e50b7bb9eb2377449203da9991f Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 3 Feb 2023 17:06:52 +0000 Subject: [PATCH 49/81] Update version to 1.4.0 --- CHANGELOG.md | 2 +- cherab/core/VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9d87c1..1ae0a7d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ Project Changelog ================= -Release 1.4.0 (TBD) +Release 1.4.0 (3 Feb 2023) ------------------- API changes: diff --git a/cherab/core/VERSION b/cherab/core/VERSION index 40b48802..88c5fb89 100644 --- a/cherab/core/VERSION +++ b/cherab/core/VERSION @@ -1 +1 @@ -1.4.0rc1 +1.4.0 From 56e4e7a3d746990f76ac66589d18eafc6930d9be Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Mon, 13 Feb 2023 10:02:22 +0000 Subject: [PATCH 50/81] Require raysect 0.8.1 --- .github/workflows/ci.yml | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- setup.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d488326..f4c15ee4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Install Python dependencies run: python -m pip install --prefer-binary cython>=0.28 ${{ matrix.numpy-version }} scipy matplotlib "pyopencl[pocl]>=2022.2.4" - name: Install Raysect from pypi - run: pip install raysect==0.8.0 + run: pip install raysect==0.8.1 - name: Build cherab run: dev/build.sh - name: Run tests diff --git a/pyproject.toml b/pyproject.toml index 8a37ce38..ce56ed60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools", "wheel", "oldest-supported-numpy", "cython>=0.28", "raysect==0.8.0"] +requires = ["setuptools", "wheel", "oldest-supported-numpy", "cython>=0.28", "raysect==0.8.1"] build-backend="setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt index d9462771..24a9b6e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ cython>=0.28 numpy>=1.14 scipy matplotlib -raysect==0.8.0 +raysect==0.8.1 diff --git a/setup.py b/setup.py index 062a5ed8..b90af19e 100644 --- a/setup.py +++ b/setup.py @@ -103,7 +103,7 @@ "numpy>=1.14", "scipy", "matplotlib", - "raysect==0.8.0", + "raysect==0.8.1", ], packages=find_packages(), include_package_data=True, From 7e201798c035d83dadcf66567c079c4aa375c8f9 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Tue, 14 Feb 2023 16:01:16 +0000 Subject: [PATCH 51/81] Force -O3 compilation Recent Anaconda and other Python distributions have changed to -O2 which results in a performance degradation. Manylinux and older Anacondas use -O3, so specify this to maintain behaviour. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b90af19e..476697e8 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ source_paths = ["cherab", "demos"] compilation_includes = [".", numpy.get_include()] -compilation_args = [] +compilation_args = ["-O3"] cython_directives = {"language_level": 3} setup_path = path.dirname(path.abspath(__file__)) From e851cee6f9870e074f59dea38ac4af7c8a60f6c7 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Tue, 14 Feb 2023 16:07:46 +0000 Subject: [PATCH 52/81] Make development version number PEP440-compliant --- cherab/core/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherab/core/VERSION b/cherab/core/VERSION index af5728b4..c831dd27 100644 --- a/cherab/core/VERSION +++ b/cherab/core/VERSION @@ -1 +1 @@ -1.5.0dev1 +1.5.0.dev1 From 0ab324ab02d2eb3e48c7982f03a0895f9cf7ee09 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Tue, 14 Feb 2023 16:08:53 +0000 Subject: [PATCH 53/81] Update Changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae0a7d3..0a17fd37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Project Changelog ================= +Release 1.5.0 (TBD) +------------------- + +New: +* Support Raysect 0.8 + + Release 1.4.0 (3 Feb 2023) ------------------- From e12fd5b79c85c2cc5bd89c92595210a1e2e5e369 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Thu, 23 Feb 2023 12:11:17 +0000 Subject: [PATCH 54/81] Fix coverage configuration to properly omit test files Omit wildcard was incorrect: should specify tests directories at all levels. --- .coveragerc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index a67a87f0..a27c0920 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,4 +1,4 @@ [run] plugins = Cython.Coverage source = cherab -omit = *tests* +omit = */tests/* From a029b09cd2a91a5ce752115fc4b85d989bfd50dc Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Thu, 23 Feb 2023 17:49:59 +0000 Subject: [PATCH 55/81] Package demo scripts and data in sdists and wheels This enables users who haven't cloned the git repository to still run the demos. A few unnecessary entries were removed from MANIFEST.in too. TODO: see whether we can get rid of MANIFEST.in completely and use setuptools' find_packages and package_data instead. --- MANIFEST.in | 7 ++----- setup.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 2f977070..2d850775 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,3 @@ -include README.md CHANGELOG.md LICENSE.txt CITE.md AUTHORS.md MANIFEST.in setup.py requirements.txt .gitignore +include CHANGELOG.md CITE.md AUTHORS.md include cherab/core/VERSION -recursive-include cherab *.py *.pyx *.pxd *.json *.cl *.npy *.obj -prune demos* - - +recursive-include cherab *.pyx *.pxd *.json *.cl *.npy *.obj diff --git a/setup.py b/setup.py index 476697e8..ba84e56e 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,10 @@ from setuptools import setup, find_packages, Extension +from collections import defaultdict import sys import numpy import os import os.path as path +from pathlib import Path import multiprocessing from Cython.Build import cythonize @@ -68,6 +70,16 @@ compiler_directives=cython_directives, ) +# Include demos in a separate directory in the distribution as data_files. +demo_parent_path = Path("share/cherab/demos/core") +data_files = defaultdict(list) +demos_source = Path("demos") +for item in demos_source.rglob("*"): + if item.is_file(): + install_dir = demo_parent_path / item.parent.relative_to(demos_source) + data_files[str(install_dir)].append(str(item)) +data_files = list(data_files.items()) + # parse the package version number with open(path.join(path.dirname(__file__), "cherab/core/VERSION")) as version_file: version = version_file.read().strip() @@ -105,8 +117,9 @@ "matplotlib", "raysect==0.8.1", ], - packages=find_packages(), + packages=find_packages(include=["cherab*"]), include_package_data=True, + data_files=data_files, zip_safe=False, ext_modules=extensions, ) From ba14ce9eee5d51ff0f46c8d9e9c1bc066f76e8b4 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Thu, 23 Feb 2023 18:00:51 +0000 Subject: [PATCH 56/81] Build extensions in parallel by default This speeds up installation from source using pip, where it is otherwise cumbersome to pass the `--parallel` option to `setup.py build_ext`. --- README.md | 7 +++++++ docs/source/installation_and_structure.rst | 6 ++++++ setup.py | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/README.md b/README.md index 963b0834..177feb9b 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,13 @@ with a build-time dependency on Cherab need to use a Cython version newer than 3.0a5, due to a [bug](https://github.com/cython/cython/issues/2918) in how earlier versions of Cython handle namespaces. +By default, pip will install from wheel archives on PyPI. If a binary wheel is not +available for your version of Python, or if you are installing in editable mode +for development, the package will be compiled locally on your machine. Compilation +is done in parallel by default, using all available processors, but can be +overridden by setting the environment variable `CHERAB_NCPU` to the number of +processors to use. + Governance ---------- diff --git a/docs/source/installation_and_structure.rst b/docs/source/installation_and_structure.rst index 3af9d3ad..e9c051bf 100644 --- a/docs/source/installation_and_structure.rst +++ b/docs/source/installation_and_structure.rst @@ -82,6 +82,12 @@ line to install the packages under your own user account. Alternatively, conside `virtual environment `_ to avoid the risk of conflicting versions of packages in your Python environment. +By default, pip will install from wheel archives on PyPI. If a binary wheel is not available for +your version of Python, or if you are installing from source in editable mode for development (see +below), the package will be compiled locally on your machine. Compilation is done in parallel by +default, using all available processors, but can be overridden by setting the environment variable +``CHERAB_NCPU`` to the number of processors to use. + Installing from source ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 476697e8..f0610a6c 100644 --- a/setup.py +++ b/setup.py @@ -34,6 +34,9 @@ compilation_args = ["-O3"] cython_directives = {"language_level": 3} setup_path = path.dirname(path.abspath(__file__)) +num_processes = int(os.getenv("CHERAB_NCPU", "-1")) +if num_processes == -1: + num_processes = multiprocessing.cpu_count() if line_profile: compilation_args.append("-DCYTHON_TRACE=1") @@ -109,6 +112,9 @@ include_package_data=True, zip_safe=False, ext_modules=extensions, + options=dict( + build_ext={"parallel": num_processes}, + ), ) # setup a rate repository with common rates From 3007d558c5af83caf8146af734deaddb39c3a278 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Fri, 24 Feb 2023 16:40:56 +0000 Subject: [PATCH 57/81] Remove MANIFEST.in and include_package_data, specify package_data manually This allows finer control over what gets packaged, and fixes a deprecation warning in recent setuptools versions (see https://github.com/pypa/setuptools/issues/3308 for detais). It also prevents Cython-transpiled C source files being included in the wheel distribution, which roughly halves the size of the installed distribution. --- MANIFEST.in | 3 --- pyproject.toml | 2 +- setup.py | 12 ++++++++---- 3 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 2d850775..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include CHANGELOG.md CITE.md AUTHORS.md -include cherab/core/VERSION -recursive-include cherab *.pyx *.pxd *.json *.cl *.npy *.obj diff --git a/pyproject.toml b/pyproject.toml index ce56ed60..a4eabed0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools", "wheel", "oldest-supported-numpy", "cython>=0.28", "raysect==0.8.1"] +requires = ["setuptools>=62.3", "oldest-supported-numpy", "cython>=0.28", "raysect==0.8.1"] build-backend="setuptools.build_meta" diff --git a/setup.py b/setup.py index ba84e56e..58d28075 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ -from setuptools import setup, find_packages, Extension from collections import defaultdict import sys -import numpy import os import os.path as path from pathlib import Path import multiprocessing +import numpy +from setuptools import setup, find_packages, Extension from Cython.Build import cythonize multiprocessing.set_start_method('fork') @@ -117,8 +117,12 @@ "matplotlib", "raysect==0.8.1", ], - packages=find_packages(include=["cherab*"]), - include_package_data=True, + packages=find_packages(include=["cherab"]), + package_data={"": [ + "**/*.pyx", "**/*.pxd", # Needed to build Cython extensions. + "**/*.json", "**/*.cl", "**/*.npy", "**/*.obj", # Supplementary data + "cherab/core/VERSION", # Used by cherab.core to determine version at run time + ]}, data_files=data_files, zip_safe=False, ext_modules=extensions, From 6b8b71c2e469c746990ca9123aa4c8364c1e8829 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Mon, 27 Feb 2023 04:58:48 -0500 Subject: [PATCH 58/81] Fix find_packages and package_data --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 58d28075..32588343 100644 --- a/setup.py +++ b/setup.py @@ -117,12 +117,13 @@ "matplotlib", "raysect==0.8.1", ], - packages=find_packages(include=["cherab"]), + packages=find_packages(include=["cherab*"]), package_data={"": [ "**/*.pyx", "**/*.pxd", # Needed to build Cython extensions. "**/*.json", "**/*.cl", "**/*.npy", "**/*.obj", # Supplementary data - "cherab/core/VERSION", # Used by cherab.core to determine version at run time - ]}, + ], + "cherab.core": ["VERSION"], # Used to determine version at run time + }, data_files=data_files, zip_safe=False, ext_modules=extensions, From 751f324960afdb7be2402a40f702c1721427e83a Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 14 Mar 2023 10:57:47 +0300 Subject: [PATCH 59/81] Add tests for VectorPeriodicTransform#D functions. --- cherab/core/math/tests/test_transform.py | 115 +++++++++++++++++++++-- 1 file changed, 109 insertions(+), 6 deletions(-) diff --git a/cherab/core/math/tests/test_transform.py b/cherab/core/math/tests/test_transform.py index 2ee4eefc..6fad98b0 100644 --- a/cherab/core/math/tests/test_transform.py +++ b/cherab/core/math/tests/test_transform.py @@ -28,10 +28,12 @@ class TestCylindricalTransform(unittest.TestCase): def setUp(self): """Initialisation with functions to map.""" - def f3d(r, phi, z): return r * np.cos(phi) + z + def f3d(r, phi, z): + return r * np.cos(phi) + z self.function3d = f3d - def vecf3d(r, phi, z): return Vector3D(np.sin(phi), r * z, np.cos(phi)) + def vecf3d(r, phi, z): + return Vector3D(np.sin(phi), r * z, np.cos(phi)) self.vectorfunction3d = vecf3d def test_cylindrical_transform(self): @@ -63,13 +65,30 @@ class TestPeriodicTransform(unittest.TestCase): def setUp(self): """Initialisation with functions to map.""" - def f1d(x): return x*np.cos(x-3) + def f1d(x): + return x * np.cos(x - 3) self.function1d = f1d - def f2d(x, y): return x*np.sin(y) + + def f2d(x, y): + return x * np.sin(y) self.function2d = f2d - def f3d(x, y, z): return x*x*np.exp(y)-2*z*y + + def f3d(x, y, z): + return x * x * np.exp(y) - 2 * z * y self.function3d = f3d + def vecf1d(x): + return Vector3D(x, x**2, x**3) + self.vectorfunction1d = vecf1d + + def vecf2d(x, y): + return Vector3D(x, y, x * y) + self.vectorfunction2d = vecf2d + + def vecf3d(x, y, z): + return Vector3D(x + y + z, (x + y) * z, x * y * z) + self.vectorfunction3d = vecf3d + def test_periodic_transform_1d(self): """1D periodic transform""" period_func = transform.PeriodicTransform1D(self.function1d, np.pi) @@ -140,7 +159,7 @@ def test_periodic_transform_3d(self): places=10) def test_periodic_transform_3d_invalid_arg(self): - """2D periodic transform. Invalid arguments.""" + """3D periodic transform. Invalid arguments.""" # 1st argument is not callable self.assertRaises(TypeError, transform.PeriodicTransform3D, "blah", np.pi, np.pi, np.pi) # period is not a number @@ -152,6 +171,90 @@ def test_periodic_transform_3d_invalid_arg(self): self.assertRaises(ValueError, transform.PeriodicTransform3D, self.function3d, np.pi, -1, np.pi) self.assertRaises(ValueError, transform.PeriodicTransform3D, self.function3d, np.pi, np.pi, -1) + def test_vector_periodic_transform_1d(self): + """1D vector periodic transform""" + period_func = transform.VectorPeriodicTransform1D(self.vectorfunction1d, 1) + vec1 = period_func(1.4) + vec2 = Vector3D(0.4, 0.16, 0.064) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + def test_vector_periodic_transform_1d_invalid_arg(self): + """1D vector periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.VectorPeriodicTransform1D, "blah", 1.) + # period is not a number + self.assertRaises(TypeError, transform.VectorPeriodicTransform1D, self.vectorfunction1d, "blah") + # period is negative + self.assertRaises(ValueError, transform.VectorPeriodicTransform1D, self.vectorfunction1d, -1) + + def test_vector_periodic_transform_2d(self): + """2D vector periodic transform""" + period_func = transform.VectorPeriodicTransform2D(self.vectorfunction2d, 1, 1) + vec1 = period_func(-0.4, 1.6) + vec2 = Vector3D(0.6, 0.6, 0.36) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + # Periodic only along x + period_func = transform.VectorPeriodicTransform2D(self.vectorfunction2d, 1, 0) + vec1 = period_func(-0.4, 1.6) + vec2 = Vector3D(0.6, 1.6, 0.96) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + # Periodic only along y + period_func = transform.VectorPeriodicTransform2D(self.vectorfunction2d, 0, 1) + vec1 = period_func(-0.4, 1.6) + vec2 = Vector3D(-0.4, 0.6, -0.24) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + def test_vector_periodic_transform_2d_invalid_arg(self): + """2D vector periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, "blah", 1, 1) + # period is not a number + self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.function2d, "blah", 1) + self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.function2d, 1, "blah") + # period is negative + self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.function2d, -1, 1) + self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.function2d, 1, -1) + + def test_vector_periodic_transform_3d(self): + """3D vector periodic transform""" + period_func = transform.VectorPeriodicTransform3D(self.vectorfunction3d, 1, 1, 1) + vec1 = period_func(-0.4, 1.6, 1.2) + vec2 = Vector3D(1.4, 0.24, 0.072) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + # Periodic along y and z + period_func = transform.VectorPeriodicTransform3D(self.vectorfunction3d, 0, 1, 1) + vec1 = period_func(-0.4, 1.6, 1.2) + vec2 = Vector3D(0.4, 0.04, -0.048) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + # Periodic along x and z + period_func = transform.VectorPeriodicTransform3D(self.vectorfunction3d, 1, 0, 1) + vec1 = period_func(-0.4, 1.6, 1.2) + vec2 = Vector3D(2.4, 0.44, 0.192) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + # Periodic along x and y + period_func = transform.VectorPeriodicTransform3D(self.vectorfunction3d, 1, 1, 0) + vec1 = period_func(-0.4, 1.6, 1.2) + vec2 = Vector3D(2.4, 1.44, 0.432) + np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) + + def test_vector_periodic_transform_3d_invalid_arg(self): + """2D vector periodic transform. Invalid arguments.""" + # 1st argument is not callable + self.assertRaises(TypeError, transform.VectorPeriodicTransform3D, "blah", 1, 1, 1) + # period is not a number + self.assertRaises(TypeError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, "blah", 1, 1) + self.assertRaises(TypeError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, 1, "blah", 1) + self.assertRaises(TypeError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, 1, 1, "blah") + # period is negative + self.assertRaises(ValueError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, -1, 1, 1) + self.assertRaises(ValueError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, 1, -1, 1) + self.assertRaises(ValueError, transform.VectorPeriodicTransform3D, self.vectorfunction3d, 1, 1, -1) + if __name__ == '__main__': unittest.main() From ab14fb8b74a61e0745553b37f6de14071bdebb5e Mon Sep 17 00:00:00 2001 From: vsnever Date: Tue, 14 Mar 2023 12:57:22 +0300 Subject: [PATCH 60/81] Fixed copy-paste errors in TestPeriodicTransform. --- cherab/core/math/tests/test_transform.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cherab/core/math/tests/test_transform.py b/cherab/core/math/tests/test_transform.py index 6fad98b0..fc3a2445 100644 --- a/cherab/core/math/tests/test_transform.py +++ b/cherab/core/math/tests/test_transform.py @@ -211,11 +211,11 @@ def test_vector_periodic_transform_2d_invalid_arg(self): # 1st argument is not callable self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, "blah", 1, 1) # period is not a number - self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.function2d, "blah", 1) - self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.function2d, 1, "blah") + self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.vectorfunction2d, "blah", 1) + self.assertRaises(TypeError, transform.VectorPeriodicTransform2D, self.vectorfunction2d, 1, "blah") # period is negative - self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.function2d, -1, 1) - self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.function2d, 1, -1) + self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.vectorfunction2d, -1, 1) + self.assertRaises(ValueError, transform.VectorPeriodicTransform2D, self.vectorfunction2d, 1, -1) def test_vector_periodic_transform_3d(self): """3D vector periodic transform""" @@ -243,7 +243,7 @@ def test_vector_periodic_transform_3d(self): np.testing.assert_almost_equal([vec1.x, vec1.y, vec1.z], [vec2.x, vec2.y, vec2.z], decimal=10) def test_vector_periodic_transform_3d_invalid_arg(self): - """2D vector periodic transform. Invalid arguments.""" + """3D vector periodic transform. Invalid arguments.""" # 1st argument is not callable self.assertRaises(TypeError, transform.VectorPeriodicTransform3D, "blah", 1, 1, 1) # period is not a number From 101456789d8ac1dcf47a8bfb17c0a6e8479358d5 Mon Sep 17 00:00:00 2001 From: "Lovell, Jack J" Date: Fri, 17 Jan 2020 13:37:52 +0000 Subject: [PATCH 61/81] Add analytic plasma demo using raysect's function framework This is roughly 25x faster than the pure python, class-based demo. --- .../analytic_plasma_function_framework.py | 165 ++++++++++++++++++ docs/source/conf.py | 2 + .../plasmas/analytic_function_plasma.rst | 22 ++- 3 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 demos/plasmas/analytic_plasma_function_framework.py diff --git a/demos/plasmas/analytic_plasma_function_framework.py b/demos/plasmas/analytic_plasma_function_framework.py new file mode 100644 index 00000000..1459f28e --- /dev/null +++ b/demos/plasmas/analytic_plasma_function_framework.py @@ -0,0 +1,165 @@ + +# Copyright 2016-2018 Euratom +# Copyright 2016-2018 United Kingdom Atomic Energy Authority +# Copyright 2016-2018 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + + +import numpy as np +import matplotlib.pyplot as plt +from scipy.constants import electron_mass, atomic_mass + +from raysect.core.math.function.float import Arg2D, Exp2D, Sqrt2D +from raysect.primitive import Cylinder +from raysect.optical import World, translate, Point3D, Vector3D, rotate_basis, Spectrum +from raysect.optical.observer import PinholeCamera, PowerPipeline2D + +from cherab.core import Species, Maxwellian, Plasma, Line +from cherab.core.math import sample3d, AxisymmetricMapper +from cherab.core.atomic import deuterium +from cherab.core.model import ExcitationLine +from cherab.openadas import OpenADAS + + +def NeutralFunction(peak_value, sigma, magnetic_axis, lcfs_radius=1): + """A neutral profile that is constant outside the plasma, + then exponentially decays inside the LCFS.""" + raxis = magnetic_axis[0] + zaxis = magnetic_axis[1] + radius_from_axis = Sqrt2D((Arg2D('x') - raxis)**2 + (Arg2D('y') - zaxis)**2) + scale = Exp2D(-((radius_from_axis - lcfs_radius)**2) / (2 * sigma**2)) + inside_lcfs = (radius_from_axis <= lcfs_radius) + # density = peak * scale * inside_lcfs + peak * (inside_lcfs - 1). + # Rearrange so inside_lcfs and scale are only called once each. + density = peak_value * (inside_lcfs * (scale - 1) + 1) + return AxisymmetricMapper(density) + + +def IonFunction(v_core, v_lcfs, magnetic_axis, p=4, q=3, lcfs_radius=1): + """An approximate toroidal plasma profile that follows a double + quadratic between the LCFS and magnetic axis.""" + r_axis = magnetic_axis[0] + z_axis = magnetic_axis[1] + radius_from_axis = Sqrt2D((Arg2D('x') - r_axis)**2 + (Arg2D('y') - z_axis)**2) + density = (v_core - v_lcfs) * (1 - (radius_from_axis / lcfs_radius)**p)**q + v_lcfs + inside_lcfs = (radius_from_axis <= lcfs_radius) + return AxisymmetricMapper(density * inside_lcfs) + + +# tunables +peak_density = 1e19 +peak_temperature = 2500 +magnetic_axis = (2.5, 0) + + +# setup scenegraph +world = World() + + +################### +# plasma creation # + +plasma = Plasma(parent=world) +plasma.atomic_data = OpenADAS(permit_extrapolation=True) +plasma.geometry = Cylinder(3.5, 2.2, transform=translate(0, 0, -1.1)) +plasma.geometry_transform = translate(0, 0, -1.1) + +# No net velocity for any species +zero_velocity = Vector3D(0, 0, 0) + +# define neutral species distribution +d0_density = NeutralFunction(peak_density, 0.1, magnetic_axis) +d0_temperature = 0.5 # constant 0.5eV temperature for all neutrals +d0_distribution = Maxwellian(d0_density, d0_temperature, zero_velocity, + deuterium.atomic_weight * atomic_mass) +d0_species = Species(deuterium, 0, d0_distribution) + +# define deuterium ion species distribution +d1_density = IonFunction(peak_density, 0, magnetic_axis) +d1_temperature = IonFunction(peak_temperature, 0, magnetic_axis) +d1_distribution = Maxwellian(d1_density, d1_temperature, zero_velocity, + deuterium.atomic_weight * atomic_mass) +d1_species = Species(deuterium, 1, d1_distribution) + +# define the electron distribution +e_density = IonFunction(peak_density, 0, magnetic_axis) +e_temperature = IonFunction(peak_temperature, 0, magnetic_axis) +e_distribution = Maxwellian(e_density, e_temperature, zero_velocity, electron_mass) + +# define species +plasma.b_field = Vector3D(1.0, 1.0, 1.0) +plasma.electron_distribution = e_distribution +plasma.composition = [d0_species, d1_species] + +# Add a balmer alpha line for visualisation purposes +d_alpha_excit = ExcitationLine(Line(deuterium, 0, (3, 2))) +plasma.models = [d_alpha_excit] + + +#################### +# Visualise Plasma # + +# Run some plots to check the distribution functions and emission profile are as expected +r, _, z, t_samples = sample3d(d1_temperature, (0, 4, 200), (0, 0, 1), (-2, 2, 200)) +plt.imshow(np.transpose(np.squeeze(t_samples)), extent=[0, 4, -2, 2]) +plt.colorbar() +plt.axis('equal') +plt.xlabel('r axis') +plt.ylabel('z axis') +plt.title("Ion temperature profile in r-z plane") + +plt.figure() +r, _, z, t_samples = sample3d(d1_temperature, (-4, 4, 400), (-4, 4, 400), (0, 0, 1)) +plt.imshow(np.transpose(np.squeeze(t_samples)), extent=[-4, 4, -4, 4]) +plt.colorbar() +plt.axis('equal') +plt.xlabel('x axis') +plt.ylabel('y axis') +plt.title("Ion temperature profile in x-y plane") + +plt.figure() +r, _, z, t_samples = sample3d(d0_density, (0, 4, 200), (0, 0, 1), (-2, 2, 200)) +plt.imshow(np.transpose(np.squeeze(t_samples)), extent=[0, 4, -2, 2]) +plt.colorbar() +plt.axis('equal') +plt.xlabel('r axis') +plt.ylabel('z axis') +plt.title("Neutral Density profile in r-z plane") + +plt.figure() +xrange = np.linspace(0, 4, 200) +yrange = np.linspace(-2, 2, 200) +d_alpha_rz_intensity = np.zeros((200, 200)) +direction = Vector3D(0, 1, 0) +for i, x in enumerate(xrange): + for j, y in enumerate(yrange): + emission = d_alpha_excit.emission(Point3D(x, 0.0, y), direction, Spectrum(650, 660, 1)) + d_alpha_rz_intensity[j, i] = emission.total() +plt.imshow(d_alpha_rz_intensity, extent=[0, 4, -2, 2], origin='lower') +plt.colorbar() +plt.xlabel('r axis') +plt.ylabel('z axis') +plt.title("D-alpha emission in R-Z") + + +camera = PinholeCamera((256, 256), pipelines=[PowerPipeline2D()], parent=world) +camera.transform = translate(2.5, -4.5, 0)*rotate_basis(Vector3D(0, 1, 0), Vector3D(0, 0, 1)) +camera.pixel_samples = 1 + +plt.ion() +camera.observe() +plt.ioff() +plt.show() diff --git a/docs/source/conf.py b/docs/source/conf.py index 60589037..d17ec793 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -39,6 +39,7 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.mathjax', + 'sphinx_tabs.tabs', ] # Add any paths that contain templates here, relative to this directory. @@ -142,6 +143,7 @@ html_context = {'css_files': [ '_static/theme_overrides.css', # override wide tables in RTD theme + '_static/tabs.css', ] } diff --git a/docs/source/demonstrations/plasmas/analytic_function_plasma.rst b/docs/source/demonstrations/plasmas/analytic_function_plasma.rst index e74ba874..627f0c66 100644 --- a/docs/source/demonstrations/plasmas/analytic_function_plasma.rst +++ b/docs/source/demonstrations/plasmas/analytic_function_plasma.rst @@ -10,11 +10,25 @@ shows how to use these functions in a plasma and visualises the results. Note that while it is possible to use pure python functions for development, they are typically ~100 times slower than their cython counterparts. Therefore, for use cases where speed is important -we recommend moving these functions to cython classes. For an example of a cython function, -see the `Gaussian `_ -cython class in the demos folder. +we recommend moving these functions to cython classes. An alternative solution which may not require +writing and compiling any additional cython code is to use Raysect's +`function framework `_ to build up +expressions which will be evaluated like Python functions. These will typically run slightly slower +than a hand-coded cython implementation but still significantly faster than a pure python +implementation. -.. literalinclude:: ../../../../demos/plasmas/analytic_plasma.py +Two examples are provided, one using a pure python implementation of analytic forms for neutral and +ion plasma species distributions, and one using objects from Raysect's function framework. + +.. tabs:: + + .. tab:: Pure python + + .. literalinclude:: ../../../../demos/plasmas/analytic_plasma.py + + .. tab:: Function framework + + .. literalinclude:: ../../../../demos/plasmas/analytic_plasma_function_framework.py .. figure:: analytic_plasma_slices.png :align: center From ac6863a5e548f6b06e4b60c5a66939e57e068472 Mon Sep 17 00:00:00 2001 From: Jack Lovell Date: Thu, 6 Apr 2023 15:48:16 +0100 Subject: [PATCH 62/81] Add a docs extras requirement for building documentation When building the docs, run `pip install cherab[docs]` to get the dependencies required for successfully running `./dev/build_docs.sh`. --- setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.py b/setup.py index f0610a6c..5d9d7a8e 100644 --- a/setup.py +++ b/setup.py @@ -108,6 +108,10 @@ "matplotlib", "raysect==0.8.1", ], + extras_require={ + # Running ./dev/build_docs.sh runs setup.py, which requires cython. + "docs": ["cython", "sphinx", "sphinx-rtd-theme", "sphinx-tabs"], + }, packages=find_packages(), include_package_data=True, zip_safe=False, From af0581e5d90079a080359ea4e7c61a8e8cafeeae Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 27 Apr 2023 17:43:15 +0300 Subject: [PATCH 63/81] Added tests for BeamCXLine model. --- cherab/core/tests/test_beamcxline.py | 167 +++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 cherab/core/tests/test_beamcxline.py diff --git a/cherab/core/tests/test_beamcxline.py b/cherab/core/tests/test_beamcxline.py new file mode 100644 index 00000000..d3aa2976 --- /dev/null +++ b/cherab/core/tests/test_beamcxline.py @@ -0,0 +1,167 @@ +# Copyright 2016-2023 Euratom +# Copyright 2016-2023 United Kingdom Atomic Energy Authority +# Copyright 2016-2023 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import unittest + +import numpy as np +from scipy.special import erf + +from raysect.core import Point3D, Vector3D, translate +from raysect.optical import World, Spectrum, Ray + +from cherab.core import Beam +from cherab.core.atomic import Line, AtomicData, BeamCXPEC, BeamStoppingRate +from cherab.core.math.integrators import GaussianQuadrature +from cherab.core.atomic import deuterium, nitrogen +from cherab.tools.plasmas.slab import build_constant_slab_plasma +from cherab.core.model import SingleRayAttenuator, BeamCXLine, GaussianLine, ZeemanTriplet + + +class ConstantBeamCXPEC(BeamCXPEC): + """ + Constant beam CX PEC for test purpose. + """ + + def __init__(self, donor_metastable, value): + self.donor_metastable = donor_metastable + self.value = value + + def evaluate(self, energy, temperature, density, z_effective, b_field): + + return self.value + + +class ConstantBeamStoppingRate(BeamStoppingRate): + """ + Constant beam CX PEC for test purpose. + """ + + def __init__(self, donor_metastable, value): + self.donor_metastable = donor_metastable + self.value = value + + def evaluate(self, energy, density, temperature): + + return self.value + + +class TestAtomicData(AtomicData): + """Fake atomic data for test purpose.""" + + def beam_cx_pec(self, donor_ion, receiver_ion, receiver_charge, transition): + + return [ConstantBeamCXPEC(1, 3.4e-34)] + + def beam_stopping_rate(self, beam_ion, plasma_ion, charge): + + return ConstantBeamStoppingRate(1, 0) + + def wavelength(self, ion, charge, transition): + + return 656.104 + + +class TestBeamCXLine(unittest.TestCase): + + world = World() + + atomic_data = TestAtomicData() + + 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 test_default_lineshape(self): + # setting up the model + line = Line(deuterium, 0, (3, 2)) # D-alpha line + self.beam.models = [BeamCXLine(line)] + + # observing + origin = Point3D(1.5, 0, 0) + direction = Vector3D(-1, 0, 0) + ray = Ray(origin=origin, direction=direction, + min_wavelength=655.1, max_wavelength=657.1, bins=512) + cx_spectrum = ray.trace(self.world) + + # validating + dx = self.beam.integrator.step + rate = self.atomic_data.beam_cx_pec(deuterium, deuterium, 1, (3, 2))[0].value + ni = self.plasma.ion_density(0.5, 0, 0) # constant slab + nd_beam = 0 # beam density + for i in range(-int(0.5 / dx), int(0.5 / dx)): + x = dx * (i + 0.5) + nd_beam += self.beam.density(x, 0, 0) # in internal beam coordinates + radiance = 0.25 * rate * ni * nd_beam * dx / np.pi + + target_species = self.plasma.composition.get(line.element, line.charge + 1) + wavelength = self.atomic_data.wavelength(line.element, line.charge, line.transition) + gaussian_line = GaussianLine(line, wavelength, target_species, self.plasma) + spectrum = Spectrum(ray.min_wavelength, ray.max_wavelength, ray.bins) + spectrum = gaussian_line.add_line(radiance, Point3D(0.5, 0, 0), direction, spectrum) + + for i in range(ray.bins): + self.assertAlmostEqual(cx_spectrum.samples[i], spectrum.samples[i], delta=1e-8, + msg='BeamCXLine model gives a wrong value at {} nm.'.format(spectrum.wavelengths[i])) + + def test_custom_lineshape(self): + # setting up the model + line = Line(deuterium, 0, (3, 2)) # D-alpha line + self.beam.models = [BeamCXLine(line, lineshape=ZeemanTriplet)] + + # observing + origin = Point3D(1.5, 0, 0) + direction = Vector3D(-1, 0, 0) + ray = Ray(origin=origin, direction=direction, + min_wavelength=655.1, max_wavelength=657.1, bins=512) + cx_spectrum = ray.trace(self.world) + + # validating + dx = self.beam.integrator.step + rate = self.atomic_data.beam_cx_pec(deuterium, deuterium, 1, (3, 2))[0].value + ni = self.plasma.ion_density(0.5, 0, 0) # constant slab + nd_beam = 0 # beam density + for i in range(-int(0.5 / dx), int(0.5 / dx)): + x = dx * (i + 0.5) + nd_beam += self.beam.density(x, 0, 0) # in internal beam coordinates + radiance = 0.25 * rate * ni * nd_beam * dx / np.pi + + target_species = self.plasma.composition.get(line.element, line.charge + 1) + wavelength = self.atomic_data.wavelength(line.element, line.charge, line.transition) + zeeman_line = ZeemanTriplet(line, wavelength, target_species, self.plasma) + spectrum = Spectrum(ray.min_wavelength, ray.max_wavelength, ray.bins) + spectrum = zeeman_line.add_line(radiance, Point3D(0.5, 0, 0), direction, spectrum) + + for i in range(ray.bins): + self.assertAlmostEqual(cx_spectrum.samples[i], spectrum.samples[i], delta=1e-8, + msg='BeamCXLine model gives a wrong value at {} nm.'.format(spectrum.wavelengths[i])) + + +if __name__ == '__main__': + unittest.main() From e4305474e8310d199f5e41f9ac592d2a7a56fd1f Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 1 May 2023 16:41:38 +0300 Subject: [PATCH 64/81] The numerical constant in the bremsstrahlung model is expressed in terms of physical constants as suggested by @skuba31. --- cherab/core/model/plasma/bremsstrahlung.pyx | 35 ++++++++++++++------- cherab/core/utility/constants.pxd | 1 + cherab/core/utility/constants.pyx | 1 + 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index fa761eae..16b10aef 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -23,14 +23,17 @@ from raysect.optical cimport Spectrum, Point3D, Vector3D from cherab.core cimport Plasma, AtomicData from cherab.core.math.integrators cimport GaussianQuadrature from cherab.core.species cimport Species -from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, SPEED_OF_LIGHT, PLANCK_CONSTANT -from libc.math cimport sqrt, log, exp +from cherab.core.utility.constants cimport RECIP_4_PI, ELEMENTARY_CHARGE, SPEED_OF_LIGHT, PLANCK_CONSTANT, ELECTRON_REST_MASS, VACUUM_PERMITTIVITY +from libc.math cimport sqrt, log, exp, M_PI cimport cython -cdef double PH_TO_J_FACTOR = PLANCK_CONSTANT * SPEED_OF_LIGHT * 1e9 +cdef double EXP_FACTOR = PLANCK_CONSTANT * SPEED_OF_LIGHT * 1e9 / ELEMENTARY_CHARGE -cdef double EXP_FACTOR = PH_TO_J_FACTOR / ELEMENTARY_CHARGE +cdef double BREMS_CONST = (ELEMENTARY_CHARGE**2 * RECIP_4_PI / VACUUM_PERMITTIVITY)**3 +BREMS_CONST *= 32 * M_PI**2 / (3 * sqrt(3) * ELECTRON_REST_MASS**2 * SPEED_OF_LIGHT**3) +BREMS_CONST *= sqrt(2 * ELECTRON_REST_MASS / (M_PI * ELEMENTARY_CHARGE)) +BREMS_CONST *= SPEED_OF_LIGHT * 1e9 * RECIP_4_PI cdef class BremsFunction(Function1D): @@ -80,9 +83,9 @@ cdef class BremsFunction(Function1D): if ni > 0: ni_gff_z2 += ni * self.gaunt_factor.evaluate(z, self.te, wvl) * z * z - # bremsstrahlung equation W/m^3/str/nm - pre_factor = 0.95e-19 * RECIP_4_PI * ni_gff_z2 * self.ne / (sqrt(self.te) * wvl) - radiance = pre_factor * exp(- EXP_FACTOR / (self.te * wvl)) * PH_TO_J_FACTOR + # bremsstrahlung equation W/m^3/str + pre_factor = BREMS_CONST * ni_gff_z2 * self.ne / (sqrt(self.te) * wvl) + radiance = pre_factor * exp(- EXP_FACTOR / (self.te * wvl)) # convert to W/m^3/str/nm return radiance / wvl @@ -93,13 +96,21 @@ cdef class Bremsstrahlung(PlasmaModel): """ Emitter that calculates bremsstrahlung emission from a plasma object. - The bremmstrahlung formula implemented is equation 2 from M. Beurskens, - et. al., 'ITER LIDAR performance analysis', Rev. Sci. Instrum. 79, 10E727 (2008), + The bremmstrahlung formula implemented is equation 5.3.40 + from I. H. Hutchinson, 'Principles of Plasma Diagnostics', second edition, + Cambridge University Press, 2002, ISBN: 9780511613630, + https://doi.org/10.1017/CBO9780511613630 .. math:: - \\epsilon (\\lambda) = \\frac{0.95 \\times 10^{-19}}{\\lambda 4 \\pi} \\sum_{i} \\left(g_{ff}(Z_i, T_e, \\lambda) n_i Z_i^2\\right) n_e T_e^{-1/2} \\times \\exp{\\frac{-hc}{\\lambda T_e}}, - - where the emission :math:`\\epsilon (\\lambda)` is in units of radiance (ph/s/sr/m^3/nm). + \\epsilon_{\\mathrm{ff}}(\\lambda) = \\left( \\frac{e^2}{4 \\pi \\varepsilon_0} \\right)^3 + \\frac{32 \\pi^2}{3 \\sqrt{3} m_\\mathrm{e}^2 c^3} + \\sqrt{\\frac{2 m_\\mathrm{e}^3}{\\pi e T_\\mathrm{e}}} + \\frac{10^{9} c}{4 \\pi \\lambda^2} + n_\\mathrm{e} \\sum_i \\left( n_\\mathrm{i} g_\\mathrm{ff} (Z_\\mathrm{i}, T_\\mathrm{e}, \\lambda) Z_\\mathrm{i}^2 \\right) + \\mathrm{e}^{-\\frac{10^9 hc}{e T_\\mathrm{e}}}\\,, + + where the emission :math:`\\epsilon_{\\mathrm{ff}}(\\lambda)` is in units of radiance (W/sr/m^3/nm), + :math:`T_\\mathrm{e}` is in eV and :math:`\\lambda` is in nm. :ivar Plasma plasma: The plasma to which this emission model is attached. Default is None. :ivar AtomicData atomic_data: The atomic data provider for this model. Default is None. diff --git a/cherab/core/utility/constants.pxd b/cherab/core/utility/constants.pxd index 9cce304d..4c59b4a8 100644 --- a/cherab/core/utility/constants.pxd +++ b/cherab/core/utility/constants.pxd @@ -30,3 +30,4 @@ cdef: double ELECTRON_CLASSICAL_RADIUS double ELECTRON_REST_MASS double RYDBERG_CONSTANT_EV + double VACUUM_PERMITTIVITY diff --git a/cherab/core/utility/constants.pyx b/cherab/core/utility/constants.pyx index 03e70617..d36b99f9 100644 --- a/cherab/core/utility/constants.pyx +++ b/cherab/core/utility/constants.pyx @@ -32,3 +32,4 @@ cdef: double ELECTRON_CLASSICAL_RADIUS = 2.8179403262e-15 double ELECTRON_REST_MASS = 9.1093837015e-31 double RYDBERG_CONSTANT_EV = 13.605693122994 + double VACUUM_PERMITTIVITY = 8.8541878128e-12 From 5f61aaec157a5f88b4b41c78636e7242527b45dc Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 1 May 2023 18:49:20 +0300 Subject: [PATCH 65/81] Updated bremsstrahlung model docstring. --- cherab/core/model/plasma/bremsstrahlung.pyx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index 16b10aef..cb8a88a6 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -112,6 +112,8 @@ cdef class Bremsstrahlung(PlasmaModel): where the emission :math:`\\epsilon_{\\mathrm{ff}}(\\lambda)` is in units of radiance (W/sr/m^3/nm), :math:`T_\\mathrm{e}` is in eV and :math:`\\lambda` is in nm. + :math:`g_\\mathrm{ff} (Z_\\mathrm{i}, T_\\mathrm{e}, \\lambda)` is the free-free Gaunt factor. + :ivar Plasma plasma: The plasma to which this emission model is attached. Default is None. :ivar AtomicData atomic_data: The atomic data provider for this model. Default is None. :ivar FreeFreeGauntFactor gaunt_factor: Free-free Gaunt factor as a function of Z, Te and From 807fc555f00520257c8dfa58f200169390fe01c0 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Mon, 1 May 2023 18:56:30 +0300 Subject: [PATCH 66/81] Removed unused imports in test_beamcxline.py --- cherab/core/tests/test_beamcxline.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cherab/core/tests/test_beamcxline.py b/cherab/core/tests/test_beamcxline.py index d3aa2976..6de8ad58 100644 --- a/cherab/core/tests/test_beamcxline.py +++ b/cherab/core/tests/test_beamcxline.py @@ -19,15 +19,13 @@ import unittest import numpy as np -from scipy.special import erf from raysect.core import Point3D, Vector3D, translate from raysect.optical import World, Spectrum, Ray from cherab.core import Beam from cherab.core.atomic import Line, AtomicData, BeamCXPEC, BeamStoppingRate -from cherab.core.math.integrators import GaussianQuadrature -from cherab.core.atomic import deuterium, nitrogen +from cherab.core.atomic import deuterium from cherab.tools.plasmas.slab import build_constant_slab_plasma from cherab.core.model import SingleRayAttenuator, BeamCXLine, GaussianLine, ZeemanTriplet From 00c70f30303eff0a3d42f05dcd6a36b3d45c4509 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Tue, 2 May 2023 01:52:47 +0300 Subject: [PATCH 67/81] Added a test for Bremsstrahlung model. --- cherab/core/tests/test_bremsstrahlung.py | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 cherab/core/tests/test_bremsstrahlung.py diff --git a/cherab/core/tests/test_bremsstrahlung.py b/cherab/core/tests/test_bremsstrahlung.py new file mode 100644 index 00000000..5373776b --- /dev/null +++ b/cherab/core/tests/test_bremsstrahlung.py @@ -0,0 +1,94 @@ +# Copyright 2016-2023 Euratom +# Copyright 2016-2023 United Kingdom Atomic Energy Authority +# Copyright 2016-2023 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"); +# You may not use this work except in compliance with the Licence. +# You may obtain a copy of the Licence at: +# +# https://joinup.ec.europa.eu/software/page/eupl5 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. +# +# See the Licence for the specific language governing permissions and limitations +# under the Licence. + +import unittest + +import numpy as np + +from raysect.core import Point3D, Vector3D +from raysect.optical import World, Ray + +from cherab.core.atomic import AtomicData, MaxwellianFreeFreeGauntFactor +from cherab.core.math.integrators import GaussianQuadrature +from cherab.core.atomic import deuterium, nitrogen +from cherab.tools.plasmas.slab import build_constant_slab_plasma +from cherab.core.model import Bremsstrahlung + +import scipy.constants as const + + +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 test_bremsstrahlung_model(self): + # setting up the model + gaunt_factor = MaxwellianFreeFreeGauntFactor() + bremsstrahlung = Bremsstrahlung(gaunt_factor=gaunt_factor) + self.plasma.models = [bremsstrahlung] + + # observing + origin = Point3D(1.5, 0, 0) + direction = Vector3D(-1, 0, 0) + ray = Ray(origin=origin, direction=direction, + min_wavelength=400., max_wavelength=800., bins=128) + brems_spectrum = ray.trace(self.world) + + # validating + brems_const = (const.e**2 * 0.25 / np.pi / const.epsilon_0)**3 + brems_const *= 32 * np.pi**2 / (3 * np.sqrt(3) * const.m_e**2 * const.c**3) + brems_const *= np.sqrt(2 * const.m_e / (np.pi * const.e)) + brems_const *= const.c * 1e9 * 0.25 / np.pi + exp_factor = const.h * const.c * 1.e9 / const. e + + ne = self.plasma.electron_distribution.density(0.5, 0, 0) + te = self.plasma.electron_distribution.effective_temperature(0.5, 0, 0) + + def brems_func(wvl): + ni_gff_z2 = 0 + for species in self.plasma.composition: + z = species.charge + ni = self.plasma.composition[(species.element, species.charge)].distribution.density(0.5, 0, 0) + ni_gff_z2 += ni * gaunt_factor(z, te, wvl) * z * z + + return brems_const * ni_gff_z2 * ne / (np.sqrt(te) * wvl * wvl) * np.exp(- exp_factor / (te * wvl)) + + integrator = GaussianQuadrature(brems_func) + + test_samples = np.zeros(brems_spectrum.bins) + delta_wavelength = (brems_spectrum.max_wavelength - brems_spectrum.min_wavelength) / brems_spectrum.bins + lower_wavelength = brems_spectrum.min_wavelength + for i in range(brems_spectrum.bins): + upper_wavelength = brems_spectrum.min_wavelength + delta_wavelength * (i + 1) + bin_integral = integrator(lower_wavelength, upper_wavelength) + test_samples[i] = bin_integral / delta_wavelength + lower_wavelength = upper_wavelength + + for i in range(brems_spectrum.bins): + self.assertAlmostEqual(brems_spectrum.samples[i], test_samples[i], delta=1e-10, + msg='BeamCXLine model gives a wrong value at {} nm.'.format(brems_spectrum.wavelengths[i])) + + +if __name__ == '__main__': + unittest.main() From d748239380890a6bbad28093512cdd3740c0ba0b Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 3 May 2023 00:57:36 +0300 Subject: [PATCH 68/81] Added 'units' attribute to RayTransferPipelineXD. Added tests for RayTransferPipelineXD. --- CHANGELOG.md | 3 + cherab/tools/raytransfer/pipelines.py | 149 ++++++++++++----- cherab/tools/tests/test_raytransfer.py | 158 +++++++++++++++++- .../geometry_matrix_with_raytransfer.py | 2 +- demos/ray_transfer/1_ray_transfer_box.py | 7 +- 5 files changed, 274 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9856d282..7f334f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ Project Changelog Release 1.5.0 (TBD) ------------------- +Bug fixes: +* Fix improper multiplication by sensitivity factor in RayTransferPixelProcessor resulting in wrong units (m^3 sr instead of m) of ray transfer matrices. (#412) + New: * Support Raysect 0.8 * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) diff --git a/cherab/tools/raytransfer/pipelines.py b/cherab/tools/raytransfer/pipelines.py index b94223ea..1ac1366f 100644 --- a/cherab/tools/raytransfer/pipelines.py +++ b/cherab/tools/raytransfer/pipelines.py @@ -34,24 +34,63 @@ from raysect.optical.observer.base import Pipeline0D, Pipeline1D, Pipeline2D, PixelProcessor -class RayTransferPipeline0D(Pipeline0D): +class RayTransferPipelineBase(): + + def __init__(self, name=None, units='power'): + + self.name = name + self._matrix = None + self._samples = 0 + self._bins = 0 + self.units = units + + @property + def units(self): + """ + The units in which the matrix is calculated. Can be 'power' or 'radiance'. + The 'power' stands for [m^3 sr] and the 'radiance' stands for [m]. + """ + return self._units + + @units.setter + def units(self, value): + _units = value.lower() + if _units in ('power', 'radiance'): + self._units = _units + else: + raise ValueError("The units property must be 'power' or 'radiance'.") + + @property + def matrix(self): + return self._matrix + + +class RayTransferPipeline0D(Pipeline0D, RayTransferPipelineBase): """ Simple 0D pipeline for ray transfer matrix (geometry matrix) calculation. + :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. + :param str units: The units in which the matrix is calculated. Can + be 'power' (default) or 'radiance'. + The 'power' stands for [m^3 sr] and when the matrix is collapsed with + the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. + The 'radiance' stands for [m] and when the matrix is collapsed with + the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. + If the 'power' is selected, the matrix is multiplied by the detector sensitivity. + Note that if the detector sensitivity is 1, the 'power' and 'radiance' + give the same results. + :ivar np.ndarray matrix: Ray transfer matrix, a 1D array of size :math:`N_{bin}`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline0D - >>> pipeline = RayTransferPipeline0D() + >>> pipeline = RayTransferPipeline0D(units='radiance') """ - def __init__(self, name=None): + def __init__(self, name='RayTransferPipeline0D', units='power'): - self.name = name or 'RayTransferPipeline0D' - self._matrix = None - self._samples = 0 - self._bins = 0 + RayTransferPipelineBase.__init__(self, name, units) def initialise(self, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): self._samples = 0 @@ -59,7 +98,10 @@ def initialise(self, min_wavelength, max_wavelength, spectral_bins, spectral_sli self._matrix = np.zeros(spectral_bins) def pixel_processor(self, slice_id): - return RayTransferPixelProcessor(self._bins) + if self._units == 'power': + return PowerRayTransferPixelProcessor(self._bins) + else: + return RadianceRayTransferPixelProcessor(self._bins) def update(self, slice_id, packed_result, pixel_samples): self._samples += pixel_samples @@ -68,30 +110,34 @@ def update(self, slice_id, packed_result, pixel_samples): def finalise(self): self._matrix /= self._samples - @property - def matrix(self): - return self._matrix - -class RayTransferPipeline1D(Pipeline1D): +class RayTransferPipeline1D(Pipeline1D, RayTransferPipelineBase): """ Simple 1D pipeline for ray transfer matrix (geometry matrix) calculation. + :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. + :param str units: The units in which the matrix is calculated. Can + be 'power' (default) or 'radiance'. + The 'power' stands for [m^3 sr] and when the matrix is collapsed with + the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. + The 'radiance' stands for [m] and when the matrix is collapsed with + the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. + If the 'power' is selected, the matrix is multiplied by the detector sensitivity. + Note that if the detector sensitivity is 1, the 'power' and 'radiance' + give the same results. + :ivar np.ndarray matrix: Ray transfer matrix, a 2D array of shape :math:`(N_{pixel}, N_{bin})`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline1D - >>> pipeline = RayTransferPipeline1D() + >>> pipeline = RayTransferPipeline1D(units='radiance') """ - def __init__(self, name=None): + def __init__(self, name='RayTransferPipeline1D', units='power'): - self.name = name or 'RayTransferPipeline1D' - self._matrix = None + RayTransferPipelineBase.__init__(self, name, units) self._pixels = None - self._samples = 0 - self._bins = 0 def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): self._pixels = pixels @@ -100,7 +146,10 @@ def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spec self._matrix = np.zeros((pixels, spectral_bins)) def pixel_processor(self, pixel, slice_id): - return RayTransferPixelProcessor(self._bins) + if self._units == 'power': + return PowerRayTransferPixelProcessor(self._bins) + else: + return RadianceRayTransferPixelProcessor(self._bins) def update(self, pixel, slice_id, packed_result): self._matrix[pixel] = packed_result[0] / self._samples @@ -108,30 +157,34 @@ def update(self, pixel, slice_id, packed_result): def finalise(self): pass - @property - def matrix(self): - return self._matrix - -class RayTransferPipeline2D(Pipeline2D): +class RayTransferPipeline2D(Pipeline2D, RayTransferPipelineBase): """ Simple 2D pipeline for ray transfer matrix (geometry matrix) calculation. + :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. + :param str units: The units in which the matrix is calculated. Can + be 'power' (default) or 'radiance'. + The 'power' stands for [m^3 sr] and when the matrix is collapsed with + the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. + The 'radiance' stands for [m] and when the matrix is collapsed with + the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. + If the 'power' is selected, the matrix is multiplied by the detector sensitivity. + Note that if the detector sensitivity is 1, the 'power' and 'radiance' + give the same results. + :ivar np.ndarray matrix: Ray transfer matrix, a 3D array of shape :math:`(N_x, N_y, N_{bin})`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline2D - >>> pipeline = RayTransferPipeline2D() + >>> pipeline = RayTransferPipeline2D(units='radiance') """ - def __init__(self, name=None): + def __init__(self, name='RayTransferPipeline2D', units='power'): - self.name = name or 'RayTransferPipeline2D' - self._matrix = None + RayTransferPipelineBase.__init__(self, name, units) self._pixels = None - self._samples = 0 - self._bins = 0 def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): self._pixels = pixels @@ -140,7 +193,10 @@ def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spec self._matrix = np.zeros((pixels[0], pixels[1], spectral_bins)) def pixel_processor(self, x, y, slice_id): - return RayTransferPixelProcessor(self._bins) + if self._units == 'power': + return PowerRayTransferPixelProcessor(self._bins) + else: + return RadianceRayTransferPixelProcessor(self._bins) def update(self, x, y, slice_id, packed_result): self._matrix[x, y] = packed_result[0] / self._samples @@ -148,21 +204,32 @@ def update(self, x, y, slice_id, packed_result): def finalise(self): pass - @property - def matrix(self): - return self._matrix - -class RayTransferPixelProcessor(PixelProcessor): +class RayTransferPixelProcessorBase(PixelProcessor): """ - PixelProcessor that stores ray transfer matrix for each pixel. + Base class for PixelProcessor that stores ray transfer matrix for each pixel. """ def __init__(self, bins): self._matrix = np.zeros(bins) - def add_sample(self, spectrum, sensitivity): - self._matrix += spectrum.samples * sensitivity - def pack_results(self): return (self._matrix, 0) + + +class RadianceRayTransferPixelProcessor(RayTransferPixelProcessorBase): + """ + PixelProcessor that stores ray transfer matrix in the units of [m] for each pixel. + """ + + def add_sample(self, spectrum, sensitivity): + self._matrix += spectrum.samples + + +class PowerRayTransferPixelProcessor(RayTransferPixelProcessorBase): + """ + PixelProcessor that stores ray transfer matrix in the units of [m^3 sr] for each pixel. + """ + + def add_sample(self, spectrum, sensitivity): + self._matrix += spectrum.samples * sensitivity diff --git a/cherab/tools/tests/test_raytransfer.py b/cherab/tools/tests/test_raytransfer.py index 38a5cdcf..29737419 100644 --- a/cherab/tools/tests/test_raytransfer.py +++ b/cherab/tools/tests/test_raytransfer.py @@ -18,9 +18,10 @@ import unittest import numpy as np -from raysect.optical import World, Ray, Point3D, Point2D, Vector3D, NumericalIntegrator +from raysect.optical import World, Ray, Point3D, Point2D, Vector3D, NumericalIntegrator, Spectrum from raysect.primitive import Box, Cylinder, Subtract from cherab.tools.raytransfer import RayTransferBox, RayTransferCylinder, CartesianRayTransferEmitter, CylindricalRayTransferEmitter +from cherab.tools.raytransfer import RayTransferPipeline0D, RayTransferPipeline1D, RayTransferPipeline2D from cherab.tools.inversions import ToroidalVoxelGrid @@ -239,3 +240,158 @@ def test_evaluate_function_3d(self): spectrum_test = np.zeros(12) spectrum_test[2] = spectrum_test[9] = np.sqrt(2.) self.assertTrue(np.allclose(spectrum_test, spectrum.samples, atol=0.001)) + + +class TestRayTransferPipeline0D(unittest.TestCase): + """ + Test cases for RayTransferPipeline0D class. + """ + + def test_initialise(self): + """ + Test initialise method. + """ + nbins = 10 + pipeline = RayTransferPipeline0D('test_pipeline_0D', units='power') + pipeline.initialise(0, 0, nbins, 0, 0) + + self.assertTrue(pipeline.matrix.shape == (nbins,)) + self.assertTrue(pipeline.name == 'test_pipeline_0D') + self.assertTrue(pipeline.units == 'power') + + self.assertRaises(ValueError, RayTransferPipeline0D, 'test_pipeline_0D', 'blah') + + def test_units(self): + """ + Test if the 'units' attribute works properly. + """ + nbins = 10 + sensitivity = 2. + spectral_value = 1. + spectrum = Spectrum(1., 2., nbins) + spectrum.samples[:] = spectral_value + + pipeline = RayTransferPipeline0D('test_pipeline_0D', units='power') + pipeline.initialise(0, 0, nbins, 0, 0) + + pixel_processor = pipeline.pixel_processor(0) + + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity + self.assertTrue(np.all(matrix == sensitivity * spectral_value)) + + pipeline.units = 'radiance' + pixel_processor = pipeline.pixel_processor(0) + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # not multiplied by sensitivity + self.assertTrue(np.all(matrix == spectral_value)) + + +class TestRayTransferPipeline1D(unittest.TestCase): + """ + Test cases for RayTransferPipeline1D class. + """ + + def test_initialise(self): + """ + Test initialise method. + """ + nbins = 10 + pixels = 20 + samples = 1 + pipeline = RayTransferPipeline1D('test_pipeline_1D', units='radiance') + pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) + + self.assertTrue(pipeline.matrix.shape == (pixels, nbins)) + self.assertTrue(pipeline.name == 'test_pipeline_1D') + self.assertTrue(pipeline.units == 'radiance') + self.assertTrue(pipeline._samples == samples) + + self.assertRaises(ValueError, RayTransferPipeline1D, 'test_pipeline_1D', 'blah') + + def test_units(self): + """ + Test if the 'units' attribute works properly. + """ + nbins = 10 + pixels = 20 + samples = 1 + sensitivity = 2. + spectral_value = 1. + spectrum = Spectrum(1., 2., nbins) + spectrum.samples[:] = spectral_value + + pipeline = RayTransferPipeline1D('test_pipeline_1D', units='power') + pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) + + pixel_processor = pipeline.pixel_processor(0, 0) + + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity + self.assertTrue(np.all(matrix == sensitivity * spectral_value)) + + pipeline.units = 'radiance' + pixel_processor = pipeline.pixel_processor(0, 0) + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # not multiplied by sensitivity + self.assertTrue(np.all(matrix == spectral_value)) + + +class TestRayTransferPipeline2D(unittest.TestCase): + """ + Test cases for RayTransferPipeline2D class. + """ + + def test_initialise(self): + """ + Test initialise method. + """ + nbins = 10 + pixels = (20, 5) + samples = 1 + pipeline = RayTransferPipeline2D('test_pipeline_2D', units='radiance') + pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) + + self.assertTrue(pipeline.matrix.shape == (pixels[0], pixels[1], nbins)) + self.assertTrue(pipeline.name == 'test_pipeline_2D') + self.assertTrue(pipeline.units == 'radiance') + self.assertTrue(pipeline._samples == samples) + + self.assertRaises(ValueError, RayTransferPipeline2D, 'test_pipeline_2D', 'blah') + + def test_units(self): + """ + Test if the 'units' attribute works properly. + """ + nbins = 10 + pixels = (20, 5) + samples = 1 + sensitivity = 2. + spectral_value = 1. + spectrum = Spectrum(1., 2., nbins) + spectrum.samples[:] = spectral_value + + pipeline = RayTransferPipeline2D('test_pipeline_2D', units='power') + pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) + + pixel_processor = pipeline.pixel_processor(0, 0, 0) + + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity + self.assertTrue(np.all(matrix == sensitivity * spectral_value)) + + pipeline.units = 'radiance' + pixel_processor = pipeline.pixel_processor(0, 0, 0) + pixel_processor.add_sample(spectrum, sensitivity) + + matrix, _ = pixel_processor.pack_results() # not multiplied by sensitivity + self.assertTrue(np.all(matrix == spectral_value)) + + +if __name__ == '__main__': + unittest.main() diff --git a/demos/observers/bolometry/geometry_matrix_with_raytransfer.py b/demos/observers/bolometry/geometry_matrix_with_raytransfer.py index a9300636..a6bee82d 100644 --- a/demos/observers/bolometry/geometry_matrix_with_raytransfer.py +++ b/demos/observers/bolometry/geometry_matrix_with_raytransfer.py @@ -240,7 +240,7 @@ def _point3d_to_rz(point): for camera in cameras: for foil in camera: print("Calculating sensitivity for {}...".format(foil.name)) - foil.pipelines = [RayTransferPipeline0D()] + foil.pipelines = [RayTransferPipeline0D(units=foil.units)] # All objects in world have wavelength-independent material properties, # so it doesn't matter which wavelength range we use (as long as # max_wavelength - min_wavelength = 1) diff --git a/demos/ray_transfer/1_ray_transfer_box.py b/demos/ray_transfer/1_ray_transfer_box.py index e4d5e8bb..a4029431 100644 --- a/demos/ray_transfer/1_ray_transfer_box.py +++ b/demos/ray_transfer/1_ray_transfer_box.py @@ -36,8 +36,8 @@ from raysect.optical.observer import PinholeCamera, FullFrameSampler2D # RayTransferPipeline2D is optimised for calculation of ray transfer matrices. -# It's also possible to use SpectralRadiancePipeline2D but for the matrices with >1000 elements -# the performance will be lower. +# It's also possible to use SpectralRadiancePipeline2D or SpectralPowerPipeline2D but +# for the matrices with >1000 elements the performance will be lower. from cherab.tools.raytransfer import RayTransferPipeline2D, RayTransferBox # Here we use special materials optimised for calculation of ray transfer matrices. @@ -66,6 +66,9 @@ rtb.step = 0.2 # creating ray transfer pipeline +# Be careful when choosing pipeline units ('power' or 'radiance'). +# In case of 'power', the matrix [m] is multiplied by the detector's sensitivity [m^2 sr]. +# For the PinholeCamera this does not matter, because its pixel sensitivity is 1. pipeline = RayTransferPipeline2D() # setting up the camera From df3c33e6a9f2cd3ae4c4c8700dc2f98d5c5ad4da Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 3 May 2023 09:10:59 +0300 Subject: [PATCH 69/81] Fix incorrect description of the new feature in CHANGELOG.md --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f334f8d..cab23889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,11 @@ Project Changelog Release 1.5.0 (TBD) ------------------- -Bug fixes: -* Fix improper multiplication by sensitivity factor in RayTransferPixelProcessor resulting in wrong units (m^3 sr instead of m) of ray transfer matrices. (#412) - New: * Support Raysect 0.8 * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) +* Add the units attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity or not. (#412) Release 1.4.0 (3 Feb 2023) From 8e719ba31aed225e19b963b191a722d56452391a Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 3 May 2023 13:28:36 +0300 Subject: [PATCH 70/81] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f982618..19f1ae56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ New: * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) * Add numerical integration of Bremsstrahlung spectrum over a spectral bin. (#395) +* Replace the coarse numerical constant in the Bremsstrahlung model with an exact expression. (#409) Release 1.4.0 (3 Feb 2023) From b3b0d5713a73eaa8e53a6be4d0a6fb605f135d2e Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 3 May 2023 23:51:47 +0300 Subject: [PATCH 71/81] Made expression for bremsstrahlung look clearer and updated docstring in response to @skuba31 comments. --- cherab/core/model/plasma/bremsstrahlung.pyx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cherab/core/model/plasma/bremsstrahlung.pyx b/cherab/core/model/plasma/bremsstrahlung.pyx index cb8a88a6..404750a2 100644 --- a/cherab/core/model/plasma/bremsstrahlung.pyx +++ b/cherab/core/model/plasma/bremsstrahlung.pyx @@ -83,12 +83,11 @@ cdef class BremsFunction(Function1D): if ni > 0: ni_gff_z2 += ni * self.gaunt_factor.evaluate(z, self.te, wvl) * z * z - # bremsstrahlung equation W/m^3/str - pre_factor = BREMS_CONST * ni_gff_z2 * self.ne / (sqrt(self.te) * wvl) + # bremsstrahlung equation W/m^3/str/nm + pre_factor = BREMS_CONST / (sqrt(self.te) * wvl * wvl) * self.ne * ni_gff_z2 radiance = pre_factor * exp(- EXP_FACTOR / (self.te * wvl)) - # convert to W/m^3/str/nm - return radiance / wvl + return radiance # todo: doppler shift? @@ -101,16 +100,20 @@ cdef class Bremsstrahlung(PlasmaModel): Cambridge University Press, 2002, ISBN: 9780511613630, https://doi.org/10.1017/CBO9780511613630 + Note that in eq. 5.3.40, the emissivity :math:`j(\\nu)` is given in (W/m^3/sr/Hz) with respect + to frequency, :math:`\\nu`. Here, the emissivity :math:`\\epsilon_{\\mathrm{ff}}(\\lambda)` + is given in (W/m^3/nm/sr) with respect to wavelength, :math:`\\lambda = \\frac{10^{9} c}{\\nu}`, + and taking into account that :math:`d\\nu=-\\frac{10^{9} c}{\\lambda^2}d\\lambda`. + .. math:: \\epsilon_{\\mathrm{ff}}(\\lambda) = \\left( \\frac{e^2}{4 \\pi \\varepsilon_0} \\right)^3 \\frac{32 \\pi^2}{3 \\sqrt{3} m_\\mathrm{e}^2 c^3} \\sqrt{\\frac{2 m_\\mathrm{e}^3}{\\pi e T_\\mathrm{e}}} \\frac{10^{9} c}{4 \\pi \\lambda^2} n_\\mathrm{e} \\sum_i \\left( n_\\mathrm{i} g_\\mathrm{ff} (Z_\\mathrm{i}, T_\\mathrm{e}, \\lambda) Z_\\mathrm{i}^2 \\right) - \\mathrm{e}^{-\\frac{10^9 hc}{e T_\\mathrm{e}}}\\,, + \\mathrm{e}^{-\\frac{10^9 hc}{e T_\\mathrm{e} \\lambda}}\\,, - where the emission :math:`\\epsilon_{\\mathrm{ff}}(\\lambda)` is in units of radiance (W/sr/m^3/nm), - :math:`T_\\mathrm{e}` is in eV and :math:`\\lambda` is in nm. + where :math:`T_\\mathrm{e}` is in eV and :math:`\\lambda` is in nm. :math:`g_\\mathrm{ff} (Z_\\mathrm{i}, T_\\mathrm{e}, \\lambda)` is the free-free Gaunt factor. From fb924d420f3dbe8c9c15d1641f40138f3744b9e7 Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 10 May 2023 16:21:27 +0300 Subject: [PATCH 72/81] Renamed 'units' attribute of the RayTransferPipelineBase as 'kind' and updated the docs. --- CHANGELOG.md | 2 +- cherab/tools/raytransfer/pipelines.py | 107 +++++++++--------- cherab/tools/tests/test_raytransfer.py | 34 +++--- .../geometry_matrix_with_raytransfer.py | 2 +- demos/ray_transfer/1_ray_transfer_box.py | 4 +- 5 files changed, 77 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cab23889..357f8fa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ New: * Support Raysect 0.8 * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) -* Add the units attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity or not. (#412) +* Add the kind attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity ('power') or not ('radiance'). (#412) Release 1.4.0 (3 Feb 2023) diff --git a/cherab/tools/raytransfer/pipelines.py b/cherab/tools/raytransfer/pipelines.py index 1ac1366f..2339915a 100644 --- a/cherab/tools/raytransfer/pipelines.py +++ b/cherab/tools/raytransfer/pipelines.py @@ -36,29 +36,34 @@ class RayTransferPipelineBase(): - def __init__(self, name=None, units='power'): + def __init__(self, name=None, kind='power'): self.name = name self._matrix = None self._samples = 0 self._bins = 0 - self.units = units + self.kind = kind @property - def units(self): + def kind(self): """ - The units in which the matrix is calculated. Can be 'power' or 'radiance'. - The 'power' stands for [m^3 sr] and the 'radiance' stands for [m]. + The kind of the pipeline. Can be 'power' or 'radiance'. + In the case of 'power', the resulting matrix is multiplied by the sensitivity + of the detector, and the units of the matrix are [m^3 sr], which gives the units + of power [W] for the product of the ray transfer matrix and the emission profile. + In case of 'radiance', the sensitivity is not taken into account and + the matrix is calculated in [m], which gives the units of radiance [W m^-2 sr^-1] + for the product of the ray transfer matrix and the emission profile. """ - return self._units + return self._kind - @units.setter - def units(self, value): - _units = value.lower() - if _units in ('power', 'radiance'): - self._units = _units + @kind.setter + def kind(self, value): + _kind = value.lower() + if _kind in ('power', 'radiance'): + self._kind = _kind else: - raise ValueError("The units property must be 'power' or 'radiance'.") + raise ValueError("The kind property must be 'power' or 'radiance'.") @property def matrix(self): @@ -70,27 +75,27 @@ class RayTransferPipeline0D(Pipeline0D, RayTransferPipelineBase): Simple 0D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str units: The units in which the matrix is calculated. Can - be 'power' (default) or 'radiance'. - The 'power' stands for [m^3 sr] and when the matrix is collapsed with - the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. - The 'radiance' stands for [m] and when the matrix is collapsed with - the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. - If the 'power' is selected, the matrix is multiplied by the detector sensitivity. - Note that if the detector sensitivity is 1, the 'power' and 'radiance' - give the same results. + :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + In the case of 'power', the resulting matrix is multiplied by the sensitivity + of the detector, and the units of the matrix are [m^3 sr], which gives the units + of power [W] for the product of the ray transfer matrix and the emission profile. + In case of 'radiance', the sensitivity is not taken into account and + the matrix is calculated in [m], which gives the units of radiance [W m^-2 sr^-1] + for the product of the ray transfer matrix and the emission profile. + Note that if the sensitivity of the detector is 1 (e.g. `PinholeCamera`, `VectorCamera`), + the 'power' and 'radiance' give the same results. :ivar np.ndarray matrix: Ray transfer matrix, a 1D array of size :math:`N_{bin}`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline0D - >>> pipeline = RayTransferPipeline0D(units='radiance') + >>> pipeline = RayTransferPipeline0D(kind='radiance') """ - def __init__(self, name='RayTransferPipeline0D', units='power'): + def __init__(self, name='RayTransferPipeline0D', kind='power'): - RayTransferPipelineBase.__init__(self, name, units) + RayTransferPipelineBase.__init__(self, name, kind) def initialise(self, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): self._samples = 0 @@ -98,7 +103,7 @@ def initialise(self, min_wavelength, max_wavelength, spectral_bins, spectral_sli self._matrix = np.zeros(spectral_bins) def pixel_processor(self, slice_id): - if self._units == 'power': + if self._kind == 'power': return PowerRayTransferPixelProcessor(self._bins) else: return RadianceRayTransferPixelProcessor(self._bins) @@ -116,27 +121,27 @@ class RayTransferPipeline1D(Pipeline1D, RayTransferPipelineBase): Simple 1D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str units: The units in which the matrix is calculated. Can - be 'power' (default) or 'radiance'. - The 'power' stands for [m^3 sr] and when the matrix is collapsed with - the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. - The 'radiance' stands for [m] and when the matrix is collapsed with - the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. - If the 'power' is selected, the matrix is multiplied by the detector sensitivity. - Note that if the detector sensitivity is 1, the 'power' and 'radiance' - give the same results. + :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + In the case of 'power', the resulting matrix is multiplied by the sensitivity + of the detector, and the units of the matrix are [m^3 sr], which gives the units + of power [W] for the product of the ray transfer matrix and the emission profile. + In case of 'radiance', the sensitivity is not taken into account and + the matrix is calculated in [m], which gives the units of radiance [W m^-2 sr^-1] + for the product of the ray transfer matrix and the emission profile. + Note that if the sensitivity of the detector is 1 (e.g. `PinholeCamera`, `VectorCamera`), + the 'power' and 'radiance' give the same results. :ivar np.ndarray matrix: Ray transfer matrix, a 2D array of shape :math:`(N_{pixel}, N_{bin})`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline1D - >>> pipeline = RayTransferPipeline1D(units='radiance') + >>> pipeline = RayTransferPipeline1D(kind='radiance') """ - def __init__(self, name='RayTransferPipeline1D', units='power'): + def __init__(self, name='RayTransferPipeline1D', kind='power'): - RayTransferPipelineBase.__init__(self, name, units) + RayTransferPipelineBase.__init__(self, name, kind) self._pixels = None def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): @@ -146,7 +151,7 @@ def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spec self._matrix = np.zeros((pixels, spectral_bins)) def pixel_processor(self, pixel, slice_id): - if self._units == 'power': + if self._kind == 'power': return PowerRayTransferPixelProcessor(self._bins) else: return RadianceRayTransferPixelProcessor(self._bins) @@ -163,27 +168,27 @@ class RayTransferPipeline2D(Pipeline2D, RayTransferPipelineBase): Simple 2D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str units: The units in which the matrix is calculated. Can - be 'power' (default) or 'radiance'. - The 'power' stands for [m^3 sr] and when the matrix is collapsed with - the emission profile [W m^-3 sr-1 nm-1] it gives the power [W nm-1]. - The 'radiance' stands for [m] and when the matrix is collapsed with - the emission profile it gives the radiance [W m^-2 sr-1 nm-1]. - If the 'power' is selected, the matrix is multiplied by the detector sensitivity. - Note that if the detector sensitivity is 1, the 'power' and 'radiance' - give the same results. + :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + In the case of 'power', the resulting matrix is multiplied by the sensitivity + of the detector, and the units of the matrix are [m^3 sr], which gives the units + of power [W] for the product of the ray transfer matrix and the emission profile. + In case of 'radiance', the sensitivity is not taken into account and + the matrix is calculated in [m], which gives the units of radiance [W m^-2 sr^-1] + for the product of the ray transfer matrix and the emission profile. + Note that if the sensitivity of the detector is 1 (e.g. `PinholeCamera`, `VectorCamera`), + the 'power' and 'radiance' give the same results. :ivar np.ndarray matrix: Ray transfer matrix, a 3D array of shape :math:`(N_x, N_y, N_{bin})`. .. code-block:: pycon >>> from cherab.tools.raytransfer import RayTransferPipeline2D - >>> pipeline = RayTransferPipeline2D(units='radiance') + >>> pipeline = RayTransferPipeline2D(kind='radiance') """ - def __init__(self, name='RayTransferPipeline2D', units='power'): + def __init__(self, name='RayTransferPipeline2D', kind='power'): - RayTransferPipelineBase.__init__(self, name, units) + RayTransferPipelineBase.__init__(self, name, kind) self._pixels = None def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spectral_bins, spectral_slices, quiet): @@ -193,7 +198,7 @@ def initialise(self, pixels, pixel_samples, min_wavelength, max_wavelength, spec self._matrix = np.zeros((pixels[0], pixels[1], spectral_bins)) def pixel_processor(self, x, y, slice_id): - if self._units == 'power': + if self._kind == 'power': return PowerRayTransferPixelProcessor(self._bins) else: return RadianceRayTransferPixelProcessor(self._bins) diff --git a/cherab/tools/tests/test_raytransfer.py b/cherab/tools/tests/test_raytransfer.py index 29737419..76ecd4d4 100644 --- a/cherab/tools/tests/test_raytransfer.py +++ b/cherab/tools/tests/test_raytransfer.py @@ -252,18 +252,18 @@ def test_initialise(self): Test initialise method. """ nbins = 10 - pipeline = RayTransferPipeline0D('test_pipeline_0D', units='power') + pipeline = RayTransferPipeline0D('test_pipeline_0D', kind='power') pipeline.initialise(0, 0, nbins, 0, 0) self.assertTrue(pipeline.matrix.shape == (nbins,)) self.assertTrue(pipeline.name == 'test_pipeline_0D') - self.assertTrue(pipeline.units == 'power') + self.assertTrue(pipeline.kind == 'power') self.assertRaises(ValueError, RayTransferPipeline0D, 'test_pipeline_0D', 'blah') - def test_units(self): + def test_kind(self): """ - Test if the 'units' attribute works properly. + Test if the 'kind' attribute works properly. """ nbins = 10 sensitivity = 2. @@ -271,7 +271,7 @@ def test_units(self): spectrum = Spectrum(1., 2., nbins) spectrum.samples[:] = spectral_value - pipeline = RayTransferPipeline0D('test_pipeline_0D', units='power') + pipeline = RayTransferPipeline0D('test_pipeline_0D', kind='power') pipeline.initialise(0, 0, nbins, 0, 0) pixel_processor = pipeline.pixel_processor(0) @@ -281,7 +281,7 @@ def test_units(self): matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity self.assertTrue(np.all(matrix == sensitivity * spectral_value)) - pipeline.units = 'radiance' + pipeline.kind = 'radiance' pixel_processor = pipeline.pixel_processor(0) pixel_processor.add_sample(spectrum, sensitivity) @@ -301,19 +301,19 @@ def test_initialise(self): nbins = 10 pixels = 20 samples = 1 - pipeline = RayTransferPipeline1D('test_pipeline_1D', units='radiance') + pipeline = RayTransferPipeline1D('test_pipeline_1D', kind='radiance') pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) self.assertTrue(pipeline.matrix.shape == (pixels, nbins)) self.assertTrue(pipeline.name == 'test_pipeline_1D') - self.assertTrue(pipeline.units == 'radiance') + self.assertTrue(pipeline.kind == 'radiance') self.assertTrue(pipeline._samples == samples) self.assertRaises(ValueError, RayTransferPipeline1D, 'test_pipeline_1D', 'blah') - def test_units(self): + def test_kind(self): """ - Test if the 'units' attribute works properly. + Test if the 'kind' attribute works properly. """ nbins = 10 pixels = 20 @@ -323,7 +323,7 @@ def test_units(self): spectrum = Spectrum(1., 2., nbins) spectrum.samples[:] = spectral_value - pipeline = RayTransferPipeline1D('test_pipeline_1D', units='power') + pipeline = RayTransferPipeline1D('test_pipeline_1D', kind='power') pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) pixel_processor = pipeline.pixel_processor(0, 0) @@ -333,7 +333,7 @@ def test_units(self): matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity self.assertTrue(np.all(matrix == sensitivity * spectral_value)) - pipeline.units = 'radiance' + pipeline.kind = 'radiance' pixel_processor = pipeline.pixel_processor(0, 0) pixel_processor.add_sample(spectrum, sensitivity) @@ -353,19 +353,19 @@ def test_initialise(self): nbins = 10 pixels = (20, 5) samples = 1 - pipeline = RayTransferPipeline2D('test_pipeline_2D', units='radiance') + pipeline = RayTransferPipeline2D('test_pipeline_2D', kind='radiance') pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) self.assertTrue(pipeline.matrix.shape == (pixels[0], pixels[1], nbins)) self.assertTrue(pipeline.name == 'test_pipeline_2D') - self.assertTrue(pipeline.units == 'radiance') + self.assertTrue(pipeline.kind == 'radiance') self.assertTrue(pipeline._samples == samples) self.assertRaises(ValueError, RayTransferPipeline2D, 'test_pipeline_2D', 'blah') def test_units(self): """ - Test if the 'units' attribute works properly. + Test if the 'kind' attribute works properly. """ nbins = 10 pixels = (20, 5) @@ -375,7 +375,7 @@ def test_units(self): spectrum = Spectrum(1., 2., nbins) spectrum.samples[:] = spectral_value - pipeline = RayTransferPipeline2D('test_pipeline_2D', units='power') + pipeline = RayTransferPipeline2D('test_pipeline_2D', kind='power') pipeline.initialise(pixels, samples, 0, 0, nbins, 1, 0) pixel_processor = pipeline.pixel_processor(0, 0, 0) @@ -385,7 +385,7 @@ def test_units(self): matrix, _ = pixel_processor.pack_results() # multiplied by sensitivity self.assertTrue(np.all(matrix == sensitivity * spectral_value)) - pipeline.units = 'radiance' + pipeline.kind = 'radiance' pixel_processor = pipeline.pixel_processor(0, 0, 0) pixel_processor.add_sample(spectrum, sensitivity) diff --git a/demos/observers/bolometry/geometry_matrix_with_raytransfer.py b/demos/observers/bolometry/geometry_matrix_with_raytransfer.py index a6bee82d..35c525e1 100644 --- a/demos/observers/bolometry/geometry_matrix_with_raytransfer.py +++ b/demos/observers/bolometry/geometry_matrix_with_raytransfer.py @@ -240,7 +240,7 @@ def _point3d_to_rz(point): for camera in cameras: for foil in camera: print("Calculating sensitivity for {}...".format(foil.name)) - foil.pipelines = [RayTransferPipeline0D(units=foil.units)] + foil.pipelines = [RayTransferPipeline0D(kind=foil.units)] # All objects in world have wavelength-independent material properties, # so it doesn't matter which wavelength range we use (as long as # max_wavelength - min_wavelength = 1) diff --git a/demos/ray_transfer/1_ray_transfer_box.py b/demos/ray_transfer/1_ray_transfer_box.py index a4029431..43461709 100644 --- a/demos/ray_transfer/1_ray_transfer_box.py +++ b/demos/ray_transfer/1_ray_transfer_box.py @@ -66,8 +66,8 @@ rtb.step = 0.2 # creating ray transfer pipeline -# Be careful when choosing pipeline units ('power' or 'radiance'). -# In case of 'power', the matrix [m] is multiplied by the detector's sensitivity [m^2 sr]. +# Be careful when setting the 'kind' attribute of the pipeline to 'power' or 'radiance'. +# In the case of 'power', the matrix [m] is multiplied by the detector's sensitivity [m^2 sr]. # For the PinholeCamera this does not matter, because its pixel sensitivity is 1. pipeline = RayTransferPipeline2D() From 41e7f70b3d3a8c6f874f1bf0df577d3c7b4fcc53 Mon Sep 17 00:00:00 2001 From: vsnever Date: Wed, 10 May 2023 16:26:20 +0300 Subject: [PATCH 73/81] Updated the docstrings of RayTransferPipelineXD. --- cherab/tools/raytransfer/pipelines.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cherab/tools/raytransfer/pipelines.py b/cherab/tools/raytransfer/pipelines.py index 2339915a..e051e3f7 100644 --- a/cherab/tools/raytransfer/pipelines.py +++ b/cherab/tools/raytransfer/pipelines.py @@ -75,7 +75,7 @@ class RayTransferPipeline0D(Pipeline0D, RayTransferPipelineBase): Simple 0D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + :param str kind: The kind of the pipeline. Can be 'power' (default) or 'radiance'. In the case of 'power', the resulting matrix is multiplied by the sensitivity of the detector, and the units of the matrix are [m^3 sr], which gives the units of power [W] for the product of the ray transfer matrix and the emission profile. @@ -121,7 +121,7 @@ class RayTransferPipeline1D(Pipeline1D, RayTransferPipelineBase): Simple 1D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + :param str kind: The kind of the pipeline. Can be 'power' (default) or 'radiance'. In the case of 'power', the resulting matrix is multiplied by the sensitivity of the detector, and the units of the matrix are [m^3 sr], which gives the units of power [W] for the product of the ray transfer matrix and the emission profile. @@ -168,7 +168,7 @@ class RayTransferPipeline2D(Pipeline2D, RayTransferPipelineBase): Simple 2D pipeline for ray transfer matrix (geometry matrix) calculation. :param str name: The name of the pipeline. Default is 'RayTransferPipeline0D'. - :param str kind: The kind of the pipeline. Can be 'power' or 'radiance'. + :param str kind: The kind of the pipeline. Can be 'power' (default) or 'radiance'. In the case of 'power', the resulting matrix is multiplied by the sensitivity of the detector, and the units of the matrix are [m^3 sr], which gives the units of power [W] for the product of the ray transfer matrix and the emission profile. From 8a5ace6ad5fc9a9365826cefe677d84c15b6afd4 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Wed, 9 Aug 2023 12:43:15 +0300 Subject: [PATCH 74/81] Fix NotImplementedError in TestLaserSpectrum. --- cherab/core/laser/tests/test_laserspectrum.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cherab/core/laser/tests/test_laserspectrum.py b/cherab/core/laser/tests/test_laserspectrum.py index 9473e43d..6545f5c7 100644 --- a/cherab/core/laser/tests/test_laserspectrum.py +++ b/cherab/core/laser/tests/test_laserspectrum.py @@ -1,9 +1,11 @@ import unittest import numpy as np -from cherab.core.laser.laserspectrum import LaserSpectrum +# The evaluate() method is not implemented in the base LaserSpectrum, so importing the simplest subclass. +from cherab.core.model.laser.laserspectrum import ConstantSpectrum as LaserSpectrum from raysect.optical.spectrum import Spectrum + class TestLaserSpectrum(unittest.TestCase): def test_laserspectrum_init(self): @@ -24,12 +26,12 @@ def test_laserspectrum_init(self): msg="LaserSpectrum did not raise a ValueError with max_wavelength < min_wavelength."): LaserSpectrum(40, 30, 200) LaserSpectrum(30, 30, 200) - + # test bins > 0 with self.assertRaises(ValueError, - msg="LaserSpectrum did not raise a ValueError with max_wavelength < min_wavelength."): - LaserSpectrum(30, 30, 0) - LaserSpectrum(30, 30, -1) + msg="LaserSpectrum did not raise a ValueError with bins <= 0."): + LaserSpectrum(30, 40, 0) + LaserSpectrum(30, 40, -1) def test_laserspectrum_changes(self): laser_spectrum = LaserSpectrum(100, 200, 100) @@ -59,4 +61,4 @@ def test_laserspectrum_changes(self): # test caching of spectrum data, behaviour should be consistent with raysect.optical.spectrum.Spectrum self.assertTrue(np.array_equal(laser_spectrum.wavelengths, spectrum.wavelengths), "LaserSpectrum.wavelengths values are not equal to Spectrum.wavelengths " - "with same boundaries and number of bins") \ No newline at end of file + "with same boundaries and number of bins") From 1aafe6276105a77aa1e284459461750a5267301f Mon Sep 17 00:00:00 2001 From: MatejTomes Date: Thu, 26 Oct 2023 20:16:43 +0200 Subject: [PATCH 75/81] Fix update bug of LaserMaterial Laser primitives have to be rebuild with the materials. Possible source of the problem: Laser node is the parent of the laser primitives After laser.transform is changed the _modified method is called before the transforms of the laser primitives is changed because the Laser node is above the laser primitives in the scenegraph. --- cherab/core/laser/node.pyx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cherab/core/laser/node.pyx b/cherab/core/laser/node.pyx index b0b821b5..16b564cf 100644 --- a/cherab/core/laser/node.pyx +++ b/cherab/core/laser/node.pyx @@ -255,7 +255,7 @@ cdef class Laser(Node): def _plasma_changed(self): """React to change of plasma and propagate the information.""" - self._configure_materials() + self.configure_geometry() def _modified(self): - self._configure_materials() + self.configure_geometry() From f0ff4f25b09afe8e61fe213425944d16ac415d09 Mon Sep 17 00:00:00 2001 From: MatejTomes Date: Thu, 26 Oct 2023 21:41:28 +0200 Subject: [PATCH 76/81] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af7646d..01daa26c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ New: * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) * Add the kind attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity ('power') or not ('radiance'). (#412) +Bug fixes: +* Fix deprecated cached transforms in LaserMaterial after laser.transform update Release 1.4.0 (3 Feb 2023) ------------------- From 09abc73540fe6fd9a08a8c083747349a69e6e4b2 Mon Sep 17 00:00:00 2001 From: MatejTomes Date: Thu, 26 Oct 2023 21:47:39 +0200 Subject: [PATCH 77/81] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01daa26c..5fde4c32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ New: * Add the kind attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity ('power') or not ('radiance'). (#412) Bug fixes: -* Fix deprecated cached transforms in LaserMaterial after laser.transform update +* Fix deprecated transforms being cached in LaserMaterial after laser.transform update (#420) Release 1.4.0 (3 Feb 2023) ------------------- From 23d1a7b17889d7ec7a2f30c8f694d9c9be0fefb2 Mon Sep 17 00:00:00 2001 From: MatejTomes Date: Fri, 27 Oct 2023 11:38:20 +0200 Subject: [PATCH 78/81] Change LaserMaterial transforms caching The transforms are cached first time the emission method is called This should be a safer option The LaserMaterial now can be assigned only to a single primitive --- cherab/core/laser/material.pxd | 6 +++++- cherab/core/laser/material.pyx | 26 +++++++++++++++++++++----- cherab/core/laser/node.pxd | 4 +++- cherab/core/laser/node.pyx | 10 ++++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/cherab/core/laser/material.pxd b/cherab/core/laser/material.pxd index c91fa416..24695146 100644 --- a/cherab/core/laser/material.pxd +++ b/cherab/core/laser/material.pxd @@ -17,7 +17,7 @@ # under the Licence. -from raysect.core.scenegraph._nodebase cimport _NodeBase +from raysect.core cimport Primitive from raysect.core.math cimport AffineMatrix3D from raysect.optical.material.emitter cimport InhomogeneousVolumeEmitter @@ -28,4 +28,8 @@ cdef class LaserMaterial(InhomogeneousVolumeEmitter): cdef: AffineMatrix3D _laser_to_plasma, _laser_segment_to_laser_node + Primitive _primitive + Laser _laser list _models + + cdef void _cache_transforms(self) \ No newline at end of file diff --git a/cherab/core/laser/material.pyx b/cherab/core/laser/material.pyx index 4732e01a..75cc46a6 100644 --- a/cherab/core/laser/material.pyx +++ b/cherab/core/laser/material.pyx @@ -17,7 +17,7 @@ # under the Licence. -from raysect.core.scenegraph._nodebase cimport _NodeBase +from raysect.core cimport Primitive from raysect.optical cimport World, Primitive, Ray, Spectrum, Point3D, Vector3D, AffineMatrix3D from raysect.optical.material.emitter cimport InhomogeneousVolumeEmitter from raysect.optical.material.emitter.inhomogeneous cimport VolumeIntegrator @@ -28,12 +28,12 @@ from cherab.core.laser.model cimport LaserModel cdef class LaserMaterial(InhomogeneousVolumeEmitter): - def __init__(self, Laser laser not None, _NodeBase laser_segment not None, list models, VolumeIntegrator integrator not None): + def __init__(self, Laser laser not None, Primitive laser_segment not None, list models, VolumeIntegrator integrator not None): super().__init__(integrator) - self._laser_segment_to_laser_node = laser_segment.to(laser) - self._laser_to_plasma = laser_segment.to(laser.plasma) + self._laser = laser + self._primitive = laser_segment self.importance = laser.importance #validate and set models @@ -54,6 +54,10 @@ cdef class LaserMaterial(InhomogeneousVolumeEmitter): Point3D point_plasma, point_laser Vector3D direction_plasma, direction_laser LaserModel model + + # cache the important transforms + if self._laser_segment_to_laser_node is None or self._laser_to_plasma is None: + self._cache_transforms() point_laser = point.transform(self._laser_segment_to_laser_node) direction_laser = direction.transform(self._laser_segment_to_laser_node) # observation vector in the laser frame @@ -63,4 +67,16 @@ cdef class LaserMaterial(InhomogeneousVolumeEmitter): for model in self._models: spectrum = model.emission(point_plasma, direction_plasma, point_laser, direction_laser, spectrum) - return spectrum + return spectrum + + cdef void _cache_transforms(self): + """ + cache transforms from laser primitive to laser and plasma + """ + + # if transforms are cached, the material should be used only for one primitive for safety + if not len(self.primitives) == 1: + raise ValueError("LaserMaterial must be attached to exactly one primitive.") + + self._laser_segment_to_laser_node = self._primitive.to(self._laser) + self._laser_to_plasma = self._primitive.to(self._laser.get_plasma()) diff --git a/cherab/core/laser/node.pxd b/cherab/core/laser/node.pxd index 6045fb4a..8fec6821 100644 --- a/cherab/core/laser/node.pxd +++ b/cherab/core/laser/node.pxd @@ -52,4 +52,6 @@ cdef class Laser(Node): list _geometry VolumeIntegrator _integrator - cdef object __weakref__ \ No newline at end of file + cdef object __weakref__ + + cdef Plasma get_plasma(self) \ No newline at end of file diff --git a/cherab/core/laser/node.pyx b/cherab/core/laser/node.pyx index 16b564cf..9475fb69 100644 --- a/cherab/core/laser/node.pyx +++ b/cherab/core/laser/node.pyx @@ -153,6 +153,12 @@ cdef class Laser(Node): self._plasma.notifier.add(self._plasma_changed) self._configure_materials() + + cdef Plasma get_plasma(self): + """ + Fast method to obtain laser's plasma reference. + """ + return self._plasma @property def importance(self): @@ -255,7 +261,7 @@ cdef class Laser(Node): def _plasma_changed(self): """React to change of plasma and propagate the information.""" - self.configure_geometry() + self._configure_materials() def _modified(self): - self.configure_geometry() + self._configure_materials() From 91ae41a8a8660e02604a853385a27a57bad4b016 Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 27 Oct 2023 13:10:26 +0300 Subject: [PATCH 79/81] Fix deprecated Polygon initialisation. --- cherab/tools/inversions/voxels.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cherab/tools/inversions/voxels.pyx b/cherab/tools/inversions/voxels.pyx index 6baaa821..c682e01a 100644 --- a/cherab/tools/inversions/voxels.pyx +++ b/cherab/tools/inversions/voxels.pyx @@ -682,7 +682,7 @@ class ToroidalVoxelGrid(VoxelCollection): patches = [] for voxel in self: - polygon = Polygon([(v.x, v.y) for v in voxel.vertices], True) + polygon = Polygon([(v.x, v.y) for v in voxel.vertices], closed=True) patches.append(polygon) p = PatchCollection(patches, cmap=cmap) From bba72296cc776c802be0842cc7d0b1bf59465660 Mon Sep 17 00:00:00 2001 From: Vladislav Neverov Date: Thu, 23 Nov 2023 13:54:31 +0300 Subject: [PATCH 80/81] Fix parsing of the ADF15 metadata for H-like ions. --- CHANGELOG.md | 1 + cherab/openadas/parse/adf15.py | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9af7646d..fdb1a75e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ New: * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) * Add the kind attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity ('power') or not ('radiance'). (#412) +* Improved parsing of the ADAS ADF15 metadata for H-like ions. Raises a runtime error if the metadata cannot be parsed. (#424) Release 1.4.0 (3 Feb 2023) diff --git a/cherab/openadas/parse/adf15.py b/cherab/openadas/parse/adf15.py index b9fe42be..14103c04 100644 --- a/cherab/openadas/parse/adf15.py +++ b/cherab/openadas/parse/adf15.py @@ -67,11 +67,18 @@ def parse_adf15(element, charge, adf_file_path, header_format=None): # use simple electron configuration structure for hydrogen-like ions if header_format == 'hydrogen' or element == hydrogen: config = _scrape_metadata_hydrogen(file, element, charge) - elif header_format == 'hydrogen-like' or element.atomic_number - charge == 1: + elif header_format == 'hydrogen-like': config = _scrape_metadata_hydrogen_like(file, element, charge) + elif element.atomic_number - charge == 1: + config = _scrape_metadata_hydrogen_like(file, element, charge) + if not config: # try hydrogen header (works for 'bnd' files) + config = _scrape_metadata_hydrogen(file, element, charge) else: config = _scrape_metadata_full(file, element, charge) + if not config: + raise RuntimeError("Unable to parse ADF15 metadata.") + # process rate data rates = RecursiveDict() for cls in ('excitation', 'recombination', 'thermalcx'): From 53ef1d32cf274595c8f9a80dff87ad324e1d3a3c Mon Sep 17 00:00:00 2001 From: vsnever Date: Fri, 1 Dec 2023 17:13:46 +0300 Subject: [PATCH 81/81] Explicitly handle the 'bnd' ADF15 files when parsing the metadata. --- CHANGELOG.md | 2 +- cherab/openadas/parse/adf15.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb1a75e..dcc88e10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ New: * Add PeriodicTransformXD and VectorPeriodicTransformXD functions to support the data simulated with periodic boundary conditions. (#387) * Add CylindricalTransform and VectorCylindricalTransform to transform functions from cylindrical to Cartesian coordinates. (#387) * Add the kind attribute to RayTransferPipelineXD that determines whether the ray transfer matrix is multiplied by sensitivity ('power') or not ('radiance'). (#412) -* Improved parsing of the ADAS ADF15 metadata for H-like ions. Raises a runtime error if the metadata cannot be parsed. (#424) +* Improved parsing of metadata from the ADAS ADF15 'bnd' files for H-like ions. Raises a runtime error if the metadata cannot be parsed. (#424) Release 1.4.0 (3 Feb 2023) diff --git a/cherab/openadas/parse/adf15.py b/cherab/openadas/parse/adf15.py index 14103c04..51bbcf6b 100644 --- a/cherab/openadas/parse/adf15.py +++ b/cherab/openadas/parse/adf15.py @@ -71,7 +71,8 @@ def parse_adf15(element, charge, adf_file_path, header_format=None): config = _scrape_metadata_hydrogen_like(file, element, charge) elif element.atomic_number - charge == 1: config = _scrape_metadata_hydrogen_like(file, element, charge) - if not config: # try hydrogen header (works for 'bnd' files) + if not config and 'bnd#' in adf_file_path: + # ADF15 files with the "bnd" suffix may have metadata in the "hydrogen" format config = _scrape_metadata_hydrogen(file, element, charge) else: config = _scrape_metadata_full(file, element, charge)