def __init__(self, x, y, cube=True, maps=True, modelcube=True, lazy=False, **kwargs): if not cube and not maps and not modelcube: raise MarvinError('no inputs defined.') self.cube_quantities = FuzzyDict({}) self.maps_quantities = FuzzyDict({}) self.modelcube_quantities = FuzzyDict({}) self._cube = cube self._maps = maps self._modelcube = modelcube for attr in ['mangaid', 'plateifu', 'release', 'bintype', 'template']: value = kwargs.pop(attr, None) or \ getattr(cube, attr, None) or \ getattr(maps, attr, None) or \ getattr(modelcube, attr, None) setattr(self, attr, value) self._kwargs = kwargs self._parent_shape = None # drop breadcrumb breadcrumb.drop(message='Initializing MarvinSpaxel {0}'.format( self.__class__), category=self.__class__) self.x = int(x) self.y = int(y) self.loaded = False self.datamodel = None if lazy is False: self.load() # Load VACs from marvin.contrib.vacs.base import VACMixIn self.vacs = VACMixIn.get_vacs(self)
def __init__(self, *args, **kwargs): ''' Initializes a Marvin Form Generates all the WTForms from the SQLAlchemy ModelClasses defined in the MaNGA DB. _param_form_lookup = dictionary of all modelclass parameters of form {'SQLalchemy ModelClass parameter name': WTForm Class} ''' self._release = kwargs.get('release', config.release) self.verbose = kwargs.get('verbose', False) if marvindb: self._modelclasses = FuzzyDict( marvindb.buildUberClassDict(release=self._release)) self._param_form_lookup = ParamFormLookupDict(**kwargs) self._param_fxn_lookup = ParamFxnLookupDict() self._paramtree = tree() self._generateFormClasses(self._modelclasses) self._generateFxns() self.SearchForm = SearchForm self._cleanParams(**kwargs)
def __init__(self, x, y, mangaid=None, plateifu=None, cube=True, maps=True, modelcube=True, lazy=False, **kwargs): self.cube_quantities = FuzzyDict({}) self.maps_quantities = FuzzyDict({}) self.modelcube_quantities = FuzzyDict({}) self._cube = cube self._maps = maps self._modelcube = modelcube self._plateifu = plateifu self._mangaid = mangaid self.kwargs = kwargs if not self._cube and not self._maps and not self._modelcube: raise MarvinError( 'either cube, maps, or modelcube must be True or ' 'a Marvin Cube, Maps, or ModelCube object must be specified.') self._parent_shape = None # drop breadcrumb breadcrumb.drop(message='Initializing MarvinSpaxel {0}'.format( self.__class__), category=self.__class__) self.x = int(x) self.y = int(y) self.loaded = False self.datamodel = None if lazy is False: self.load()
class Spaxel(object): """A base class that contains information about a spaxel. This class represents an spaxel with information from the reduced DRP spectrum, the DAP maps properties, and the model spectrum from the DAP logcube. A `.SpaxelBase` can be initialised with all or only part of that information, and either from a file, a database, or remotely via the Marvin API. The `~marvin.tools.cube.Cube`, `~marvin.tools.maps.Maps` , and `~marvin.tools.modelcube.ModelCube` quantities for the spaxel are available in ``cube_quantities``, ``maps_quantities``, and ``modelcube_quantities``, respectively. For convenience, the quantities can also be accessed directly from the `.SpaxelBase` itself (e.g., ``spaxel.emline_gflux_ha_6465``). Parameters: x,y (int): The `x` and `y` coordinates of the spaxel in the cube (0-indexed). cube (`~marvin.tools.cube.Cube` object or path or bool): If ``cube`` is a `~marvin.tools.cube.Cube` object, that cube will be used for the `.SpaxelBase` instantiation. This mode is mostly intended for `~marvin.utils.general.general.getSpaxel` as it significantly improves loading time. Otherwise, ``cube`` can be ``True`` (default), in which case a cube will be instantiated using the input ``filename``, ``mangaid``, or ``plateifu``. If ``cube=False``, no cube will be used and the cube associated quantities will not be available. ``cube`` can also be the path to the DRP cube to use. maps (`~marvin.tools.maps.Maps` object or path or bool) As ``cube`` but for the DAP measurements corresponding to the spaxel in the `.Maps`. modelcube (`marvin.tools.modelcube.ModelCube` object or path or bool) As ``maps`` but for the DAP measurements corresponding to the spaxel in the `.ModelCube`. lazy (bool): If ``False``, the spaxel data is loaded on instantiation. Otherwise, only the metadata is created. The associated quantities can be then loaded by calling `.SpaxelBase.load()`. kwargs (dict): Arguments to be passed to `.Cube`, `.Maps`, and `.ModelCube` when (and if) they are initialised. Attributes: cube_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.Spectrum` quantities derived from `.Cube` and matching ``x, y``. datamodel (object): An object containing the DRP and DAP datamodels. maps_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.AnalysisProperty` quantities derived from `.Maps` and matching ``x, y``. model_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.Spectrum` quantities derived from `.ModelCube` and matching ``x, y``. ra,dec (float): Right ascension and declination of the spaxel. Not available until the spaxel has been `loaded <.SpaxelBase.load>`. """ def __init__(self, x, y, cube=True, maps=True, modelcube=True, lazy=False, **kwargs): if not cube and not maps and not modelcube: raise MarvinError('no inputs defined.') self.cube_quantities = FuzzyDict({}) self.maps_quantities = FuzzyDict({}) self.modelcube_quantities = FuzzyDict({}) self._cube = cube self._maps = maps self._modelcube = modelcube for attr in ['mangaid', 'plateifu', 'release', 'bintype', 'template']: value = kwargs.pop(attr, None) or \ getattr(cube, attr, None) or \ getattr(maps, attr, None) or \ getattr(modelcube, attr, None) setattr(self, attr, value) self._kwargs = kwargs self._parent_shape = None # drop breadcrumb breadcrumb.drop(message='Initializing MarvinSpaxel {0}'.format( self.__class__), category=self.__class__) self.x = int(x) self.y = int(y) self.loaded = False self.datamodel = None if lazy is False: self.load() def __dir__(self): class_members = list(list(zip(*inspect.getmembers(self.__class__)))[0]) instance_attr = list(self.__dict__.keys()) items = self.cube_quantities.__dir__() items += self.maps_quantities.__dir__() items += self.modelcube_quantities.__dir__() items += class_members + instance_attr return sorted(items) def __getattr__(self, value): _getattr = super(Spaxel, self).__getattribute__ for tool_quantity_dict in [ 'cube_quantities', 'maps_quantities', 'modelcube_quantities' ]: if value in _getattr(tool_quantity_dict): return _getattr(tool_quantity_dict)[value] return super(Spaxel, self).__getattribute__(value) def __repr__(self): """Spaxel representation.""" if not self.loaded: return '<Marvin Spaxel (x={0.x:d}, y={0.y:d}, loaded=False)'.format( self) # Gets the coordinates relative to the centre of the cube/maps. y_mid, x_mid = np.array(self._parent_shape) / 2. x_centre = int(self.x - x_mid) y_centre = int(self.y - y_mid) # Determine what tools are loaded. tools = np.array(['cube', 'maps', 'modelcube']) load_idx = np.where([self._cube, self._maps, self._modelcube])[0] flags = '/'.join(tools[load_idx]) return ('<Marvin Spaxel (plateifu={0.plateifu}, x={0.x:d}, y={0.y:d}; ' 'x_cen={1:d}, y_cen={2:d}, loaded={3})>'.format( self, x_centre, y_centre, flags)) def _check_versions(self, attr): """Checks that all input object have the same versions. Runs sanity checks to make sure that ``attr`` has the same value in the input `.Cube`, `.Maps`, and `.ModelCube`. Returns the value for the attribute or ``None`` if the attribute does not exist. """ out_value = None inputs = [] for obj in [self._cube, self._maps, self._modelcube]: if obj is not None and not isinstance(obj, bool): inputs.append(obj) if len(inputs) == 1: return getattr(inputs[0], attr, None) for obj_a, obj_b in itertools.combinations(inputs, 2): if hasattr(obj_a, attr) and hasattr(obj_b, attr): assert getattr(obj_a, attr) == getattr(obj_b, attr), \ 'inconsistent {!r} between {!r} and {!r}'.format(attr, obj_a, obj_b) out_value = getattr(obj_a, attr, None) or getattr( obj_b, attr, None) return out_value def _set_radec(self): """Calculates ra and dec for this spaxel.""" self.ra = None self.dec = None for obj in [self._cube, self._maps, self._modelcube]: if hasattr(obj, 'wcs'): if obj.wcs.naxis == 2: self.ra, self.dec = obj.wcs.wcs_pix2world( [[self.x, self.y]], 0)[0] elif obj.wcs.naxis == 3: self.ra, self.dec, __ = obj.wcs.wcs_pix2world( [[self.x, self.y, 0]], 0)[0] def save(self, path, overwrite=False): """Pickles the spaxel to a file. Parameters: path (str): The path of the file to which the `.Spaxel` will be saved. Unlike for other Marvin Tools that derive from `~marvin.tools.core.MarvinToolsClass`, ``path`` is mandatory for `.Spaxel.save` as there is no default path for a given spaxel. overwrite (bool): If True, and the ``path`` already exists, overwrites it. Otherwise it will fail. Returns: path (str): The realpath to which the file has been saved. """ return marvin.core.marvin_pickle.save(self, path=path, overwrite=overwrite) @classmethod def restore(cls, path, delete=False): """Restores a Spaxel object from a pickled file. If ``delete=True``, the pickled file will be removed after it has been unplickled. Note that, for objects with ``data_origin='file'``, the original file must exists and be in the same path as when the object was first created. """ return marvin.core.marvin_pickle.restore(path, delete=delete) def load(self, force=None): """Loads the spaxel data. Loads the spaxel data for cubes/maps/modelcube. By default attempts to load whatever is specified when spaxels are instantianted from other Marvin Tools. Can manually force load a data type with the force keyword. Parameters: ----------- force : {cube|maps|modelcube} Datatype to force load. """ if self.loaded and force is None: warnings.warn('already loaded', MarvinUserWarning) return assert force in [None, 'cube', 'maps', 'modelcube'], \ 'force can only be cube, maps, or modelcube' for tool in ['cube', 'maps', 'modelcube']: self._load_tool(tool, force=(force is not None and force == tool)) self._set_radec() self.loaded = True for attr in ['mangaid', 'plateifu', 'release', 'bintype', 'template']: setattr(self, attr, self._check_versions(attr)) self.datamodel = DataModel(self.release) def _load_tool(self, tool, force=False): """Loads the tool and the associated quantities.""" if tool == 'cube': class_name = marvin.tools.cube.Cube method = self.getCube quantities_dict = 'cube_quantities' elif tool == 'maps': class_name = marvin.tools.maps.Maps method = self.getMaps quantities_dict = 'maps_quantities' elif tool == 'modelcube': class_name = marvin.tools.modelcube.ModelCube method = self.getModelCube quantities_dict = 'modelcube_quantities' attr_value = getattr(self, '_' + tool) if (attr_value is False or attr_value is None) and force is False: setattr(self, '_' + tool, None) return if not isinstance(attr_value, class_name): if tool == 'modelcube' and self.release == 'MPL-4': warnings.warn('ModelCube cannot be instantiated for MPL-4.', MarvinUserWarning) self._modelcube = None return else: setattr(self, '_' + tool, method()) else: if force is True: warnings.warn('{0} is already loaded'.format(tool), MarvinUserWarning) self._parent_shape = getattr(getattr(self, '_' + tool), '_shape') setattr( self, quantities_dict, getattr(getattr(self, '_' + tool), '_get_spaxel_quantities')(self.x, self.y, spaxel=self)) def getCube(self): """Returns the associated `~marvin.tools.cube.Cube`""" if isinstance(self._cube, marvin.tools.cube.Cube): return self._cube cube_input = (self._cube if self._cube is not True else None) \ or self.plateifu or self.mangaid return marvin.tools.cube.Cube(cube_input, release=self.release, **self._kwargs) def getMaps(self): """Returns the associated `~marvin.tools.maps.Maps`""" if isinstance(self._maps, marvin.tools.maps.Maps): return self._maps maps_input = (self._maps if self._maps is not True else None) \ or self.plateifu or self.mangaid return marvin.tools.maps.Maps(maps_input, bintype=self.bintype, template=self.template, release=self.release, **self._kwargs) def getModelCube(self): """Returns the associated `~marvin.tools.modelcube.ModelCube`""" if isinstance(self._modelcube, marvin.tools.modelcube.ModelCube): return self._modelcube modelcube_input = (self._modelcube if self._modelcube is not True else None) \ or self.plateifu or self.mangaid return marvin.tools.modelcube.ModelCube(modelcube_input, bintype=self.bintype, template=self.template, release=self.release, **self._kwargs) @property def quality_flags(self): """Bundle Cube DRP3QUAL and Maps DAPQUAL flags.""" drp3qual = self.datamodel.drp.bitmasks['MANGA_DRP3QUAL'] cube = self.getCube() drp3qual.mask = int(cube.header['DRP3QUAL']) qual_flags = [drp3qual] if self.release != 'MPL-4': qual_flags.append(self.datamodel.dap.bitmasks['MANGA_DAPQUAL']) return qual_flags
class SpaxelBase(six.with_metaclass(SpaxelABC, object)): """A base class that contains information about a spaxel. This class represents an spaxel with information from the reduced DRP spectrum, the DAP maps properties, and the model spectrum from the DAP logcube. A `.SpaxelBase` can be initialised with all or only part of that information, and either from a file, a database, or remotely via the Marvin API. The `~marvin.tools.cube.Cube`, `~marvin.tools.maps.Maps` , and `~marvin.tools.modelcube.ModelCube` quantities for the spaxel are available in ``cube_quantities``, ``maps_quantities``, and ``modelcube_quantities``, respectively. For convenience, the quantities can also be accessed directly from the `.SpaxelBase` itself (e.g., ``spaxel.emline_gflux_ha_6465``). Parameters: x,y (int): The `x` and `y` coordinates of the spaxel in the cube (0-indexed). mangaid (str): The mangaid of the cube/maps/modelcube of the spaxel to load. plateifu (str): The plate-ifu of the cube/maps/modelcube of the spaxel to load (either ``mangaid`` or ``plateifu`` can be used, but not both). cube (`~marvin.tools.cube.Cube` object or path or bool): If ``cube`` is a `~marvin.tools.cube.Cube` object, that cube will be used for the `.SpaxelBase` instantiation. This mode is mostly intended for `~marvin.utils.general.general.getSpaxel` as it significantly improves loading time. Otherwise, ``cube`` can be ``True`` (default), in which case a cube will be instantiated using the input ``filename``, ``mangaid``, or ``plateifu``. If ``cube=False``, no cube will be used and the cube associated quantities will not be available. ``cube`` can also be the path to the DRP cube to use. maps (`~marvin.tools.maps.Maps` object or path or bool) As ``cube`` but for the DAP measurements corresponding to the spaxel in the `.Maps`. modelcube (`marvin.tools.modelcube.ModelCube` object or path or bool) As ``maps`` but for the DAP measurements corresponding to the spaxel in the `.ModelCube`. lazy (bool): If ``False``, the spaxel data is loaded on instantiation. Otherwise, only the metadata is created. The associated quantities can be then loaded by calling `.SpaxelBase.load()`. kwargs (dict): Arguments to be passed to `.Cube`, `.Maps`, and `.ModelCube` when (and if) they are initialised. Attributes: cube_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.Spectrum` quantities derived from `.Cube` and matching ``x, y``. datamodel (object): An object contianing the DRP and DAP datamodels. maps_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.AnalysisProperty` quantities derived from `.Maps` and matching ``x, y``. model_quantities (`~marvin.utils.general.structs.FuzzyDict`): A querable dictionary with the `.Spectrum` quantities derived from `.ModelCube` and matching ``x, y``. ra,dec (float): Right ascension and declination of the spaxel. Not available until the spaxel has been `loaded <.SpaxelBase.load>`. """ def __init__(self, x, y, mangaid=None, plateifu=None, cube=True, maps=True, modelcube=True, lazy=False, **kwargs): self.cube_quantities = FuzzyDict({}) self.maps_quantities = FuzzyDict({}) self.modelcube_quantities = FuzzyDict({}) self._cube = cube self._maps = maps self._modelcube = modelcube self._plateifu = plateifu self._mangaid = mangaid self.kwargs = kwargs if not self._cube and not self._maps and not self._modelcube: raise MarvinError( 'either cube, maps, or modelcube must be True or ' 'a Marvin Cube, Maps, or ModelCube object must be specified.') self._parent_shape = None # drop breadcrumb breadcrumb.drop(message='Initializing MarvinSpaxel {0}'.format( self.__class__), category=self.__class__) self.x = int(x) self.y = int(y) self.loaded = False self.datamodel = None if lazy is False: self.load() def __dir__(self): class_members = list(list(zip(*inspect.getmembers(self.__class__)))[0]) instance_attr = list(self.__dict__.keys()) items = self.cube_quantities.__dir__() items += self.maps_quantities.__dir__() items += self.modelcube_quantities.__dir__() items += class_members + instance_attr return sorted(items) def __getattr__(self, value): _getattr = super(SpaxelBase, self).__getattribute__ if value in _getattr('cube_quantities'): return _getattr('cube_quantities')[value] if value in _getattr('maps_quantities'): return _getattr('maps_quantities')[value] if value in _getattr('modelcube_quantities'): return _getattr('modelcube_quantities')[value] return super(SpaxelBase, self).__getattribute__(value) @abc.abstractmethod def __repr__(self): return '<SpaxelBase>' def _check_versions(self, attr): """Checks that all input object have the same versions. Runs sanity checks to make sure that ``attr`` has the same value in the input `.Cube`, `.Maps`, and `.ModelCube`. Returns the value for the attribute or ``None`` if the attribute does not exist. """ out_value = None inputs = [] for obj in [self._cube, self._maps, self._modelcube]: if obj is not None and not isinstance(obj, bool): inputs.append(obj) if len(inputs) == 1: return getattr(inputs[0], attr, None) for obj_a, obj_b in itertools.combinations(inputs, 2): if hasattr(obj_a, attr) and hasattr(obj_b, attr): assert getattr(obj_a, attr) == getattr(obj_b, attr), \ 'inconsistent {!r} between {!r} and {!r}'.format(attr, obj_a, obj_b) out_value = getattr(obj_a, attr, None) or getattr( obj_b, attr, None) return out_value def _set_radec(self): """Calculates ra and dec for this spaxel.""" self.ra = None self.dec = None for obj in [self._cube, self._maps, self._modelcube]: if hasattr(obj, 'wcs'): if obj.wcs.naxis == 2: self.ra, self.dec = obj.wcs.wcs_pix2world( [[self.x, self.y]], 0)[0] elif obj.wcs.naxis == 3: self.ra, self.dec, __ = obj.wcs.wcs_pix2world( [[self.x, self.y, 0]], 0)[0] def load(self, force=None): """Loads the spaxel data. Loads the spaxel data for cubes/maps/modelcubes. By default attempts to load whatever is specified when spaxels are instantianted from other Marvin Tools. Can manually force load a data type with the force keyword. Parameters: force ({cube|maps|models}): Str datatype to force load """ if self.loaded and force is None: warnings.warn('already loaded', MarvinUserWarning) return # setup what will be loaded self._setup_load(force=force) self._load_cube() self._load_maps() self._load_modelcube() self._set_radec() self.loaded = True for attr in ['mangaid', 'plateifu', 'release', 'bintype', 'template']: self._check_versions(attr) self._plateifu = self.plateifu self._mangaid = self.mangaid self.datamodel = DataModel(self.release) def save(self, path, overwrite=False): """Pickles the spaxel to a file. Parameters: path (str): The path of the file to which the `.Spaxel` will be saved. Unlike for other Marvin Tools that derive from `~marvin.core.core.MarvinToolsClass`, ``path`` is mandatory for `.Spaxel.save` as there is no default path for a given spaxel. overwrite (bool): If True, and the ``path`` already exists, overwrites it. Otherwise it will fail. Returns: path (str): The realpath to which the file has been saved. """ return marvin.core.marvin_pickle.save(self, path=path, overwrite=overwrite) @classmethod def restore(cls, path, delete=False): """Restores a Spaxel object from a pickled file. If ``delete=True``, the pickled file will be removed after it has been unplickled. Note that, for objects with ``data_origin='file'``, the original file must exists and be in the same path as when the object was first created. """ return marvin.core.marvin_pickle.restore(path, delete=delete) def _load_cube(self): """Loads the cube and the associated quantities.""" if self._cube is False or self._cube is None: self._cube = None return elif not isinstance(self._cube, marvin.tools.cube.Cube): self._cube = self.getCube() self._parent_shape = self._cube._shape self.cube_quantities = self._cube._get_spaxel_quantities( self.x, self.y) def _load_maps(self): """Loads the cube and the properties.""" if self._maps is False or self._maps is None: self._maps = None return elif not isinstance(self._maps, marvin.tools.maps.Maps): self._maps = self.getMaps() self._parent_shape = self._maps._shape self.maps_quantities = self._maps._get_spaxel_quantities( self.x, self.y) def _load_modelcube(self): """Loads the modelcube and associated arrays.""" if self._modelcube is False or self._modelcube is None: self._modelcube = None return elif not isinstance(self._modelcube, marvin.tools.modelcube.ModelCube): if self.release == 'MPL-4': warnings.warn('ModelCube cannot be instantiated for MPL-4.', MarvinUserWarning) self._modelcube = None return self._modelcube = self.getModelCube() self._parent_shape = self._modelcube._shape self.modelcube_quantities = self._modelcube._get_spaxel_quantities( self.x, self.y) def _setup_load(self, force=None): ''' Setup the loading for cube/maps/models Can manually force load a data type. Parameters: force ({cube|maps|models}): Str datatype to force load ''' # get what is currently loaded flag = self._get_loaded() # only do something if force to set. Otherwise do the original nothing. if force: assert force in ['cube', 'maps', 'models' ], 'force can only be cube, maps, or models' if force in flag: warnings.warn('{0} is already loaded'.format(force), MarvinUserWarning) else: if force == 'cube' and not self._cube: self._cube = True elif force == 'maps' and not self._maps: self._maps = True elif force == 'models' and not self._modelcube: self._modelcube = True else: # do nothing pass def _get_loaded(self): ''' Get a flag to indicate what is or is not loaded ''' dataloads = [self._cube, self._maps, self._modelcube] flags = np.array(['cube', 'maps', 'models']) load_idx = np.where(dataloads)[0] flag = '/'.join(flags[load_idx]) return flag def getCube(self): """Returns the associated `~marvin.tools.cube.Cube`""" if isinstance(self._cube, marvin.tools.cube.Cube): return self._cube cube_kwargs = self.kwargs.copy() cube_kwargs.pop('bintype', None) cube_kwargs.pop('template', None) return marvin.tools.cube.Cube( (self._cube if self._cube is not True else None) or self._plateifu or self._mangaid, **cube_kwargs) def getMaps(self): """Returns the associated `~marvin.tools.maps.Maps`""" if isinstance(self._maps, marvin.tools.maps.Maps): return self._maps maps_kwargs = self.kwargs.copy() bintype = maps_kwargs.pop('bintype', None) or self.bintype template = maps_kwargs.pop('template', None) or self.template release = maps_kwargs.pop('release', None) or self.release return marvin.tools.maps.Maps( (self._maps if self._maps is not True else None) or self._plateifu or self._mangaid, bintype=bintype, template=template, release=release, **maps_kwargs) def getModelCube(self): """Returns the associated `~marvin.tools.modelcube.ModelCube`""" if isinstance(self._modelcube, marvin.tools.modelcube.ModelCube): return self._modelcube modelcube_kwargs = self.kwargs.copy() bintype = modelcube_kwargs.pop('bintype', None) or self.bintype template = modelcube_kwargs.pop('template', None) or self.template release = modelcube_kwargs.pop('release', None) or self.release return marvin.tools.modelcube.ModelCube( ((self._modelcube if self._modelcube is not True else None) or self._plateifu or self._mangaid), bintype=bintype, template=template, release=release, **modelcube_kwargs) @property def plateifu(self): """Returns the plateifu.""" return self._check_versions('plateifu') @property def mangaid(self): """Returns the mangaid.""" return self._check_versions('mangaid') @property def release(self): """Returns the release.""" return self._check_versions('release') @property def bintype(self): """Returns the bintype.""" return self._check_versions('bintype') @property def template(self): """Returns the template.""" return self._check_versions('template') @property def manga_target1(self): """Return MANGA_TARGET1 flag.""" return self.datamodel.drp.bitmasks['MANGA_TARGET1'] @property def manga_target2(self): """Return MANGA_TARGET2 flag.""" return self.datamodel.drp.bitmasks['MANGA_TARGET2'] @property def manga_target3(self): """Return MANGA_TARGET3 flag.""" return self.datamodel.drp.bitmasks['MANGA_TARGET3'] @property def target_flags(self): """Bundle MaNGA targeting flags.""" return [self.manga_target1, self.manga_target2, self.manga_target3] @property def quality_flags(self): """Bundle Cube DRP3QUAL and Maps DAPQUAL flags.""" drp3qual = self.datamodel.drp.bitmasks['MANGA_DRP3QUAL'] cube = self.getCube() drp3qual.mask = int(cube.header['DRP3QUAL']) qual_flags = [drp3qual] if self.release != 'MPL-4': qual_flags.append(self.datamodel.dap.bitmasks['MANGA_DAPQUAL']) return qual_flags