Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Release 1.6.0 (TBD)
-------------------

API changes:
* Rename `TargettedPixelGroup` to `TargetedPixelGroup` for correct spelling. Still keep `TargettedPixelGroup` as an alias for backwards compatibility until the next major release. (#487)
* Add emission model attribute access to line and lineshape . (#294)

New:
Expand Down
2 changes: 1 addition & 1 deletion cherab/tools/observers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
from .calcam import load_calcam_calibration
from .intersections import find_wall_intersection
from .spectroscopy import SpectroscopicSightLine, SpectroscopicFibreOptic
from .group import PixelGroup, TargettedPixelGroup, SightLineGroup, FibreOpticGroup, SpectroscopicFibreOpticGroup, SpectroscopicSightLineGroup
from .group import PixelGroup, TargetedPixelGroup, TargettedPixelGroup, SightLineGroup, FibreOpticGroup, SpectroscopicFibreOpticGroup, SpectroscopicSightLineGroup
5 changes: 3 additions & 2 deletions cherab/tools/observers/group/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
# under the Licence.

from .fibreoptic import FibreOpticGroup
from .sightline import SightLineGroup
from .targettedpixel import TargettedPixelGroup
from .pixel import PixelGroup
from .sightline import SightLineGroup
from .spectroscopic import SpectroscopicFibreOpticGroup, SpectroscopicSightLineGroup
from .targetedpixel import TargetedPixelGroup
from .targettedpixel import TargettedPixelGroup
123 changes: 123 additions & 0 deletions cherab/tools/observers/group/targetedpixel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# 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 numpy import ndarray
from raysect.optical.observer import TargetedPixel

from .base import Observer0DGroup


class TargetedPixelGroup(Observer0DGroup):
"""
A group of targeted pixels under a single scene-graph node.

A scene-graph object regrouping a series of 'TargetedPixel'
observers as a scene-graph parent. Allows combined observation and display
control simultaneously.

:ivar list x_width: Width of pixel along local x axis
:ivar list y_width: Width of pixel along local y axis
:ivar list targets: Targets for preferential sampling
:ivar list targeted_path_prob: Probability of ray being casted at the target
"""

_OBSERVER_TYPE = TargetedPixel

@property
def x_width(self):
return [pixel.x_width for pixel in self._observers]

@x_width.setter
def x_width(self, value):
if isinstance(value, (list, tuple, ndarray)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.x_width = v
else:
raise ValueError(
"The length of 'x_width' ({}) mismatches the number of pixels ({}).".format(len(value), len(self._observers))
)
else:
for pixel in self._observers:
pixel.x_width = value

@property
def y_width(self):
return [pixel.y_width for pixel in self._observers]

@y_width.setter
def y_width(self, value):
if isinstance(value, (list, tuple, ndarray)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.y_width = v
else:
raise ValueError(
"The length of 'y_width' ({}) mismatches the number of pixels ({}).".format(len(value), len(self._observers))
)
else:
for pixel in self._observers:
pixel.y_width = value

@property
def targets(self):
"""
List of target lists used by pixels for preferential sampling

:param list value: List of primitives to be set to each pixel or
list of lists containing targets specific for each pixel
in this case the number of lists must match number of pixels

:rtype: list
"""
return [pixel.targets for pixel in self._observers]

@targets.setter
def targets(self, value):
if all(isinstance(v, (list, tuple)) for v in value):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.targets = v
else:
raise ValueError(
"The number of provided target lists' ({}) mismatches the number of pixels ({}).".format(
len(value), len(self._observers)
)
)
else:
# assuming a list of primitives, the pixel's setter will throw an error if not
for pixel in self._observers:
pixel.targets = value

@property
def targeted_path_prob(self):
return [pixel.targeted_path_prob for pixel in self._observers]

@targeted_path_prob.setter
def targeted_path_prob(self, value):
if isinstance(value, (list, tuple)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.targeted_path_prob = v
else:
raise ValueError(
"The length of 'value' ({}) mismatches the number of pixels ({}).".format(len(value), len(self._observers))
)
else:
for pixel in self._observers:
pixel.targeted_path_prob = value
95 changes: 18 additions & 77 deletions cherab/tools/observers/group/targettedpixel.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@
# See the Licence for the specific language governing permissions and limitations
# under the Licence.

from numpy import ndarray
from raysect.optical.observer import TargetedPixel
import warnings

from .base import Observer0DGroup
from .targetedpixel import TargetedPixelGroup as _TargetedPixelGroup


class TargettedPixelGroup(Observer0DGroup):
class TargettedPixelGroup(_TargetedPixelGroup):
"""
A group of targeted pixel under a single scene-graph node.

A scene-graph object regrouping a series of 'TargettedPixel'
.. deprecated::
`TargettedPixelGroup` is deprecated and will be removed in version 2.0.
Use `TargetedPixelGroup` instead.

A scene-graph object regrouping a series of `TargetedPixel`
observers as a scene-graph parent. Allows combined observation and display
control simultaneously.

Expand All @@ -36,81 +39,19 @@ class TargettedPixelGroup(Observer0DGroup):
:ivar list targetted_path_prob: Probability of ray being casted at the target
"""

_OBSERVER_TYPE = TargetedPixel

@property
def x_width(self):
return [pixel.x_width for pixel in self._observers]

@x_width.setter
def x_width(self, value):
if isinstance(value, (list, tuple, ndarray)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.x_width = v
else:
raise ValueError("The length of 'x_width' ({}) "
"mismatches the number of pixels ({}).".format(len(value), len(self._observers)))
else:
for pixel in self._observers:
pixel.x_width = value

@property
def y_width(self):
return [pixel.y_width for pixel in self._observers]

@y_width.setter
def y_width(self, value):
if isinstance(value, (list, tuple, ndarray)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.y_width = v
else:
raise ValueError("The length of 'y_width' ({}) "
"mismatches the number of pixels ({}).".format(len(value), len(self._observers)))
else:
for pixel in self._observers:
pixel.y_width = value

@property
def targets(self):
"""
List of target lists used by pixels for preferential sampling

:param list value: List of primitives to be set to each pixel or
list of lists containing targets specific for each pixel
in this case the number of lists must match number of pixels

:rtype: list
"""
return [pixel.targets for pixel in self._observers]

@targets.setter
def targets(self, value):
if all(isinstance(v, (list, tuple)) for v in value):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.targets = v
else:
raise ValueError("The number of provided target lists' ({}) "
"mismatches the number of pixels ({}).".format(len(value), len(self._observers)))
else:
# assuming a list of primitives, the pixel's setter will throw an error if not
for pixel in self._observers:
pixel.targets = value
def __init__(self, *args, **kwargs):
warnings.warn(
"TargettedPixelGroup is deprecated and will be removed in version 2.0. "
+ "Use TargetedPixelGroup instead.",
DeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwargs)

@property
def targetted_path_prob(self):
return [pixel.targeted_path_prob for pixel in self._observers]
return self.targeted_path_prob

@targetted_path_prob.setter
def targetted_path_prob(self, value):
if isinstance(value, (list, tuple)):
if len(value) == len(self._observers):
for pixel, v in zip(self._observers, value):
pixel.targeted_path_prob = v
else:
raise ValueError("The length of 'value' ({}) mismatches the number of pixels ({}).".format(len(value), len(self._observers)))
else:
for pixel in self._observers:
pixel.targeted_path_prob = value
self.targeted_path_prob = value
37 changes: 28 additions & 9 deletions cherab/tools/tests/test_observer_groups.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import unittest
import warnings

from raysect.core.workflow import RenderEngine
from raysect.optical.observer import Observer0D, SightLine, FibreOptic, Pixel, TargetedPixel, PowerPipeline0D, SpectralPowerPipeline0D
from raysect.primitive import Sphere

from cherab.tools.observers.group import FibreOpticGroup, PixelGroup, SightLineGroup, TargetedPixelGroup, TargettedPixelGroup
from cherab.tools.observers.group.base import Observer0DGroup
from cherab.tools.observers.group import SightLineGroup, FibreOpticGroup, PixelGroup, TargettedPixelGroup
from cherab.tools.raytransfer import pipelines


Expand Down Expand Up @@ -348,8 +349,8 @@ def test_widths(self):
group.y_width = [1e-1] * (len(group) + 1)


class TargettedPixelGroupTestCase(PixelGroupTestCase):
_GROUP_CLASS = TargettedPixelGroup
class TargetedPixelGroupTestCase(PixelGroupTestCase):
_GROUP_CLASS = TargetedPixelGroup

def setUp(self):
self.observers = [TargetedPixel(targets=[Sphere()], pipelines=[PowerPipeline0D()]) for _ in range(self._NUM)]
Expand All @@ -374,15 +375,33 @@ def test_targets(self):
with self.assertRaises(ValueError):
group.targets = targets

# targetted path prob
# targeted path prob
prob = [0.9, 0.95, 1]
group.targetted_path_prob = prob
self.assertListEqual(group.targetted_path_prob, prob)
group.targeted_path_prob = prob
self.assertListEqual(group.targeted_path_prob, prob)

prob = 0.8
group.targetted_path_prob = prob
for group_targeted_path_prob in group.targetted_path_prob:
group.targeted_path_prob = prob
for group_targeted_path_prob in group.targeted_path_prob:
self.assertEqual(group_targeted_path_prob, prob)

with self.assertRaises(ValueError):
group.targetted_path_prob = [0.7] * (len(group) + 1)
group.targeted_path_prob = [0.7] * (len(group) + 1)


class TargettedPixelGroupTestCase(TargetedPixelGroupTestCase):
"""Test case for deprecated TargettedPixelGroup class."""

_GROUP_CLASS = TargettedPixelGroup

def test_deprecation_warning(self):
"""Test that using TargettedPixelGroup raises a deprecation warning."""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
group = TargettedPixelGroup(observers=self.observers)

# Check that a warning was issued
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, DeprecationWarning))
self.assertIn("TargettedPixelGroup is deprecated", str(w[0].message))
self.assertIn("Use TargetedPixelGroup instead", str(w[0].message))
3 changes: 3 additions & 0 deletions docs/source/tools/observers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ in the group.
.. autoclass:: cherab.tools.observers.group.PixelGroup
:members:

.. autoclass:: cherab.tools.observers.group.TargetedPixelGroup
:members:

.. autoclass:: cherab.tools.observers.group.TargettedPixelGroup
:members:

Expand Down