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


[docs]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']
[docs] 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[f'isochrones/{self.tag}/evolution'].attrs['model'] evolution = np.asarray(h5_file[f'isochrones/{self.tag}/evolution']) if model == 'baraffe': filters = list(h5_file[f'isochrones/{self.tag}/filters']) magnitudes = np.asarray(h5_file[f'isochrones/{self.tag}/magnitudes']) if model == 'baraffe': 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)
[docs] 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]) if model1.get_parameters() != ['teff', 'logg']: raise ValueError('Creating synthetic colors and magnitudes from isochrones is ' 'currently only implemented for models with only Teff and log(g) ' 'as free parameters. Please contact Tomas Stolker if additional ' 'functionalities are required.') 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], '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)
[docs] def get_color_color(self, age, masses, model, filters_colors): """ 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_colors : 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_colors[0][0]) model2 = read_model.ReadModel(model=model, filter_name=filters_colors[0][1]) model3 = read_model.ReadModel(model=model, filter_name=filters_colors[1][0]) model4 = read_model.ReadModel(model=model, filter_name=filters_colors[1][1]) if model1.get_parameters() != ['teff', 'logg']: raise ValueError('Creating synthetic colors and magnitudes from isochrones is ' 'currently only implemented for models with only Teff and log(g) ' 'as free parameters. Please contact Tomas Stolker if additional ' 'functionalities are required.') 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], '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) 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_colors, color1=mag1-mag2, color2=mag3-mag4, sptype=masses)