Source code for gdt.missions.fermi.gbm.collection

# CONTAINS TECHNICAL DATA/COMPUTER SOFTWARE DELIVERED TO THE U.S. GOVERNMENT WITH UNLIMITED RIGHTS
#
# Contract No.: CA 80MSFC17M0022
# Contractor Name: Universities Space Research Association
# Contractor Address: 7178 Columbia Gateway Drive, Columbia, MD 21046
#
# Copyright 2017-2022 by Universities Space Research Association (USRA). All rights reserved.
#
# Developed by: William Cleveland and Adam Goldstein
#               Universities Space Research Association
#               Science and Technology Institute
#               https://sti.usra.edu
#
# Developed by: Daniel Kocevski
#               National Aeronautics and Space Administration (NASA)
#               Marshall Space Flight Center
#               Astrophysics Branch (ST-12)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing permissions and limitations under the
# License.
#
from gdt.core.collection import DataCollection

__all__ = ['GbmDetectorCollection']

[docs]class GbmDetectorCollection(DataCollection): """A container for a collection of GBM-specific data objects, such as a collection of :class:`~.phaii.GbmPhaii` objects from different detectors. The special behavior of this class is to provide a way to interact with a collection of detector data that may contain a mix of different *types* of detectors. For example, many times we want a collection of GBM NaI and GBM BGO detectors. These detectors have very different energy ranges, and so may require different inputs for a variety of functions. This collection allows one to specify the different arguments for NaI and BGO data without having to implement many ugly and space-wasting loops and ``if...else`` blocks. In addition to the GbmDetectorCollection methods, all of the individual object attributes and methods are exposed, and they become methods of the DataCollection. Note that individual object attributes become *methods* i.e. if you have an item attribute called item.name, then the corresponding DataCollection method would be item.name(). """ def __init__(self): super().__init__() self._dets = []
[docs] @classmethod def from_list(cls, data_list, names=None, dets=None): """Given a list of objects and optionally a list of corresponding names and corresponding detector names, create a new GbmDetectorCollection. Args: data_list (list of :obj:`objects`): The list of objects to be in the collection names (list of :obj:`str`, optional): The list of corresponding names to the objects. If not set, will try to retrieve a name from object.filename (assuming it's a data object). If that fails, each item will be named ambiguously 'item1', 'item2', etc. dets (list of :obj:`str`, optional): The detector names for each object. If not set, will try to retrieve from the object.detector attribute. If that attribute doesn't exist, an error will be raised, and the user will need to specify this list. Returns :py:class:`GbmDetectorCollection`: The newly created collection """ obj = cls() # set the detector names if dets is not None: if len(dets) != len(data_list): raise ValueError( 'Detector list must be same size as data list') else: try: dets = [data_item.detector for data_item in data_list] except: raise AttributeError('Cannot find detector information. ' 'Need to manually set') # set the names if names is not None: if len(names) != len(data_list): raise ValueError('Names list must be same size as data list') else: names = [None] * len(data_list) # include the objects [obj.include(data_item, det, name=name) for (data_item, det, name) in zip(data_list, dets, names)] return obj
[docs] def remove(self, item_name): """Remove an object from the collection given the name Args: item_name (str): The name of the item to remove """ index = [item == item_name for item in self.items].index(True) self._dets.pop(index) self._data_dict.pop(item_name)
[docs] def include(self, data_item, det, name=None): """Insert an object into the GbmDetectorCollection. The first item inserted will set the immutable type. Args: data_item (:obj:`object`): A data object to include det (str): The corresponding detector for the item name (str, optional): An optional corresponding name. If not set, will try to retrieve a name from object.filename (assuming it's a data object). If that fails, each item will be named ambiguously 'item1', 'item2', etc. """ super().include(data_item, name=name) self._dets.append(det)
def _method_call(self, method_name, *args, nai_args=(), nai_kwargs=None, bgo_args=(), bgo_kwargs=None, **kwargs): """This is the wrapper for the attribute and method calls. Applies method_name over all items in the GbmDetectorCollection. Args: method_name (str): The name of the method or attribute *args: Additional arguments to be passed to the method nai_args: Arguments to be applied only to the NaI objects bgo_args: Arguments to be applied only to the BGO objects nai_kwargs: Keywords to be applied only to the NaI objects bgo_kwargs: Keywords to be applied only to the BGO objects **kwargs: Additional keyword arguments to be passed to the method. Will be applied to both NaI and BGO objects and will be appended to any existing keywords from nai_kwargs or bgo_kwargs Returns: None or list: If not None, will return the results from all objects in the list """ if nai_kwargs is None: nai_kwargs = {} if bgo_kwargs is None: bgo_kwargs = {} if len(args) > 0: nai_args = args bgo_args = args if len(kwargs) > 0: nai_kwargs.update(kwargs) bgo_kwargs.update(kwargs) # get the attributes/methods for each item refs = [getattr(obj, method_name) for obj in self._data_dict.values()] # if method_name is a method, then it will be callable if callable(refs[0]): res = [] for obj, det in zip(self._data_dict.values(), self._dets): if 'n' in det: our_args = nai_args our_kwargs = nai_kwargs elif 'b' in det: our_args = bgo_args our_kwargs = bgo_kwargs res.append(getattr(obj, method_name)(*our_args, **our_kwargs)) # otherwise, method_name will not be callable if it is an attribute else: # we are setting an attribute if len(nai_args) != 0 or len(bgo_args) != 0: res = [] for obj, det in zip(self._data_dict.values(), self._dets): if 'n' in obj.detector: our_args = nai_args elif 'b' in obj.detector: our_args = bgo_args res.append(setattr(obj, method_name, *args)) # we are retrieving an attribute else: res = refs if res[0] is not None: return res