ModuleMirror

class MirrorPlane:
 44class MirrorPlane:
 45    """
 46    A plane mirror.
 47
 48    Attributes
 49    ----------
 50        support : ART.ModuleSupport.Support
 51            Mirror support
 52        type : str = 'Plane Mirror'
 53            Human readable mirror type
 54    Methods
 55    -------
 56        MirrorPlane.get_normal(Point)
 57
 58        MirrorPlane.get_centre()
 59
 60        MirrorPlane.get_grid3D(NbPoints)
 61    """
 62
 63    def __init__(self, Support):
 64        """
 65        Create a plane mirror on a given Support.
 66
 67        Parameters
 68        ----------
 69            Support : ART.ModuleSupport.Support
 70
 71        """
 72        self.support = Support
 73        self.type = "Plane Mirror"
 74
 75    def _get_intersection(self, Ray):
 76        """Return the intersection point between Ray and the xy-plane."""
 77        t = -Ray.point[2] / Ray.vector[2]
 78        Intersect = Ray.vector * t + Ray.point
 79        if t > 0 and self.support._IncludeSupport(Intersect):
 80            PointIntersection = Ray.vector * t + Ray.point
 81        else:
 82            PointIntersection = None
 83
 84        return PointIntersection
 85
 86    def get_normal(self, Point: np.ndarray):
 87        """Return normal unit vector in point 'Point' on the plane mirror."""
 88        Normal = np.array([0, 0, 1])
 89        return Normal
 90
 91    def get_centre(self):
 92        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
 93        return np.array([0, 0, 0])
 94
 95    def get_grid3D(self, NbPoint: int, **kwargs):
 96        """
 97        Get grid of points on mirror surface.
 98
 99        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
100        sampling the support in a number NbPoints of points.
101        """
102        E = "edges" in kwargs and kwargs["edges"]
103        ListCoordXYZ = []
104        contour = int(round(0.1 * NbPoint))
105        contours = self.support._Contour_points(contour, **kwargs)
106        if E:
107            contours, contour_edges = contours
108        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
109        for k in ListCoordXY:
110            z = 0
111            ListCoordXYZ.append(np.array([k[0], k[1], z]))
112        if E:
113            return ListCoordXYZ, contour_edges
114
115        return ListCoordXYZ

A plane mirror.

Attributes

support : ART.ModuleSupport.Support
    Mirror support
type : str = 'Plane Mirror'
    Human readable mirror type

Methods

MirrorPlane.get_normal(Point)

MirrorPlane.get_centre()

MirrorPlane.get_grid3D(NbPoints)
MirrorPlane(Support)
63    def __init__(self, Support):
64        """
65        Create a plane mirror on a given Support.
66
67        Parameters
68        ----------
69            Support : ART.ModuleSupport.Support
70
71        """
72        self.support = Support
73        self.type = "Plane Mirror"

Create a plane mirror on a given Support.

Parameters

Support : ART.ModuleSupport.Support
def get_normal(self, Point: numpy.ndarray):
86    def get_normal(self, Point: np.ndarray):
87        """Return normal unit vector in point 'Point' on the plane mirror."""
88        Normal = np.array([0, 0, 1])
89        return Normal

Return normal unit vector in point 'Point' on the plane mirror.

def get_centre(self):
91    def get_centre(self):
92        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
93        return np.array([0, 0, 0])

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint: int, **kwargs):
 95    def get_grid3D(self, NbPoint: int, **kwargs):
 96        """
 97        Get grid of points on mirror surface.
 98
 99        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
100        sampling the support in a number NbPoints of points.
101        """
102        E = "edges" in kwargs and kwargs["edges"]
103        ListCoordXYZ = []
104        contour = int(round(0.1 * NbPoint))
105        contours = self.support._Contour_points(contour, **kwargs)
106        if E:
107            contours, contour_edges = contours
108        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
109        for k in ListCoordXY:
110            z = 0
111            ListCoordXYZ.append(np.array([k[0], k[1], z]))
112        if E:
113            return ListCoordXYZ, contour_edges
114
115        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

class MirrorSpherical:
119class MirrorSpherical:
120    """
121    Spherical mirror surface with eqn. $x^2 + y^2 + z^2  = R^2$, where $R$ is the radius.
122
123    ![Illustration of a spherical mirror.](sphericalmirror.svg)
124
125    Attributes
126    ----------
127        radius : float
128            Radius of curvature. A postive value for concave mirror, a negative value for a convex mirror.
129
130        support : ART.ModuleSupport.Support
131
132        type : str SphericalCC Mirror' or SphericalCX Mirror'
133
134    Methods
135    -------
136        MirrorSpherical.get_normal(Point)
137
138        MirrorSpherical.get_centre()
139
140        MirrorSpherical.get_grid3D(NbPoints)
141
142    """
143
144    def __init__(self, Radius, Support):
145        """
146        Construct a spherical mirror.
147
148        Parameters
149        ----------
150            Radius : float
151                The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.
152
153            Support : ART.ModuleSupport.Support
154
155        """
156        if Radius < 0:
157            self.type = "SphericalCX Mirror"
158            self.radius = -Radius
159        else:
160            self.type = "SphericalCC Mirror"
161            self.radius = Radius
162
163        self.support = Support
164
165    def _get_intersection(self, Ray):
166        """Return the intersection point between the ray and the sphere."""
167        a = np.dot(Ray.vector, Ray.vector)
168        b = 2 * np.dot(Ray.vector, Ray.point)
169        c = np.dot(Ray.point, Ray.point) - self.radius**2
170
171        Solution = mgeo.SolverQuadratic(a, b, c)
172        Solution = mgeo.KeepPositiveSolution(Solution)
173
174        ListPointIntersection = []
175        for t in Solution:
176            Intersect = Ray.vector * t + Ray.point
177            if Intersect[2] < 0 and self.support._IncludeSupport(Intersect):
178                ListPointIntersection.append(Intersect)
179
180        return _IntersectionRayMirror(Ray.point, ListPointIntersection)
181
182    def get_normal(self, Point):
183        """Return the normal unit vector on the spherical surface at point Point."""
184        Gradient = Point
185        return mgeo.Normalize(-Gradient)
186
187    def get_centre(self):
188        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
189        return np.array([0, 0, -self.radius])
190
191    def get_grid3D(self, NbPoint, **kwargs):
192        """
193        Get grid of points on mirror surface.
194
195        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
196        sampling the support in a number NbPoints of points.
197        """
198        E = "edges" in kwargs and kwargs["edges"]
199        ListCoordXYZ = []
200        contour = int(round(0.1 * NbPoint))
201        contours = self.support._Contour_points(contour, **kwargs)
202        if E:
203            contours, contour_edges = contours
204        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
205        for k in ListCoordXY:
206            z = -np.sqrt(self.radius**2 - (k[0] ** 2 + k[1] ** 2))
207            ListCoordXYZ.append(np.array([k[0], k[1], z]))
208        if E:
209            return ListCoordXYZ, contour_edges
210        return ListCoordXYZ

Spherical mirror surface with eqn. $x^2 + y^2 + z^2 = R^2$, where $R$ is the radius.

Illustration of a spherical mirror.

Attributes

radius : float
    Radius of curvature. A postive value for concave mirror, a negative value for a convex mirror.

support : ART.ModuleSupport.Support

type : str SphericalCC Mirror' or SphericalCX Mirror'

Methods

MirrorSpherical.get_normal(Point)

MirrorSpherical.get_centre()

MirrorSpherical.get_grid3D(NbPoints)
MirrorSpherical(Radius, Support)
144    def __init__(self, Radius, Support):
145        """
146        Construct a spherical mirror.
147
148        Parameters
149        ----------
150            Radius : float
151                The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.
152
153            Support : ART.ModuleSupport.Support
154
155        """
156        if Radius < 0:
157            self.type = "SphericalCX Mirror"
158            self.radius = -Radius
159        else:
160            self.type = "SphericalCC Mirror"
161            self.radius = Radius
162
163        self.support = Support

Construct a spherical mirror.

Parameters

Radius : float
    The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.

Support : ART.ModuleSupport.Support
def get_normal(self, Point):
182    def get_normal(self, Point):
183        """Return the normal unit vector on the spherical surface at point Point."""
184        Gradient = Point
185        return mgeo.Normalize(-Gradient)

Return the normal unit vector on the spherical surface at point Point.

def get_centre(self):
187    def get_centre(self):
188        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
189        return np.array([0, 0, -self.radius])

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint, **kwargs):
191    def get_grid3D(self, NbPoint, **kwargs):
192        """
193        Get grid of points on mirror surface.
194
195        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
196        sampling the support in a number NbPoints of points.
197        """
198        E = "edges" in kwargs and kwargs["edges"]
199        ListCoordXYZ = []
200        contour = int(round(0.1 * NbPoint))
201        contours = self.support._Contour_points(contour, **kwargs)
202        if E:
203            contours, contour_edges = contours
204        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
205        for k in ListCoordXY:
206            z = -np.sqrt(self.radius**2 - (k[0] ** 2 + k[1] ** 2))
207            ListCoordXYZ.append(np.array([k[0], k[1], z]))
208        if E:
209            return ListCoordXYZ, contour_edges
210        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

class MirrorParabolic:
214class MirrorParabolic:
215    r"""
216    Parabolic mirror.
217
218    A paraboloid with vertex at the origin [0,0,0] and symmetry axis z,
219    with the center of the support shifted off axis along the x-direction.
220    Its eqn. is therefore $z = \frac{1}{2p}[(x+x_c)^2 + y^2]$ where $p$ is the semi latus rectum,
221    equal to twice the focal lenght of the *mother* parabola (i.e. off-axis angle $\alpha=0$).
222
223    The effective focal length $f_\mathrm{eff}$ is related to the semi latus rectum by
224    $ p = f_\mathrm{eff} (1+\cos\alpha)$, where $\alpha$ is the off-axis angle.
225
226    ![Illustration of a parabolic mirror.](parabola.svg)
227
228    Attributes
229    ----------
230        offaxisangle : float
231            Off-axis angle of the parabola. Modifying this also updates p, keeping feff constant.
232            Attention: The off-axis angle must be *given in degrees*, but is stored and will be *returned in radian* !
233
234        feff : float
235            Effective focal length of the parabola in mm. Modifying this also updates p, keeping offaxisangle constant.
236
237        p : float
238            Semi latus rectum of the parabola in mm. Modifying this also updates feff, keeping offaxisangle constant.
239
240        support : ART.ModuleSupport.Support
241
242        type : str 'Parabolic Mirror'.
243
244    Methods
245    -------
246        MirrorParabolic.get_normal(Point)
247
248        MirrorParabolic.get_centre()
249
250        MirrorParabolic.get_grid3D(NbPoints)
251
252    """
253
254    def __init__(self, FocalEffective: float, OffAxisAngle: float, Support):
255        """
256        Initialise an Parabolic mirror.
257
258        Parameters
259        ----------
260            FocalEffective : float
261                Effective focal length of the parabola in mm.
262
263            OffAxisAngle : float
264                Off-axis angle *in degrees* of the parabola.
265
266            Support : ART.ModuleSupport.Support
267
268        """
269        self._offaxisangle = np.deg2rad(OffAxisAngle)
270        self.support = Support
271        self.type = "Parabolic Mirror"
272        self._feff = FocalEffective  # effective focal length
273        self._p = FocalEffective * (
274            1 + np.cos(self.offaxisangle)
275        )  # semi latus rectum
276
277    @property
278    def offaxisangle(self):
279        """Return off-axis angle of parabolic mirror."""
280        return self._offaxisangle
281
282    @offaxisangle.setter
283    def offaxisangle(self, OffAxisAngle):
284        self._offaxisangle = np.deg2rad(OffAxisAngle)
285        self._p = self._feff * (
286            1 + np.cos(self._offaxisangle)
287        )  # make sure to always update p
288
289    @property
290    def feff(self):
291        """Get effective focal length."""
292        return self._feff
293
294    @feff.setter
295    def feff(self, FocalEffective):
296        self._feff = FocalEffective
297        self._p = self._feff * (
298            1 + np.cos(self._offaxisangle)
299        )  # make sure to always update p
300
301    @property
302    def p(self):
303        """Get simi-latus-rectum."""
304        return self._p
305
306    @p.setter
307    def p(self, SemiLatusRectum):
308        self._p = SemiLatusRectum
309        self._feff = self._p / (
310            1 + np.cos(self._offaxisangle)
311        )  # make sure to always update feff
312
313    def _get_intersection(self, Ray):
314        """Return the intersection point between the ray and the parabola."""
315        ux = Ray.vector[0]
316        uy = Ray.vector[1]
317        uz = Ray.vector[2]
318        xA = Ray.point[0]
319        yA = Ray.point[1]
320        zA = Ray.point[2]
321
322        da = ux**2 + uy**2
323        db = 2 * (ux * xA + uy * yA) - 2 * self._p * uz
324        dc = xA**2 + yA**2 - 2 * self._p * zA
325
326        Solution = mgeo.SolverQuadratic(da, db, dc)
327        Solution = mgeo.KeepPositiveSolution(Solution)
328
329        ListPointIntersection = []
330        for t in Solution:
331            Intersect = Ray.vector * t + Ray.point
332            if self.support._IncludeSupport(Intersect - self.get_centre()):
333                ListPointIntersection.append(Intersect)
334
335        return _IntersectionRayMirror(Ray.point, ListPointIntersection)
336
337    def get_normal(self, Point):
338        """Return the normal unit vector on the paraboloid surface at point Point."""
339        Gradient = np.zeros(3)
340        Gradient[0] = -Point[0]
341        Gradient[1] = -Point[1]
342        Gradient[2] = self._p
343        return mgeo.Normalize(Gradient)
344
345    def get_centre(self):
346        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
347        return np.array(
348            [
349                self.feff * np.sin(self.offaxisangle),
350                0,
351                self._p * 0.5 - self.feff * np.cos(self.offaxisangle),
352            ]
353        )
354
355    def get_grid3D(self, NbPoint, **kwargs):
356        """
357        Get grid of points on mirror surface.
358
359        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
360        sampling the support in a number NbPoints of points.
361        """
362        E = "edges" in kwargs and kwargs["edges"]
363        ListCoordXYZ = []
364        contour = int(round(0.1 * NbPoint))
365        contours = self.support._Contour_points(contour, **kwargs)
366        if E:
367            contours, contour_edges = contours
368        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
369        xc = self.feff * np.sin(self.offaxisangle)
370        for k in ListCoordXY:
371            z = ((k[0] + xc) ** 2 + k[1] ** 2) / 2 / self._p
372            ListCoordXYZ.append(np.array([k[0] + xc, k[1], z]))
373        if E:
374            return ListCoordXYZ, contour_edges
375        return ListCoordXYZ

Parabolic mirror.

A paraboloid with vertex at the origin [0,0,0] and symmetry axis z, with the center of the support shifted off axis along the x-direction. Its eqn. is therefore $z = \frac{1}{2p}[(x+x_c)^2 + y^2]$ where $p$ is the semi latus rectum, equal to twice the focal lenght of the mother parabola (i.e. off-axis angle $\alpha=0$).

The effective focal length $f_\mathrm{eff}$ is related to the semi latus rectum by $ p = f_\mathrm{eff} (1+\cos\alpha)$, where $\alpha$ is the off-axis angle.

Illustration of a parabolic mirror.

Attributes

offaxisangle : float
    Off-axis angle of the parabola. Modifying this also updates p, keeping feff constant.
    Attention: The off-axis angle must be *given in degrees*, but is stored and will be *returned in radian* !

feff : float
    Effective focal length of the parabola in mm. Modifying this also updates p, keeping offaxisangle constant.

p : float
    Semi latus rectum of the parabola in mm. Modifying this also updates feff, keeping offaxisangle constant.

support : ART.ModuleSupport.Support

type : str 'Parabolic Mirror'.

Methods

MirrorParabolic.get_normal(Point)

MirrorParabolic.get_centre()

MirrorParabolic.get_grid3D(NbPoints)
MirrorParabolic(FocalEffective: float, OffAxisAngle: float, Support)
254    def __init__(self, FocalEffective: float, OffAxisAngle: float, Support):
255        """
256        Initialise an Parabolic mirror.
257
258        Parameters
259        ----------
260            FocalEffective : float
261                Effective focal length of the parabola in mm.
262
263            OffAxisAngle : float
264                Off-axis angle *in degrees* of the parabola.
265
266            Support : ART.ModuleSupport.Support
267
268        """
269        self._offaxisangle = np.deg2rad(OffAxisAngle)
270        self.support = Support
271        self.type = "Parabolic Mirror"
272        self._feff = FocalEffective  # effective focal length
273        self._p = FocalEffective * (
274            1 + np.cos(self.offaxisangle)
275        )  # semi latus rectum

Initialise an Parabolic mirror.

Parameters

FocalEffective : float
    Effective focal length of the parabola in mm.

OffAxisAngle : float
    Off-axis angle *in degrees* of the parabola.

Support : ART.ModuleSupport.Support
offaxisangle

Return off-axis angle of parabolic mirror.

feff

Get effective focal length.

p

Get simi-latus-rectum.

def get_normal(self, Point):
337    def get_normal(self, Point):
338        """Return the normal unit vector on the paraboloid surface at point Point."""
339        Gradient = np.zeros(3)
340        Gradient[0] = -Point[0]
341        Gradient[1] = -Point[1]
342        Gradient[2] = self._p
343        return mgeo.Normalize(Gradient)

Return the normal unit vector on the paraboloid surface at point Point.

def get_centre(self):
345    def get_centre(self):
346        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
347        return np.array(
348            [
349                self.feff * np.sin(self.offaxisangle),
350                0,
351                self._p * 0.5 - self.feff * np.cos(self.offaxisangle),
352            ]
353        )

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint, **kwargs):
355    def get_grid3D(self, NbPoint, **kwargs):
356        """
357        Get grid of points on mirror surface.
358
359        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
360        sampling the support in a number NbPoints of points.
361        """
362        E = "edges" in kwargs and kwargs["edges"]
363        ListCoordXYZ = []
364        contour = int(round(0.1 * NbPoint))
365        contours = self.support._Contour_points(contour, **kwargs)
366        if E:
367            contours, contour_edges = contours
368        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
369        xc = self.feff * np.sin(self.offaxisangle)
370        for k in ListCoordXY:
371            z = ((k[0] + xc) ** 2 + k[1] ** 2) / 2 / self._p
372            ListCoordXYZ.append(np.array([k[0] + xc, k[1], z]))
373        if E:
374            return ListCoordXYZ, contour_edges
375        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

class MirrorToroidal:
379class MirrorToroidal:
380    r"""
381    Toroidal mirror surface with eqn.$(\sqrt{x^2+z^2}-R)^2 + y^2 = r^2$ where $R$ and $r$ the major and minor radii.
382
383    ![Illustration of a toroidal mirror.](toroidal.svg)
384
385    Attributes
386    ----------
387        majorradius : float
388            Major radius of the toroid in mm.
389
390        minorradius : float
391            Minor radius of the toroid in mm.
392
393        support : ART.ModuleSupport.Support
394
395        type : str 'Toroidal Mirror'.
396
397    Methods
398    -------
399        MirrorToroidal.get_normal(Point)
400
401        MirrorToroidal.get_centre()
402
403        MirrorToroidal.get_grid3D(NbPoints)
404
405    """
406
407    def __init__(self, MajorRadius, MinorRadius, Support):
408        """
409        Construct a toroidal mirror.
410
411        Parameters
412        ----------
413            MajorRadius : float
414                Major radius of the toroid in mm.
415
416            MinorRadius : float
417                Minor radius of the toroid in mm.
418
419            Support : ART.ModuleSupport.Support
420
421        """
422        self.majorradius = MajorRadius
423        self.minorradius = MinorRadius
424        self.support = Support
425        self.type = "Toroidal Mirror"
426
427    def _get_intersection(self, Ray):
428        """Return the intersection point between Ray and the toroidal mirror surface."""
429        ux = Ray.vector[0]
430        uz = Ray.vector[2]
431        xA = Ray.point[0]
432        zA = Ray.point[2]
433
434        G = 4.0 * self.majorradius**2 * (ux**2 + uz**2)
435        H = 8.0 * self.majorradius**2 * (ux * xA + uz * zA)
436        I = 4.0 * self.majorradius**2 * (xA**2 + zA**2)
437        J = np.dot(Ray.vector, Ray.vector)
438        K = 2.0 * np.dot(Ray.vector, Ray.point)
439        L = (
440            np.dot(Ray.point, Ray.point)
441            + self.majorradius**2
442            - self.minorradius**2
443        )
444
445        a = J**2
446        b = 2 * J * K
447        c = 2 * J * L + K**2 - G
448        d = 2 * K * L - H
449        e = L**2 - I
450
451        Solution = mgeo.SolverQuartic(a, b, c, d, e)
452        Solution = mgeo.KeepPositiveSolution(Solution)
453
454        ListPointIntersection = []
455        for t in Solution:
456            Intersect = Ray.vector * t + Ray.point
457            if Intersect[2] < -self.majorradius and self.support._IncludeSupport(
458                Intersect
459            ):  # For realistic mirror
460                ListPointIntersection.append(Intersect)
461
462        return _IntersectionRayMirror(Ray.point, ListPointIntersection)
463
464    def get_normal(self, Point):
465        """Return the normal unit vector on the toroidal surface at point Point."""
466        x = Point[0]
467        y = Point[1]
468        z = Point[2]
469        A = self.majorradius**2 - self.minorradius**2
470
471        Gradient = np.zeros(3)
472        Gradient[0] = (
473            4 * (x**3 + x * y**2 + x * z**2 + x * A)
474            - 8 * x * self.majorradius**2
475        )
476        Gradient[1] = 4 * (y**3 + y * x**2 + y * z**2 + y * A)
477        Gradient[2] = (
478            4 * (z**3 + z * x**2 + z * y**2 + z * A)
479            - 8 * z * self.majorradius**2
480        )
481
482        return mgeo.Normalize(-Gradient)
483
484    def get_centre(self):
485        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
486        return np.array([0, 0, -self.majorradius - self.minorradius])
487
488    def get_grid3D(self, NbPoint, **kwargs):
489        """
490        Get grid of points on mirror surface.
491
492        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
493        sampling the support in a number NbPoints of points.
494        """
495        E = "edges" in kwargs and kwargs["edges"]
496        ListCoordXYZ = []
497        contour = int(round(0.1 * NbPoint))
498        contours = self.support._Contour_points(contour, **kwargs)
499        if E:
500            contours, contour_edges = contours
501        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
502        for k in ListCoordXY:
503            z = -np.sqrt(
504                (np.sqrt(self.minorradius**2 - k[1] ** 2) + self.majorradius)
505                ** 2
506                - k[0] ** 2
507            )
508            ListCoordXYZ.append(np.array([k[0], k[1], z]))
509        if E:
510            return ListCoordXYZ, contour_edges
511        return ListCoordXYZ

Toroidal mirror surface with eqn.$(\sqrt{x^2+z^2}-R)^2 + y^2 = r^2$ where $R$ and $r$ the major and minor radii.

Illustration of a toroidal mirror.

Attributes

majorradius : float
    Major radius of the toroid in mm.

minorradius : float
    Minor radius of the toroid in mm.

support : ART.ModuleSupport.Support

type : str 'Toroidal Mirror'.

Methods

MirrorToroidal.get_normal(Point)

MirrorToroidal.get_centre()

MirrorToroidal.get_grid3D(NbPoints)
MirrorToroidal(MajorRadius, MinorRadius, Support)
407    def __init__(self, MajorRadius, MinorRadius, Support):
408        """
409        Construct a toroidal mirror.
410
411        Parameters
412        ----------
413            MajorRadius : float
414                Major radius of the toroid in mm.
415
416            MinorRadius : float
417                Minor radius of the toroid in mm.
418
419            Support : ART.ModuleSupport.Support
420
421        """
422        self.majorradius = MajorRadius
423        self.minorradius = MinorRadius
424        self.support = Support
425        self.type = "Toroidal Mirror"

Construct a toroidal mirror.

Parameters

MajorRadius : float
    Major radius of the toroid in mm.

MinorRadius : float
    Minor radius of the toroid in mm.

Support : ART.ModuleSupport.Support
def get_normal(self, Point):
464    def get_normal(self, Point):
465        """Return the normal unit vector on the toroidal surface at point Point."""
466        x = Point[0]
467        y = Point[1]
468        z = Point[2]
469        A = self.majorradius**2 - self.minorradius**2
470
471        Gradient = np.zeros(3)
472        Gradient[0] = (
473            4 * (x**3 + x * y**2 + x * z**2 + x * A)
474            - 8 * x * self.majorradius**2
475        )
476        Gradient[1] = 4 * (y**3 + y * x**2 + y * z**2 + y * A)
477        Gradient[2] = (
478            4 * (z**3 + z * x**2 + z * y**2 + z * A)
479            - 8 * z * self.majorradius**2
480        )
481
482        return mgeo.Normalize(-Gradient)

Return the normal unit vector on the toroidal surface at point Point.

def get_centre(self):
484    def get_centre(self):
485        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
486        return np.array([0, 0, -self.majorradius - self.minorradius])

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint, **kwargs):
488    def get_grid3D(self, NbPoint, **kwargs):
489        """
490        Get grid of points on mirror surface.
491
492        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
493        sampling the support in a number NbPoints of points.
494        """
495        E = "edges" in kwargs and kwargs["edges"]
496        ListCoordXYZ = []
497        contour = int(round(0.1 * NbPoint))
498        contours = self.support._Contour_points(contour, **kwargs)
499        if E:
500            contours, contour_edges = contours
501        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
502        for k in ListCoordXY:
503            z = -np.sqrt(
504                (np.sqrt(self.minorradius**2 - k[1] ** 2) + self.majorradius)
505                ** 2
506                - k[0] ** 2
507            )
508            ListCoordXYZ.append(np.array([k[0], k[1], z]))
509        if E:
510            return ListCoordXYZ, contour_edges
511        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

def ReturnOptimalToroidalRadii( Focal: float, AngleIncidence: float) -> (<class 'float'>, <class 'float'>):
517def ReturnOptimalToroidalRadii(
518    Focal: float, AngleIncidence: float
519) -> (float, float):
520    """
521    Get optimal parameters for a toroidal mirror.
522
523    Useful helper function to get the optimal major and minor radii for a toroidal mirror to achieve a
524    focal length 'Focal' with an angle of incidence 'AngleIncidence' and with vanishing astigmatism.
525
526    Parameters
527    ----------
528        Focal : float
529            Focal length in mm.
530
531        AngleIncidence : int
532            Angle of incidence in degrees.
533
534    Returns
535    -------
536        OptimalMajorRadius, OptimalMinorRadius : float, float.
537    """
538    AngleIncidenceRadian = AngleIncidence * np.pi / 180
539    OptimalMajorRadius = (
540        2
541        * Focal
542        * (1 / np.cos(AngleIncidenceRadian) - np.cos(AngleIncidenceRadian))
543    )
544    OptimalMinorRadius = 2 * Focal * np.cos(AngleIncidenceRadian)
545    return OptimalMajorRadius, OptimalMinorRadius

Get optimal parameters for a toroidal mirror.

Useful helper function to get the optimal major and minor radii for a toroidal mirror to achieve a focal length 'Focal' with an angle of incidence 'AngleIncidence' and with vanishing astigmatism.

Parameters

Focal : float
    Focal length in mm.

AngleIncidence : int
    Angle of incidence in degrees.

Returns

OptimalMajorRadius, OptimalMinorRadius : float, float.
class MirrorEllipsoidal:
549class MirrorEllipsoidal:
550    """
551    Ellipdoidal mirror surface with eqn. $(x/a)^2 + (y/b)^2 + (z/b)^2 = 1$, where $a$ and $b$ are semi major and semi minor axes.
552
553    ![Illustration of a ellipsoidal mirror.](ellipsoid.svg)
554
555    Attributes
556    ----------
557        a : float
558            Semi major axis of the ellipsoid in mm.
559
560        b : float
561            Semi minor axis of the ellipsoid in mm.
562
563        support : ART.ModuleSupport.Support
564
565        type : str 'Ellipsoidal Mirror'.
566
567    Methods
568    -------
569        MirrorEllipsoidal.get_normal(Point)
570
571        MirrorEllipsoidal.get_centre()
572
573        MirrorEllipsoidal.get_grid3D(NbPoints)
574
575    """
576
577    def __init__(
578        self,
579        Support,
580        SemiMajorAxis=None,
581        SemiMinorAxis=None,
582        OffAxisAngle=None,
583        f_object=None,
584        f_image=None,
585    ):
586        """
587        Generate an ellipsoidal mirror with given parameters.
588
589        Depending on the parameters provided by the vendor, you can either specify:
590            - the Semi Major and Semi Minor axes (default)
591            - The object and image distances
592        You can also specify the Off-Axis angle in degrees. Keep in mind that its value will be stored and returned in radian.
593
594        Parameters
595        ----------
596        Support : TYPE
597            ART.ModuleSupport.Support.
598        SemiMajorAxis : float
599            Semi major axis of the ellipsoid in mm..
600        SemiMinorAxis : float
601            Semi minor axis of the ellipsoid in mm..
602        OffAxisAngle : float
603            Off-axis angle of the mirror in mm. Defined as the angle at the centre of the mirror between the two foci..
604        f_object : float
605            Object focal distance in mm.
606        f_image : float
607            Image focal distance in mm.
608        """
609        self.type = "Ellipsoidal Mirror"
610        self.support = Support
611        self.a = None
612        self.b = None
613        self._offaxisangle = None
614        if SemiMajorAxis is not None and SemiMinorAxis is not None:
615            self.a = SemiMajorAxis
616            self.b = SemiMinorAxis
617        if OffAxisAngle is not None:
618            self._offaxisangle = np.deg2rad(OffAxisAngle)
619            if f_object is not None and f_image is not None:
620                f_o = f_object
621                f_i = f_image
622                foci_sq = (
623                    f_o**2
624                    + f_i**2
625                    - 2 * f_o * f_i * np.cos(self._offaxisangle)
626                )
627                self.a = (f_i + f_o) / 2
628                self.b = np.sqrt(self.a**2 - foci_sq / 4)
629        else:
630            if f_object is not None and f_image is not None:
631                f_o = f_object
632                f_i = f_image
633                if self.a is not None and self.b is not None:
634                    foci = 2 * np.sqrt(self.a**2 - self.b**2)
635                    self._offaxisangle = np.arccos(
636                        (f_i**2 + f_o**2 - foci**2) / (2 * f_i * f_o)
637                    )
638
639            elif self.a is not None and self.b is not None:
640                foci = 2 * np.sqrt(self.a**2 - self.b**2)
641                f = self.a
642                self._offaxisangle = np.arccos(1 - foci**2 / (2 * f**2))
643        if self.a is None or self.b is None or self._offaxisangle is None:
644            raise ValueError("Invalid mirror parameters")
645
646    def _get_intersection(self, Ray):
647        """Return the intersection point between Ray and the ellipsoidal mirror surface."""
648        ux, uy, uz = Ray.vector
649        xA, yA, zA = Ray.point
650
651        da = (uy**2 + uz**2) / self.b**2 + (ux / self.a) ** 2
652        db = 2 * ((uy * yA + uz * zA) / self.b**2 + (ux * xA) / self.a**2)
653        dc = (yA**2 + zA**2) / self.b**2 + (xA / self.a) ** 2 - 1
654
655        Solution = mgeo.SolverQuadratic(da, db, dc)
656        Solution = mgeo.KeepPositiveSolution(Solution)
657
658        ListPointIntersection = []
659        C = self.get_centre()
660        for t in Solution:
661            Intersect = Ray.vector * t + Ray.point
662            if Intersect[2] < 0 and self.support._IncludeSupport(
663                Intersect - C
664            ):
665                ListPointIntersection.append(Intersect)
666
667        return _IntersectionRayMirror(Ray.point, ListPointIntersection)
668
669    def get_normal(self, Point):
670        """Return the normal unit vector on the ellipsoidal surface at point Point."""
671        Gradient = np.zeros(3)
672
673        Gradient[0] = -Point[0] / self.a**2
674        Gradient[1] = -Point[1] / self.b**2
675        Gradient[2] = -Point[2] / self.b**2
676
677        return mgeo.Normalize(Gradient)
678
679    def get_centre(self):
680        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
681        foci = 2 * np.sqrt(self.a**2 - self.b**2)
682        h = -foci / 2 / np.tan(self._offaxisangle)
683        R = np.sqrt(foci**2 / 4 + h**2)
684        sign = 1
685        if math.isclose(self._offaxisangle, np.pi / 2):
686            h = 0
687        elif self._offaxisangle > np.pi / 2:
688            h = -h
689            sign = -1
690        a = 1 - self.a**2 / self.b**2
691        b = -2 * h
692        c = self.a**2 + h**2 - R**2
693        z = (-b + sign * np.sqrt(b**2 - 4 * a * c)) / (2 * a)
694        if math.isclose(z**2, self.b**2):
695            return np.array([0, 0, -self.b])
696        x = self.a * np.sqrt(1 - z**2 / self.b**2)
697        centre = np.array([x, 0, sign * z])
698        return centre
699
700    def get_grid3D(self, NbPoint, **kwargs):
701        """
702        Get grid of points on mirror surface.
703
704        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
705        sampling the support in a number NbPoints of points.
706        """
707        E = "edges" in kwargs and kwargs["edges"]
708        ListCoordXYZ = []
709        contour = int(round(0.1 * NbPoint))
710        contours = self.support._Contour_points(contour, **kwargs)
711        if E:
712            contours, contour_edges = contours
713        ListCoordXY = self.support._get_grid(NbPoint - contour)
714        centre = self.get_centre()
715        for i, k in enumerate(ListCoordXY):
716            x = k[0] + centre[0]
717            y = k[1]
718            sideways = (x / self.a) ** 2 + (y / self.b) ** 2
719            if sideways <= 1:
720                z = -self.b * np.sqrt(1 - sideways)
721                ListCoordXYZ.append(np.array([x, y, z]))
722        new_contour_edges = []
723        for j in contour_edges:
724            new_contour_edges += [[]]
725            for i in j:
726                x = contours[i][0] + centre[0]
727                y = contours[i][1]
728                sideways = (x / self.a) ** 2 + (y / self.b) ** 2
729                if sideways <= 1:
730                    z = -self.b * np.sqrt(1 - sideways)
731                    ListCoordXYZ.append(np.array([x, y, z]))
732                    new_contour_edges[-1] += [len(ListCoordXYZ) - 1]
733        if E:
734            return ListCoordXYZ, new_contour_edges
735        return ListCoordXYZ

Ellipdoidal mirror surface with eqn. $(x/a)^2 + (y/b)^2 + (z/b)^2 = 1$, where $a$ and $b$ are semi major and semi minor axes.

Illustration of a ellipsoidal mirror.

Attributes

a : float
    Semi major axis of the ellipsoid in mm.

b : float
    Semi minor axis of the ellipsoid in mm.

support : ART.ModuleSupport.Support

type : str 'Ellipsoidal Mirror'.

Methods

MirrorEllipsoidal.get_normal(Point)

MirrorEllipsoidal.get_centre()

MirrorEllipsoidal.get_grid3D(NbPoints)
MirrorEllipsoidal( Support, SemiMajorAxis=None, SemiMinorAxis=None, OffAxisAngle=None, f_object=None, f_image=None)
577    def __init__(
578        self,
579        Support,
580        SemiMajorAxis=None,
581        SemiMinorAxis=None,
582        OffAxisAngle=None,
583        f_object=None,
584        f_image=None,
585    ):
586        """
587        Generate an ellipsoidal mirror with given parameters.
588
589        Depending on the parameters provided by the vendor, you can either specify:
590            - the Semi Major and Semi Minor axes (default)
591            - The object and image distances
592        You can also specify the Off-Axis angle in degrees. Keep in mind that its value will be stored and returned in radian.
593
594        Parameters
595        ----------
596        Support : TYPE
597            ART.ModuleSupport.Support.
598        SemiMajorAxis : float
599            Semi major axis of the ellipsoid in mm..
600        SemiMinorAxis : float
601            Semi minor axis of the ellipsoid in mm..
602        OffAxisAngle : float
603            Off-axis angle of the mirror in mm. Defined as the angle at the centre of the mirror between the two foci..
604        f_object : float
605            Object focal distance in mm.
606        f_image : float
607            Image focal distance in mm.
608        """
609        self.type = "Ellipsoidal Mirror"
610        self.support = Support
611        self.a = None
612        self.b = None
613        self._offaxisangle = None
614        if SemiMajorAxis is not None and SemiMinorAxis is not None:
615            self.a = SemiMajorAxis
616            self.b = SemiMinorAxis
617        if OffAxisAngle is not None:
618            self._offaxisangle = np.deg2rad(OffAxisAngle)
619            if f_object is not None and f_image is not None:
620                f_o = f_object
621                f_i = f_image
622                foci_sq = (
623                    f_o**2
624                    + f_i**2
625                    - 2 * f_o * f_i * np.cos(self._offaxisangle)
626                )
627                self.a = (f_i + f_o) / 2
628                self.b = np.sqrt(self.a**2 - foci_sq / 4)
629        else:
630            if f_object is not None and f_image is not None:
631                f_o = f_object
632                f_i = f_image
633                if self.a is not None and self.b is not None:
634                    foci = 2 * np.sqrt(self.a**2 - self.b**2)
635                    self._offaxisangle = np.arccos(
636                        (f_i**2 + f_o**2 - foci**2) / (2 * f_i * f_o)
637                    )
638
639            elif self.a is not None and self.b is not None:
640                foci = 2 * np.sqrt(self.a**2 - self.b**2)
641                f = self.a
642                self._offaxisangle = np.arccos(1 - foci**2 / (2 * f**2))
643        if self.a is None or self.b is None or self._offaxisangle is None:
644            raise ValueError("Invalid mirror parameters")

Generate an ellipsoidal mirror with given parameters.

Depending on the parameters provided by the vendor, you can either specify: - the Semi Major and Semi Minor axes (default) - The object and image distances You can also specify the Off-Axis angle in degrees. Keep in mind that its value will be stored and returned in radian.

Parameters

Support : TYPE ART.ModuleSupport.Support. SemiMajorAxis : float Semi major axis of the ellipsoid in mm.. SemiMinorAxis : float Semi minor axis of the ellipsoid in mm.. OffAxisAngle : float Off-axis angle of the mirror in mm. Defined as the angle at the centre of the mirror between the two foci.. f_object : float Object focal distance in mm. f_image : float Image focal distance in mm.

def get_normal(self, Point):
669    def get_normal(self, Point):
670        """Return the normal unit vector on the ellipsoidal surface at point Point."""
671        Gradient = np.zeros(3)
672
673        Gradient[0] = -Point[0] / self.a**2
674        Gradient[1] = -Point[1] / self.b**2
675        Gradient[2] = -Point[2] / self.b**2
676
677        return mgeo.Normalize(Gradient)

Return the normal unit vector on the ellipsoidal surface at point Point.

def get_centre(self):
679    def get_centre(self):
680        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
681        foci = 2 * np.sqrt(self.a**2 - self.b**2)
682        h = -foci / 2 / np.tan(self._offaxisangle)
683        R = np.sqrt(foci**2 / 4 + h**2)
684        sign = 1
685        if math.isclose(self._offaxisangle, np.pi / 2):
686            h = 0
687        elif self._offaxisangle > np.pi / 2:
688            h = -h
689            sign = -1
690        a = 1 - self.a**2 / self.b**2
691        b = -2 * h
692        c = self.a**2 + h**2 - R**2
693        z = (-b + sign * np.sqrt(b**2 - 4 * a * c)) / (2 * a)
694        if math.isclose(z**2, self.b**2):
695            return np.array([0, 0, -self.b])
696        x = self.a * np.sqrt(1 - z**2 / self.b**2)
697        centre = np.array([x, 0, sign * z])
698        return centre

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint, **kwargs):
700    def get_grid3D(self, NbPoint, **kwargs):
701        """
702        Get grid of points on mirror surface.
703
704        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
705        sampling the support in a number NbPoints of points.
706        """
707        E = "edges" in kwargs and kwargs["edges"]
708        ListCoordXYZ = []
709        contour = int(round(0.1 * NbPoint))
710        contours = self.support._Contour_points(contour, **kwargs)
711        if E:
712            contours, contour_edges = contours
713        ListCoordXY = self.support._get_grid(NbPoint - contour)
714        centre = self.get_centre()
715        for i, k in enumerate(ListCoordXY):
716            x = k[0] + centre[0]
717            y = k[1]
718            sideways = (x / self.a) ** 2 + (y / self.b) ** 2
719            if sideways <= 1:
720                z = -self.b * np.sqrt(1 - sideways)
721                ListCoordXYZ.append(np.array([x, y, z]))
722        new_contour_edges = []
723        for j in contour_edges:
724            new_contour_edges += [[]]
725            for i in j:
726                x = contours[i][0] + centre[0]
727                y = contours[i][1]
728                sideways = (x / self.a) ** 2 + (y / self.b) ** 2
729                if sideways <= 1:
730                    z = -self.b * np.sqrt(1 - sideways)
731                    ListCoordXYZ.append(np.array([x, y, z]))
732                    new_contour_edges[-1] += [len(ListCoordXYZ) - 1]
733        if E:
734            return ListCoordXYZ, new_contour_edges
735        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

def ReturnOptimalEllipsoidalAxes(Focal: float, AngleIncidence: float):
739def ReturnOptimalEllipsoidalAxes(Focal: float, AngleIncidence: float):
740    """
741    Get optimal parameters for an ellipsoidal mirror.
742
743    Useful helper function to get the optimal major and minor axes for an ellipsoidal mirror to achieve a
744    focal length 'Focal' with an angle of incidence 'AngleIncidence'.
745
746    Parameters
747    ----------
748        Focal : float
749            Focal length in mm.
750
751        AngleIncidence : int
752            Angle of incidence in degrees.
753
754    Returns
755    -------
756        OptimalSemiMajorAxis, OptimalSemiMinorAxis : float, float.
757    """
758    AngleIncidenceRadian = np.deg2rad(AngleIncidence)
759    OptimalSemiMajorAxis = Focal
760    OptimalSemiMinorAxis = OptimalSemiMajorAxis * np.cos(AngleIncidenceRadian)
761    return OptimalSemiMajorAxis, OptimalSemiMinorAxis

Get optimal parameters for an ellipsoidal mirror.

Useful helper function to get the optimal major and minor axes for an ellipsoidal mirror to achieve a focal length 'Focal' with an angle of incidence 'AngleIncidence'.

Parameters

Focal : float
    Focal length in mm.

AngleIncidence : int
    Angle of incidence in degrees.

Returns

OptimalSemiMajorAxis, OptimalSemiMinorAxis : float, float.
class MirrorCylindrical:
765class MirrorCylindrical:
766    """
767    Cylindrical mirror surface with eqn. $y^2 + z^2  = R^2$, where $R$ is the radius.
768
769    Attributes
770    ----------
771        radius : float
772            Radius of curvature. A postive value for concave mirror, a negative value for a convex mirror.
773
774        support : ART.ModuleSupport.Support
775
776        type : str 'Ellipsoidal Mirror'.
777
778    Methods
779    -------
780        MirrorCylindrical.get_normal(Point)
781
782        MirrorCylindrical.get_centre()
783
784        MirrorCylindrical.get_grid3D(NbPoints)
785    """
786
787    def __init__(self, Radius, Support):
788        """
789        Construct a cylindrical mirror.
790
791        Parameters
792        ----------
793            Radius : float
794                The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.
795
796            Support : ART.ModuleSupport.Support
797
798        """
799        if Radius < 0:
800            self.type = "CylindricalCX Mirror"
801            self.radius = -Radius
802        else:
803            self.type = "CylindricalCC Mirror"
804            self.radius = Radius
805
806        self.support = Support
807
808    def _get_intersection(self, Ray):
809        """Return the intersection point between the Ray and the cylinder."""
810        uy = Ray.vector[1]
811        uz = Ray.vector[2]
812        yA = Ray.point[1]
813        zA = Ray.point[2]
814
815        a = uy**2 + uz**2
816        b = 2 * (uy * yA + uz * zA)
817        c = yA**2 + zA**2 - self.radius**2
818
819        Solution = mgeo.SolverQuadratic(a, b, c)
820        Solution = mgeo.KeepPositiveSolution(Solution)
821
822        ListPointIntersection = []
823        for t in Solution:
824            Intersect = Ray.vector * t + Ray.point
825            if Intersect[2] < 0 and self.support._IncludeSupport(Intersect):
826                ListPointIntersection.append(Intersect)
827
828        return _IntersectionRayMirror(Ray.point, ListPointIntersection)
829
830    def get_normal(self, Point):
831        """Return the normal unit vector on the cylinder surface at point P."""
832        Gradient = np.array([0, -Point[1], -Point[2]])
833        return mgeo.Normalize(Gradient)
834
835    def get_centre(self):
836        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
837        return np.array([0, 0, -self.radius])
838
839    def get_grid3D(self, NbPoint, **kwargs):
840        """
841        Get grid of points on mirror surface.
842
843        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
844        sampling the support in a number NbPoints of points.
845        """
846        E = "edges" in kwargs and kwargs["edges"]
847        ListCoordXYZ = []
848        contour = int(round(0.1 * NbPoint))
849        contours = self.support._Contour_points(contour, **kwargs)
850        if E:
851            contours, contour_edges = contours
852        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
853        for k in ListCoordXY:
854            z = -np.sqrt(self.radius**2 - k[1] ** 2)
855            ListCoordXYZ.append(np.array([k[0], k[1], z]))
856        if E:
857            return ListCoordXYZ, contour_edges
858        return ListCoordXYZ

Cylindrical mirror surface with eqn. $y^2 + z^2 = R^2$, where $R$ is the radius.

Attributes

radius : float
    Radius of curvature. A postive value for concave mirror, a negative value for a convex mirror.

support : ART.ModuleSupport.Support

type : str 'Ellipsoidal Mirror'.

Methods

MirrorCylindrical.get_normal(Point)

MirrorCylindrical.get_centre()

MirrorCylindrical.get_grid3D(NbPoints)
MirrorCylindrical(Radius, Support)
787    def __init__(self, Radius, Support):
788        """
789        Construct a cylindrical mirror.
790
791        Parameters
792        ----------
793            Radius : float
794                The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.
795
796            Support : ART.ModuleSupport.Support
797
798        """
799        if Radius < 0:
800            self.type = "CylindricalCX Mirror"
801            self.radius = -Radius
802        else:
803            self.type = "CylindricalCC Mirror"
804            self.radius = Radius
805
806        self.support = Support

Construct a cylindrical mirror.

Parameters

Radius : float
    The radius of curvature in mm. A postive value for concave mirror, a negative value for a convex mirror.

Support : ART.ModuleSupport.Support
def get_normal(self, Point):
830    def get_normal(self, Point):
831        """Return the normal unit vector on the cylinder surface at point P."""
832        Gradient = np.array([0, -Point[1], -Point[2]])
833        return mgeo.Normalize(Gradient)

Return the normal unit vector on the cylinder surface at point P.

def get_centre(self):
835    def get_centre(self):
836        """Return 3D coordinates of the point on the mirror surface at the center of its support."""
837        return np.array([0, 0, -self.radius])

Return 3D coordinates of the point on the mirror surface at the center of its support.

def get_grid3D(self, NbPoint, **kwargs):
839    def get_grid3D(self, NbPoint, **kwargs):
840        """
841        Get grid of points on mirror surface.
842
843        Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface,
844        sampling the support in a number NbPoints of points.
845        """
846        E = "edges" in kwargs and kwargs["edges"]
847        ListCoordXYZ = []
848        contour = int(round(0.1 * NbPoint))
849        contours = self.support._Contour_points(contour, **kwargs)
850        if E:
851            contours, contour_edges = contours
852        ListCoordXY = contours + self.support._get_grid(NbPoint - contour)
853        for k in ListCoordXY:
854            z = -np.sqrt(self.radius**2 - k[1] ** 2)
855            ListCoordXYZ.append(np.array([k[0], k[1], z]))
856        if E:
857            return ListCoordXYZ, contour_edges
858        return ListCoordXYZ

Get grid of points on mirror surface.

Returns list of numpy-arrays containing the 3D-coordinates of points in the mirror surface, sampling the support in a number NbPoints of points.

def ReflectionMirrorRayList(Mirror, ListRay):
896def ReflectionMirrorRayList(Mirror, ListRay):
897    """
898    Return the the reflected rays according to the law of reflection for the list of incident rays ListRay.
899
900    Rays that do not hit the support are not further propagated.
901
902    Updates the reflected rays' incidence angle and path.
903
904    Parameters
905    ----------
906        Mirror : Mirror-object
907
908        ListRay : list[Ray-object]
909
910    """
911    Deformed = type(Mirror) == DeformedMirror
912    ListRayReflected = []
913    for k in ListRay:
914        PointMirror = Mirror._get_intersection(k)
915
916        if PointMirror is not None:
917            if Deformed and k.number == 0:
918                M = Mirror.Mirror
919            else:
920                M = Mirror
921            RayReflected = _ReflectionMirrorRay(M, PointMirror, k)
922            ListRayReflected.append(RayReflected)
923    return ListRayReflected

Return the the reflected rays according to the law of reflection for the list of incident rays ListRay.

Rays that do not hit the support are not further propagated.

Updates the reflected rays' incidence angle and path.

Parameters

Mirror : Mirror-object

ListRay : list[Ray-object]
class DeformedMirror:
929class DeformedMirror:
930    def __init__(self, Mirror, DeformationList):
931        self.Mirror = Mirror
932        self.DeformationList = DeformationList
933        self.type = Mirror.type
934        self.support = self.Mirror.support
935
936    def get_normal(self, PointMirror):
937        base_normal = self.Mirror.get_normal(PointMirror)
938        C = self.get_centre()
939        defects_normals = [
940            d.get_normal(PointMirror - C) for d in self.DeformationList
941        ]
942        for i in defects_normals:
943            base_normal = normal_add(base_normal, i)
944            base_normal /= np.linalg.norm(base_normal)
945        return base_normal
946
947    def get_centre(self):
948        return self.Mirror.get_centre()
949
950    def get_grid3D(self, NbPoint, **kwargs):
951        return self.Mirror.get_grid3D(NbPoint, **kwargs)
952
953    def _get_intersection(self, Ray):
954        Intersect = self.Mirror._get_intersection(Ray)
955        if Intersect is not None:
956            h = sum(
957                D.get_offset(Intersect - self.get_centre())
958                for D in self.DeformationList
959            )
960            alpha = mgeo.AngleBetweenTwoVectors(
961                -Ray.vector, self.Mirror.get_normal(Intersect)
962            )
963            Intersect -= Ray.vector * h / np.cos(alpha)
964        return Intersect
DeformedMirror(Mirror, DeformationList)
930    def __init__(self, Mirror, DeformationList):
931        self.Mirror = Mirror
932        self.DeformationList = DeformationList
933        self.type = Mirror.type
934        self.support = self.Mirror.support
def get_normal(self, PointMirror):
936    def get_normal(self, PointMirror):
937        base_normal = self.Mirror.get_normal(PointMirror)
938        C = self.get_centre()
939        defects_normals = [
940            d.get_normal(PointMirror - C) for d in self.DeformationList
941        ]
942        for i in defects_normals:
943            base_normal = normal_add(base_normal, i)
944            base_normal /= np.linalg.norm(base_normal)
945        return base_normal
def get_centre(self):
947    def get_centre(self):
948        return self.Mirror.get_centre()
def get_grid3D(self, NbPoint, **kwargs):
950    def get_grid3D(self, NbPoint, **kwargs):
951        return self.Mirror.get_grid3D(NbPoint, **kwargs)
def normal_add(N1, N2):
966def normal_add(N1, N2):
967    normal1 = N1 / np.linalg.norm(N1)
968    normal2 = N2 / np.linalg.norm(N2)
969    grad1X = -normal1[0] / normal1[2]
970    grad1Y = -normal1[1] / normal1[2]
971    grad2X = -normal2[0] / normal2[2]
972    grad2Y = -normal2[1] / normal2[2]
973    gradX = grad1X + grad2X
974    gradY = grad1Y + grad2Y
975    return np.array([-gradX, -gradY, 1])