Пример #1
0
    def make_fixedslit_bkg(self):
        """Add a background to a MIR_lrs-fixedslit observation"""
        for product in self['products']:
            members = product['members']
            # Split out the science exposures
            science_exps = [
                member for member in members if member['exptype'] == 'science'
            ]
            # Create new members for each science exposure in the association,
            # using the the base name + _x1d as background.
            results = []
            # Loop over all science exposures in the association
            for science_exp in science_exps:
                sci_name = science_exp['expname']
                science_exp['expname'] = sci_name
                # Construct the name for the background file
                bkg_name = remove_suffix(
                    splitext(split(science_exp['expname'])[1])[0])[0]
                bkg_name = bkg_name + '_x1d.fits'
                now_background = Member(science_exp)
                now_background['expname'] = bkg_name
                now_background['exptype'] = 'background'
                # Add the background file to the association table
                members.append(now_background)

            if self.is_valid:
                results.append(self)

            return results
Пример #2
0
    def make_nod_asns(self):
        """Make background nod Associations

        For observing modes, such as NIRSpec MSA, exposures can be
        nodded, such that the object is in a different position in the
        slitlet. The association creation simply groups these all
        together as a single association, all exposures marked as
        `science`. When complete, this method will create separate
        associations each exposure becoming the single science
        exposure, and the other exposures then become `background`.

        Returns
        -------
        associations : [association[, ...]]
            List of new associations to be used in place of
            the current one.

        """

        for product in self['products']:
            members = product['members']

            # Split out the science vs. non-science
            # The non-science exposures will get attached
            # to every resulting association.
            science_exps = [
                member for member in members if member['exptype'] == 'science'
            ]
            nonscience_exps = [
                member for member in members if member['exptype'] != 'science'
            ]

            # Create new associations for each science, using
            # the other science as background.
            results = []
            for science_exp in science_exps:
                asn = copy.deepcopy(self)
                asn.data['products'] = None

                product_name = remove_suffix(
                    splitext(split(science_exp['expname'])[1])[0])[0]
                asn.new_product(product_name)
                new_members = asn.current_product['members']
                new_members.append(science_exp)

                for other_science in science_exps:
                    if other_science['expname'] != science_exp['expname']:
                        now_background = Member(other_science)
                        now_background['exptype'] = 'background'
                        new_members.append(now_background)

                new_members += nonscience_exps

                if asn.is_valid:
                    results.append(asn)

            return results
Пример #3
0
    def _add_items(self,
                   items,
                   product_name=None,
                   with_exptype=False,
                   **kwargs):
        """ Force adding items to the association

        Parameters
        ----------
        items : [object[, ...]]
            A list of items to make members of the association.

        product_name : str or None
            The name of the product to add the items to.
            If the product does not already exist, it will be created.
            If None, the default DMS Level3 naming
            conventions will be attempted.

        with_exptype : bool
            If True, each item is expected to be a 2-tuple with
            the first element being the item to add as `expname`
            and the second items is the `exptype`

        kwargs : dict
            Allows other keyword arguments used by other subclasses.

        Notes
        -----
        This is a low-level shortcut into adding members, such as file names,
        to an association. All defined shortcuts and other initializations are
        by-passed, resulting in a potentially unusable association.
        """
        if product_name is None:
            raise AssociationNotValidError(
                'Product name needs to be specified'
            )

        self.new_product(product_name)
        members = self.current_product['members']
        for item in items:
            exptype = 'science'
            if with_exptype:
                item, exptype = item
            member = Member(
                {
                    'expname': item,
                    'exptype': exptype
                },
                item=item
            )
            self.update_validity(member)
            members.append(member)
        self.sequence = next(self._sequence)
Пример #4
0
    def make_fixedslit_bkg(self):
        """Add a background to a MIR_lrs-fixedslit observation"""

        # check to see if these are nodded backgrounds, if they are setup
        # the background members, otherwise return the original association
        # to test for the string 'nod' we need to copy and pop the value out of the set
        if 'nod' not in self.constraints['patttype_spectarg'].found_values.copy().pop():
            results = []
            results.append(self)
            return results

        for product in self['products']:
            members = product['members']
            # Split out the science exposures
            science_exps = [
                member
                for member in members
                if member['exptype'] == 'science'
            ]
            # if there is only one science observation it cannot be the background
            # return with original association.
            if len(science_exps) < 2:
                return results

            # Create new members for each science exposure in the association,
            # using the the base name + _x1d as background.
            results = []
            # Loop over all science exposures in the association
            for science_exp in science_exps:
                sci_name = science_exp['expname']
                science_exp['expname'] = sci_name
                # Construct the name for the background file
                bkg_name = remove_suffix(
                    splitext(split(science_exp['expname'])[1])[0])[0]
                bkg_name = bkg_name+'_x1d.fits'
                now_background = Member(science_exp)
                now_background['expname'] = bkg_name
                now_background['exptype'] = 'background'
                # Add the background file to the association table
                members.append(now_background)

            if self.is_valid:
                results.append(self)

            return results
Пример #5
0
    def make_member(self, item):
        """Create a member from the item

        Parameters
        ----------
        item : dict
            The item to create member from.

        Returns
        -------
        member : Member
            The member
        """

        # Set exposure error status.
        try:
            exposerr = item['exposerr']
        except KeyError:
            exposerr = None

        # Create the member.
        # `is_item_tso` is used to determine whether the name should
        # represent the integrations form of the data.
        # Though coronagraphic data is not TSO,
        # it does remain in the separate integrations.
        member = Member(
            {
                'expname':
                Utility.rename_to_level2a(
                    item['filename'],
                    use_integrations=self.is_item_tso(
                        item, other_exp_types=CORON_EXP_TYPES),
                ),
                'exptype':
                self.get_exposure_type(item),
                'exposerr':
                exposerr,
            },
            item=item)

        return member
Пример #6
0
    def make_member(self, item):
        """Create a member from the item

        Parameters
        ----------
        item : dict
            The item to create member from.

        Returns
        -------
        member : Member
            The member
        """
        try:
            exposerr = item['exposerr']
        except KeyError:
            exposerr = None

        # Get exposure type
        exptype = self.get_exposure_type(item)

        # Determine expected member name
        expname = Utility.rename_to_level2(
            item['filename'], exp_type=item['exp_type'],
            is_tso=self.is_item_tso(item, other_exp_types=CORON_EXP_TYPES),
            member_exptype=exptype
        )

        member = Member(
            {
                'expname': expname,
                'exptype': exptype,
                'exposerr': exposerr,
                'asn_candidate': item['asn_candidate']
            },
            item=item
        )
        return member
Пример #7
0
    def _add_items(self,
                   items,
                   meta=None,
                   product_name_func=None,
                   acid='o999',
                   **kwargs):
        """Force adding items to the association

        Parameters
        ----------
        items : [object[, ...]]
            A list of items to make members of the association.

        meta : dict
            A dict to be merged into the association meta information.
            The following are suggested to be assigned:
                - `asn_type`
                    The type of association.
                - `asn_rule`
                    The rule which created this association.
                - `asn_pool`
                    The pool from which the exposures came from
                - `program`
                    Originating observing program

        product_name_func : func
            Used if product name is 'undefined' using
            the class's procedures.

        acid : str
            The association candidate id to use. Since Level2
            associations require it, one must be specified.

        Notes
        -----
        This is a low-level shortcut into adding members, such as file names,
        to an association. All defined shortcuts and other initializations are
        by-passed, resulting in a potentially unusable association.

        `product_name_func` is used to define the product names instead of
        the default methods. The call signature is:

            product_name_func(item, idx)

        where `item` is each item being added and `idx` is the count of items.

        """
        if meta is None:
            meta = {}

        # Setup association candidate.
        if acid.startswith('o'):
            ac_type = 'observation'
        elif acid.startswith('c'):
            ac_type = 'background'
        else:
            raise ValueError(
                'Invalid association id specified: "{}"'
                '\n\tMust be of form "oXXX" or "c1XXX"'.format(acid)
            )
        self._acid = ACID((acid, ac_type))

        # set the default exptype
        exptype = 'science'

        for idx, item in enumerate(items, start=1):
            self.new_product()
            members = self.current_product['members']
            if isinstance(item, tuple):
                expname = item[0]
            else:
                expname = item

            # check to see if kwargs are passed and if exptype is given
            if kwargs:
                if 'with_exptype' in kwargs:
                    if item[1]:
                        exptype = item[1]
                    else:
                        exptype = 'science'
            member = Member({
                'expname': expname,
                'exptype': exptype
            }, item=item)
            members.append(member)
            self.update_validity(member)
            self.update_asn()

            # If a product name function is given, attempt
            # to use.
            if product_name_func is not None:
                try:
                    self.current_product['name'] = product_name_func(item, idx)
                except Exception:
                    logger.debug(
                        'Attempted use of product_name_func failed.'
                        ' Default product name used.'
                    )

        self.data.update(meta)
        self.sequence = next(self._sequence)
Пример #8
0
    def add_catalog_members(self):
        """Add catalog and direct image member based on direct image members"""
        directs = self.members_by_type('direct_image')
        if not directs:
            raise AssociationNotValidError(
                '{} has no required direct image exposures'.format(
                    self.__class__.__name__
                )
            )

        sciences = self.members_by_type('science')
        if not sciences:
            raise AssociationNotValidError(
                '{} has no required science exposure'.format(
                    self.__class__.__name__
                )
            )
        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:
                # For NIRCam, only consider direct images from the same channel
                # as the grism image
                if direct.item['exp_type'] == 'nrc_image':
                    science_channel = getattr_from_list(science.item, ['channel'], _EMPTY)[1]
                    direct_channel = getattr_from_list(direct.item, ['channel'], _EMPTY)[1]
                    if direct_channel != science_channel:
                        continue
                # For NIRISS, only consider direct images with the same PUPIL value
                if direct.item['exp_type'] == 'nis_image':
                    science_pupil = getattr_from_list(science.item, ['pupil'], _EMPTY)[1]
                    direct_pupil = getattr_from_list(direct.item, ['pupil'], _EMPTY)[1]
                    if direct_pupil != science_pupil:
                        continue
                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']
        direct_idxs = [
            idx
            for idx, member in enumerate(members)
            if member['exptype'] == 'direct_image'
        ]
        deque((
            list.pop(members, idx)
            for idx in sorted(direct_idxs, reverse=True)
        ))

        # Add the Level3 catalog, direct image, and segmentation map members
        lv3_direct_image_root = DMS_Level3_Base._dms_product_name(self)
        members.append(
            Member({
                'expname': lv3_direct_image_root + '_i2d.fits',
                'exptype': 'direct_image'
            })
        )
        members.append(
            Member({
                'expname': lv3_direct_image_root + '_cat.ecsv',
                'exptype': 'sourcecat'
            })
        )
        members.append(
            Member({
                'expname': lv3_direct_image_root + '_segm.fits',
                'exptype': 'segmap'
            })
        )