Source code for galaxia_ananke.photometry.Formatting

#!/usr/bin/env python
#
# Author: Adrien CR Thob
# Copyright (C) 2022  Adrien CR Thob
#
# This file is part of the py-Galaxia-ananke project,
# <https://github.com/athob/py-Galaxia-ananke>, which is licensed
# under the GNU Affero General Public License v3.0 (AGPL-3.0).
# 
# The full copyright notice, including terms governing use, modification,
# and redistribution, is contained in the files LICENSE and COPYRIGHT,
# which can be found at the root of the source code distribution tree:
# - LICENSE <https://github.com/athob/py-Galaxia-ananke/blob/main/LICENSE>
# - COPYRIGHT <https://github.com/athob/py-Galaxia-ananke/blob/main/COPYRIGHT>
#
"""
Docstring
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Tuple, List, Dict
from numpy.typing import ArrayLike, NDArray
from functools import cached_property
from operator import itemgetter
import dataclasses as dc

import numpy as np
import pandas as pd
from astropy import table, units, constants

from .._constants import *
from ..utils import classproperty

if TYPE_CHECKING:
    from .Isochrone import Isochrone
    from .IsochroneFile import IsochroneFile

__all__ = ['default_formatting', 'padova_formatting', 'oldpadova_fomatting', 'oldpadova_fomatting_withlogage']


units.Zsun = units.def_unit('Zsun') # TODO could define PhysicalType "abundance" ?
units.integer = units.Quantity(1, dtype='int') # units.def_unit('integer', units.Quantity(1, dtype='int')) # TODO pull issue in astropy for integer dtype unit?


class _BaseFormatting:
    _zini = 'Z_ini'
    _unit_zini = units.LogUnit(units.Zsun)
    _age = 'Age'
    _unit_age = units.LogUnit(units.yr)
    _mini = 'M_ini'
    _mact = 'M_act'
    _unit_mass = units.Msun
    _radi = 'Radius'
    _unit_radi = units.Rsun
    _lum = 'Lum'
    _unit_lum = units.LogUnit(units.Lsun)
    _teff = 'T_eff'
    _unit_temp = units.LogUnit(units.Kelvin)
    _grav = 'Grav'
    _unit_grav = units.LogUnit(units.Gal)
    _label = 'Label'
    _unit_label = units.integer
    @classproperty
    def units_mapper(cls):
        return {
            cls._zini: cls._unit_zini,
            cls._age: cls._unit_age,
            cls._mini: cls._unit_mass,
            cls._mact: cls._unit_mass,
            cls._radi: cls._unit_radi,
            cls._lum: cls._unit_lum,
            cls._teff: cls._unit_temp,
            cls._grav: cls._unit_grav,
            cls._label: cls._unit_label
        }

[docs] @dc.dataclass() class Formatting(_BaseFormatting): """ Formatting object """ i_age: int i_mini: int i_mact: int i_lum: int i_teff: int i_grav: int i_label: int lin_age: bool = False feh_sun: float = 0.0152 # TODO figure out that conversion situation @cached_property def format_mapper(self) -> Dict[int,str]: return { self.i_age: self._age, self.i_mini: self._mini, self.i_mact: self._mact, self.i_lum: self._lum, self.i_teff: self._teff, self.i_grav: self._grav, self.i_label: self._label } @cached_property def nonmagnitude_itemgetter(self) -> itemgetter: return itemgetter(*self.format_mapper.keys())
[docs] def metallicity_converter(self, metallicity: ArrayLike) -> NDArray: return np.log10(metallicity/np.array(self.feh_sun))
[docs] def qtable_per_age_from_isochronefile(self, iso_file: IsochroneFile) -> table.QTable: isochrone: Isochrone = iso_file._isochrone units_mapper = self.units_mapper column_names: Tuple[str] = self.nonmagnitude_itemgetter(iso_file.data.keys()) + isochrone.magnitude_itemgetter(iso_file.data.keys()) final_names: List[str] = list(self.format_mapper.values()) + isochrone.mag_names column_mapper: Dict[str,str] = dict(zip(column_names, final_names)) reduced_data: pd.DataFrame = iso_file.data[column_names].to_pandas().rename(columns=column_mapper).reset_index().sort_values([self._age, self._mini, 'index']).drop('index', axis=1) reduced_data.insert(0, self._zini, self.metallicity_converter(iso_file.metallicity)) reduced_data.insert(5, self._radi, np.sqrt(constants.G*reduced_data[self._mact].to_numpy()*self._unit_mass/(reduced_data[self._grav].to_numpy()*self._unit_grav).to(self._unit_grav.physical_unit)).to(self._unit_radi).value) if self.lin_age: reduced_data[self._age] = np.log10(reduced_data[self._age]) return { age: table.QTable({ key: units.Magnitude(value) if key in isochrone.mag_names else value*units_mapper[key] for key,value in df.to_dict(orient='list').items() }) for age,df in reduced_data.groupby(self._age) }
default_formatting = Formatting(0, 1, 2, 3, 4, 5, 6, False) # Python and others padova_formatting = Formatting(2, 3, 5, 6, 7, 8, 9, False) # CTIO__DECam, LSST_DP0, Roman, Euclid, JWST oldpadova_fomatting = Formatting(1, 2, 3, 4, 5, 6, 7, True) # WFIRST, LSST, GAIA__0, GAIA__DR2 oldpadova_fomatting_withlogage = Formatting(1, 2, 3, 4, 5, 6, 7, False) # WFIRST+HST__WFC3 if __name__ == '__main__': raise NotImplementedError()