Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JP-3737: Handle micrometeorite flashes #308

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 114 additions & 80 deletions src/stcal/jump/jump.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
min_diffs_single_pass=10,
mask_persist_grps_next_int=True,
persist_grps_flagged=25,
mmflashfrac=1.0,
):
"""
This is the high-level controlling routine for the jump detection process.
Expand Down Expand Up @@ -221,6 +222,11 @@
min_diffs_single_pass : int
The minimum number of groups to switch to flagging all outliers in a single pass.

mmflashfrac: float
Fraction of the array in a given group that has to have a jump detected
in order to flag the entire array as a jump. This is designed to deal with
sporadic micrometeorite flashes.

Returns
-------
gdq : int, 4D array
Expand Down Expand Up @@ -298,46 +304,7 @@
dqflags['DO_NOT_USE']
gdq[gdq == np.bitwise_or(dqflags['SATURATED'], dqflags['JUMP_DET'])] = \
dqflags['SATURATED']
# This is the flag that controls the flagging of snowballs.
if expand_large_events:
gdq, total_snowballs = flag_large_events(
gdq,
jump_flag,
sat_flag,
min_sat_area=min_sat_area,
min_jump_area=min_jump_area,
expand_factor=expand_factor,
sat_required_snowball=sat_required_snowball,
min_sat_radius_extend=min_sat_radius_extend,
edge_size=edge_size,
sat_expand=sat_expand,
max_extended_radius=max_extended_radius,
mask_persist_grps_next_int=mask_persist_grps_next_int,
persist_grps_flagged=persist_grps_flagged,
)
log.info("Total snowballs = %i", total_snowballs)
number_extended_events = total_snowballs
if find_showers:
gdq, num_showers = find_faint_extended(
data,
gdq,
pdq,
readnoise_2d,
frames_per_group,
minimum_sigclip_groups,
dqflags,
snr_threshold=extend_snr_threshold,
min_shower_area=extend_min_area,
inner=extend_inner_radius,
outer=extend_outer_radius,
sat_flag=sat_flag,
jump_flag=jump_flag,
ellipse_expand=extend_ellipse_expand_ratio,
num_grps_masked=grps_masked_after_shower,
max_extended_radius=max_extended_radius,
)
log.info("Total showers= %i", num_showers)
number_extended_events = num_showers

else:
yinc = int(n_rows // n_slices)
slices = []
Expand Down Expand Up @@ -463,46 +430,54 @@
gdq[gdq == np.bitwise_or(dqflags['SATURATED'], dqflags['JUMP_DET'])] = \
dqflags['SATURATED']

# This is the flag that controls the flagging of snowballs.
if expand_large_events:
gdq, total_snowballs = flag_large_events(
gdq,
jump_flag,
sat_flag,
min_sat_area=min_sat_area,
min_jump_area=min_jump_area,
expand_factor=expand_factor,
sat_required_snowball=sat_required_snowball,
min_sat_radius_extend=min_sat_radius_extend,
edge_size=edge_size,
sat_expand=sat_expand,
max_extended_radius=max_extended_radius,
mask_persist_grps_next_int=mask_persist_grps_next_int,
persist_grps_flagged=persist_grps_flagged,
)
log.info("Total snowballs = %i", total_snowballs)
number_extended_events = total_snowballs
if find_showers:
gdq, num_showers = find_faint_extended(
data,
gdq,
pdq,
readnoise_2d,
frames_per_group,
minimum_sigclip_groups,
dqflags,
snr_threshold=extend_snr_threshold,
min_shower_area=extend_min_area,
inner=extend_inner_radius,
outer=extend_outer_radius,
sat_flag=sat_flag,
jump_flag=jump_flag,
ellipse_expand=extend_ellipse_expand_ratio,
num_grps_masked=grps_masked_after_shower,
max_extended_radius=max_extended_radius,
)
log.info("Total showers= %i", num_showers)
number_extended_events = num_showers
# Look for snowballs in near-IR data
if expand_large_events:
gdq, total_snowballs = flag_large_events(

Check warning on line 435 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L435

Added line #L435 was not covered by tests
gdq,
jump_flag,
sat_flag,
min_sat_area=min_sat_area,
min_jump_area=min_jump_area,
expand_factor=expand_factor,
sat_required_snowball=sat_required_snowball,
min_sat_radius_extend=min_sat_radius_extend,
edge_size=edge_size,
sat_expand=sat_expand,
max_extended_radius=max_extended_radius,
mask_persist_grps_next_int=mask_persist_grps_next_int,
persist_grps_flagged=persist_grps_flagged,
)
log.info("Total snowballs = %i", total_snowballs)
number_extended_events = total_snowballs

Check warning on line 451 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L450-L451

Added lines #L450 - L451 were not covered by tests

# Look for showers in mid-IR data
if find_showers:
gdq, num_showers = find_faint_extended(

Check warning on line 455 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L455

Added line #L455 was not covered by tests
data,
gdq,
pdq,
readnoise_2d,
frames_per_group,
minimum_sigclip_groups,
dqflags,
snr_threshold=extend_snr_threshold,
min_shower_area=extend_min_area,
inner=extend_inner_radius,
outer=extend_outer_radius,
sat_flag=sat_flag,
jump_flag=jump_flag,
ellipse_expand=extend_ellipse_expand_ratio,
num_grps_masked=grps_masked_after_shower,
max_extended_radius=max_extended_radius,
)
log.info("Total showers= %i", num_showers)
number_extended_events = num_showers

Check warning on line 474 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L473-L474

Added lines #L473 - L474 were not covered by tests

# Look for micrometeorite flashes if the triggering
# threshold is less than the entire array
if (mmflashfrac < 1):
gdq = find_micrometeorite_flashes(gdq, jump_flag, mmflashfrac)

Check warning on line 479 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L479

Added line #L479 was not covered by tests

elapsed = time.time() - start
log.info("Total elapsed time = %g sec", elapsed)

Expand All @@ -514,6 +489,65 @@
# Return the updated data quality arrays
return gdq, pdq, total_primary_crs, number_extended_events, stddev

# Find micrometeorite flashes
def find_micrometeorite_flashes(gdq, jump_flag, mmflashfrac, mmflashnmax=5):
"""
This routine looks for micrometeorite flashes that light up the entire array in a small number
of groups. It does this by looking for cases where greater than mmflash_pct percent
of the array is flagged as 'JUMP_DET', and flags the entire array as JUMP_DET in such cases.

Since such flashes are rare (a few per instrument per year, although they can affect 2-3 groups)
this routine also applies a safety catch to ensure that not too many are flagged in any one
exposure due to unexpected detector effects.

Parameters
----------
gdq : int, 4D array
Group dq array
jump_flag : int
DQ flag for jump detection.
mmflashfrac : float
Fraction of the array that can be flagged as a jump before the entire array
will be flagged.
mmflashnmax : float
Maximum number of groups in any given exposure that can be affected by
micrometeorites before we declare a detection failure and flag nothing.
Returns
-------
gdq : int, 4D array
Updated group dq array

"""
log.info("Looking for micrometeorite flashes")

Check warning on line 521 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L521

Added line #L521 was not covered by tests

nints, ngroups, nrows, ncols = gdq.shape

Check warning on line 523 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L523

Added line #L523 was not covered by tests

npix = nrows * ncols # Number of pixels in array

Check warning on line 525 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L525

Added line #L525 was not covered by tests

# Initial loop over integrations + groups to find flashes
flash_int, flash_group = [], []

Check warning on line 528 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L528

Added line #L528 was not covered by tests
# Loop over integrations
for ii in range(0, nints):

Check warning on line 530 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L530

Added line #L530 was not covered by tests
# Loop over groups
for jj in range(0, ngroups):
indx = np.where(gdq[ii, jj, :, :] & jump_flag != 0)
fraction = float(len(indx[0])) / npix
if (fraction > mmflashfrac):
flash_int.append(ii)
flash_group.append(jj)

Check warning on line 537 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L532-L537

Added lines #L532 - L537 were not covered by tests

# If an unrealistically large number of flashes were found, fail out
nflash=len(flash_int)
if (nflash > mmflashnmax):
log.info(f"Unreasonably large number of possible micrometeorite flashes detected ({nflash})")
log.info("Quitting micrometeorite routine and flagging nothing.")

Check warning on line 543 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L540-L543

Added lines #L540 - L543 were not covered by tests
else:
for kk in range(0, nflash):
ii, jj = flash_int[kk], flash_group[kk]
gdq[ii, jj, :, :] = gdq[ii, jj, :, :] | jump_flag
log.info(f"Flagged a micrometeorite flash in integ = {ii}, group = {jj}")

Check warning on line 548 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L545-L548

Added lines #L545 - L548 were not covered by tests

return gdq

Check warning on line 550 in src/stcal/jump/jump.py

View check run for this annotation

Codecov / codecov/patch

src/stcal/jump/jump.py#L550

Added line #L550 was not covered by tests

def flag_large_events(
gdq,
Expand Down
Loading