ModuleMask

Provides a class for masks, which are a type of optical element that simply stops rays that hit it.

Also provides the function TransmitMaskRayList that returns the rays transmitted by the mask.

Illustration the Mask-class.

Created in 2021

@author: Stefan Haessler + André Kalouguine

  1"""
  2Provides a class for masks, which are a type of optical element that simply stops rays that hit it.
  3
  4Also provides the function *TransmitMaskRayList* that returns the rays transmitted by the mask.
  5
  6![Illustration the Mask-class.](Mask.svg)
  7
  8
  9
 10Created in 2021
 11
 12@author: Stefan Haessler + André Kalouguine
 13"""
 14# %% Modules
 15import ARTcore.ModuleGeometry as mgeo
 16from ARTcore.ModuleGeometry import Point, Vector, Origin
 17import ARTcore.ModuleSupport as msup
 18import ARTcore.ModuleOpticalRay as mray
 19import ARTcore.ModuleOpticalElement as moe
 20import ARTcore.ModuleMirror as mmirror
 21
 22import numpy as np
 23from copy import copy
 24import logging
 25
 26logger = logging.getLogger(__name__)
 27
 28# %%############################################################################
 29class Mask(moe.OpticalElement):
 30    """
 31    A mask: a plane surface of the shape of its [Support](ModuleSupport.html), which stops all rays that hit it,
 32    while all other rays continue their path unchanged. No diffraction effects.
 33
 34    Attributes
 35    ----------
 36        support : [Support](ModuleSupport.html)-object
 37
 38        type : str 'Mask'.
 39
 40    Methods
 41    ----------
 42        get_local_normal(Point)
 43
 44        get_centre()
 45
 46        get_grid3D(NbPoints)
 47
 48    """
 49
 50    def __init__(self, Support, **kwargs):
 51        """
 52        Parameters
 53        ----------
 54            Support : [Support](ModuleSupport.html)-object
 55        """
 56        self.type = "Mask"
 57        self.support = Support
 58        self.curvature = mmirror.Curvature.FLAT
 59
 60        self.r0 = mgeo.Point([0.0, 0.0, 0.0])
 61        self._r = mgeo.Vector([0.0, 0.0, 0.0])
 62        self._q = np.quaternion(1)
 63
 64        self.centre_ref = mgeo.Point([0, 0, 0])
 65
 66        self.support_normal_ref = mgeo.Vector([0, 0, 1])
 67        self.normal_ref = mgeo.Vector([0, 0, 1])
 68        self.majoraxis_ref = mgeo.Vector([1, 0, 0])
 69
 70        self.add_global_vectors("support_normal", "normal", "majoraxis")
 71        self.add_global_points("centre")
 72
 73        super().__init__()
 74
 75    def _get_intersection(self, Ray):
 76        """
 77        Return the intersection point between Ray and the xy-plane.
 78        If not in alignment mode, any intersection point that is on the support is blocked.
 79        """
 80        t = -Ray.point[2] / Ray.vector[2]
 81        I = mgeo.Point(Ray.point +Ray.vector * t)
 82        return I, I in self.support
 83    
 84    def _get_intersections(self, RayList):
 85        """
 86        Return the intersection point between Ray and the xy-plane.
 87        If not in alignment mode, any intersection point that is on the support is blocked.
 88        """
 89        vector = mgeo.VectorArray([ray.vector for ray in RayList])
 90        point = mgeo.PointArray([ray.point for ray in RayList])
 91        t = -point[:, 2] / vector[:, 2]
 92        I = mgeo.PointArray(point + vector * t[:, np.newaxis])
 93        return I, [not(i in self.support) for i in I]
 94
 95    def get_local_normal(self, Point):
 96        """Return normal unit vector in point 'Point' on the mask."""
 97        return np.array([0, 0, 1])
 98    
 99    def _zfunc(self, PointArray):
100        """Return the z-values of the plane surface at the points in PointArray."""
101        return np.zeros(len(PointArray))
102
103    def propagate_raylist(self, RayList, alignment=False):
104        """
105        Propagate a list of rays through the mask, returning the transmitted rays.
106
107        Parameters
108        ----------
109        RayList : list
110            List of Ray objects to be propagated through the mask.
111        alignment : bool, optional
112            If True, the alignment of the mask is considered. Default is False.
113
114        Returns
115        -------
116        list
117            List of transmitted Ray objects.
118        """
119        transmitted_rays = []
120        local_rays = [ray.to_basis(*self.basis) for ray in RayList]
121        intersection_points, OK = self._get_intersections(local_rays)
122        N = len(RayList)
123        for i in range(N):
124            # Then we find the intersection point in the mirror reference frame
125            intersection_point = intersection_points[i]
126            local_ray = local_rays[i]
127            if OK[i]:
128                local_transmittedray = copy(local_ray)
129                local_transmittedray.point = intersection_point
130                local_transmittedray.vector = local_ray.vector
131                local_transmittedray.incidence = mgeo.AngleBetweenTwoVectors(-local_ray.vector, self.normal_ref)
132                local_transmittedray.path = local_ray.path + (np.linalg.norm(intersection_point - local_ray.point),)
133                transmitted_rays.append(local_transmittedray.from_basis(*self.basis))
134        if len(transmitted_rays) == 0:
135            logger.warning("No rays were transmitted by the mask.")
136            logger.debug(f"Mask: {self}")
137            logger.debug(f"First ray: {RayList[0]}")
138            logger.debug(f"First ray in mask reference frame: {RayList[0].to_basis(self.r0, self.r, self.q)}")
139            logger.debug(f"First ray intersection point: {self._get_intersection(RayList[0].to_basis(self.r0, self.r, self.q))}")
140        return mray.RayList.from_list(transmitted_rays)
141
142
143# %%############################################################################
144def _TransmitMaskRay(Mask, PointMask, Ray):
145    """Returns the transmitted ray"""
146    PointRay = Ray.point
147    VectorRay = Ray.vector
148    NormalMask = Mask.get_local_normal(PointMask)
149
150    AngleIncidence = mgeo.AngleBetweenTwoVectors(VectorRay, NormalMask)
151    Path = Ray.path + (np.linalg.norm(PointMask - PointRay),)
152
153    RayTransmitted = Ray.copy_ray()
154    RayTransmitted.point = PointMask
155    RayTransmitted.vector = VectorRay
156    RayTransmitted.incidence = AngleIncidence
157    RayTransmitted.path = Path
158
159    return RayTransmitted
160
161
162# %%
163def TransmitMaskRayList(Mask, RayList):
164    """
165    Returns the the transmitted rays that pass the mask for the list of
166    incident rays ListRay.
167
168    Rays that hit the support are not further propagated.
169
170    Updates the reflected rays' incidence angle and path.
171
172    Parameters
173    ----------
174        Mask : Mask-object
175
176        ListRay : list[Ray-object]
177
178    """
179    ListRayTransmitted = []
180    for Ray in RayList:
181        PointMask = Mask._get_intersection(Ray)
182
183        if PointMask is not None:
184            RayTransmitted = _TransmitMaskRay(Mask, PointMask, Ray)
185            ListRayTransmitted.append(RayTransmitted)
186
187    return ListRayTransmitted
logger = <Logger ARTcore.ModuleMask (WARNING)>
 30class Mask(moe.OpticalElement):
 31    """
 32    A mask: a plane surface of the shape of its [Support](ModuleSupport.html), which stops all rays that hit it,
 33    while all other rays continue their path unchanged. No diffraction effects.
 34
 35    Attributes
 36    ----------
 37        support : [Support](ModuleSupport.html)-object
 38
 39        type : str 'Mask'.
 40
 41    Methods
 42    ----------
 43        get_local_normal(Point)
 44
 45        get_centre()
 46
 47        get_grid3D(NbPoints)
 48
 49    """
 50
 51    def __init__(self, Support, **kwargs):
 52        """
 53        Parameters
 54        ----------
 55            Support : [Support](ModuleSupport.html)-object
 56        """
 57        self.type = "Mask"
 58        self.support = Support
 59        self.curvature = mmirror.Curvature.FLAT
 60
 61        self.r0 = mgeo.Point([0.0, 0.0, 0.0])
 62        self._r = mgeo.Vector([0.0, 0.0, 0.0])
 63        self._q = np.quaternion(1)
 64
 65        self.centre_ref = mgeo.Point([0, 0, 0])
 66
 67        self.support_normal_ref = mgeo.Vector([0, 0, 1])
 68        self.normal_ref = mgeo.Vector([0, 0, 1])
 69        self.majoraxis_ref = mgeo.Vector([1, 0, 0])
 70
 71        self.add_global_vectors("support_normal", "normal", "majoraxis")
 72        self.add_global_points("centre")
 73
 74        super().__init__()
 75
 76    def _get_intersection(self, Ray):
 77        """
 78        Return the intersection point between Ray and the xy-plane.
 79        If not in alignment mode, any intersection point that is on the support is blocked.
 80        """
 81        t = -Ray.point[2] / Ray.vector[2]
 82        I = mgeo.Point(Ray.point +Ray.vector * t)
 83        return I, I in self.support
 84    
 85    def _get_intersections(self, RayList):
 86        """
 87        Return the intersection point between Ray and the xy-plane.
 88        If not in alignment mode, any intersection point that is on the support is blocked.
 89        """
 90        vector = mgeo.VectorArray([ray.vector for ray in RayList])
 91        point = mgeo.PointArray([ray.point for ray in RayList])
 92        t = -point[:, 2] / vector[:, 2]
 93        I = mgeo.PointArray(point + vector * t[:, np.newaxis])
 94        return I, [not(i in self.support) for i in I]
 95
 96    def get_local_normal(self, Point):
 97        """Return normal unit vector in point 'Point' on the mask."""
 98        return np.array([0, 0, 1])
 99    
100    def _zfunc(self, PointArray):
101        """Return the z-values of the plane surface at the points in PointArray."""
102        return np.zeros(len(PointArray))
103
104    def propagate_raylist(self, RayList, alignment=False):
105        """
106        Propagate a list of rays through the mask, returning the transmitted rays.
107
108        Parameters
109        ----------
110        RayList : list
111            List of Ray objects to be propagated through the mask.
112        alignment : bool, optional
113            If True, the alignment of the mask is considered. Default is False.
114
115        Returns
116        -------
117        list
118            List of transmitted Ray objects.
119        """
120        transmitted_rays = []
121        local_rays = [ray.to_basis(*self.basis) for ray in RayList]
122        intersection_points, OK = self._get_intersections(local_rays)
123        N = len(RayList)
124        for i in range(N):
125            # Then we find the intersection point in the mirror reference frame
126            intersection_point = intersection_points[i]
127            local_ray = local_rays[i]
128            if OK[i]:
129                local_transmittedray = copy(local_ray)
130                local_transmittedray.point = intersection_point
131                local_transmittedray.vector = local_ray.vector
132                local_transmittedray.incidence = mgeo.AngleBetweenTwoVectors(-local_ray.vector, self.normal_ref)
133                local_transmittedray.path = local_ray.path + (np.linalg.norm(intersection_point - local_ray.point),)
134                transmitted_rays.append(local_transmittedray.from_basis(*self.basis))
135        if len(transmitted_rays) == 0:
136            logger.warning("No rays were transmitted by the mask.")
137            logger.debug(f"Mask: {self}")
138            logger.debug(f"First ray: {RayList[0]}")
139            logger.debug(f"First ray in mask reference frame: {RayList[0].to_basis(self.r0, self.r, self.q)}")
140            logger.debug(f"First ray intersection point: {self._get_intersection(RayList[0].to_basis(self.r0, self.r, self.q))}")
141        return mray.RayList.from_list(transmitted_rays)

A mask: a plane surface of the shape of its Support, which stops all rays that hit it, while all other rays continue their path unchanged. No diffraction effects.

Attributes

support : [Support](ModuleSupport.html)-object

type : str 'Mask'.

Methods

get_local_normal(Point)

get_centre()

get_grid3D(NbPoints)
Mask(Support, **kwargs)
51    def __init__(self, Support, **kwargs):
52        """
53        Parameters
54        ----------
55            Support : [Support](ModuleSupport.html)-object
56        """
57        self.type = "Mask"
58        self.support = Support
59        self.curvature = mmirror.Curvature.FLAT
60
61        self.r0 = mgeo.Point([0.0, 0.0, 0.0])
62        self._r = mgeo.Vector([0.0, 0.0, 0.0])
63        self._q = np.quaternion(1)
64
65        self.centre_ref = mgeo.Point([0, 0, 0])
66
67        self.support_normal_ref = mgeo.Vector([0, 0, 1])
68        self.normal_ref = mgeo.Vector([0, 0, 1])
69        self.majoraxis_ref = mgeo.Vector([1, 0, 0])
70
71        self.add_global_vectors("support_normal", "normal", "majoraxis")
72        self.add_global_points("centre")
73
74        super().__init__()

Parameters

Support : [Support](ModuleSupport.html)-object
type
support
curvature
r0
centre_ref
support_normal_ref
normal_ref
majoraxis_ref
def get_local_normal(self, Point):
96    def get_local_normal(self, Point):
97        """Return normal unit vector in point 'Point' on the mask."""
98        return np.array([0, 0, 1])

Return normal unit vector in point 'Point' on the mask.

def propagate_raylist(self, RayList, alignment=False):
104    def propagate_raylist(self, RayList, alignment=False):
105        """
106        Propagate a list of rays through the mask, returning the transmitted rays.
107
108        Parameters
109        ----------
110        RayList : list
111            List of Ray objects to be propagated through the mask.
112        alignment : bool, optional
113            If True, the alignment of the mask is considered. Default is False.
114
115        Returns
116        -------
117        list
118            List of transmitted Ray objects.
119        """
120        transmitted_rays = []
121        local_rays = [ray.to_basis(*self.basis) for ray in RayList]
122        intersection_points, OK = self._get_intersections(local_rays)
123        N = len(RayList)
124        for i in range(N):
125            # Then we find the intersection point in the mirror reference frame
126            intersection_point = intersection_points[i]
127            local_ray = local_rays[i]
128            if OK[i]:
129                local_transmittedray = copy(local_ray)
130                local_transmittedray.point = intersection_point
131                local_transmittedray.vector = local_ray.vector
132                local_transmittedray.incidence = mgeo.AngleBetweenTwoVectors(-local_ray.vector, self.normal_ref)
133                local_transmittedray.path = local_ray.path + (np.linalg.norm(intersection_point - local_ray.point),)
134                transmitted_rays.append(local_transmittedray.from_basis(*self.basis))
135        if len(transmitted_rays) == 0:
136            logger.warning("No rays were transmitted by the mask.")
137            logger.debug(f"Mask: {self}")
138            logger.debug(f"First ray: {RayList[0]}")
139            logger.debug(f"First ray in mask reference frame: {RayList[0].to_basis(self.r0, self.r, self.q)}")
140            logger.debug(f"First ray intersection point: {self._get_intersection(RayList[0].to_basis(self.r0, self.r, self.q))}")
141        return mray.RayList.from_list(transmitted_rays)

Propagate a list of rays through the mask, returning the transmitted rays.

Parameters

RayList : list List of Ray objects to be propagated through the mask. alignment : bool, optional If True, the alignment of the mask is considered. Default is False.

Returns

list List of transmitted Ray objects.

def render( Mirror, Npoints=1000, draw_support=False, draw_points=False, draw_vectors=True, recenter_support=True):
234def _RenderMirror(Mirror, Npoints=1000, draw_support = False, draw_points = False, draw_vectors = True , recenter_support = True):
235    """
236    This function renders a mirror in 3D.
237    """
238    mesh = Mirror._Render(Npoints)
239    p = pv.Plotter()
240    p.add_mesh(mesh)
241    if draw_support:
242        support = Mirror.support._Render()
243        if recenter_support:
244            support.translate(Mirror.r0,inplace=True)
245        p.add_mesh(support, color="gray", opacity=0.5)
246    
247    if draw_vectors:
248        # We draw the important vectors of the optical element
249        # For that, if we have a "vectors" attribute, we use that
250        #  (a dictionary with the vector names as keys and the colors as values)
251        # Otherwise we use the default vectors: "support_normal", "majoraxis"
252        if hasattr(Mirror, "vectors"):
253            vectors = Mirror.vectors
254        else:
255            vectors = {"support_normal_ref": "red", "majoraxis_ref": "blue"}
256        for vector, color in vectors.items():
257            if hasattr(Mirror, vector):
258                p.add_arrows(Mirror.r0, 10*getattr(Mirror, vector), color=color)
259    
260    if draw_points:
261        # We draw the important points of the optical element
262        # For that, if we have a "points" attribute, we use that
263        #  (a dictionary with the point names as keys and the colors as values)
264        # Otherwise we use the default points: "centre_ref"
265        if hasattr(Mirror, "points"):
266            points = Mirror.points
267        else:
268            points = {"centre_ref": "red"}
269        for point, color in points.items():
270            if hasattr(Mirror, point):
271                p.add_mesh(pv.Sphere(radius=1, center=getattr(Mirror, point)), color=color)
272    else:
273        p.add_mesh(pv.Sphere(radius=1, center=Mirror.r0), color="red")
274    p.show()
275    return p

This function renders a mirror in 3D.

def TransmitMaskRayList(Mask, RayList):
164def TransmitMaskRayList(Mask, RayList):
165    """
166    Returns the the transmitted rays that pass the mask for the list of
167    incident rays ListRay.
168
169    Rays that hit the support are not further propagated.
170
171    Updates the reflected rays' incidence angle and path.
172
173    Parameters
174    ----------
175        Mask : Mask-object
176
177        ListRay : list[Ray-object]
178
179    """
180    ListRayTransmitted = []
181    for Ray in RayList:
182        PointMask = Mask._get_intersection(Ray)
183
184        if PointMask is not None:
185            RayTransmitted = _TransmitMaskRay(Mask, PointMask, Ray)
186            ListRayTransmitted.append(RayTransmitted)
187
188    return ListRayTransmitted

Returns the the transmitted rays that pass the mask for the list of incident rays ListRay.

Rays that hit the support are not further propagated.

Updates the reflected rays' incidence angle and path.

Parameters

Mask : Mask-object

ListRay : list[Ray-object]