Padova provides pythonic access to Padova group's stellar isochrone web app, CMD. This notebook will briefly show you what Padova can do. First, some setup for this notebook:
In [1]:
%matplotlib inline
%config InlineBackend.figure_format='retina'
import numpy as np
In [2]:
%%bash
pip install -U palettable
Padova provides three classes tailored to the types of isochrone queries you want to make.
IsochroneRequest will query for a single isochroneAgeGridRequest will query for a set of isochrones with a single metallicity for a grid of agesMetallicityGridRequest will query for a set of isochrones with a single age, for a grid of metallicities.
In [3]:
from padova import IsochroneRequest, AgeGridRequest, MetallicityGridRequest
To obtain a single isochrone for a speific age and metallicity we'll create a IsochroneRequest instance and pass the stellar population settings: the age as $\log (A/\mathrm{yr})$, metallicity as a fraction the composition. We also specify the photometric system, (WFC3 filters). Since WFC3 isn't supported by the latest bolometric correction library, we use the older Girardi et al 2008 specification ('odfnew').
In [4]:
r = IsochroneRequest(log_age=9, z=0.02, photsys='wfc3_wide', photsys_version='odfnew')
Now that the request has been computed and downloaded from the CMD API, we can inspect the isochrones. First, we can look at the raw result:
In [5]:
r.data[:2000]
Out[5]:
The Padova package parses this result into Astropy-compatible tables. You can access the isochrone table with isochone attribute.
In [6]:
isoc = r.isochrone
print("Isochrone of Z={0:.2f}, age={0:.3e}".format(isoc.z, isoc.age))
print("Available filters: {0}".format(" ".join(isoc.filter_names)))
print(isoc.meta)
print(isoc)
We can plot up the isochrones as if they were in a nearby galaxy:
In [7]:
from astropy.coordinates import Distance
import astropy.units as u
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(4, 4), dpi=300)
gs = mpl.gridspec.GridSpec(1, 1)
ax = fig.add_subplot(gs[0])
d = Distance(785 * u.kpc)
ax.plot(isoc['F475W'] - isoc['F814W'], isoc['F814W'] + d.distmod.value)
ax.set_xlim(-1, 4.)
ax.set_ylim(36., 16.)
ax.set_xlabel("F475W-F814W")
ax.set_ylabel("F814W")
fig.show()
In [8]:
r2 = AgeGridRequest(z=0.02,
min_log_age=7., max_log_age=10.1, delta_log_age=0.1,
photsys='wfc3_wide', photsys_version='odfnew')
In [9]:
r2_isochrones = r2.isochrone_set
In [10]:
from palettable.cubehelix import perceptual_rainbow_16
from astropy.coordinates import Distance
import astropy.units as u
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(4, 4), dpi=300)
gs = mpl.gridspec.GridSpec(1, 1)
ax = fig.add_subplot(gs[0])
scalar_map = mpl.cm.ScalarMappable(norm=mpl.colors.Normalize(vmin=7., vmax=10.1),
cmap=perceptual_rainbow_16.mpl_colormap)
scalar_map.set_array(np.array([isoc.age for isoc in r2_isochrones]))
d = Distance(785 * u.kpc)
for isoc in r2_isochrones:
ax.plot(isoc['F475W'] - isoc['F814W'], isoc['F814W'] + d.distmod.value,
c=scalar_map.to_rgba(np.log10(isoc.age)))
cb = plt.colorbar(mappable=scalar_map, cax=None, ax=ax)
cb.set_label(r"$\log(A/\mathrm{yr})$")
ax.set_xlim(-1, 4.)
ax.set_ylim(36., 16.)
ax.set_xlabel("F475W-F814W")
ax.set_ylabel("F814W")
fig.show()
In [11]:
r3 = MetallicityGridRequest(log_age=9., min_z=0.0001, max_z=0.03, delta_z=0.001,
photsys='wfc3_wide', photsys_version='odfnew')
r3_isochrones = r3.isochrone_set
In [12]:
from palettable.cubehelix import perceptual_rainbow_16
from astropy.coordinates import Distance
import astropy.units as u
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(4, 4), dpi=300)
gs = mpl.gridspec.GridSpec(1, 1)
ax = fig.add_subplot(gs[0])
scale_z = lambda z: np.log10(z / 0.019)
z_values = np.array([scale_z(isoc.z) for isoc in r3_isochrones])
scalar_map = mpl.cm.ScalarMappable(norm=mpl.colors.Normalize(vmin=z_values.min(), vmax=z_values.max()),
cmap=perceptual_rainbow_16.mpl_colormap)
scalar_map.set_array(z_values)
d = Distance(785 * u.kpc)
for isoc in r3_isochrones:
ax.plot(isoc['F475W'] - isoc['F814W'], isoc['F814W'] + d.distmod.value,
c=scalar_map.to_rgba(scale_z(isoc.z)))
cb = plt.colorbar(mappable=scalar_map, cax=None, ax=ax)
cb.set_label(r"$\log(Z/Z_\odot)$")
ax.set_xlim(-1, 4.)
ax.set_ylim(36., 16.)
ax.set_xlabel("F475W-F814W")
ax.set_ylabel("F814W")
fig.show()
In [13]:
r.settings.__hash__()
Out[13]:
We can verify that the request we just made has been cached:
In [14]:
from padova.resultcache import PadovaCache
cache = PadovaCache()
r.settings in cache
Out[14]:
Note that by default the cache files are located in ~/.padova_cache.
In [15]:
isoc.export_for_starfish("here")
In [ ]: