species.read.read_isochrone — species 0.1.2 documentation

# Source code for species.read.read_isochrone

    """
    Module with reading functionalities for isochrones.
    """

    import os
    import configparser

    import h5py
    import numpy as np

    from scipy.interpolate import griddata

    from species.core import box
    from species.read import read_model

    class ReadIsochrone:
        """
        Class for reading an isochrone from the database.
        """

        def __init__(self,
                     tag):
            """
            Parameters
            ----------
            tag : str
                Database tag of the isochrone data.

            Returns
            -------
            NoneType
                None
            """

            self.tag = tag

            config_file = os.path.join(os.getcwd(), 'species_config.ini')

            config = configparser.ConfigParser()
            config.read_file(open(config_file))

            self.database = config['species']['database']

        def get_isochrone(self,
                          age,
                          masses,
                          filters_color,
                          filter_mag):
            """
            Function for selecting an isochrone.

            Parameters
            ----------
            age : str
                Age (Myr) at which the isochrone data is interpolated.
            masses : numpy.ndarray
                Masses (Mjup) at which the isochrone data is interpolated.
            filters_color : tuple(str, str), None
                Filter IDs for the color as listed in the file with the isochrone data. Not selected if
                set to None or if only evolutionary tracks are available.
            filter_mag : str, None
                Filter ID for the absolute magnitude as listed in the file with the isochrone data. Not
                selected if set to None or if only evolutionary tracks are available.

            Returns
            -------
            species.core.box.IsochroneBox
                Box with the isochrone.
            """

            age_points = np.repeat(age, masses.shape[0])  # [Myr]

            color = None
            mag_abs = None

            index_teff = 2
            index_logg = 4

            with h5py.File(self.database, 'r') as h5_file:
                model = h5_file['isochrones/'+self.tag+'/evolution'].attrs['model']
                evolution = np.asarray(h5_file['isochrones/'+self.tag+'/evolution'])

                if model == 'baraffe':
                    filters = list(h5_file['isochrones/'+self.tag+'/filters'])
                    magnitudes = np.asarray(h5_file['isochrones/'+self.tag+'/magnitudes'])

            if model == 'baraffe':
                for i, item in enumerate(filters):
                    filters[i] = item.decode()

                if filters_color is not None:
                    index_color_1 = filters.index(filters_color[0])
                    index_color_2 = filters.index(filters_color[1])

                if filter_mag is not None:
                    index_mag = filters.index(filter_mag)

                if filters_color is not None:
                    mag_color_1 = griddata(points=evolution[:, 0:2],
                                           values=magnitudes[:, index_color_1],
                                           xi=np.stack((age_points, masses), axis=1),
                                           method='linear',
                                           fill_value='nan',
                                           rescale=False)

                    mag_color_2 = griddata(points=evolution[:, 0:2],
                                           values=magnitudes[:, index_color_2],
                                           xi=np.stack((age_points, masses), axis=1),
                                           method='linear',
                                           fill_value='nan',
                                           rescale=False)

                    color = mag_color_1-mag_color_2

                if filter_mag is not None:
                    mag_abs = griddata(points=evolution[:, 0:2],
                                       values=magnitudes[:, index_mag],
                                       xi=np.stack((age_points, masses), axis=1),
                                       method='linear',
                                       fill_value='nan',
                                       rescale=False)

            teff = griddata(points=evolution[:, 0:2],
                            values=evolution[:, index_teff],
                            xi=np.stack((age_points, masses), axis=1),
                            method='linear',
                            fill_value='nan',
                            rescale=False)

            logg = griddata(points=evolution[:, 0:2],
                            values=evolution[:, index_logg],
                            xi=np.stack((age_points, masses), axis=1),
                            method='linear',
                            fill_value='nan',
                            rescale=False)

            return box.create_box(boxtype='isochrone',
                                  model=self.tag,
                                  filters_color=filters_color,
                                  filter_mag=filter_mag,
                                  color=color,
                                  magnitude=mag_abs,
                                  teff=teff,
                                  logg=logg,
                                  masses=masses)

        def get_color_magnitude(self,
                                age,
                                masses,
                                model,
                                filters_color,
                                filter_mag):
            """
            Function for calculating color-magnitude combinations from a selected isochrone.

            Parameters
            ----------
            age : str
                Age (Myr) at which the isochrone data is interpolated.
            masses : numpy.ndarray
                Masses (Mjup) at which the isochrone data is interpolated.
            model : str
                Atmospheric model used to compute the synthetic photometry.
            filters_color : tuple(str, str)
                Filter IDs for the color as listed in the file with the isochrone data. The filter IDs
                should be provided in the format of the SVO Filter Profile Service.
            filter_mag : str
                Filter ID for the absolute magnitude as listed in the file with the isochrone data. The
                value should be equal to one of the ``filters_color`` values.

            Returns
            -------
            species.core.box.ColorMagBox
                Box with the color-magnitude data.
            """

            isochrone = self.get_isochrone(age=age,
                                           masses=masses,
                                           filters_color=None,
                                           filter_mag=None)

            model1 = read_model.ReadModel(model=model, filter_name=filters_color[0])
            model2 = read_model.ReadModel(model=model, filter_name=filters_color[1])

            mag1 = np.zeros(isochrone.masses.shape[0])
            mag2 = np.zeros(isochrone.masses.shape[0])

            for i, mass_item in enumerate(isochrone.masses):
                model_param = {'teff': isochrone.teff[i],
                               'logg': isochrone.logg[i],
                               'feh': 0.,
                               'mass': mass_item,
                               'distance': 10.}

                if np.isnan(isochrone.teff[i]):
                    mag1[i] = np.nan
                    mag2[i] = np.nan

                else:
                    for item_bounds in model1.get_bounds():
                        if model_param[item_bounds] <= model1.get_bounds()[item_bounds][0]:
                            mag1[i] = np.nan
                            mag2[i] = np.nan

                        elif model_param[item_bounds] >= model1.get_bounds()[item_bounds][1]:
                            mag1[i] = np.nan
                            mag2[i] = np.nan

                    if not np.isnan(mag1[i]):
                        mag1[i], _ = model1.get_magnitude(model_param=model_param)
                        mag2[i], _ = model2.get_magnitude(model_param=model_param)

            if filter_mag == filters_color[0]:
                abs_mag = mag1

            elif filter_mag == filters_color[1]:
                abs_mag = mag2

            else:
                raise ValueError('The filter_mag argument should be equal to one of the two filter '
                                 'values of filters_color.')

            return box.create_box(boxtype='colormag',
                                  library=model,
                                  object_type='model',
                                  filters_color=filters_color,
                                  filter_mag=filter_mag,
                                  color=mag1-mag2,
                                  magnitude=abs_mag,
                                  sptype=masses)

        def get_color_color(self,
                            age,
                            masses,
                            model,
                            filters):
            """
            Function for calculating color-magnitude combinations from a selected isochrone.

            Parameters
            ----------
            age : str
                Age (Myr) at which the isochrone data is interpolated.
            masses : numpy.ndarray
                Masses (Mjup) at which the isochrone data is interpolated.
            model : str
                Atmospheric model used to compute the synthetic photometry.
            filters : tuple(tuple(str, str), tuple(str, str))
                Filter IDs for the colors as listed in the file with the isochrone data. The filter IDs
                should be provided in the format of the SVO Filter Profile Service.

            Returns
            -------
            species.core.box.ColorColorBox
                Box with the color-color data.
            """

            isochrone = self.get_isochrone(age=age,
                                           masses=masses,
                                           filters_color=None,
                                           filter_mag=None)

            model1 = read_model.ReadModel(model=model, filter_name=filters[0][0])
            model2 = read_model.ReadModel(model=model, filter_name=filters[0][1])
            model3 = read_model.ReadModel(model=model, filter_name=filters[1][0])
            model4 = read_model.ReadModel(model=model, filter_name=filters[1][1])

            mag1 = np.zeros(isochrone.masses.shape[0])
            mag2 = np.zeros(isochrone.masses.shape[0])
            mag3 = np.zeros(isochrone.masses.shape[0])
            mag4 = np.zeros(isochrone.masses.shape[0])

            for i, mass_item in enumerate(isochrone.masses):
                model_param = {'teff': isochrone.teff[i],
                               'logg': isochrone.logg[i],
                               'feh': 0.,
                               'mass': mass_item,
                               'distance': 10.}

                mag1[i], _ = model1.get_magnitude(model_param=model_param)
                mag2[i], _ = model2.get_magnitude(model_param=model_param)
                mag3[i], _ = model3.get_magnitude(model_param=model_param)
                mag4[i], _ = model4.get_magnitude(model_param=model_param)

            return box.create_box(boxtype='colorcolor',
                                  library=model,
                                  object_type='model',
                                  filters=filters,
                                  color1=mag1-mag2,
                                  color2=mag3-mag4,
                                  sptype=masses)