Choose the Simple Stellar Population library

We provide a set of Simple Stellar Population libraries, already formatted for usage by galapy functions and classes.

We can print a list of available libraries by calling

[1]:
from galapy.CompositeStellarPopulation import print_ssp_libs
print_ssp_libs()
Available SSP formats
---------------------
* bc03.stelib.chab.extrap;
* bc03.stelib.chab;
* bc03.basel.chab;
* bc03.basel.chab.refined;
* parsec22.NTL.refined;
* parsec22.NT;
* parsec22.NTL;
* parsec22.NT.refined;

with the naming convention: author.method[.imf.filling_schema]

  • family: An achronym for the authors of the SSP library

  • method: if present, shows which method was used to compute the SSP

  • imf: if present shows the initial mass function used to compute the SSP

  • filling_schema: all the SSPs’ wavelength domain has been extended to span from \(1\ \mathring{A}\) to \(10^{10}\ \mathring{A}\). This code provides the strategy used (not present = filled with zeros, extrap = extrapolated linearly in the logarithm, refined = thinner lambda grid obtained by linearly-interpolating the extend equivalent)

They are divided into two main families providing different features each. The details are reported in the following sections.

Note that the different families are divided in flavours all of which have different properties. The main property that regulates the impact on the sampling performances is the size of the wavelength grid: the smaller the fastest.

Look around:

We can load a SSP table by invoking the dedicated function:

[2]:
from galapy.CompositeStellarPopulation import load_SSP_table

which returns a tuple with

  • the wavelength grid

  • the age grid

  • the metallicity grid

  • the table itself

[3]:
l, t, Z, L = load_SSP_table('bc03.basel.chab')

Our tables are stored as flattened, contiguous objects, mainly for internal usage.

[4]:
L.shape, l.size*t.size*Z.size
[4]:
((3438981,), 3438981)

We can reshape them into a 3D matrix by calling the dedicated function:

[5]:
from galapy.CompositeStellarPopulation import reshape_SSP_table

this function takes two arguments:

  • the L table

  • a shape tuple consisting of 3 elements: the wavelength grid size, the age grid size and the metallicity grid size

[6]:
L = reshape_SSP_table( L, shape=(l.size, t.size, Z.size) )
L.shape
[6]:
(2223, 221, 7)

Bruzual & Charlot 2003: bc03

the classic and popular Bruzual & Charlot (2003) in its updated version (v2016). This library provides the continuum luminosity from SSPs for a set of different IMFs, at varying wavelength, age and metallicity.

bc03 SSP tables only include stellar emission (atmospheres) thus, if the user wants to also model further emission components due to stars, these have to be computed separately. Namely it is required to build the synchrotron and nebular free-free contributions separately (see galapy.Synchrotron and galapy.NebularFreeFree).

General to all the libraries in the family:

size

values

Time grid

221

irregularly distributed values in the interval \(0 < \tau < 2\times10^{10}\ \text{years}\)

Metallicity grid

7

[0.0001, 0.0004, 0.004, 0.008, 0.02, 0.05, 0.1]

Specific to the different flavours:

  • basel.chab : lower resolution wavelength grid (\(N_\lambda < 3000\)), with Chabrier IMF

  • stelib.chab: higher resolution wavelength grid (\(N_\lambda > 7000\)), with Chabrier IMF

flavour

Wavelength grid

Description

basel.chab

2223

Extended from the original work to span from \(1 \mathring{A}\) to \(10^{10}\mathring{A}\), the filling method is zeros padding

basel.chab.refined

2837

Same as above but the density of wavelength grid points has been increased to have at least 128 values per-each order of magnitude

stelib.chab

7325

Same as basel.chab but with more resolution in the Optical/UV bands

stelib.chab.extrap

7325

Same as above but instead of zeros padding, the padding values have been extrapolated linearly in log-space from the last two grid points in the original table

Tips

  • the SSP libraries of choice for comparison with other works (as these tables are present in most of the other SED fitting tools)

  • highly tested and verified

  • the stelib flavour includes the tables with the highest wavelength resolution from those included in the default database.

  • the stelib.*.extrap flavour introduces extrapolation at long and short wavelength instead of padding with zeros the table.

  • flavours marked refined should be used when computing the transmitted band flux in photometric systems including bands from the submm/mm bands and longer (lower frequency).

Plot single SSPs

It might be useful to visualise the different SSPs before choosing which one best suits someones needs

[7]:
from galapy.analysis.plot import plt

(the plt module in galapy.analysis.plot is just a matplotlib.pyplot where some tweaking of the default layout has been applied)

Load the two stelib flavours, to show the difference between the default zeros-padding and the extrapolated library:

[8]:
l, t, Z, Lbc03zerosp = load_SSP_table('bc03.stelib.chab')
Lbc03zerosp = reshape_SSP_table( Lbc03zerosp, shape=(l.size, t.size, Z.size) )
*_, Lbc03extrap = load_SSP_table('bc03.stelib.chab.extrap')
Lbc03extrap = reshape_SSP_table( Lbc03extrap, shape=(l.size, t.size, Z.size) )

(since the wavelength, age and metallicity grids are all the same for the two cases, we store them just from the first table)

We select some different ages from the table picking some indices and check the value from the age-grid t

[9]:
tidx = [1, 100, 150, 200]
iz = 3
print( f'Metallicity: {Z[iz]}')
print( 'Ages:')
for it in tidx :
    print( f'{t[it]:.2e} years' )
Metallicity: 0.008
Ages:
1.00e+05 years
3.70e+07 years
2.60e+09 years
1.50e+10 years

And finally, we plot in 4 different panels the four different ages. Note how the tails of the emissions are different (solid blue line VS dashed green line)

[10]:
fig, axs = plt.subplots(2,2, figsize=(14,8), sharex=True, sharey=True,
                        gridspec_kw={'hspace':0.0, 'wspace':0.0},
                        tight_layout=True)

for ii, it in enumerate(tidx) :
    jj = int(ii/2)
    kk = int(ii%2)
    if jj != 0 :
        axs[jj,kk].set_xlabel('$\\lambda\\ [\\AA]$')
    if kk == 0 :
        axs[jj,kk].set_ylabel('$L_\\lambda\\ [L_\\odot\\;\\AA^{-1}]$')
    axs[jj,kk].set_xscale('log')
    axs[jj,kk].set_yscale('log')
    axs[jj,kk].set_xlim(2.*10**0,10**10)
    axs[jj,kk].plot(l, Lbc03zerosp[:,it,3], label='zeros padding')
    axs[jj,kk].plot(l, Lbc03extrap[:,it,3], ls='--', label='extrapolated')
    if ii == 3 :
        axs[jj,kk].legend()
../_images/notebooks_choose_ssp_lib_23_0.png

PARSEC22: parsec22

Produced with the PARSEC code (Bressan et al., 2012; Chen et al., 2014; Chen et al., 2015) for a Chabrier IMF and varying ages and metallicities, including emission from dusty AGB stars Bressan et al., 1998.

These libraries come in two flavours, the first one with continuum emission only and the second also including nebular emission. In the former, besides continuum stellar emission, non-thermal synchrotron emission from core-collapse supernovae is also included in each SSP spectrum (see, e.g., Vega et al., 2008). In the latter, on top of the stellar continuum and non-thermal synchrotron, nebular emission is also included, with both free-free continuum and nebular emission (see, e.g., Maya et al., 2004), calculated with CLOUDY.

We highlight that, using the PARSEC22 SSP libraries come with the advantage of reducing the total amount of computations the code has to perform for getting to a final equivalent SED. Namely, using our custom SSP libraries avoids the need to compute separately the radio stellar emissions. Furthermore, nebular line emission is currently only available with the PARSEC22 SSP libraries.}

General to all the libraries in the family:

size

values

Time grid

146

irregularly distributed values in the interval \(0 < \tau < 1.4\times10^{10}\ \text{years}\)

Metallicity grid

7

[1.e-04, 5.e-04, 1.e-03, 4.e-03, 8.e-03, 2.e-02, 1.e+00]

Specific to the different flavours:

  • NT : stellar atmospheres + Non-Thermal emission (i.e. Super-Nova Synchrotron)

  • NTL: stellar atmospheres + Non-Thermal emission (i.e. Super-Nova Synchrotron) + Nebular emission (i.e. Bremstrhalung + Emission Lines)

flavour

Wavelength grid

Description

NT

1562

See above, spanning from \(1\mathring{A}\) to \(10^{10}\mathring{A}\), the missing parts are padded with zeros

NT.refined

2189

Same as above but the density of wavelength grid points has been increased to have at least 128 values per-each order of magnitude in the wavelength grid

NTL

1562

Same as NT but with more resolution in the Optical/UV bands

NTL.refined

2189

Same as NT.refined

Tips

  • the parsec22 family is our default, it is the most updated and has been developed with a resolution largely sufficient for most of the applications.

  • currently, using parsec22.NTL libraries is the only method to account for the nebular contribution both in terms of

    • energy balance

    • line emission

  • flavours marked refined should be used when computing the transmitted band flux in photometric systems including bands from the submm/mm bands and longer (lower frequency).

Some plots

Let’s check the difference between the NT and NTL flavours:

[11]:
l, t, Z, Lp22nt = load_SSP_table('parsec22.NT')
Lp22nt = reshape_SSP_table( Lp22nt, shape=(l.size, t.size, Z.size) )
*_, Lp22ntl = load_SSP_table('parsec22.NTL')
Lp22ntl = reshape_SSP_table( Lp22ntl, shape=(l.size, t.size, Z.size) )

(since the wavelength, age and metallicity grids are all the same for the two cases, we store them just from the first table)

We select some different ages from the table picking some indices and check the value from the age-grid t

[12]:
tidx = [1, 25, 75, 125]
iz = 3
print( f'Metallicity: {Z[iz]}')
print( 'Ages:')
for it in tidx :
    print( f'{t[it]:.2e} years' )
Metallicity: 0.004
Ages:
1.00e+05 years
3.80e+06 years
5.00e+07 years
4.00e+09 years

And finally, we plot in 4 different panels the four different ages. Note how the difference is evident just at the youngest ages (solid blue line VS dashed green line in the two upper plots)

[13]:
fig, axs = plt.subplots(2,2, figsize=(14,8), sharex=True, sharey=True,
                        gridspec_kw={'hspace':0.0, 'wspace':0.0},
                        tight_layout=True)

for ii, it in enumerate(tidx) :
    jj = int(ii/2)
    kk = int(ii%2)
    if jj != 0 :
        axs[jj,kk].set_xlabel('$\\lambda\\ [\\AA]$')
    if kk == 0 :
        axs[jj,kk].set_ylabel('$L_\\lambda\\ [L_\\odot\\;\\AA^{-1}]$')
    axs[jj,kk].set_xscale('log')
    axs[jj,kk].set_yscale('log')
    axs[jj,kk].set_xlim(2.*10**0,10**10)
    axs[jj,kk].plot(l, Lp22nt[:,it,3], label='non-thermal')
    axs[jj,kk].plot(l, Lp22ntl[:,it,3], ls='--', label='non-thermal + nebular')
    if ii == 3 :
        axs[jj,kk].legend()
../_images/notebooks_choose_ssp_lib_29_0.png