@@ -63,6 +63,7 @@ def flag_saturated_pixels(
63
63
updated pixel dq array
64
64
"""
65
65
nints , ngroups , nrows , ncols = data .shape
66
+ dnu = dqflags ["DO_NOT_USE" ]
66
67
saturated = dqflags ["SATURATED" ]
67
68
ad_floor = dqflags ["AD_FLOOR" ]
68
69
no_sat_check = dqflags ["NO_SAT_CHECK" ]
@@ -81,16 +82,11 @@ def flag_saturated_pixels(
81
82
sat_thresh [no_sat_check_mask ] = atod_limit + 1
82
83
83
84
for ints in range (nints ):
85
+ # Work forward through the groups for initial pass at saturation
84
86
for group in range (ngroups ):
85
87
plane = data [ints , group , :, :]
86
88
87
- if read_pattern is not None :
88
- dilution_factor = np .mean (read_pattern [group ]) / read_pattern [group ][- 1 ]
89
- dilution_factor = np .where (no_sat_check_mask , 1 , dilution_factor )
90
- else :
91
- dilution_factor = 1
92
-
93
- flagarray , flaglowarray = plane_saturation (plane , sat_thresh * dilution_factor , dqflags )
89
+ flagarray , flaglowarray = plane_saturation (plane , sat_thresh , dqflags )
94
90
95
91
# for saturation, the flag is set in the current plane
96
92
# and all following planes.
@@ -108,6 +104,77 @@ def flag_saturated_pixels(
108
104
109
105
gdq [ints , group , :, :] = adjacent_pixels (gdq_slice , saturated , n_pix_grow_sat )
110
106
107
+ # Work backward through the groups for a second pass at saturation
108
+ # This is to flag things that actually saturated in prior groups but
109
+ # were not obvious because of group averaging
110
+ for group in range (ngroups - 2 , - 1 , - 1 ):
111
+ plane = data [ints , group , :, :]
112
+ thisdq = gdq [ints , group , :, :]
113
+ nextdq = gdq [ints , group + 1 , :, :]
114
+
115
+ # Determine the dilution factor due to group averaging
116
+ if read_pattern is not None :
117
+ # Single value dilution factor for this group
118
+ dilution_factor = np .mean (read_pattern [group ]) / read_pattern [group ][- 1 ]
119
+ # Broadcast to array size
120
+ dilution_factor = np .where (no_sat_check_mask , 1 , dilution_factor )
121
+ else :
122
+ dilution_factor = 1
123
+
124
+ # Find where this plane looks like it might saturate given the dilution factor
125
+ flagarray , _ = plane_saturation (plane , sat_thresh * dilution_factor , dqflags )
126
+
127
+ # Find the overlap of where this plane looks like it might saturate, was not currently
128
+ # flagged as saturation or DO_NOT_USE, and the next group had saturation flagged.
129
+ indx = np .where ((np .bitwise_and (flagarray , saturated ) != 0 ) & \
130
+ (np .bitwise_and (thisdq , saturated ) == 0 ) & \
131
+ (np .bitwise_and (thisdq , dnu ) == 0 ) & \
132
+ (np .bitwise_and (nextdq , saturated ) != 0 ))
133
+
134
+ # Reset flag array to only pixels passing this gauntlet
135
+ flagarray [:] = 0
136
+ flagarray [indx ] = 2
137
+
138
+ # Grow the newly-flagged saturating pixels
139
+ if n_pix_grow_sat > 0 :
140
+ flagarray = adjacent_pixels (flagarray , saturated , n_pix_grow_sat )
141
+
142
+ # Add them to the gdq array
143
+ np .bitwise_or (gdq [ints , group , :, :], flagarray , gdq [ints , group , :, :])
144
+
145
+ # Add an additional pass to look for things saturating in the second group
146
+ # that can be particularly tricky to identify
147
+ if ((read_pattern is not None ) & (ngroups > 2 )):
148
+ dq2 = gdq [ints , 1 , :, :]
149
+ dq3 = gdq [ints , 2 , :, :]
150
+
151
+ # Identify groups which we wouldn't expect to saturate by the third group,
152
+ # on the basis of the first group
153
+ scigp1 = data [ints , 0 , :, :]
154
+ mask = scigp1 / np .mean (read_pattern [0 ]) * read_pattern [2 ][- 1 ] < sat_thresh
155
+
156
+ # Identify groups with suspiciously large values in the second group
157
+ # In the limit of groups with just nframe this just checks if second group
158
+ # is over the regular saturation limit.
159
+ scigp2 = data [ints , 1 , :, :]
160
+ mask &= scigp2 > sat_thresh / len (read_pattern [1 ])
161
+
162
+ # Identify groups that are saturated in the third group but not yet flagged in the second
163
+ gp3mask = np .where ((np .bitwise_and (dq3 , saturated ) != 0 ) & \
164
+ (np .bitwise_and (dq2 , saturated ) == 0 ), True , False )
165
+ mask &= gp3mask
166
+
167
+ # Flag the 2nd group for the pixels passing that gauntlet
168
+ flagarray = np .zeros_like (mask ,dtype = 'uint8' )
169
+ flagarray [mask ] = saturated
170
+ # flag any pixels that border these new pixels
171
+ if n_pix_grow_sat > 0 :
172
+ flagarray = adjacent_pixels (flagarray , saturated , n_pix_grow_sat )
173
+
174
+ # Add them to the gdq array
175
+ np .bitwise_or (gdq [ints , 1 , :, :], flagarray , gdq [ints , 1 , :, :])
176
+
177
+
111
178
# Check ZEROFRAME.
112
179
if zframe is not None :
113
180
plane = zframe [ints , :, :]
0 commit comments