forked from Chandra-MARX/marxs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
detector.py
113 lines (86 loc) · 4.32 KB
/
detector.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# Licensed under GPL version 3 - see LICENSE.rst
import warnings
import numpy as np
from transforms3d.affines import decompose44
from .base import FlatOpticalElement, OpticalElement
from ..utils import SimulationSetupWarning
from ..math.geometry import Cylinder
class FlatDetector(FlatOpticalElement):
'''Flat detector with square pixels
Processing the a photon with this detector adds four columns to the photon
properties:
- ``det_x``, ``det_y``: Event position on the detector in mm
- ``detpix_x``, ``detpix_y``: Event position in detector coordinates, where
(0, 0) is on the corner of the chip.
The (x,y) coordinate system on the chip is such that it falls on the (y,z)
plane of the global x,y,z coordinate system (it would be more logical to
call the chip system (y,z), but traditionally that is not how chip
coordinates are named). The pixel in the corner has coordinates (0, 0) in
the pixel center.
Parameters
----------
pixsize : float
size of pixels in mm
ignore_pixel_warning : bool
ignore warning if derived pixel number is not close to an integer
kwargs :
see `args for optical elements`
'''
loc_coos_name = ['det_x', 'det_y']
'''name for output columns that contain the interaction point in local coordinates.'''
detpix_name = ['detpix_x', 'detpix_y']
'''name for output columns that contain this pixel number.'''
display = {'color': (1.0, 1.0, 0.),
'shape': 'box',
'box-half': '+x'}
def __init__(self, pixsize=1, ignore_pixel_warning=False, **kwargs):
self.pixsize = pixsize
super(FlatDetector, self).__init__(**kwargs)
t, r, zoom, s = decompose44(self.pos4d)
self.npix = [0, 0]
self.centerpix = [0, 0]
for i in (0, 1):
z = zoom[i + 1]
self.npix[i] = int(np.round(2. * z / self.pixsize))
if (np.abs(2. * z / self.pixsize - self.npix[i]) > 1e-2) and not ignore_pixel_warning:
warnings.warn('Detector size is not an integer multiple of pixel size in direction {0}. It will be rounded.'.format('xy'[i]), SimulationSetupWarning)
self.centerpix[i] = (self.npix[i] - 1) / 2
def specific_process_photons(self, photons, intersect, interpos, intercoos):
detx = intercoos[intersect, 0] / self.pixsize + self.centerpix[0]
dety = intercoos[intersect, 1] / self.pixsize + self.centerpix[1]
return {self.detpix_name[0]: detx, self.detpix_name[1]: dety}
class CircularDetector(OpticalElement):
'''A detector shaped like a ring or tube.
This detector is shaped like a tube. The form is a circle in the xy plane
and and flat along the z-direction. While most CCDs are flat in practice,
the `CircularDetector` simulates a setup that can follow the Rowland circle
geometry exactly which is useful, e.g. to study the resolution of a
spectrograph without worrying about the details of the detector geometry.
Parameters
----------
position, orientation, zoom, pos4d : see description of `pos4d`
The radius of the tube is given by the ``zoom`` keyword, see `pos4d`.
Use ``zoom[0] == zoom[1]`` to make a circular tube. ``zoom[0] != zoom[1]`` gives
an elliptical profile. ``zoom[2]`` sets the extension in the z direction.
pixsize : float
size of pixels in mm
phi_offset : float
This defines the center (pixel = 0) in radian. In other words:
The output ``det_phi`` column has its zero position at ``phi_offset`` and
values for ``phi`` are in the range [-pi, pi].
'''
loc_coos_name = ['det_phi', 'det_y']
detpix_name = ['detpix_x', 'detpix_y']
'''name for output columns that contain this pixel number.'''
display = {'color': (1.0, 1.0, 0.),
'opacity': 0.7,
}
centerpix = [0, 0]
default_geometry = Cylinder
def __init__(self, pixsize=1, **kwargs):
self.pixsize = pixsize
super(CircularDetector, self).__init__(**kwargs)
def specific_process_photons(self, photons, intersect, interpos, intercoos):
detx = intercoos[intersect, 0] * self.geometry['R'] / self.pixsize + self.centerpix[0]
dety = intercoos[intersect, 1] / self.pixsize + self.centerpix[1]
return {self.detpix_name[0]: detx, self.detpix_name[1]: dety}