ModuleDetector
26class Detector: 27 """ 28 A detector is simply a plane in 3D-lab-space. 29 It is defined by a point Detector.centre and its 30 normal vector Detector.normal (thought to point towards the incoming rays). 31 These are optional arguments when creating a Detector-instance, because they can 32 later be set automatically by the method Detector.autoplace(). 33 The Detector has a reference point "RefPoint", with respect to which a distance 34 can be returned via the method Detector.get distance. 35 36 Attributes 37 ---------- 38 centre : np.ndarray 39 3D Point in the Detector plane. 40 41 normal : np.ndarray 42 3D Normal vector on the Detector plane. 43 44 refpoint : np.ndarray 45 3D reference point from which to measure the Detector distance. 46 """ 47 48 def __init__(self, RefPoint: np.ndarray, Centre=None, Normal=None): 49 """ 50 Parameters 51 ---------- 52 RefPoint : np.ndarray 53 3D Reference point from which to measure the Detector distance. 54 55 Centre : np.ndarray, optional 56 3D Point in the Detector plane. 57 58 Normal : np.ndarray, optional 59 3D Normal vector on the Detector plane. 60 """ 61 self.centre = Centre 62 self.normal = Normal 63 self.refpoint = RefPoint 64 65 @property 66 def centre(self): 67 return self._centre 68 69 # a setter function 70 @centre.setter 71 def centre(self, Centre): 72 if type(Centre) == np.ndarray and Centre.shape == (3,) or Centre is None: 73 self._centre = Centre 74 else: 75 raise TypeError("Detector Centre must be a 3D-vector, given as numpy.ndarray of shape (3,).") 76 77 @property 78 def normal(self): 79 return self._normal 80 81 @normal.setter 82 def normal(self, Normal): 83 if type(Normal) == np.ndarray and Normal.shape == (3,) and np.linalg.norm(Normal) > 0: 84 self._normal = Normal / np.linalg.norm(Normal) 85 elif Normal is None: 86 self._normal = Normal 87 else: 88 raise TypeError("Detector Normal must be a 3D-vector of norm >0, given as numpy.ndarray of shape (3,).") 89 90 @property 91 def refpoint(self): 92 return self._refpoint 93 94 # a setter function 95 @refpoint.setter 96 def refpoint(self, RefPoint): 97 if type(RefPoint) == np.ndarray and RefPoint.shape == (3,): 98 self._refpoint = RefPoint 99 else: 100 raise TypeError("Detector RefPoint must a 3D-vector, given as numpy.ndarray of shape (3,).") 101 102 # %% METHODS FOR PLACING THE DETECTOR ################################################################## 103 104 def copy_detector(self): 105 """ 106 Returns a new Detector object with the same properties. 107 """ 108 return Detector(self.refpoint, self.centre, self.normal) 109 110 def autoplace(self, RayList, DistanceDetector: float): 111 """ 112 Automatically place and orient the detector such that it is normal to the central ray 113 of the supplied RayList, at the distance DistanceDetector the origin point of that central ray. 114 115 Parameters 116 ---------- 117 RayList : list[Ray] 118 A list of objects of the ModuleOpticalRay.Ray-class. 119 120 DistanceDetector : float 121 The distance at which to place the Detector. 122 """ 123 CentralRay = mp.FindCentralRay(RayList) 124 if CentralRay is None: 125 DetectorNormal = np.array([0, 0, 0]) 126 CentralPoint = np.array([0, 0, 0]) 127 for k in RayList: 128 DetectorNormal = DetectorNormal + k.vector 129 CentralPoint = CentralPoint + k.point 130 DetectorNormal = -DetectorNormal / len(RayList) 131 CentralPoint = CentralPoint / len(RayList) 132 else: 133 DetectorNormal = -CentralRay.vector 134 CentralPoint = CentralRay.point 135 136 self.normal = DetectorNormal 137 self.centre = CentralPoint - DetectorNormal * DistanceDetector 138 self.refpoint = CentralPoint 139 140 def get_distance(self): 141 """ 142 Return distance of the Detector-plane from its reference point Detector.refpoint. 143 """ 144 return np.linalg.norm( 145 self.refpoint - mgeo.IntersectionLinePlane(self.refpoint, -self.normal, self.centre, self.normal) 146 ) 147 148 def shiftToDistance(self, NewDistance: float): 149 """ 150 Shift the Detector to the distance NewDistance from its reference point Detector.refpoint. 151 152 Parameters 153 ---------- 154 NewDistance : float 155 The distance (absolute) to which to shift the Detector. 156 """ 157 if type(NewDistance) == int or type(NewDistance) == float or type(NewDistance) == np.float64: 158 shiftby = NewDistance - self.get_distance() # by that much in the self.normal-direction 159 else: 160 raise TypeError("The new Detector Distance must be int or float.") 161 162 self._centre += -shiftby * self.normal 163 164 def shiftByDistance(self, Shift: float): 165 """ 166 Shift the Detector *by* the distance Shift along its normal vector Detector.normal. 167 168 Parameters 169 ---------- 170 Shift : float 171 The distance (relative) *by* which to shift the Detector. 172 """ 173 if type(Shift) == int or type(Shift) == float or type(Shift) == np.float64: 174 self._centre = self.centre - Shift * self.normal # directly set _centre, i.e. circumvent setter 175 # because we already checked shift here, and centre 176 # and normal have been checked before 177 else: 178 raise TypeError("The Detector Distance Shift must be int or float.") 179 180 def _iscomplete(self): 181 """ 182 Checks whether the Detector plane is defined by a centre-point and normal-vector. 183 """ 184 if self.centre is None or self.normal is None: 185 raise TypeError("The detector has no centre and normal vectors defined yet.") 186 return False 187 else: 188 return True 189 190 # %% METHODS TO GET THE DETECTOR REPONSE ################################################################## 191 192 def get_PointList3D(self, RayList) -> list[np.ndarray]: 193 """ 194 Returns the list of 3D-points in lab-space where the rays in the 195 list RayList hit the detector plane. 196 197 Parameters 198 ---------- 199 RayList : list[Ray] 200 A list of objects of the ModuleOpticalRay.Ray-class. 201 202 Returns 203 ---------- 204 ListPointDetector3D : list[np.ndarray of shape (3,)] 205 """ 206 if self._iscomplete(): 207 ListPointDetector3D = [] 208 append = ListPointDetector3D.append 209 for k in RayList: 210 append(mgeo.IntersectionLinePlane(k.point, k.vector, self.centre, self.normal)) 211 return ListPointDetector3D 212 213 def get_PointList2D(self, RayList) -> list[np.ndarray]: 214 """ 215 Returns the list of 2D-points in the detector plane, with the origin at Detector.centre. 216 217 Parameters 218 ---------- 219 RayList : list[Ray] 220 A list of objects of the ModuleOpticalRay.Ray-class. 221 222 Returns 223 ---------- 224 ListPointDetector2D : list[np.ndarray of shape (2,)] 225 """ 226 if self._iscomplete(): 227 ListPointDetector3D = self.get_PointList3D(RayList) 228 229 ListPointDetector3D = [ 230 k - self.centre for k in ListPointDetector3D 231 ] # Equivalent to taking the detector's central point as the origin 232 ListPointDetector3D = mgeo.RotationPointList(ListPointDetector3D, self.normal, np.array([0, 0, 1])) 233 234 ListPointDetector2D = [k[0:2] for k in ListPointDetector3D] 235 return ListPointDetector2D 236 237 def get_PointList2DCentre(self, RayList) -> list[np.ndarray]: 238 """ 239 Returns the list of 2D-points in the detector plane, with the origin centered in the point cloud. 240 241 Parameters 242 ---------- 243 RayLis* : list[Ray] 244 A list of objects of the ModuleOpticalRay.Ray-class. 245 246 Returns 247 ---------- 248 ListPointDetector2DCentre : list[np.ndarray of shape (2,)] 249 """ 250 if self._iscomplete(): 251 ListPointDetector2D = self.get_PointList2D(RayList) 252 ListPointDetector2DCentre = mgeo.CentrePointList(ListPointDetector2D) 253 return ListPointDetector2DCentre 254 255 def get_Delays(self, RayList) -> list[float]: 256 """ 257 Returns the list of delays of the rays of RayList as they hit the detector plane, 258 calculated as their total path length divided by the speed of light. 259 The delays are relative to the mean “travel time”, i.e. the mean path length of RayList 260 divided by the speed of light. 261 The list index corresponds to that of the RayList. 262 263 Parameters 264 ---------- 265 RayList : list[Ray] 266 A list of objects of the ModuleOpticalRay.Ray-class. 267 268 Returns 269 ---------- 270 DelayList : list[float] 271 """ 272 if self._iscomplete(): 273 DetectorPointList3D = self.get_PointList3D(RayList) 274 OpticalPathList = [] 275 for k in range(len(RayList)): 276 OpticalPathList.append(np.linalg.norm(RayList[k].point - DetectorPointList3D[k]) + np.sum(RayList[k].path)) 277 278 MeanPath = np.mean(OpticalPathList) 279 DelayList = [(k - MeanPath) / LightSpeed * 1e15 for k in OpticalPathList] # in fs, c in mm/s 280 return DelayList
A detector is simply a plane in 3D-lab-space. It is defined by a point Detector.centre and its normal vector Detector.normal (thought to point towards the incoming rays). These are optional arguments when creating a Detector-instance, because they can later be set automatically by the method Detector.autoplace(). The Detector has a reference point "RefPoint", with respect to which a distance can be returned via the method Detector.get distance.
Attributes
centre : np.ndarray
3D Point in the Detector plane.
normal : np.ndarray
3D Normal vector on the Detector plane.
refpoint : np.ndarray
3D reference point from which to measure the Detector distance.
48 def __init__(self, RefPoint: np.ndarray, Centre=None, Normal=None): 49 """ 50 Parameters 51 ---------- 52 RefPoint : np.ndarray 53 3D Reference point from which to measure the Detector distance. 54 55 Centre : np.ndarray, optional 56 3D Point in the Detector plane. 57 58 Normal : np.ndarray, optional 59 3D Normal vector on the Detector plane. 60 """ 61 self.centre = Centre 62 self.normal = Normal 63 self.refpoint = RefPoint
Parameters
RefPoint : np.ndarray
3D Reference point from which to measure the Detector distance.
Centre : np.ndarray, optional
3D Point in the Detector plane.
Normal : np.ndarray, optional
3D Normal vector on the Detector plane.
104 def copy_detector(self): 105 """ 106 Returns a new Detector object with the same properties. 107 """ 108 return Detector(self.refpoint, self.centre, self.normal)
Returns a new Detector object with the same properties.
110 def autoplace(self, RayList, DistanceDetector: float): 111 """ 112 Automatically place and orient the detector such that it is normal to the central ray 113 of the supplied RayList, at the distance DistanceDetector the origin point of that central ray. 114 115 Parameters 116 ---------- 117 RayList : list[Ray] 118 A list of objects of the ModuleOpticalRay.Ray-class. 119 120 DistanceDetector : float 121 The distance at which to place the Detector. 122 """ 123 CentralRay = mp.FindCentralRay(RayList) 124 if CentralRay is None: 125 DetectorNormal = np.array([0, 0, 0]) 126 CentralPoint = np.array([0, 0, 0]) 127 for k in RayList: 128 DetectorNormal = DetectorNormal + k.vector 129 CentralPoint = CentralPoint + k.point 130 DetectorNormal = -DetectorNormal / len(RayList) 131 CentralPoint = CentralPoint / len(RayList) 132 else: 133 DetectorNormal = -CentralRay.vector 134 CentralPoint = CentralRay.point 135 136 self.normal = DetectorNormal 137 self.centre = CentralPoint - DetectorNormal * DistanceDetector 138 self.refpoint = CentralPoint
Automatically place and orient the detector such that it is normal to the central ray of the supplied RayList, at the distance DistanceDetector the origin point of that central ray.
Parameters
RayList : list[Ray]
A list of objects of the ModuleOpticalRay.Ray-class.
DistanceDetector : float
The distance at which to place the Detector.
140 def get_distance(self): 141 """ 142 Return distance of the Detector-plane from its reference point Detector.refpoint. 143 """ 144 return np.linalg.norm( 145 self.refpoint - mgeo.IntersectionLinePlane(self.refpoint, -self.normal, self.centre, self.normal) 146 )
Return distance of the Detector-plane from its reference point Detector.refpoint.
148 def shiftToDistance(self, NewDistance: float): 149 """ 150 Shift the Detector to the distance NewDistance from its reference point Detector.refpoint. 151 152 Parameters 153 ---------- 154 NewDistance : float 155 The distance (absolute) to which to shift the Detector. 156 """ 157 if type(NewDistance) == int or type(NewDistance) == float or type(NewDistance) == np.float64: 158 shiftby = NewDistance - self.get_distance() # by that much in the self.normal-direction 159 else: 160 raise TypeError("The new Detector Distance must be int or float.") 161 162 self._centre += -shiftby * self.normal
Shift the Detector to the distance NewDistance from its reference point Detector.refpoint.
Parameters
NewDistance : float
The distance (absolute) to which to shift the Detector.
164 def shiftByDistance(self, Shift: float): 165 """ 166 Shift the Detector *by* the distance Shift along its normal vector Detector.normal. 167 168 Parameters 169 ---------- 170 Shift : float 171 The distance (relative) *by* which to shift the Detector. 172 """ 173 if type(Shift) == int or type(Shift) == float or type(Shift) == np.float64: 174 self._centre = self.centre - Shift * self.normal # directly set _centre, i.e. circumvent setter 175 # because we already checked shift here, and centre 176 # and normal have been checked before 177 else: 178 raise TypeError("The Detector Distance Shift must be int or float.")
Shift the Detector by the distance Shift along its normal vector Detector.normal.
Parameters
Shift : float
The distance (relative) *by* which to shift the Detector.
192 def get_PointList3D(self, RayList) -> list[np.ndarray]: 193 """ 194 Returns the list of 3D-points in lab-space where the rays in the 195 list RayList hit the detector plane. 196 197 Parameters 198 ---------- 199 RayList : list[Ray] 200 A list of objects of the ModuleOpticalRay.Ray-class. 201 202 Returns 203 ---------- 204 ListPointDetector3D : list[np.ndarray of shape (3,)] 205 """ 206 if self._iscomplete(): 207 ListPointDetector3D = [] 208 append = ListPointDetector3D.append 209 for k in RayList: 210 append(mgeo.IntersectionLinePlane(k.point, k.vector, self.centre, self.normal)) 211 return ListPointDetector3D
Returns the list of 3D-points in lab-space where the rays in the list RayList hit the detector plane.
Parameters
RayList : list[Ray]
A list of objects of the ModuleOpticalRay.Ray-class.
Returns
ListPointDetector3D : list[np.ndarray of shape (3,)]
213 def get_PointList2D(self, RayList) -> list[np.ndarray]: 214 """ 215 Returns the list of 2D-points in the detector plane, with the origin at Detector.centre. 216 217 Parameters 218 ---------- 219 RayList : list[Ray] 220 A list of objects of the ModuleOpticalRay.Ray-class. 221 222 Returns 223 ---------- 224 ListPointDetector2D : list[np.ndarray of shape (2,)] 225 """ 226 if self._iscomplete(): 227 ListPointDetector3D = self.get_PointList3D(RayList) 228 229 ListPointDetector3D = [ 230 k - self.centre for k in ListPointDetector3D 231 ] # Equivalent to taking the detector's central point as the origin 232 ListPointDetector3D = mgeo.RotationPointList(ListPointDetector3D, self.normal, np.array([0, 0, 1])) 233 234 ListPointDetector2D = [k[0:2] for k in ListPointDetector3D] 235 return ListPointDetector2D
Returns the list of 2D-points in the detector plane, with the origin at Detector.centre.
Parameters
RayList : list[Ray]
A list of objects of the ModuleOpticalRay.Ray-class.
Returns
ListPointDetector2D : list[np.ndarray of shape (2,)]
237 def get_PointList2DCentre(self, RayList) -> list[np.ndarray]: 238 """ 239 Returns the list of 2D-points in the detector plane, with the origin centered in the point cloud. 240 241 Parameters 242 ---------- 243 RayLis* : list[Ray] 244 A list of objects of the ModuleOpticalRay.Ray-class. 245 246 Returns 247 ---------- 248 ListPointDetector2DCentre : list[np.ndarray of shape (2,)] 249 """ 250 if self._iscomplete(): 251 ListPointDetector2D = self.get_PointList2D(RayList) 252 ListPointDetector2DCentre = mgeo.CentrePointList(ListPointDetector2D) 253 return ListPointDetector2DCentre
Returns the list of 2D-points in the detector plane, with the origin centered in the point cloud.
Parameters
RayLis* : list[Ray]
A list of objects of the ModuleOpticalRay.Ray-class.
Returns
ListPointDetector2DCentre : list[np.ndarray of shape (2,)]
255 def get_Delays(self, RayList) -> list[float]: 256 """ 257 Returns the list of delays of the rays of RayList as they hit the detector plane, 258 calculated as their total path length divided by the speed of light. 259 The delays are relative to the mean “travel time”, i.e. the mean path length of RayList 260 divided by the speed of light. 261 The list index corresponds to that of the RayList. 262 263 Parameters 264 ---------- 265 RayList : list[Ray] 266 A list of objects of the ModuleOpticalRay.Ray-class. 267 268 Returns 269 ---------- 270 DelayList : list[float] 271 """ 272 if self._iscomplete(): 273 DetectorPointList3D = self.get_PointList3D(RayList) 274 OpticalPathList = [] 275 for k in range(len(RayList)): 276 OpticalPathList.append(np.linalg.norm(RayList[k].point - DetectorPointList3D[k]) + np.sum(RayList[k].path)) 277 278 MeanPath = np.mean(OpticalPathList) 279 DelayList = [(k - MeanPath) / LightSpeed * 1e15 for k in OpticalPathList] # in fs, c in mm/s 280 return DelayList
Returns the list of delays of the rays of RayList as they hit the detector plane, calculated as their total path length divided by the speed of light. The delays are relative to the mean “travel time”, i.e. the mean path length of RayList divided by the speed of light. The list index corresponds to that of the RayList.
Parameters
RayList : list[Ray]
A list of objects of the ModuleOpticalRay.Ray-class.
Returns
DelayList : list[float]