From 9b074a0e7bfdd2df1404a55abf879b982d28c211 Mon Sep 17 00:00:00 2001 From: Jonathan Eisenhamer Date: Tue, 4 Jun 2024 11:54:43 -0400 Subject: [PATCH] JP-3500 Create WFSS Pure-Parallel associations (#8528) --- CHANGES.rst | 2 + jwst/associations/lib/constraint.py | 42 ++++--- jwst/associations/lib/dms_base.py | 7 +- jwst/associations/lib/rules_level2_base.py | 93 ++++++++++------ jwst/associations/lib/rules_level2b.py | 104 ++++++++++++++++++ jwst/associations/lib/rules_level3_base.py | 22 +++- .../tests/data/pool_034_wfss_parallel.csv | 34 ++++++ jwst/associations/tests/test_constraints.py | 12 ++ jwst/regtest/test_associations_standards.py | 1 + 9 files changed, 265 insertions(+), 52 deletions(-) create mode 100755 jwst/associations/tests/data/pool_034_wfss_parallel.csv diff --git a/CHANGES.rst b/CHANGES.rst index b9bdbf8fce..c353bf0c74 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -36,6 +36,8 @@ associations - Updated Level3 rules for new handling of NIRSpec MOS source_id formatting when constructing output file names. [#8442] +- Create WFSS Pure-Parallel associations [#8528] + dark_current ------------ diff --git a/jwst/associations/lib/constraint.py b/jwst/associations/lib/constraint.py index 34193033e0..7ae0f34e45 100644 --- a/jwst/associations/lib/constraint.py +++ b/jwst/associations/lib/constraint.py @@ -108,6 +108,7 @@ def check_and_set(self, item): - List of `~jwst.associations.ProcessList`. """ self.matched = True + self.found_values.add(self.value) return self.matched, [] @property @@ -140,26 +141,33 @@ def copy(self): """Copy ourselves""" return deepcopy(self) - def get_all_attr(self, attribute: str): # -> list[tuple[SimpleConstraint, typing.Any]]: + def get_all_attr(self, attribute, name=None): """Return the specified attribute - This method is meant to be overridden by classes - that need to traverse a list of constraints. + This method exists solely to support `Constraint.get_all_attr`. + This obviates the need for class/method checking. Parameters ---------- attribute : str The attribute to retrieve + name : str or None + Only return attribute if the name of the current constraint + matches the requested named constraints. If None, always + return value. + Returns ------- [(self, value)] : [(SimpleConstraint, object)] The value of the attribute in a tuple. If there is no attribute, an empty tuple is returned. """ - value = getattr(self, attribute) - if value is not None: - return [(self, value)] + if name is None or name == self.name: + value = getattr(self, attribute, None) + if value is not None: + if not isinstance(value, (list, set)) or len(value): + return [(self, value)] return [] def restore(self): @@ -352,6 +360,7 @@ def check_and_set(self, item): if self.matched: if self.force_unique: self.value = source_value + self.found_values.add(self.value) # Determine reprocessing reprocess = [] @@ -769,17 +778,19 @@ def copy(self): """Copy ourselves""" return deepcopy(self) - def get_all_attr(self, attribute: str): # -> list[tuple[typing.Union[SimpleConstraint, Constraint], typing.Any]]: - """Return the specified attribute - - This method is meant to be overridden by classes - that need to traverse a list of constraints. + def get_all_attr(self, attribute, name=None): + """Return the specified attribute for specified constraints Parameters ---------- attribute : str The attribute to retrieve + name : str or None + Only return attribute if the name of the current constraint + matches the requested named constraints. If None, always + return value. + Returns ------- result : [(SimpleConstraint or Constraint, object)[,...]] @@ -792,11 +803,12 @@ def get_all_attr(self, attribute: str): # -> list[tuple[typing.Union[SimpleConst If the attribute is not found. """ result = [] - value = getattr(self, attribute) - if value is not None: - result = [(self, value)] + if name is None or name == self.name: + value = getattr(self, attribute, None) + if value is not None: + result = [(self, value)] for constraint in self.constraints: - result.extend(constraint.get_all_attr(attribute)) + result.extend(constraint.get_all_attr(attribute, name=name)) return result diff --git a/jwst/associations/lib/dms_base.py b/jwst/associations/lib/dms_base.py index bbd8053a66..56d8ed921f 100644 --- a/jwst/associations/lib/dms_base.py +++ b/jwst/associations/lib/dms_base.py @@ -802,7 +802,12 @@ def _get_target(self): The Level3 Product name representation of the target or source ID. """ - target_id = format_list(self.constraints['target'].found_values) + attrs = self.constraints.get_all_attr('found_values', name='target') + if attrs: + value = attrs[0][1] + else: + value = [] + target_id = format_list(value) target = 't{0:0>3s}'.format(str(target_id)) return target diff --git a/jwst/associations/lib/rules_level2_base.py b/jwst/associations/lib/rules_level2_base.py index fe07c1463a..8821b00da9 100644 --- a/jwst/associations/lib/rules_level2_base.py +++ b/jwst/associations/lib/rules_level2_base.py @@ -1021,14 +1021,27 @@ def __init__(self, exclude_exp_types=None): ) -class Constraint_Target(DMSAttrConstraint): +class Constraint_Target(Constraint): """Select on target id""" def __init__(self): - super(Constraint_Target, self).__init__( - name='target', - sources=['targetid'], - ) + constraints = [ + Constraint([ + DMSAttrConstraint( + name='acdirect', + sources=['asn_candidate'], + value=r"\[\('c\d{4}', 'direct_image'\)\]" + ), + SimpleConstraint( + name='target', + sources=lambda item: '000' + )]), + DMSAttrConstraint( + name='target', + sources=['targetid'], + ) + ] + super(Constraint_Target, self).__init__(constraints, reduce=Constraint.any) # --------------------------------------------- @@ -1148,32 +1161,6 @@ def add_catalog_members(self): ) science = sciences[0] - # Get the exposure sequence for the science. Then, find - # the direct image greater than but closest to this value. - closest = directs[0] # If the search fails, just use the first. - try: - expspcin = int(getattr_from_list(science.item, ['expspcin'], _EMPTY)[1]) - except KeyError: - # If exposure sequence cannot be determined, just fall through. - logger.debug('Science exposure %s has no EXPSPCIN defined.', science) - else: - min_diff = 9999 # Initialize to an invalid value. - for direct in directs: - try: - direct_expspcin = int(getattr_from_list( - direct.item, ['expspcin'], _EMPTY - )[1]) - except KeyError: - # Try the next one. - logger.debug('Direct image %s has no EXPSPCIN defined.', direct) - continue - diff = direct_expspcin - expspcin - if diff < min_diff and diff > 0: - min_diff = diff - closest = direct - - # Note the selected direct image. Used in `Asn_Lv2WFSS._get_opt_element` - self.direct_image = closest # Remove all direct images from the association. members = self.current_product['members'] @@ -1188,6 +1175,7 @@ def add_catalog_members(self): )) # Add the Level3 catalog, direct image, and segmentation map members + self.direct_image = self.find_closest_direct(science, directs) lv3_direct_image_root = DMS_Level3_Base._dms_product_name(self) members.append( Member({ @@ -1239,6 +1227,49 @@ def get_exposure_type(self, item, default='science'): return exp_type + @staticmethod + def find_closest_direct(science, directs): + """Find the direct image that is closest to the science + + Closeness is defined as number difference in the exposure sequence number, + as defined in the column EXPSPCIN. + + Parameters + ---------- + science : dict + The science member to compare against + + directs : [dict[,...]] + The available direct members + + Returns + ------- + closest : dict + The direct image that is the "closest" + """ + closest = directs[0] # If the search fails, just use the first. + try: + expspcin = int(getattr_from_list(science.item, ['expspcin'], _EMPTY)[1]) + except KeyError: + # If exposure sequence cannot be determined, just fall through. + logger.debug('Science exposure %s has no EXPSPCIN defined.', science) + else: + min_diff = 9999 # Initialize to an invalid value. + for direct in directs: + try: + direct_expspcin = int(getattr_from_list( + direct.item, ['expspcin'], _EMPTY + )[1]) + except KeyError: + # Try the next one. + logger.debug('Direct image %s has no EXPSPCIN defined.', direct) + continue + diff = direct_expspcin - expspcin + if diff < min_diff and diff > 0: + min_diff = diff + closest = direct + return closest + def _get_opt_element(self): """Get string representation of the optical elements diff --git a/jwst/associations/lib/rules_level2b.py b/jwst/associations/lib/rules_level2b.py index a6c2677ccd..f176a3ffc4 100644 --- a/jwst/associations/lib/rules_level2b.py +++ b/jwst/associations/lib/rules_level2b.py @@ -43,6 +43,7 @@ 'Asn_Lv2SpecTSO', 'Asn_Lv2WFSSNIS', 'Asn_Lv2WFSSNRC', + 'Asn_Lv2WFSSParallel', 'Asn_Lv2WFSC', ] @@ -1034,3 +1035,106 @@ def _init_hook(self, item): super(Asn_Lv2WFSC, self)._init_hook(item) self.data['asn_type'] = 'wfs-image2' + + +@RegistryMarker.rule +class Asn_Lv2WFSSParallel( + AsnMixin_Lv2WFSS, + AsnMixin_Lv2Spectral, +): + """Level 2b WFSS/GRISM associations for WFSS taken in pure-parallel mode + + Characteristics: + - Association type: ``spec2`` + - Pipeline: ``calwebb_spec2`` + - Multi-object science exposures + - Single Science exposure + - Require a source catalog from processing of the corresponding direct imagery. + + WFSS is executed different when taken as part of a pure-parallel proposal than when WFSS + is done as the primary. The differences are as follows. When primary, all components, the direct + image and the two GRISM exposures, are all executed within the same observation. When in parallel, + each component is taken as a separate observation. + These are always in associations of type DIRECT_IMAGE. + + Another difference is that there is no ``targetid`` assigned to the parallel exposures. However, since + WFSS parallels are very specific, there is not need to constrain on target. A default value is used + for the Level 3 product naming. + """ + + def __init__(self, *args, **kwargs): + + self.constraints = Constraint([ + DMSAttrConstraint( + name='acdirect', + sources=['asn_candidate'], + value=r"\[\('c\d{4}', 'direct_image'\)\]" + ), + Constraint([ + DMSAttrConstraint( + name='exp_type', + sources=['exp_type'], + value='nis_wfss|nrc_wfss', + ), + DMSAttrConstraint( + name='image_exp_type', + sources=['exp_type'], + value='nis_image|nrc_image', + force_reprocess=ListCategory.NONSCIENCE, + only_on_match=True, + ), + ], reduce=Constraint.any), + Constraint([ + SimpleConstraint( + value='science', + test=lambda value, item: self.get_exposure_type(item) != value, + force_unique=False, + ), + Constraint_Single_Science(self.has_science, self.get_exposure_type), + ], reduce=Constraint.any), + Constraint_Target(), + DMSAttrConstraint( + name='instrument', + sources=['instrume'], + ), + ]) + + super(Asn_Lv2WFSSParallel, self).__init__(*args, **kwargs) + + @staticmethod + def find_closest_direct(science, directs): + """Find the direct image that is closest to the science + + For pure-parallel WFSS, there is only ever one direct image. + Simply return that. + + Parameters + ---------- + science : dict + The science member to compare against + + directs : [dict[,...]] + The available direct members + + Returns + ------- + closest : dict + The direct image that is the "closest" + """ + return directs[0] + + def validate_candidates(self, member): + """Stub to always return True + + For this association, stub this to always return True + + Parameters + ---------- + member : Member + Member being added. Ignored. + + Returns + ------- + True + """ + return True diff --git a/jwst/associations/lib/rules_level3_base.py b/jwst/associations/lib/rules_level3_base.py index ce7c5c631b..756ca3e3a6 100644 --- a/jwst/associations/lib/rules_level3_base.py +++ b/jwst/associations/lib/rules_level3_base.py @@ -895,7 +895,7 @@ def __init__(self): ) -class Constraint_Target(DMSAttrConstraint): +class Constraint_Target(Constraint): """Select on target Parameters @@ -905,19 +905,31 @@ class Constraint_Target(DMSAttrConstraint): to as part of the target selection. """ def __init__(self, association=None): + constraints = [Constraint([ + DMSAttrConstraint( + name='acdirect', + sources=['asn_candidate'], + value=r"\[\('c\d{4}', 'direct_image'\)\]" + ), + SimpleConstraint( + name='target', + sources=lambda item: '000' + )] + )] if association is None: - super(Constraint_Target, self).__init__( + constraints.append(DMSAttrConstraint( name='target', sources=['targetid'], - ) + )) else: - super(Constraint_Target, self).__init__( + constraints.append(DMSAttrConstraint( name='target', sources=['targetid'], onlyif=lambda item: association.get_exposure_type(item) != 'background', force_reprocess=ListCategory.EXISTING, only_on_match=True, - ) + )) + super(Constraint_Target, self).__init__(constraints, reduce=Constraint.any) # ----------- diff --git a/jwst/associations/tests/data/pool_034_wfss_parallel.csv b/jwst/associations/tests/data/pool_034_wfss_parallel.csv new file mode 100755 index 0000000000..f02d9b11a3 --- /dev/null +++ b/jwst/associations/tests/data/pool_034_wfss_parallel.csv @@ -0,0 +1,34 @@ +FILENAME|OBS_ID|PROGRAM|OBS_NUM|VISIT|VISIT_ID|VISITGRP|VISITYPE|SEQ_ID|ACT_ID|EXPOSURE|EXP_TYPE|NEXPOSUR|EXPCOUNT|INSTRUME|DETECTOR|CHANNEL|TARGETID|TARGPROP|TARGNAME|TARGTYPE|TEMPLATE|PNTGTYPE|PNTG_SEQ|TARGORDN|EXPSPCIN|DITHPTIN|MOSTILNO|MODULE|FILTER|PUPIL|DITHERID|PATTTYPE|PATTSTRT|NUMDTHPT|PATTSIZE|SUBPXPTS|PATT_NUM|SUBPIXEL|APERNAME|SDP_VER|SUBARRAY|GRATING|FXD_SLIT|BAND|GWA_XTIL|GWA_YTIL|ASN_CANDIDATE|EXPOSERR|IS_PSF|IS_IMPRT|BKGDTARG|TSOVISIT|MSASTATE|MSAMETFL|OPMODE|LAMP|SPEC_NUM|SPAT_NUM|DMS_NOTE|EXSEGTOT +jw00025001001_03201_00001_nis_uncal.fits|V00024001001P0002500103201|25|1|1|00025001001|3|PARALLEL_PURE|2|01|1|NIS_IMAGE|1|1|NIRISS|NIS|NULL|NULL|UNKNOWN|NULL|UNKNOWN|NIRISS Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|NULL|CLEAR|F150W|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NIS_CEN|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o001', 'OBSERVATION'), ('c1000', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NONE|NULL|NULL|NULL|NULL +jw00025002001_04201_00001_nis_uncal.fits|V00024001001P0002500204201|25|2|1|00025002001|4|PARALLEL_PURE|2|01|1|NIS_WFSS|1|4|NIRISS|NIS|NULL|NULL|UNKNOWN|NULL|UNKNOWN|NIRISS Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|NULL|GR150C|F150W|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NIS_CEN|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o002', 'OBSERVATION'), ('c1000', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NONE|NULL|NULL|NULL|NULL +jw00025003001_05201_00001_nis_uncal.fits|V00024001001P0002500305201|25|3|1|00025003001|5|PARALLEL_PURE|2|01|1|NIS_WFSS|1|6|NIRISS|NIS|NULL|NULL|UNKNOWN|NULL|UNKNOWN|NIRISS Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|NULL|GR150R|F150W|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NIS_CEN|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o003', 'OBSERVATION'), ('c1000', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NONE|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrca1_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCA1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrca2_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCA2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrca3_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCA3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrca4_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCA4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcalong_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCALONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F356W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcb1_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCB1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcb2_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCB2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcb3_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCB3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcb4_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCB4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025004001_03201_00001_nrcblong_uncal.fits|V00024002001P0002500403201|25|4|1|00025004001|3|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|2|NIRCAM|NRCBLONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F356W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o004', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrca1_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCA1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrca2_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCA2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrca3_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCA3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrca4_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCA4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcalong_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_WFSS|1|5|NIRCAM|NRCALONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F356W|GRISMC|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcb1_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCB1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcb2_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCB2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcb3_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCB3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcb4_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|5|NIRCAM|NRCB4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025005001_05201_00001_nrcblong_uncal.fits|V00024002001P0002500505201|25|5|1|00025005001|5|PARALLEL_PURE|2|01|1|NRC_WFSS|1|5|NIRCAM|NRCBLONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F356W|GRISMC|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o005', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrca1_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCA1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrca2_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCA2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrca3_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCA3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrca4_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCA4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcalong_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_WFSS|1|7|NIRCAM|NRCALONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|A|F356W|GRISMR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCA5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcb1_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCB1|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB1_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcb2_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCB2|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB2_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcb3_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCB3|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB3_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcb4_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_IMAGE|1|7|NIRCAM|NRCB4|SHORT|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F115W|CLEAR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB4_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL +jw00025006001_07201_00001_nrcblong_uncal.fits|V00024002001P0002500607201|25|6|1|00025006001|7|PARALLEL_PURE|2|01|1|NRC_WFSS|1|7|NIRCAM|NRCBLONG|LONG|NULL|UNKNOWN|NULL|UNKNOWN|NIRCam Wide Field Slitless Spectroscopy|SCIENCE|1|1|1|1|1|B|F356W|GRISMR|NULL|NONE|NULL|1|NULL|NULL|1|NULL|NRCB5_FULL|2023_4|FULL|NULL|NULL|NULL|NULL|NULL|[('o006', 'OBSERVATION'), ('c1001', 'DIRECT_IMAGE')]|NULL|NULL|NULL|F|F|NULL|NULL|NULL|NULL|NULL|NULL|NULL|NULL diff --git a/jwst/associations/tests/test_constraints.py b/jwst/associations/tests/test_constraints.py index e38b27b35a..6e506d0b68 100644 --- a/jwst/associations/tests/test_constraints.py +++ b/jwst/associations/tests/test_constraints.py @@ -88,6 +88,18 @@ def test_constraint_get_all_attr(): assert set(result) == set(expected) +def test_constraint_get_all_attr_with_name(): + """Get attribute value of all constraints with a name""" + names = ['sc1', 'sc2'] + constraints = [ + SimpleConstraint(name=name) + for name in names + ] + c = Constraint(constraints, name='c1') + result = c.get_all_attr('name', name='sc1') + assert result == [(constraints[0], 'sc1')] + + def test_simpleconstraint_reprocess_match(): """Test options for reprocessing""" sc = SimpleConstraint( diff --git a/jwst/regtest/test_associations_standards.py b/jwst/regtest/test_associations_standards.py index 18a087c502..b8ba75c0b6 100644 --- a/jwst/regtest/test_associations_standards.py +++ b/jwst/regtest/test_associations_standards.py @@ -90,6 +90,7 @@ def __init__( MakePars('pool_030_mir_lrs_nods_bkg'), MakePars('pool_031_mir_lrs_nonod_bkg'), MakePars('pool_032_nircam_wfss'), + MakePars('pool_034_wfss_parallel'), ]