Source code for pyvo.mivot.writer.mango_object

'''
Created on 22 Jan 2025

@author: laurentmichel
'''
from pyvo.mivot.utils.exceptions import MappingError
from pyvo.mivot.utils.mivot_utils import MivotUtils
from pyvo.mivot.writer.instance import MivotInstance
from pyvo.mivot.glossary import (
    IvoaType, ModelPrefix, Roles, CoordSystems)


[docs] class Property(MivotInstance): """ Class representing one property of a MangoInstance. MangoInstance property instances are `pyvo.mivot.writer.MivotInstance` augmented with a semantics block. """ def __init__(self, dmtype=None, *, dmrole=None, dmid=None, semantics={}): """ Parameters ---------- dmtype : str dmtype of the INSTANCE (mandatory) dmrole : str, optional (default as None) dmrole of the INSTANCE dmid : str, optional (default as None) dmid of the INSTANCE semantics : dict, optional (default as {}) Mapping of the semantic block (supported key: descripton, uri, label) Raises ------ MappingError If ``dmtype`` is not provided """ super().__init__(dmtype, dmrole=dmrole, dmid=dmid) if "description" in semantics: # we assume the description as always being a literal self.add_attribute(dmtype="ivoa:string", dmrole="mango:Property.description", value=f"*{semantics['description']}") if "uri" in semantics or "label" in semantics: semantics_instance = MivotInstance(dmtype="mango:VocabularyTerm", dmrole="mango:Property.semantics") if "uri" in semantics: semantics_instance.add_attribute(dmtype="ivoa:string", dmrole="mango:VocabularyTerm.uri", value=f"*{semantics['uri']}") if "label" in semantics: semantics_instance.add_attribute(dmtype="ivoa:string", dmrole="mango:VocabularyTerm.label", value=f"*{semantics['label']}") self.add_instance(semantics_instance)
[docs] class MangoObject(object): """ This class handles all the components of a MangoObject (properties, origin, instance identifier). It is meant to be used by `pyvo.mivot.writer.InstancesFromModels` but not by end users. - There is one specific method for each supported property (EpochPosition, photometry and QueryOrigin). - The internal structure of the classes is hard-coded in the class logic. """ def __init__(self, table, *, dmid=None): ''' Constructor parameters: parameters ---------- table : astropy.io.votable.tree.TableElement VOTable table which data is mapped on Mango dmid: stringn optional (default as None) Reference of the column to be used as a MangoObject identifier ''' self._table = table self._properties = [] self._dmid = dmid def _get_error_instance(self, class_name, dmrole, mapping): """ Private method building and returning an Mango error instance Returns: MivotInstance """ prop_err_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:error.{class_name}", dmrole=dmrole) MivotUtils.populate_instance(prop_err_instance, class_name, mapping, self._table, IvoaType.RealQuantity, package="error") return prop_err_instance def _add_epoch_position_correlations(self, **correlations): """ Private method building and returning the correlation block of the EpocPosition object. Returns ------- `Property` The EpochPosition correlations component """ epc_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:EpochPositionCorrelations", dmrole=f"{ModelPrefix.mango}:EpochPosition.correlations") MivotUtils.populate_instance(epc_instance, "EpochPositionCorrelations", correlations, self._table, IvoaType.real) return epc_instance def _add_epoch_position_errors(self, **errors): """ Private method building and returning the error block of the EpocPosition object. Returns ------- `Property` The EpochPosition error instance """ err_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:EpochPositionErrors", dmrole=f"{ModelPrefix.mango}:EpochPosition.errors") for role, mapping in errors.items(): error_class = mapping["class"] if (role in Roles.EpochPositionErrors and error_class in ["PErrorSym2D", "PErrorSym1D", "PErrorAsym1D"]): err_instance.add_instance( self._get_error_instance(error_class, f"{ModelPrefix.mango}:EpochPositionErrors.{role}", mapping)) return err_instance def _add_epoch_position_epoch(self, **mapping): """ Private method building and returning the observation date (DateTime) of the EpohPosition. Parameters ---------- mapping: dict(representation, datetime) Mapping of the DateTime fields Returns ------- `Property` The EpochPosition observation date instance """ datetime_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:DateTime", dmrole=f"{ModelPrefix.mango}:EpochPosition.obsDate") representation = mapping.get("representation") value = mapping["dateTime"] if representation not in CoordSystems.time_formats: raise MappingError(f"epoch representation {representation} not supported. " f"Take on of {CoordSystems.time_formats}") datetime_instance.add_attribute(IvoaType.string, f"{ModelPrefix.mango}:DateTime.representation", value=MivotUtils.as_literal(representation)) datetime_instance.add_attribute(IvoaType.datetime, f"{ModelPrefix.mango}:DateTime.dateTime", value=value) return datetime_instance
[docs] def add_epoch_position(self, space_frame_id, time_frame_id, mapping, semantics): """ Add an ``EpochPosition`` instance to the properties of the current ``MangoObject``. Both mapping and semantics arguments inherit from `pyvo.mivot.writer.InstancesFromModels.add_mango_epoch_position`. Parameters ---------- space_frame_id : string Identifier (dmid) of space system INSTANCE located in the GLOBALS time_frame_id : string Identifier (dmid) of time system INSTANCE located in the GLOBALS mapping : dict Mapping of the EpochPosition fields semantics : dict Mapping of the MangoObject property Returns ------- `Property` The EpochPosition instance """ ep_instance = Property(dmtype=f"{ModelPrefix.mango}:EpochPosition", semantics=semantics) MivotUtils.populate_instance(ep_instance, "EpochPosition", mapping, self._table, IvoaType.RealQuantity) if "obsDate" in mapping: ep_instance.add_instance(self._add_epoch_position_epoch(**mapping["obsDate"])) if "correlations" in mapping: ep_instance.add_instance(self._add_epoch_position_correlations(**mapping["correlations"])) if "errors" in mapping: ep_instance.add_instance(self._add_epoch_position_errors(**mapping["errors"])) if space_frame_id: ep_instance.add_reference(dmrole=f"{ModelPrefix.mango}:EpochPosition.spaceSys", dmref=space_frame_id) if time_frame_id: ep_instance.add_reference(dmrole=f"{ModelPrefix.mango}:EpochPosition.timeSys", dmref=time_frame_id) self._properties.append(ep_instance) return ep_instance
[docs] def add_brightness_property(self, filter_id, mapping, semantics={}): """ Add a ``Brightness`` instance to the properties of the current ``MangoObject``. Both mapping and semantics arguments inherit from `pyvo.mivot.writer.InstancesFromModels.add_mango_brightness`. Parameters ---------- filter_id : string Identifier (dmid) of the PhotCal INSTANCE located in the GLOBALS mapping : dict Mapping of the EpochPosition fields semantics : dict Mapping of the MangoObject property Returns ------- `Property` The Brightness instance """ # create the MIVOT instance mapping the MANGO property mag_instance = Property(dmtype=f"{ModelPrefix.mango}:Brightness", semantics=semantics) # set MANGO property attribute MivotUtils.populate_instance(mag_instance, "PhotometricProperty", mapping, self._table, IvoaType.RealQuantity) # build the error instance if it is mapped if "error" in mapping: error_mapping = mapping["error"] error_class = error_mapping["class"] mag_instance.add_instance( self._get_error_instance(error_class, f"{ModelPrefix.mango}:PhotometricProperty.error", error_mapping)) # add MIVOT reference to the photometric calibration instance mag_instance.add_reference(dmrole=f"{ModelPrefix.mango}:Brightness.photCal", dmref=filter_id) self._properties.append(mag_instance) return mag_instance
[docs] def add_color_instance(self, filter_low_id, filter_high_id, mapping, semantics={}): """ Add an ``Color`` instance to the properties of the current ``MangoObject``. Both mapping and semantics arguments inherit from `pyvo.mivot.writer.InstancesFromModels.add_mango_color`. Parameters ---------- filter_low_id : string Identifier (dmid) of the low energy Photfilter INSTANCE located in the GLOBALS filter_high_id : string Identifier (dmid) of the high energy Photfilter INSTANCE located in the GLOBALS mapping : dict Mapping of the EpochPosition fields semantics : dict Mapping of the MangoObject property Returns ------- `Property` The Color instance """ error_mapping = mapping["error"] mag_instance = Property(dmtype=f"{ModelPrefix.mango}:Color", semantics=semantics) coldef_instance = MivotInstance(dmtype=f"{ModelPrefix.mango}:ColorDef", dmrole=f"{ModelPrefix.mango}:Color.colorDef") mapped_roles = MivotUtils._valid_mapped_dmroles(mapping.items(), "Color") def_found = False for dmrole, column in mapped_roles: if dmrole.endswith("definition"): def_found = True coldef_instance.add_attribute(dmtype="mango:ColorDefinition", dmrole="mango:ColorDef.definition", value=f"*{column}") if not def_found: raise MappingError("Missing color definition") mapping.pop("definition") MivotUtils.populate_instance(mag_instance, "PhotometricProperty", mapping, self._table, IvoaType.RealQuantity) coldef_instance.add_reference(dmrole=f"{ModelPrefix.mango}:ColorDef.low", dmref=filter_low_id) coldef_instance.add_reference(dmrole=f"{ModelPrefix.mango}:ColorDef.high", dmref=filter_high_id) error_class = error_mapping["class"] mag_instance.add_instance(self._get_error_instance(error_class, f"{ModelPrefix.mango}:PhotometricProperty.error", error_mapping)) mag_instance.add_instance(coldef_instance) self._properties.append(mag_instance) return mag_instance
[docs] def get_mango_object(self, with_origin=False): """ Make and return the XML serialization of the MangoObject. Parameters ---------- with_origin : bool Ask for adding a reference (_origin) to the query origin possibly located in the GLOBALS Returns ------- string The XML serialization of the MangoObject """ mango_object = MivotInstance(dmtype="mango:MangoObject", dmid=self._dmid) if self._dmid: ref, value = MivotUtils.get_ref_or_literal(self._dmid) att_value = ref if ref else value mango_object.add_attribute(dmrole="mango:MangoObject.identifier", dmtype=IvoaType.string, value=att_value) if with_origin: mango_object.add_reference("mango:MangoObject.queryOrigin", "_origin") m_properties = [] for prop in self._properties: m_properties.append(prop.xml_string()) mango_object.add_collection("mango:MangoObject.propertyDock", m_properties) return mango_object