Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.4.0 #392

Merged
merged 90 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
d4b0b99
Added first spectroscopic instruments.
vsnever Jun 16, 2021
f637989
Made 'resolution' a property of CzernyTurnerSpectrometer.
vsnever Jun 16, 2021
ce7d9ff
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Jun 24, 2021
aea4603
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Jul 23, 2021
439f5b2
Added Sphinx documentation and unit tests for spectroscopic instruments.
vsnever Jul 26, 2021
829b231
Aligned the docs for spectroscopic instruments with the style used in…
vsnever Jul 29, 2021
b674e01
Moved spectroscopic instruments from 'observers' to 'spectroscopy' su…
vsnever Aug 3, 2021
996a36a
Made Instrument.pipelines() a funstion instead of property to avoid c…
vsnever Aug 3, 2021
ecb6c6b
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Aug 25, 2021
2763b70
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Oct 13, 2021
bbb219d
Fixed merging conflict.
vsnever Nov 11, 2021
6b48415
Renamed SpectroscopicInstrument.pipelines() to SpectroscopicInstrumen…
vsnever Nov 11, 2021
808126a
Improved implementation of Polychromator and PolychromatorFilter.
vsnever Nov 13, 2021
5172888
Updated the tests for the Polychromator and the filters.
vsnever Nov 13, 2021
7dc613d
Reimplemented spectrometers in response to reviewer's comments.
vsnever Nov 18, 2021
6e7c75e
Renamed SpectroscopicInstrument's new_pipelines() to create_pipeline().
vsnever Nov 23, 2021
1e591e8
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Nov 29, 2021
3867bc4
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Dec 13, 2021
e11a6d5
In CzernyTurnerSpectrometer invoke wavelength_to_pixel update when ch…
vsnever Dec 13, 2021
3399bcb
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Dec 31, 2021
95c89bc
Added more accurate Gaunt factor for Bremsstrahlung emission model.
vsnever Jan 24, 2022
0246b9d
Improve FreeFreeGauntFactor.__call__() docstring and update CHANGELOG.
vsnever Jan 27, 2022
c627749
Made EFITEquilibrium.f_profile a public readonly attribute.
vsnever Jan 31, 2022
560cc53
Updated changelog.
vsnever Jan 31, 2022
729ef4f
Updated EFITEquilibrium docstring with f_profile ivar description.
vsnever Jan 31, 2022
5337eb8
Merge pull request #355 from vsnever/enhancement/readonly_f_profile
jacklovell Jan 31, 2022
9bdd61b
Fix f_profile definition in EFITEquilibrium docstring and changelog.
vsnever Jan 31, 2022
b84f009
Merge pull request #356 from vsnever/enhancement/readonly_f_profile
jacklovell Jan 31, 2022
cc57399
Resolve merge conflict in CHANGELOG.md.
vsnever Feb 16, 2022
349ae82
Use summation over charged species instead of Zeff in Bremsstrahlung …
vsnever Feb 17, 2022
a892e26
Enable testing of SART OpenCL inversion routines with POCL
jacklovell Feb 22, 2022
70a88fb
Merge pull request #357 from cherab/opencl-test-fixes
jacklovell Feb 23, 2022
dee48c6
Add group observers for Pixel and TargetedPixel (#332)
skuba31 Feb 24, 2022
f4d316b
Improve SartOpencl solver and OpenCL utilities (#359)
vsnever Mar 7, 2022
df2964a
Merge development and resolve merge conflict in CHANGELOG.md.
vsnever Mar 8, 2022
bbe65d5
Add gaunt factor as optional parameter of the Bremsstrahlung emission…
vsnever Mar 8, 2022
c3d467f
Resolve merging conflict in observers.rst.
vsnever Mar 21, 2022
00289d2
Generomak/core plasma (#360)
Mateasek Mar 23, 2022
a823630
Replace pipeline_properties with pipeline_classes and pipeline_kwargs…
vsnever Mar 23, 2022
ee6a54b
Merge branch 'development' into feature/spectroscopic_instruments
vsnever Mar 23, 2022
3b77644
Update CHANGELOG.md.
vsnever Mar 23, 2022
e4ba124
Feature/toroidal mesh from polygon (#365)
wave46 Apr 4, 2022
0f83e5d
Add Generomak blended plasma profiles.
vsnever Aug 4, 2022
e9a272f
Correct Generomak plasma demo descriptions.
vsnever Aug 4, 2022
6ff197c
Fix typo in Bremsstrahlung docstrings
skuba31 Aug 18, 2022
1f945c1
Fix the docstring for the Bremsstrahlung model (#375).
vsnever Aug 18, 2022
b202dbb
Add Gaussian quadrature integrator and tests.
vsnever Aug 30, 2022
a32a6a7
Fix an error in GaussianQuadrature. Increase default relative toleran…
vsnever Aug 31, 2022
c4a604d
Add NumericallyIntegrableLineShapeModel class. Update StarkBroadenedL…
vsnever Aug 31, 2022
6308e0f
Update changelog.
vsnever Aug 31, 2022
526cc17
Make Integrator1D a Function2D instance.
vsnever Sep 11, 2022
86d908b
Remove NumericallyIntegratedLineShapeModel. Add integrator to LineSha…
vsnever Sep 11, 2022
7f1e732
Fix CI by pinning raysect install version in script (#381)
jacklovell Oct 13, 2022
a023f16
Merge pull request #375 from skuba31/fix/typo-bremsstrahlung
jacklovell Oct 13, 2022
52e274c
Add quiet property to Observer0DGroup
skuba31 Aug 18, 2022
3ce7a34
Reorder and add missing attributes
skuba31 Aug 19, 2022
30d37c8
Update tests
skuba31 Aug 19, 2022
175dda6
Fix docstrings
skuba31 Aug 26, 2022
803d529
Merge branch 'development' into feature/quadrature_integration
vsnever Oct 13, 2022
d2eebec
Merge branch 'development' into enhancement/blended_plasma
vsnever Oct 13, 2022
6eee183
Merge pull request #376 from skuba31/group-quiet
jacklovell Oct 13, 2022
368965a
Explicitly specify build-backend
jacklovell Jan 27, 2022
0b2a21a
Update installation instructions to use modern best practices
jacklovell Jan 27, 2022
183e803
Remove Cython as a runtime dependency
jacklovell Jan 28, 2022
b1b1b7f
Use oldest-supported-numpy as build dependency
jacklovell Feb 22, 2022
c47a09c
Merge pull request #353 from cherab/packaging-improvements
jacklovell Oct 13, 2022
6a915f9
Remove Function2D inheritance for Integrator1D. Forbid setting the in…
vsnever Oct 17, 2022
e62f0ad
Add initialisation checks to StarkFunction and make it return a norma…
vsnever Oct 17, 2022
308208c
Update CHANGELOG.md
vsnever Oct 18, 2022
e8b05ca
Fix Bremsstrahlung trapezium indexing
Mateasek Nov 7, 2022
337f01e
Merge pull request #385 from Mateasek/fix/bremsstrahlung_trapezium
vsnever Nov 9, 2022
84d087e
Resolve merging conflict in CHANGELOG.md.
vsnever Nov 30, 2022
d9fcd2c
Use ionisation balance for core profiles to fulfill plasma neutrality…
vsnever Dec 2, 2022
f4215ce
Fixed merge conflicts.
vsnever Dec 8, 2022
65b545b
Added pre-calculated core profiles and the functions to load them. Sw…
vsnever Dec 22, 2022
d7fa638
Update CI with new python and numpy versions (#391)
jacklovell Dec 22, 2022
a7caca2
Rewritten TS model with segmented laser geometry (#219)
Mateasek Dec 22, 2022
d302910
Merge pull request #300 from vsnever/feature/spectroscopic_instruments
jacklovell Dec 22, 2022
f301aa6
Merge branch 'development' into enhancement/free_free_gaunt_factor
jacklovell Dec 22, 2022
2c07bd5
Merge pull request #352 from vsnever/enhancement/free_free_gaunt_factor
jacklovell Dec 22, 2022
f0bc1aa
Merge branch 'development' into feature/quadrature_integration
jacklovell Dec 22, 2022
98223bc
Merge pull request #378 from vsnever/feature/quadrature_integration
jacklovell Dec 22, 2022
da14d73
Merge branch 'development' into enhancement/blended_plasma
jacklovell Dec 22, 2022
4a23823
Merge pull request #373 from vsnever/enhancement/blended_plasma
jacklovell Dec 22, 2022
ab6df92
Fixup changelog
jacklovell Dec 23, 2022
f63dcda
Update version in docs and VERSION file
jacklovell Dec 23, 2022
365c211
Add some notes on how to build wheels for PyPI
jacklovell Dec 23, 2022
7711680
Remove duplicate changelog entry
jacklovell Feb 3, 2023
7154407
Merge branch 'master' into development
jacklovell Feb 3, 2023
cf77c57
Update version to 1.4.0
jacklovell Feb 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ New:
* 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)
* Add common spectroscopic instruments: Polychromator, SurveySpectrometer, CzernyTurnerSpectrometer. (#299)


Bug Fixes:
----------
Expand Down
22 changes: 22 additions & 0 deletions cherab/tools/spectroscopy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

# 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 .instrument import SpectroscopicInstrument
from .polychromator import PolychromatorFilter, TrapezoidalFilter, Polychromator
from .spectrometer import Spectrometer, CzernyTurnerSpectrometer
118 changes: 118 additions & 0 deletions cherab/tools/spectroscopy/instrument.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

# 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.

class SpectroscopicInstrument:
"""
Base class for spectroscopic instruments (spectrometers, polychromators, etc.).
This is an abstract class.

:param str name: Instrument name.

: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()

@property
def name(self):
# Instrument name.
return self._name

@name.setter
def name(self, value):
self._name = str(value)
self._pipeline_kwargs = None

@property
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_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_classes`
and keyword arguments."""
if self._pipeline_classes is None:
self._update_pipeline_classes()
if self._pipeline_kwargs is None:
self._update_pipeline_kwargs()

pipelines = []
for PipelineClass, kwargs in zip(self._pipeline_classes, self._pipeline_kwargs):
pipeline = PipelineClass(**kwargs)
pipelines.append(pipeline)

return pipelines

@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_classes(self):
raise NotImplementedError("To be defined in subclass.")

def _update_pipeline_kwargs(self):
raise NotImplementedError("To be defined in subclass.")
221 changes: 221 additions & 0 deletions cherab/tools/spectroscopy/polychromator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@

# 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 numpy as np
from raysect.optical import InterpolatedSF
from raysect.optical.observer import RadiancePipeline0D

from .instrument import SpectroscopicInstrument


class PolychromatorFilter(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.
: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, central_wavelength, window=3., flat_top=None, name=''):

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

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'.")

self._flat_top = flat_top

if flat_top == window:
flat_top -= flat_top * 1.e-15

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


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.
: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, TrapezoidalFilter
>>>
>>> world = World()
>>> 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.create_pipelines()
"""

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_classes = None
self._pipeline_kwargs = None

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):

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.min_wavelength)
max_wavelength = max(max_wavelength, poly_filter.max_wavelength)

self._min_wavelength = min_wavelength
self._max_wavelength = max_wavelength
self._spectral_bins = int(np.ceil((max_wavelength - min_wavelength) / step))
Loading