emccd-detect 2.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- emccd_detect/__init__.py +2 -0
- emccd_detect/cosmics.py +124 -0
- emccd_detect/emccd_detect.py +693 -0
- emccd_detect/rand_em_gain.py +187 -0
- emccd_detect/util/__init__.py +1 -0
- emccd_detect/util/metadata.yaml +60 -0
- emccd_detect/util/read_metadata.py +90 -0
- emccd_detect/util/read_metadata_wrapper.py +157 -0
- emccd_detect-2.2.5.dist-info/METADATA +69 -0
- emccd_detect-2.2.5.dist-info/RECORD +12 -0
- emccd_detect-2.2.5.dist-info/WHEEL +5 -0
- emccd_detect-2.2.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""Generate random numbers according to EM gain pdfs."""
|
3
|
+
|
4
|
+
import numpy as np
|
5
|
+
from scipy import special
|
6
|
+
|
7
|
+
|
8
|
+
class RandEMGainException(Exception):
|
9
|
+
"""Exception class for rand_em_gain module."""
|
10
|
+
|
11
|
+
|
12
|
+
def rand_em_gain(n_in_array, em_gain):
|
13
|
+
"""Generate random numbers according to EM gain pdfs.
|
14
|
+
|
15
|
+
Parameters
|
16
|
+
----------
|
17
|
+
n_in_array : array_like
|
18
|
+
Array of electron values (e-).
|
19
|
+
em_gain : float
|
20
|
+
CCD em_gain (e-/photon).
|
21
|
+
|
22
|
+
Returns
|
23
|
+
-------
|
24
|
+
array_like
|
25
|
+
Electron values multiplied by random EM gain distribution (e-).
|
26
|
+
|
27
|
+
Notes
|
28
|
+
-----
|
29
|
+
This function returns an array of the same size as n_in_array. Every element
|
30
|
+
in n_in_array is multiplied by em_gain*rand_val, where rand_val is a random
|
31
|
+
number drawn from a specific pdf selected based on the value of the
|
32
|
+
n_in_array element.
|
33
|
+
|
34
|
+
References
|
35
|
+
----------
|
36
|
+
[1] http://matlabtricks.com/post-44/generate-random-numbers-with-a-given-distribution
|
37
|
+
[2] https://arxiv.org/pdf/astro-ph/0307305.pdf
|
38
|
+
|
39
|
+
"""
|
40
|
+
if em_gain < 1:
|
41
|
+
raise RandEMGainException('EM gain cannot be set to less than 1')
|
42
|
+
elif em_gain == 1:
|
43
|
+
return n_in_array
|
44
|
+
else:
|
45
|
+
# Apply gain to regular counts
|
46
|
+
n_out_array = np.random.gamma(n_in_array, em_gain)
|
47
|
+
n_out_array = np.round(n_out_array)
|
48
|
+
return n_out_array
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
if __name__ == '__main__':
|
54
|
+
import time
|
55
|
+
import matplotlib.pyplot as plt
|
56
|
+
|
57
|
+
# Generally, the agreement b/w the old and new methods is good. The new
|
58
|
+
# method just speeds up the code a lot, especially when cosmics are present.
|
59
|
+
# Old method functions below:
|
60
|
+
|
61
|
+
def _apply_gain(n_in_array, em_gain, max_out):
|
62
|
+
"""Apply a specific em_gain to all nonzero n_in values."""
|
63
|
+
# Initialize output count array
|
64
|
+
n_out_array = np.zeros_like(n_in_array)
|
65
|
+
|
66
|
+
# Get unique nonzero n_in values
|
67
|
+
n_in_unique = np.unique(n_in_array)
|
68
|
+
n_in_unique = n_in_unique[n_in_unique > 0]
|
69
|
+
|
70
|
+
# Generate random numbers according to the gain distribution for each n_in
|
71
|
+
for n_in in n_in_unique:
|
72
|
+
inds = np.where(n_in_array == n_in)[0]
|
73
|
+
n_out_array[inds] = _rand_pdf(n_in, em_gain, max_out, len(inds))
|
74
|
+
|
75
|
+
# n_out_array = np.random.gamma(n_in_array, em_gain)
|
76
|
+
# n_out_array = np.round(n_out_array)
|
77
|
+
|
78
|
+
return n_out_array
|
79
|
+
|
80
|
+
|
81
|
+
def _rand_pdf(n_in, em_gain, x_max, size):
|
82
|
+
"""Draw samples from the EM gain distribution."""
|
83
|
+
x = np.random.random(size)
|
84
|
+
|
85
|
+
# Use exact solutions for n_in == 1 and 2
|
86
|
+
if n_in == 1:
|
87
|
+
n_out = -em_gain * np.log(1 - x)
|
88
|
+
elif n_in == 2:
|
89
|
+
n_out = -em_gain * special.lambertw((x-1)/np.exp(1), -1).real - em_gain
|
90
|
+
else:
|
91
|
+
# For n > 2 use CDF approximation
|
92
|
+
# Use x values ranging from 0 to maximum allowable x output
|
93
|
+
x_axis = np.arange(0, x_max).astype(float)
|
94
|
+
x_axis[0] = np.finfo(float).eps # Use epsilon to avoid divide by 0
|
95
|
+
cdf = _get_cdf(n_in, em_gain, x_axis)
|
96
|
+
|
97
|
+
if cdf is None:
|
98
|
+
# If cdf maxes out, return maximum value
|
99
|
+
n_out = np.ones_like(x) * x_max
|
100
|
+
else:
|
101
|
+
# Draw random samples from the CDF
|
102
|
+
cdf_lookups = (cdf.max() - cdf.min()) * x + cdf.min()
|
103
|
+
n_out = x_axis[np.searchsorted(cdf, cdf_lookups)] # XXX This could be made more accurate
|
104
|
+
|
105
|
+
return np.round(n_out)
|
106
|
+
|
107
|
+
|
108
|
+
def _get_cdf(n_in, em_gain, x):
|
109
|
+
"""Return an approximate CDF for the EM gain distribution.
|
110
|
+
|
111
|
+
Basden 2003 probability distribution function is as follows:
|
112
|
+
|
113
|
+
pdf = x^(n_in-1) * exp(-x/g) / (g^n_in * factorial(n_in-1))
|
114
|
+
|
115
|
+
"""
|
116
|
+
# Because of the cancellation of very large numbers, first work in log space
|
117
|
+
logpdf = (n_in-1)*np.log(x) - x/em_gain - n_in*np.log(em_gain) - special.gammaln(n_in)
|
118
|
+
pdf = np.exp(logpdf)
|
119
|
+
|
120
|
+
# XXX This is a rough but safe solution
|
121
|
+
sum_pdf = np.sum(pdf)
|
122
|
+
if sum_pdf == 0:
|
123
|
+
cdf = None
|
124
|
+
else:
|
125
|
+
cdf = np.cumsum(pdf / sum_pdf)
|
126
|
+
|
127
|
+
return cdf
|
128
|
+
|
129
|
+
def compare_stats(g, n, n_samples, max_val, num_bins, plot=False):
|
130
|
+
|
131
|
+
n_in_array = np.array([n]*n_samples)
|
132
|
+
old_method = _apply_gain(n_in_array, g, max_val)
|
133
|
+
|
134
|
+
# gamma distribution:
|
135
|
+
x = rand_em_gain(n_in_array, g)
|
136
|
+
|
137
|
+
print("For n={}, g={}:".format(n,g))
|
138
|
+
print('Mean for old method: ', np.mean(old_method))
|
139
|
+
print('Std dev for old method: ', np.std(old_method))
|
140
|
+
print('Mean of gamma distribution: ', np.mean(x))
|
141
|
+
print('Std dev for gamma distribution: ', np.std(x))
|
142
|
+
print('theoretical mean: ', g*n)
|
143
|
+
print('theortical std dev: ', g*np.sqrt(n))
|
144
|
+
print()
|
145
|
+
|
146
|
+
if plot==True:
|
147
|
+
fig, ax = plt.subplots()
|
148
|
+
H = ax.hist(old_method, bins = num_bins)
|
149
|
+
ax.set_ylabel('number of occurrences')
|
150
|
+
ax.set_xlabel('gained counts (e-)')
|
151
|
+
ax.set_title('Histogram of Gained Counts (Old Method, n={})'.format(n))
|
152
|
+
|
153
|
+
fig, ax = plt.subplots()
|
154
|
+
H = ax.hist(x, bins = num_bins)
|
155
|
+
ax.set_ylabel('number of occurrences')
|
156
|
+
ax.set_xlabel('gained counts (e-)')
|
157
|
+
ax.set_title('Histogram of Gained Counts (Gamma Distribution, n={})'.format(n))
|
158
|
+
|
159
|
+
plt.show()
|
160
|
+
|
161
|
+
g = 2 #20 #200
|
162
|
+
n_samples = 10000
|
163
|
+
#max_val = 200000
|
164
|
+
num_bins = 40
|
165
|
+
# let max_out be the mean + 4*std dev from gamma dist for the max value
|
166
|
+
# from serial_counts (using ENF ~ sqrt(2), which is fine even for low
|
167
|
+
# gain since we just want an upper limit)
|
168
|
+
def max_val(g, n):
|
169
|
+
return g*n + 4*g*np.sqrt(2*n)
|
170
|
+
|
171
|
+
# in original code, max_val used max(n_in_array) where that array was for
|
172
|
+
# all serial cells; so artifically inflate by multiplying by 100
|
173
|
+
n = 1
|
174
|
+
compare_stats(g, n, n_samples, 100*max_val(g,n), num_bins)
|
175
|
+
|
176
|
+
n2 = 2
|
177
|
+
compare_stats(g, n2, n_samples, 100*max_val(g,n), num_bins)
|
178
|
+
|
179
|
+
# now a value of n for which these methods differed
|
180
|
+
n3 = 3
|
181
|
+
compare_stats(g, n3, n_samples, 100*max_val(g,n), num_bins)
|
182
|
+
|
183
|
+
n4 = 40
|
184
|
+
compare_stats(g, n4, n_samples, 100*max_val(g,n), num_bins)
|
185
|
+
|
186
|
+
n5 = 100
|
187
|
+
compare_stats(g, n5, n_samples, 100*max_val(g,n), num_bins)
|
@@ -0,0 +1 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Any regions not specified are assumed to be shielded or unused pixels.
|
2
|
+
#
|
3
|
+
# Geometry regions are defined as:
|
4
|
+
# rows: number of region rows
|
5
|
+
# cols: number of region columns
|
6
|
+
# r0c0: coordinates (row, col) of the corner closest to (0, 0) of the array
|
7
|
+
#
|
8
|
+
# For example, in a 5x5 array, the following geometry would look as follows:
|
9
|
+
# rows: 2
|
10
|
+
# cols: 3
|
11
|
+
# r0c0:
|
12
|
+
# - 2
|
13
|
+
# - 1
|
14
|
+
#
|
15
|
+
# [
|
16
|
+
# [0, 0, 0, 0, 0],
|
17
|
+
# [0, 0, 0, 0, 0],
|
18
|
+
# [0, 1, 1, 1, 0],
|
19
|
+
# [0, 1, 1, 1, 0],
|
20
|
+
# [0, 0, 0, 0, 0]
|
21
|
+
# ]
|
22
|
+
#
|
23
|
+
# where (0, 0) is defined as the top left of this array.
|
24
|
+
frame_rows: 1200
|
25
|
+
frame_cols: 2200
|
26
|
+
geom:
|
27
|
+
image:
|
28
|
+
rows: 1024
|
29
|
+
cols: 1024
|
30
|
+
r0c0:
|
31
|
+
- 13
|
32
|
+
- 1088
|
33
|
+
prescan:
|
34
|
+
rows: 1200
|
35
|
+
cols: 1088
|
36
|
+
# good, reliable cols used for getting row-by-row bias, relative to r0c0
|
37
|
+
col_start: 800
|
38
|
+
col_end: 1000
|
39
|
+
r0c0:
|
40
|
+
- 0
|
41
|
+
- 0
|
42
|
+
parallel_overscan:
|
43
|
+
rows: 163
|
44
|
+
cols: 1056
|
45
|
+
r0c0:
|
46
|
+
- 1037
|
47
|
+
- 1088
|
48
|
+
serial_overscan:
|
49
|
+
rows: 1200
|
50
|
+
cols: 56
|
51
|
+
r0c0:
|
52
|
+
- 0
|
53
|
+
- 2144
|
54
|
+
eperdn: 8.2
|
55
|
+
fwc: 105000 #serial
|
56
|
+
sat_thresh: 0.99
|
57
|
+
plat_thresh: 0.85
|
58
|
+
cosm_filter: 2
|
59
|
+
tail_filter: #5
|
60
|
+
cic_thresh: #100
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""Detector geometry metadata."""
|
3
|
+
|
4
|
+
import yaml
|
5
|
+
|
6
|
+
|
7
|
+
class ReadMetadataException(Exception):
|
8
|
+
"""Exception class for read_metadata module."""
|
9
|
+
|
10
|
+
|
11
|
+
class Metadata(object):
|
12
|
+
"""Create masks for different regions of the WFIRST CGI EMCCD detector.
|
13
|
+
|
14
|
+
Parameters
|
15
|
+
----------
|
16
|
+
meta_path : str
|
17
|
+
Full path of metadta yaml.
|
18
|
+
|
19
|
+
Attributes
|
20
|
+
----------
|
21
|
+
data : dict
|
22
|
+
Data from metadata file.
|
23
|
+
geom : SimpleNamespace
|
24
|
+
Geometry specific data.
|
25
|
+
eperdn : float
|
26
|
+
Electrons per dn conversion factor (detector k gain).
|
27
|
+
fwc : float
|
28
|
+
Full well capacity of detector.
|
29
|
+
sat_thresh : float
|
30
|
+
Multiplication factor for fwc that determines saturated cosmic pixels.
|
31
|
+
plat_thresh : float
|
32
|
+
Multiplication factor for fwc that determines edges of cosmic plateu.
|
33
|
+
cosm_filter : int
|
34
|
+
Minimum length in pixels of cosmic plateus to be identified.
|
35
|
+
tail_filter : int
|
36
|
+
Moving median filter window size for cosmic tail subtraction.
|
37
|
+
cic_thresh : float
|
38
|
+
Multiplication factor for readnoise that determines beginning of cic.
|
39
|
+
|
40
|
+
B Nemati and S Miller - UAH - 03-Aug-2018
|
41
|
+
|
42
|
+
"""
|
43
|
+
|
44
|
+
def __init__(self, meta_path):
|
45
|
+
self.meta_path = meta_path
|
46
|
+
|
47
|
+
self.data = self.get_data()
|
48
|
+
self.frame_rows = self.data['frame_rows']
|
49
|
+
self.frame_cols = self.data['frame_cols']
|
50
|
+
self.geom = self.data['geom']
|
51
|
+
self.eperdn = self.data['eperdn']
|
52
|
+
self.fwc = self.data['fwc']
|
53
|
+
self.sat_thresh = self.data['sat_thresh']
|
54
|
+
self.plat_thresh = self.data['plat_thresh']
|
55
|
+
self.cosm_filter = self.data['cosm_filter']
|
56
|
+
self.tail_filter = self.data['tail_filter']
|
57
|
+
self.cic_thresh = self.data['cic_thresh']
|
58
|
+
|
59
|
+
def get_data(self):
|
60
|
+
"""Read yaml data into dictionary."""
|
61
|
+
with open(self.meta_path, 'r') as stream:
|
62
|
+
data = yaml.safe_load(stream)
|
63
|
+
return data
|
64
|
+
|
65
|
+
def slice_section(self, frame, key):
|
66
|
+
"""Slice 2d section out of frame.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
frame : array_like
|
71
|
+
Full frame consistent with size given in frame_rows, frame_cols.
|
72
|
+
key : str
|
73
|
+
Keyword referencing section to be sliced; must exist in geom.
|
74
|
+
|
75
|
+
"""
|
76
|
+
rows, cols, r0c0 = self._unpack_geom(key)
|
77
|
+
|
78
|
+
section = frame[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols]
|
79
|
+
if section.size == 0:
|
80
|
+
raise ReadMetadataException('Corners invalid')
|
81
|
+
return section
|
82
|
+
|
83
|
+
def _unpack_geom(self, key):
|
84
|
+
"""Safely check format of geom sub-dictionary and return values."""
|
85
|
+
coords = self.geom[key]
|
86
|
+
rows = coords['rows']
|
87
|
+
cols = coords['cols']
|
88
|
+
r0c0 = coords['r0c0']
|
89
|
+
|
90
|
+
return rows, cols, r0c0
|
@@ -0,0 +1,157 @@
|
|
1
|
+
"""Wrapper for read_metadata to allow use in emccd_detect simulator."""
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
|
5
|
+
from emccd_detect.util.read_metadata import Metadata
|
6
|
+
|
7
|
+
|
8
|
+
class ReadMetadataWrapperException(Exception):
|
9
|
+
"""Exception class for read_metadata_wrapper module."""
|
10
|
+
|
11
|
+
|
12
|
+
class MetadataWrapper(Metadata):
|
13
|
+
"""Wrapper for Metadata class to add functionality for emccd_detect.
|
14
|
+
|
15
|
+
Parameters
|
16
|
+
----------
|
17
|
+
meta_path : str
|
18
|
+
Full path of metadta yaml.
|
19
|
+
|
20
|
+
Attributes
|
21
|
+
----------
|
22
|
+
data : dict
|
23
|
+
Data from metadata file.
|
24
|
+
geom : SimpleNamespace
|
25
|
+
Geometry specific data.
|
26
|
+
eperdn : float
|
27
|
+
Electrons per dn conversion factor (detector k gain).
|
28
|
+
fwc : float
|
29
|
+
Full well capacity of detector.
|
30
|
+
sat_thresh : float
|
31
|
+
Multiplication factor for fwc that determines saturated cosmic pixels.
|
32
|
+
plat_thresh : float
|
33
|
+
Multiplication factor for fwc that determines edges of cosmic plateu.
|
34
|
+
cosm_filter : int
|
35
|
+
Minimum length in pixels of cosmic plateus to be identified.
|
36
|
+
tail_filter : int
|
37
|
+
Moving median filter window size for cosmic tail subtraction.
|
38
|
+
cic_thresh : float
|
39
|
+
Multiplication factor for readnoise that determines beginning of cic.
|
40
|
+
|
41
|
+
"""
|
42
|
+
|
43
|
+
def __init__(self, *args, **kwargs):
|
44
|
+
super().__init__(*args, **kwargs)
|
45
|
+
|
46
|
+
# Get imaging area geometry
|
47
|
+
self.rows_im, self.cols_im, self.r0c0_im = self._imaging_area_geom()
|
48
|
+
|
49
|
+
# Make some zeros frames for initial creation of arrays
|
50
|
+
self.imaging_area_zeros = np.zeros((self.rows_im, self.cols_im))
|
51
|
+
self.full_frame_zeros = np.zeros((self.frame_rows, self.frame_cols))
|
52
|
+
|
53
|
+
def mask(self, key):
|
54
|
+
full_frame_m = self.full_frame_zeros.copy()
|
55
|
+
|
56
|
+
rows, cols, r0c0 = self._unpack_geom(key)
|
57
|
+
full_frame_m[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols] = 1
|
58
|
+
return full_frame_m.astype(bool)
|
59
|
+
|
60
|
+
def embed(self, frame, key, data):
|
61
|
+
rows, cols, r0c0 = self._unpack_geom(key)
|
62
|
+
try:
|
63
|
+
frame[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols] = data
|
64
|
+
except Exception:
|
65
|
+
raise ReadMetadataWrapperException('Data does not fit in selected '
|
66
|
+
'section')
|
67
|
+
return frame
|
68
|
+
|
69
|
+
def embed_im(self, im_area, key, data):
|
70
|
+
rows, cols, r0c0 = self._unpack_geom_im(key)
|
71
|
+
try:
|
72
|
+
im_area[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols] = data
|
73
|
+
except Exception:
|
74
|
+
raise ReadMetadataWrapperException('Data does not fit in selected '
|
75
|
+
'section')
|
76
|
+
return im_area
|
77
|
+
|
78
|
+
def imaging_slice(self, frame):
|
79
|
+
"""Select only the real counts from full frame and exclude virtual.
|
80
|
+
|
81
|
+
Use this to transform mask and embed from acting on the full frame to
|
82
|
+
acting on only the image frame.
|
83
|
+
|
84
|
+
"""
|
85
|
+
rows, cols, r0c0 = self._imaging_area_geom()
|
86
|
+
|
87
|
+
return frame[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols]
|
88
|
+
|
89
|
+
def imaging_embed(self, frame, im_area):
|
90
|
+
"""Add the imaging area back to the full frame."""
|
91
|
+
rows, cols, r0c0 = self._imaging_area_geom()
|
92
|
+
|
93
|
+
frame[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols] = im_area
|
94
|
+
return frame
|
95
|
+
|
96
|
+
def _unpack_geom_corners(self, key):
|
97
|
+
"""Returns corners corresponding to geometry."""
|
98
|
+
rows, cols, r0c0 = self._unpack_geom(key)
|
99
|
+
r1c1 = (r0c0[0]+rows-1, r0c0[1]+cols-1)
|
100
|
+
|
101
|
+
return r0c0, r1c1
|
102
|
+
|
103
|
+
def _unpack_geom_im(self, key):
|
104
|
+
"""Wrapper for _unpack_geom, transforms r0c0 locations from full frame
|
105
|
+
coords to imaging area coords.
|
106
|
+
|
107
|
+
"""
|
108
|
+
# Unpack geomotry of requested section
|
109
|
+
rows, cols, r0c0_original = self._unpack_geom(key)
|
110
|
+
# Unpack geometry of imaging area
|
111
|
+
_, _, r0c0_im = self._imaging_area_geom()
|
112
|
+
|
113
|
+
# Shift r0c0 locations by the r0c0 of the imaging area
|
114
|
+
r0c0 = r0c0_original.copy()
|
115
|
+
r0c0[0] -= r0c0_im[0]
|
116
|
+
r0c0[1] -= r0c0_im[1]
|
117
|
+
|
118
|
+
# Make sure new geom is valid
|
119
|
+
pass
|
120
|
+
|
121
|
+
return rows, cols, r0c0
|
122
|
+
|
123
|
+
def _imaging_area_geom(self):
|
124
|
+
"""Return geometry of imaging area in reference to full frame."""
|
125
|
+
_, cols_pre, _ = self._unpack_geom('prescan')
|
126
|
+
_, cols_serial_ovr, _ = self._unpack_geom('serial_overscan')
|
127
|
+
rows_parallel_ovr, _, _ = self._unpack_geom('parallel_overscan')
|
128
|
+
#_, _, r0c0_image = self._unpack_geom('image')
|
129
|
+
fluxmap_rows, _, r0c0_image = self._unpack_geom('image')
|
130
|
+
|
131
|
+
rows_im = self.frame_rows - rows_parallel_ovr
|
132
|
+
cols_im = self.frame_cols - cols_pre - cols_serial_ovr
|
133
|
+
r0c0_im = r0c0_image.copy()
|
134
|
+
r0c0_im[0] = r0c0_im[0] - (rows_im - fluxmap_rows)
|
135
|
+
|
136
|
+
return rows_im, cols_im, r0c0_im
|
137
|
+
|
138
|
+
def slice_section_im(self, im_area, key):
|
139
|
+
"""Slice 2d section out of imaging area of frame.
|
140
|
+
|
141
|
+
Parameters
|
142
|
+
----------
|
143
|
+
im_area : array_like
|
144
|
+
Imaging area of frame, i.e. the full frame with the prescan and
|
145
|
+
overscan removed:
|
146
|
+
full_frame[:overscan[r0c0[0]], overscan[r0c0[1]]:]
|
147
|
+
key : str
|
148
|
+
Keyword referencing section to be sliced; must exist in geom and
|
149
|
+
must not be 'prescan' or 'overscan'.
|
150
|
+
|
151
|
+
"""
|
152
|
+
rows, cols, r0c0 = self._unpack_geom_im(key)
|
153
|
+
|
154
|
+
section = im_area[r0c0[0]:r0c0[0]+rows, r0c0[1]:r0c0[1]+cols]
|
155
|
+
if section.size == 0:
|
156
|
+
raise ReadMetadataWrapperException('Corners invalid')
|
157
|
+
return section
|
@@ -0,0 +1,69 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: emccd_detect
|
3
|
+
Version: 2.2.5
|
4
|
+
Summary: EMCCD detector image simulation
|
5
|
+
Home-page: https://github.jpl.nasa.gov/WFIRST-CGI/emccd_detect
|
6
|
+
Author: Bijan Nemati, Sam Miller, Kevin Ludwick
|
7
|
+
Author-email: bijan.nemati@tellus1.com, sam.miller@uah.edu, kevin.ludwick@uah.edu
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
9
|
+
Classifier: Intended Audience :: Developers
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: Programming Language :: Python :: 3.6
|
12
|
+
Classifier: Programming Language :: Python :: 3.7
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
14
|
+
Requires-Python: >=3.6
|
15
|
+
Description-Content-Type: text/markdown
|
16
|
+
Requires-Dist: astropy
|
17
|
+
Requires-Dist: matplotlib
|
18
|
+
Requires-Dist: numpy
|
19
|
+
Requires-Dist: scipy
|
20
|
+
Requires-Dist: pynufft ==2020.0.0
|
21
|
+
Requires-Dist: pyyaml
|
22
|
+
|
23
|
+
# EMCCD Detect
|
24
|
+
|
25
|
+
Given an input fluxmap, emccd_detect will return a simulated EMCCD detector image.
|
26
|
+
|
27
|
+
|
28
|
+
# Version
|
29
|
+
|
30
|
+
The latest version of emccd\_detect is 2.2.5.
|
31
|
+
|
32
|
+
|
33
|
+
## Getting Started
|
34
|
+
### Installing
|
35
|
+
|
36
|
+
This package requires Python version 3.6 or higher. If the user wants the ability to apply charge transfer inefficiency (CTI) to detector frames using the optional tool provided in emccd\_detect, then the Python version should be >=3.6 and <=3.9.
|
37
|
+
|
38
|
+
To install emccd\_detect, navigate to the emccd\_detect directory where setup.py is located and use
|
39
|
+
|
40
|
+
pip install .
|
41
|
+
|
42
|
+
This will install emccd\_detect and its dependencies, which are as follows:
|
43
|
+
|
44
|
+
* astropy
|
45
|
+
* matplotlib
|
46
|
+
* numpy
|
47
|
+
* scipy
|
48
|
+
* pynufft==2020.0.0
|
49
|
+
* pyyaml
|
50
|
+
|
51
|
+
To optionally implement CTI capabilities, navigate to the arcticpy directory (<https://github.com/roman-corgi/emccd_detect/tree/master/arcticpy_folder>), and there will be a file called setup.py in that directory. Use
|
52
|
+
|
53
|
+
pip install .
|
54
|
+
|
55
|
+
This will install arcticpy version 1.0, which is an older version of arcticpy which runs purely on Python (<https://github.com/jkeger/arcticpy/tree/row_wise/arcticpy>). If
|
56
|
+
you have Python>=3.10, the CTI functionality will not work if you are using the arcticpy installation that was included with this emccd_detect package, but everything else will work fine.
|
57
|
+
|
58
|
+
|
59
|
+
### Usage
|
60
|
+
|
61
|
+
For an example of how to use emccd\_detect, see example_script.py.
|
62
|
+
|
63
|
+
|
64
|
+
## Authors
|
65
|
+
|
66
|
+
* Bijan Nemati (<bijan.nemati@tellus1.com>)
|
67
|
+
* Sam Miller (<sam.miller@uah.edu>)
|
68
|
+
* Kevin Ludwick (<kevin.ludwick@uah.edu>)
|
69
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
emccd_detect/__init__.py,sha256=rQ0MYUU5kTHWjOTy7kyoV4spMKntp-VbXP69qDLTRwI,45
|
2
|
+
emccd_detect/cosmics.py,sha256=wRE47QOB3fwxkH5PHTeoyLjJ0fgJki6Z8hLDPx2h3SQ,3991
|
3
|
+
emccd_detect/emccd_detect.py,sha256=x8At7uER_ccsdjO6DHq9mLdrKdO71CcdcBdnl1YdBgE,22363
|
4
|
+
emccd_detect/rand_em_gain.py,sha256=3eF9T7PNYFZT0coGZwBmNTYz6B9pj2lXxTR8ROG6_7Q,6297
|
5
|
+
emccd_detect/util/__init__.py,sha256=iwhKnzeBJLKxpRVjvzwiRE63_zNpIBfaKLITauVph-0,24
|
6
|
+
emccd_detect/util/metadata.yaml,sha256=hcKTg4kMy12dfbCmmvZeKEqjeUA3BYiAcZc5vZpc3bE,1149
|
7
|
+
emccd_detect/util/read_metadata.py,sha256=r511ENJ6zbIvLDWiVic7KsVXYrBphSdTKUQbuwocjLs,2764
|
8
|
+
emccd_detect/util/read_metadata_wrapper.py,sha256=oBh2KpJ-uLTSIY_hPzw8sNIcJ6MENBSf38ks8OaFOSQ,5473
|
9
|
+
emccd_detect-2.2.5.dist-info/METADATA,sha256=AtPSg_JzaaRAvEuvGgOSubLj21JNEF0NdReNez9V4kA,2307
|
10
|
+
emccd_detect-2.2.5.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
11
|
+
emccd_detect-2.2.5.dist-info/top_level.txt,sha256=V0qxOcGf8TowSJXnTxWEMuK9BBsySwhtKNitfdokD0A,13
|
12
|
+
emccd_detect-2.2.5.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
emccd_detect
|