ModuleOpticalElement
Provides the class for a general optical element, which serves to connect the “lab-frame”, in which the light rays are traced, to the proper “optic” coordinate frame in which an optic is defined. So this class is what serves to "align" the optics in lab-space, and it provides methods to modify its alignment.
The optic can be a Mirror-object or a Mask-object.
Created in Apr 2020
@author: Anthony Guillaume + Stefan Haessler
1""" 2Provides the class for a general optical element, which serves to connect the “lab-frame”, 3in which the light rays are traced, to the proper “optic” coordinate frame in 4which an optic is defined. So this class is what serves to "align" the optics in lab-space, 5and it provides methods to modify its alignment. 6 7The optic can be a [Mirror-object](ModuleMirror.html) or a [Mask-object](ModuleMask.html). 8 9 10 11 12 13Created in Apr 2020 14 15@author: Anthony Guillaume + Stefan Haessler 16""" 17# %% 18import ARTcore.ModuleGeometry as mgeo 19from ARTcore.ModuleGeometry import Origin 20 21import numpy as np 22from abc import ABC, abstractmethod 23import logging 24 25logger = logging.getLogger(__name__) 26 27 28# %% 29class OpticalElement(ABC): 30 """ 31 An optical element, can be either a Mirror or a Mask. In the future, one could add Gratings, DispersiveMedium etc... 32 33 Attributes: TODO update 34 ---------- 35 position : np.ndarray 36 Coordinate vector of the optical element’s center point in the lab frame. 37 What this center is, depends on the 'type', but it is generally the center of symmetry 38 of the Support of the optic. It is marked by the point 'P' in the drawings in the 39 documentation of the Mirror-classes for example. 40 41 orientation: np.quaternion 42 Orientation of the optic in the lab reference frame. From this, we calculate 43 the normal, the majoraxis and any other interesting vectors that are of 44 interest for a specific OpticalElement subclass. 45 46 normal : np.ndarray 47 Lab-frame vector pointing against the direction that would be considered 48 as normal incidence on the optical element. 49 50 majoraxis : np.ndarray 51 Lab-frame vector of another distinguished axis of non-rotationally symmetric optics, 52 like the major axes of toroidal/elliptical mirrors or the off-axis direction of 53 off-axis parabolas. This fixes the optical element’s rotation about 'normal'. 54 It is required to be perpendicular to 'normal', and is usually the x-axis in the 55 optic's proper coordinate frame. 56 57 What this 'majoraxis' is, e.g. for the different kinds of mirrors, is illustrated 58 in the documentation of the Mirror-classes. 59 60 For pure p or s polarization, the light incidence plane should be the 61 plane spanned by 'normal' and 'majoraxis', so that the incidence angle is varied 62 by rotating the optical element around the cross product 'normal' x 'majoraxis'. 63 64 65 Methods 66 ---------- 67 rotate_pitch_by(angle) 68 69 rotate_roll_by(angle) 70 71 rotate_yaw_by(angle) 72 73 rotate_random_by(angle) 74 75 shift_along_normal(distance) 76 77 shift_along_major(distance) 78 79 shift_along_cross(distance) 80 81 shift_along_random(distance) 82 83 """ 84 # %% Starting 3d orientation definition 85 _description = "Generic Optical Element" 86 87 def __hash__(self): 88 return super().__hash__()+hash(self._r)+hash(self._q) 89 90 @property 91 def description(self): 92 """ 93 Return a description of the optical element. 94 """ 95 return self._description 96 97 @property 98 def r(self): 99 """ 100 Return the offset of the optical element from its reference frame to the lab reference frame. 101 Not that this is **NOT** the position of the optical element's center point. Rather it is the 102 offset of the reference frame of the optical element from the lab reference frame. 103 """ 104 return self._r 105 106 @r.setter 107 def r(self, NewPosition): 108 """ 109 Set the offset of the optical element from its reference frame to the lab reference frame. 110 """ 111 if isinstance(NewPosition, mgeo.Point) and len(NewPosition) == 3: 112 self._r = NewPosition 113 else: 114 raise TypeError("Position must be a 3D mgeo.Point.") 115 @property 116 def q(self): 117 """ 118 Return the orientation of the optical element. 119 The orientation is stored as a unit quaternion representing the rotation from the optic's coordinate frame to the lab frame. 120 """ 121 return self._q 122 123 @q.setter 124 def q(self, NewOrientation): 125 """ 126 Set the orientation of the optical element. 127 This function normalizes the input quaternion before storing it. 128 If the input is not a quaternion, raise a TypeError. 129 """ 130 if isinstance(NewOrientation, np.quaternion): 131 self._q = NewOrientation.normalized() 132 else: 133 raise TypeError("Orientation must be a quaternion.") 134 135 @property 136 def position(self): 137 """ 138 Return the position of the basepoint of the optical element. Often it is the same as the optical centre. 139 This position is the one around which all rotations are performed. 140 """ 141 return self.r0 + self.r 142 143 @property 144 def orientation(self): 145 """ 146 Return the orientation of the optical element. 147 The utility of this method is unclear. 148 """ 149 return self.q 150 151 @property 152 def basis(self): 153 return self.r0, self.r, self.q 154 # %% Start of other methods 155 def __init__(self): 156 self._r = mgeo.Vector([0.0, 0.0, 0.0]) 157 self._q = np.quaternion(1, 0, 0, 0) 158 self.r0 = mgeo.Point([0.0, 0.0, 0.0]) 159 160 @abstractmethod 161 def propagate_raylist(self, RayList, alignment=False): 162 """ 163 This method is used to propagate a list of rays through the optical element. Implement this method in the subclasses. 164 In the case of a mirror, the method should reflect the rays off the mirror surface. 165 In the case of a mask, the method should block the rays that hit the mask. 166 In the case of a grating, the method should diffract the rays according to the grating equation. 167 """ 168 pass 169 170 def add_global_points(self, *args): 171 """ 172 Automatically add global properties for point attributes. 173 As arguments it takes the names of the global point attributes and seeks for the corresponding local point attributes. 174 Then it creates a property for the global point attribute. 175 176 Example: 177 Suppose the optical element has an attribute 'center_ref' that is the center of the optical element in the optic's coordinate frame. 178 Then, calling object.add_global_points('center') will create a property 'center' that returns the global position of the center of the optical element. 179 It takes into account the position and orientation of the optical element. 180 """ 181 for arg in args: 182 local_attr = f"{arg}_ref" 183 if hasattr(self, local_attr): 184 # Dynamically define a property for the global point 185 setattr(self.__class__, arg, property(self._create_global_point_property(local_attr))) 186 187 def add_global_vectors(self, *args): 188 """ 189 Automatically add global properties for vector attributes. 190 As arguments it takes the names of the global vector attributes and seeks for the corresponding local vector attributes. 191 Then it creates a property for the global vector attribute. 192 193 Example: 194 Suppose the optical element has an attribute 'normal_ref' that is the normal of the optical element in the optic's coordinate frame. 195 Then, calling object.add_global_vectors('normal') will create a property 'normal' that returns the global normal of the optical element. 196 """ 197 for arg in args: 198 local_attr = f"{arg}_ref" 199 if hasattr(self, local_attr): 200 # Dynamically define a property for the global vector 201 setattr(self.__class__, arg, property(self._create_global_vector_property(local_attr))) 202 203 def _create_global_point_property(self, local_attr): 204 """ 205 Return a function that computes the global point. 206 This is the actual function that is used to create the global point property. It performs the transformation of the local point to the global reference frame. 207 """ 208 def global_point(self): 209 # Translate the local point to the global reference frame 210 local_point = getattr(self, local_attr) 211 return local_point.from_basis(*self.basis) 212 return global_point 213 214 def _create_global_vector_property(self, local_attr): 215 """ 216 Return a function that computes the global vector. 217 This is the actual function that is used to create the global vector property. It performs the transformation of the local vector to the global reference frame. 218 """ 219 def global_vector(self): 220 # Rotate the local vector to the global reference frame 221 local_vector = getattr(self, local_attr) 222 return local_vector.from_basis(*self.basis) 223 return global_vector 224 # %% Starting 3d misalignment definitions 225 # This section needs to be reworked to be more general and to allow for more flexibility in the alignment of the optical elements. TODO 226 227 def rotate_pitch_by(self, angle): 228 """ 229 Pitch rotation, i.e. rotates the optical element about the axis ('normal' x 'majoraxis'), by the 230 given angle. 231 If the plane spanned by 'normal' and 'majoraxis' is the incidence plane (normally the case 232 in a "clean alignment" situation for pure p or s polarization), then this is simply a modificaiton 233 of the incidence angle by "angle". But in general, if the optical element has some odd orientation, 234 there is not a direct correspondence. 235 236 Parameters 237 ---------- 238 angle : float 239 Rotation angle in *degrees*. 240 """ 241 rotation_axis = np.cross(self.support_normal, self.majoraxis) 242 self.q = mgeo.QRotationAroundAxis(rotation_axis, np.deg2rad(angle))*self.q 243 244 def rotate_roll_by(self, angle): 245 """ 246 Roll rotation, i.e. rotates the optical element about its 'majoraxis' by the given angle. 247 248 Parameters 249 ---------- 250 angle : float 251 Rotation angle in *degrees*. 252 """ 253 254 self.q = mgeo.QRotationAroundAxis(self.majoraxis, np.deg2rad(angle))*self.q 255 256 def rotate_yaw_by(self, angle): 257 """ 258 Yaw rotation, i.e. rotates the optical element about its 'normal' by the given angle. 259 260 Parameters 261 ---------- 262 angle : float 263 Rotation angle in *degrees*. 264 """ 265 self.q = mgeo.QRotationAroundAxis(self.support_normal, np.deg2rad(angle))*self.q 266 267 def rotate_random_by(self, angle): 268 """ 269 Rotates the optical element about a randomly oriented axis by the given angle. 270 271 Parameters 272 ---------- 273 angle : float 274 Rotation angle in *degrees*. 275 """ 276 277 self.q = mgeo.QRotationAroundAxis(np.random.random(3), np.deg2rad(angle))*self.q 278 279 def shift_along_normal(self, distance): 280 """ 281 Shifts the optical element along its 'normal' by the given distance. 282 283 Parameters 284 ---------- 285 distance : float 286 Shift distance in mm. 287 """ 288 self.r = self.r + distance * self.support_normal 289 290 def shift_along_major(self, distance): 291 """ 292 Shifts the optical element along its 'majoraxis' by the given distance. 293 294 Parameters 295 ---------- 296 distance : float 297 Shift distance in mm. 298 """ 299 self.r = self.r + distance * self.majoraxis 300 301 def shift_along_cross(self, distance): 302 """ 303 Shifts the optical element along the axis 'normal'x'majoraxis' 304 (typically normal to the light incidence plane) by the given distance. 305 306 Parameters 307 ---------- 308 distance : float 309 Shift distance in mm. 310 """ 311 self.r = self.r + distance * mgeo.Normalize(np.cross(self.support_normal, self.majoraxis)) 312 313 def shift_along_random(self, distance): 314 """ 315 Shifts the optical element along a random direction by the given distance. 316 317 Parameters 318 ---------- 319 distance : float 320 Shift distance in mm. 321 """ 322 self.r = self.r + distance * mgeo.Normalize(np.random.random(3))
30class OpticalElement(ABC): 31 """ 32 An optical element, can be either a Mirror or a Mask. In the future, one could add Gratings, DispersiveMedium etc... 33 34 Attributes: TODO update 35 ---------- 36 position : np.ndarray 37 Coordinate vector of the optical element’s center point in the lab frame. 38 What this center is, depends on the 'type', but it is generally the center of symmetry 39 of the Support of the optic. It is marked by the point 'P' in the drawings in the 40 documentation of the Mirror-classes for example. 41 42 orientation: np.quaternion 43 Orientation of the optic in the lab reference frame. From this, we calculate 44 the normal, the majoraxis and any other interesting vectors that are of 45 interest for a specific OpticalElement subclass. 46 47 normal : np.ndarray 48 Lab-frame vector pointing against the direction that would be considered 49 as normal incidence on the optical element. 50 51 majoraxis : np.ndarray 52 Lab-frame vector of another distinguished axis of non-rotationally symmetric optics, 53 like the major axes of toroidal/elliptical mirrors or the off-axis direction of 54 off-axis parabolas. This fixes the optical element’s rotation about 'normal'. 55 It is required to be perpendicular to 'normal', and is usually the x-axis in the 56 optic's proper coordinate frame. 57 58 What this 'majoraxis' is, e.g. for the different kinds of mirrors, is illustrated 59 in the documentation of the Mirror-classes. 60 61 For pure p or s polarization, the light incidence plane should be the 62 plane spanned by 'normal' and 'majoraxis', so that the incidence angle is varied 63 by rotating the optical element around the cross product 'normal' x 'majoraxis'. 64 65 66 Methods 67 ---------- 68 rotate_pitch_by(angle) 69 70 rotate_roll_by(angle) 71 72 rotate_yaw_by(angle) 73 74 rotate_random_by(angle) 75 76 shift_along_normal(distance) 77 78 shift_along_major(distance) 79 80 shift_along_cross(distance) 81 82 shift_along_random(distance) 83 84 """ 85 # %% Starting 3d orientation definition 86 _description = "Generic Optical Element" 87 88 def __hash__(self): 89 return super().__hash__()+hash(self._r)+hash(self._q) 90 91 @property 92 def description(self): 93 """ 94 Return a description of the optical element. 95 """ 96 return self._description 97 98 @property 99 def r(self): 100 """ 101 Return the offset of the optical element from its reference frame to the lab reference frame. 102 Not that this is **NOT** the position of the optical element's center point. Rather it is the 103 offset of the reference frame of the optical element from the lab reference frame. 104 """ 105 return self._r 106 107 @r.setter 108 def r(self, NewPosition): 109 """ 110 Set the offset of the optical element from its reference frame to the lab reference frame. 111 """ 112 if isinstance(NewPosition, mgeo.Point) and len(NewPosition) == 3: 113 self._r = NewPosition 114 else: 115 raise TypeError("Position must be a 3D mgeo.Point.") 116 @property 117 def q(self): 118 """ 119 Return the orientation of the optical element. 120 The orientation is stored as a unit quaternion representing the rotation from the optic's coordinate frame to the lab frame. 121 """ 122 return self._q 123 124 @q.setter 125 def q(self, NewOrientation): 126 """ 127 Set the orientation of the optical element. 128 This function normalizes the input quaternion before storing it. 129 If the input is not a quaternion, raise a TypeError. 130 """ 131 if isinstance(NewOrientation, np.quaternion): 132 self._q = NewOrientation.normalized() 133 else: 134 raise TypeError("Orientation must be a quaternion.") 135 136 @property 137 def position(self): 138 """ 139 Return the position of the basepoint of the optical element. Often it is the same as the optical centre. 140 This position is the one around which all rotations are performed. 141 """ 142 return self.r0 + self.r 143 144 @property 145 def orientation(self): 146 """ 147 Return the orientation of the optical element. 148 The utility of this method is unclear. 149 """ 150 return self.q 151 152 @property 153 def basis(self): 154 return self.r0, self.r, self.q 155 # %% Start of other methods 156 def __init__(self): 157 self._r = mgeo.Vector([0.0, 0.0, 0.0]) 158 self._q = np.quaternion(1, 0, 0, 0) 159 self.r0 = mgeo.Point([0.0, 0.0, 0.0]) 160 161 @abstractmethod 162 def propagate_raylist(self, RayList, alignment=False): 163 """ 164 This method is used to propagate a list of rays through the optical element. Implement this method in the subclasses. 165 In the case of a mirror, the method should reflect the rays off the mirror surface. 166 In the case of a mask, the method should block the rays that hit the mask. 167 In the case of a grating, the method should diffract the rays according to the grating equation. 168 """ 169 pass 170 171 def add_global_points(self, *args): 172 """ 173 Automatically add global properties for point attributes. 174 As arguments it takes the names of the global point attributes and seeks for the corresponding local point attributes. 175 Then it creates a property for the global point attribute. 176 177 Example: 178 Suppose the optical element has an attribute 'center_ref' that is the center of the optical element in the optic's coordinate frame. 179 Then, calling object.add_global_points('center') will create a property 'center' that returns the global position of the center of the optical element. 180 It takes into account the position and orientation of the optical element. 181 """ 182 for arg in args: 183 local_attr = f"{arg}_ref" 184 if hasattr(self, local_attr): 185 # Dynamically define a property for the global point 186 setattr(self.__class__, arg, property(self._create_global_point_property(local_attr))) 187 188 def add_global_vectors(self, *args): 189 """ 190 Automatically add global properties for vector attributes. 191 As arguments it takes the names of the global vector attributes and seeks for the corresponding local vector attributes. 192 Then it creates a property for the global vector attribute. 193 194 Example: 195 Suppose the optical element has an attribute 'normal_ref' that is the normal of the optical element in the optic's coordinate frame. 196 Then, calling object.add_global_vectors('normal') will create a property 'normal' that returns the global normal of the optical element. 197 """ 198 for arg in args: 199 local_attr = f"{arg}_ref" 200 if hasattr(self, local_attr): 201 # Dynamically define a property for the global vector 202 setattr(self.__class__, arg, property(self._create_global_vector_property(local_attr))) 203 204 def _create_global_point_property(self, local_attr): 205 """ 206 Return a function that computes the global point. 207 This is the actual function that is used to create the global point property. It performs the transformation of the local point to the global reference frame. 208 """ 209 def global_point(self): 210 # Translate the local point to the global reference frame 211 local_point = getattr(self, local_attr) 212 return local_point.from_basis(*self.basis) 213 return global_point 214 215 def _create_global_vector_property(self, local_attr): 216 """ 217 Return a function that computes the global vector. 218 This is the actual function that is used to create the global vector property. It performs the transformation of the local vector to the global reference frame. 219 """ 220 def global_vector(self): 221 # Rotate the local vector to the global reference frame 222 local_vector = getattr(self, local_attr) 223 return local_vector.from_basis(*self.basis) 224 return global_vector 225 # %% Starting 3d misalignment definitions 226 # This section needs to be reworked to be more general and to allow for more flexibility in the alignment of the optical elements. TODO 227 228 def rotate_pitch_by(self, angle): 229 """ 230 Pitch rotation, i.e. rotates the optical element about the axis ('normal' x 'majoraxis'), by the 231 given angle. 232 If the plane spanned by 'normal' and 'majoraxis' is the incidence plane (normally the case 233 in a "clean alignment" situation for pure p or s polarization), then this is simply a modificaiton 234 of the incidence angle by "angle". But in general, if the optical element has some odd orientation, 235 there is not a direct correspondence. 236 237 Parameters 238 ---------- 239 angle : float 240 Rotation angle in *degrees*. 241 """ 242 rotation_axis = np.cross(self.support_normal, self.majoraxis) 243 self.q = mgeo.QRotationAroundAxis(rotation_axis, np.deg2rad(angle))*self.q 244 245 def rotate_roll_by(self, angle): 246 """ 247 Roll rotation, i.e. rotates the optical element about its 'majoraxis' by the given angle. 248 249 Parameters 250 ---------- 251 angle : float 252 Rotation angle in *degrees*. 253 """ 254 255 self.q = mgeo.QRotationAroundAxis(self.majoraxis, np.deg2rad(angle))*self.q 256 257 def rotate_yaw_by(self, angle): 258 """ 259 Yaw rotation, i.e. rotates the optical element about its 'normal' by the given angle. 260 261 Parameters 262 ---------- 263 angle : float 264 Rotation angle in *degrees*. 265 """ 266 self.q = mgeo.QRotationAroundAxis(self.support_normal, np.deg2rad(angle))*self.q 267 268 def rotate_random_by(self, angle): 269 """ 270 Rotates the optical element about a randomly oriented axis by the given angle. 271 272 Parameters 273 ---------- 274 angle : float 275 Rotation angle in *degrees*. 276 """ 277 278 self.q = mgeo.QRotationAroundAxis(np.random.random(3), np.deg2rad(angle))*self.q 279 280 def shift_along_normal(self, distance): 281 """ 282 Shifts the optical element along its 'normal' by the given distance. 283 284 Parameters 285 ---------- 286 distance : float 287 Shift distance in mm. 288 """ 289 self.r = self.r + distance * self.support_normal 290 291 def shift_along_major(self, distance): 292 """ 293 Shifts the optical element along its 'majoraxis' by the given distance. 294 295 Parameters 296 ---------- 297 distance : float 298 Shift distance in mm. 299 """ 300 self.r = self.r + distance * self.majoraxis 301 302 def shift_along_cross(self, distance): 303 """ 304 Shifts the optical element along the axis 'normal'x'majoraxis' 305 (typically normal to the light incidence plane) by the given distance. 306 307 Parameters 308 ---------- 309 distance : float 310 Shift distance in mm. 311 """ 312 self.r = self.r + distance * mgeo.Normalize(np.cross(self.support_normal, self.majoraxis)) 313 314 def shift_along_random(self, distance): 315 """ 316 Shifts the optical element along a random direction by the given distance. 317 318 Parameters 319 ---------- 320 distance : float 321 Shift distance in mm. 322 """ 323 self.r = self.r + distance * mgeo.Normalize(np.random.random(3))
An optical element, can be either a Mirror or a Mask. In the future, one could add Gratings, DispersiveMedium etc...
Attributes: TODO update
position : np.ndarray
Coordinate vector of the optical element’s center point in the lab frame.
What this center is, depends on the 'type', but it is generally the center of symmetry
of the Support of the optic. It is marked by the point 'P' in the drawings in the
documentation of the Mirror-classes for example.
orientation: np.quaternion
Orientation of the optic in the lab reference frame. From this, we calculate
the normal, the majoraxis and any other interesting vectors that are of
interest for a specific OpticalElement subclass.
normal : np.ndarray
Lab-frame vector pointing against the direction that would be considered
as normal incidence on the optical element.
majoraxis : np.ndarray
Lab-frame vector of another distinguished axis of non-rotationally symmetric optics,
like the major axes of toroidal/elliptical mirrors or the off-axis direction of
off-axis parabolas. This fixes the optical element’s rotation about 'normal'.
It is required to be perpendicular to 'normal', and is usually the x-axis in the
optic's proper coordinate frame.
What this 'majoraxis' is, e.g. for the different kinds of mirrors, is illustrated
in the documentation of the Mirror-classes.
For pure p or s polarization, the light incidence plane should be the
plane spanned by 'normal' and 'majoraxis', so that the incidence angle is varied
by rotating the optical element around the cross product 'normal' x 'majoraxis'.
Methods
rotate_pitch_by(angle)
rotate_roll_by(angle)
rotate_yaw_by(angle)
rotate_random_by(angle)
shift_along_normal(distance)
shift_along_major(distance)
shift_along_cross(distance)
shift_along_random(distance)
91 @property 92 def description(self): 93 """ 94 Return a description of the optical element. 95 """ 96 return self._description
Return a description of the optical element.
98 @property 99 def r(self): 100 """ 101 Return the offset of the optical element from its reference frame to the lab reference frame. 102 Not that this is **NOT** the position of the optical element's center point. Rather it is the 103 offset of the reference frame of the optical element from the lab reference frame. 104 """ 105 return self._r
Return the offset of the optical element from its reference frame to the lab reference frame. Not that this is NOT the position of the optical element's center point. Rather it is the offset of the reference frame of the optical element from the lab reference frame.
116 @property 117 def q(self): 118 """ 119 Return the orientation of the optical element. 120 The orientation is stored as a unit quaternion representing the rotation from the optic's coordinate frame to the lab frame. 121 """ 122 return self._q
Return the orientation of the optical element. The orientation is stored as a unit quaternion representing the rotation from the optic's coordinate frame to the lab frame.
136 @property 137 def position(self): 138 """ 139 Return the position of the basepoint of the optical element. Often it is the same as the optical centre. 140 This position is the one around which all rotations are performed. 141 """ 142 return self.r0 + self.r
Return the position of the basepoint of the optical element. Often it is the same as the optical centre. This position is the one around which all rotations are performed.
144 @property 145 def orientation(self): 146 """ 147 Return the orientation of the optical element. 148 The utility of this method is unclear. 149 """ 150 return self.q
Return the orientation of the optical element. The utility of this method is unclear.
161 @abstractmethod 162 def propagate_raylist(self, RayList, alignment=False): 163 """ 164 This method is used to propagate a list of rays through the optical element. Implement this method in the subclasses. 165 In the case of a mirror, the method should reflect the rays off the mirror surface. 166 In the case of a mask, the method should block the rays that hit the mask. 167 In the case of a grating, the method should diffract the rays according to the grating equation. 168 """ 169 pass
This method is used to propagate a list of rays through the optical element. Implement this method in the subclasses. In the case of a mirror, the method should reflect the rays off the mirror surface. In the case of a mask, the method should block the rays that hit the mask. In the case of a grating, the method should diffract the rays according to the grating equation.
171 def add_global_points(self, *args): 172 """ 173 Automatically add global properties for point attributes. 174 As arguments it takes the names of the global point attributes and seeks for the corresponding local point attributes. 175 Then it creates a property for the global point attribute. 176 177 Example: 178 Suppose the optical element has an attribute 'center_ref' that is the center of the optical element in the optic's coordinate frame. 179 Then, calling object.add_global_points('center') will create a property 'center' that returns the global position of the center of the optical element. 180 It takes into account the position and orientation of the optical element. 181 """ 182 for arg in args: 183 local_attr = f"{arg}_ref" 184 if hasattr(self, local_attr): 185 # Dynamically define a property for the global point 186 setattr(self.__class__, arg, property(self._create_global_point_property(local_attr)))
Automatically add global properties for point attributes. As arguments it takes the names of the global point attributes and seeks for the corresponding local point attributes. Then it creates a property for the global point attribute.
Example: Suppose the optical element has an attribute 'center_ref' that is the center of the optical element in the optic's coordinate frame. Then, calling object.add_global_points('center') will create a property 'center' that returns the global position of the center of the optical element. It takes into account the position and orientation of the optical element.
188 def add_global_vectors(self, *args): 189 """ 190 Automatically add global properties for vector attributes. 191 As arguments it takes the names of the global vector attributes and seeks for the corresponding local vector attributes. 192 Then it creates a property for the global vector attribute. 193 194 Example: 195 Suppose the optical element has an attribute 'normal_ref' that is the normal of the optical element in the optic's coordinate frame. 196 Then, calling object.add_global_vectors('normal') will create a property 'normal' that returns the global normal of the optical element. 197 """ 198 for arg in args: 199 local_attr = f"{arg}_ref" 200 if hasattr(self, local_attr): 201 # Dynamically define a property for the global vector 202 setattr(self.__class__, arg, property(self._create_global_vector_property(local_attr)))
Automatically add global properties for vector attributes. As arguments it takes the names of the global vector attributes and seeks for the corresponding local vector attributes. Then it creates a property for the global vector attribute.
Example: Suppose the optical element has an attribute 'normal_ref' that is the normal of the optical element in the optic's coordinate frame. Then, calling object.add_global_vectors('normal') will create a property 'normal' that returns the global normal of the optical element.
228 def rotate_pitch_by(self, angle): 229 """ 230 Pitch rotation, i.e. rotates the optical element about the axis ('normal' x 'majoraxis'), by the 231 given angle. 232 If the plane spanned by 'normal' and 'majoraxis' is the incidence plane (normally the case 233 in a "clean alignment" situation for pure p or s polarization), then this is simply a modificaiton 234 of the incidence angle by "angle". But in general, if the optical element has some odd orientation, 235 there is not a direct correspondence. 236 237 Parameters 238 ---------- 239 angle : float 240 Rotation angle in *degrees*. 241 """ 242 rotation_axis = np.cross(self.support_normal, self.majoraxis) 243 self.q = mgeo.QRotationAroundAxis(rotation_axis, np.deg2rad(angle))*self.q
Pitch rotation, i.e. rotates the optical element about the axis ('normal' x 'majoraxis'), by the given angle. If the plane spanned by 'normal' and 'majoraxis' is the incidence plane (normally the case in a "clean alignment" situation for pure p or s polarization), then this is simply a modificaiton of the incidence angle by "angle". But in general, if the optical element has some odd orientation, there is not a direct correspondence.
Parameters
angle : float
Rotation angle in *degrees*.
245 def rotate_roll_by(self, angle): 246 """ 247 Roll rotation, i.e. rotates the optical element about its 'majoraxis' by the given angle. 248 249 Parameters 250 ---------- 251 angle : float 252 Rotation angle in *degrees*. 253 """ 254 255 self.q = mgeo.QRotationAroundAxis(self.majoraxis, np.deg2rad(angle))*self.q
Roll rotation, i.e. rotates the optical element about its 'majoraxis' by the given angle.
Parameters
angle : float
Rotation angle in *degrees*.
257 def rotate_yaw_by(self, angle): 258 """ 259 Yaw rotation, i.e. rotates the optical element about its 'normal' by the given angle. 260 261 Parameters 262 ---------- 263 angle : float 264 Rotation angle in *degrees*. 265 """ 266 self.q = mgeo.QRotationAroundAxis(self.support_normal, np.deg2rad(angle))*self.q
Yaw rotation, i.e. rotates the optical element about its 'normal' by the given angle.
Parameters
angle : float
Rotation angle in *degrees*.
268 def rotate_random_by(self, angle): 269 """ 270 Rotates the optical element about a randomly oriented axis by the given angle. 271 272 Parameters 273 ---------- 274 angle : float 275 Rotation angle in *degrees*. 276 """ 277 278 self.q = mgeo.QRotationAroundAxis(np.random.random(3), np.deg2rad(angle))*self.q
Rotates the optical element about a randomly oriented axis by the given angle.
Parameters
angle : float
Rotation angle in *degrees*.
280 def shift_along_normal(self, distance): 281 """ 282 Shifts the optical element along its 'normal' by the given distance. 283 284 Parameters 285 ---------- 286 distance : float 287 Shift distance in mm. 288 """ 289 self.r = self.r + distance * self.support_normal
Shifts the optical element along its 'normal' by the given distance.
Parameters
distance : float
Shift distance in mm.
291 def shift_along_major(self, distance): 292 """ 293 Shifts the optical element along its 'majoraxis' by the given distance. 294 295 Parameters 296 ---------- 297 distance : float 298 Shift distance in mm. 299 """ 300 self.r = self.r + distance * self.majoraxis
Shifts the optical element along its 'majoraxis' by the given distance.
Parameters
distance : float
Shift distance in mm.
302 def shift_along_cross(self, distance): 303 """ 304 Shifts the optical element along the axis 'normal'x'majoraxis' 305 (typically normal to the light incidence plane) by the given distance. 306 307 Parameters 308 ---------- 309 distance : float 310 Shift distance in mm. 311 """ 312 self.r = self.r + distance * mgeo.Normalize(np.cross(self.support_normal, self.majoraxis))
Shifts the optical element along the axis 'normal'x'majoraxis' (typically normal to the light incidence plane) by the given distance.
Parameters
distance : float
Shift distance in mm.
314 def shift_along_random(self, distance): 315 """ 316 Shifts the optical element along a random direction by the given distance. 317 318 Parameters 319 ---------- 320 distance : float 321 Shift distance in mm. 322 """ 323 self.r = self.r + distance * mgeo.Normalize(np.random.random(3))
Shifts the optical element along a random direction by the given distance.
Parameters
distance : float
Shift distance in mm.