ModuleDetector

class Detector:
 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.
Detector(RefPoint: numpy.ndarray, Centre=None, Normal=None)
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.
def copy_detector(self):
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.

def autoplace(self, RayList, DistanceDetector: float):
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.
def get_distance(self):
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.

def shiftToDistance(self, NewDistance: float):
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.
def shiftByDistance(self, Shift: float):
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.
def get_PointList3D(self, RayList) -> list[numpy.ndarray]:
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,)]
def get_PointList2D(self, RayList) -> list[numpy.ndarray]:
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,)]
def get_PointList2DCentre(self, RayList) -> list[numpy.ndarray]:
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,)]
def get_Delays(self, RayList) -> list[float]:
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]