Searching for specific star systems in BPASS using EvE¶
This jupyter notebook is an introduction to the EvE (Evolution Explorer) database that I created for myself to make searching for specific star systems in the BPASS stellar library easier and faster.
The BPASS stellar library is a collection of >250,000 text files, each corresponding to a given star system simulated in BPASS. These textfiles contain a table that summarises the evolution of that star system, recording physical and observed properties (e.g. Luminosity, Temperature, Radii, but also UBVRI and other broad band magnitudes).
So what is the point of EvE? Well say you’re looking for the progenitor of a Luminous Red Nova, the explosion from a common envelope expulsion (or merger as a result of a common envelope), even if you have a good idea of the specific metallicity you want to look at (and therefore can focus on 1/13th of the models in the stellar library, because there are 13 metallicities in BPASS), you’ll still need to paruse tens of thousands of files, looking through each of them to check which ones go through a common envelope, then looking through those for parameters that fit your pre-explosion images. It’s not all that hard, but it takes a bit of time and if you look for transient progenitors regularly (or other star systems) you end up doing this over and over again. But there’s no point! the models are pre-calculated, why don’t we have some nice look up tables that summarise some key properties so we can discard all the models that we know we don’t care about and then open up the ones we are interested in.
In this tutorial we’re going to be looking for an arbitrary (as in with properties I chose) super-luminous supernova. Once we’ve found our favourite potential progenitors we will explore their life by looking through their corresponding files in the BPASS stellar library.
To do this tutorial you will need: * The BPASS stellar library. It’s about 8GB to download and 50GB (yes, of text files) once it is unzipped. You can find the data you need from a diet version of the BPASSv2.2.1 I created called the BPASS starter kit. I have put it on zenodo for your convenience. May the god of fast internet speeds be with you.
The EvE data base [only download the .hdf5 file]. I have put the alpha version on zenodo as well. The reason it is called the alpha version is that there are things that could do with being ironed out. Turns out that computationally exploring a bunch of tables is harder than it might seem when you’re trying to summaries physical properties from simulations of physics that is…. challenging. For example don’t use the main sequen lifetime column wihtout caution. It’s hard to define the end of the Main Sequence when you’re looking at models. Also note that you don’t need the fortran code that is in this release - it’s only there so that if someone finds a weird behaviour in the library they can check my code to find the inevitable silent bugs (or poor choices) that lie within it.
My code hoki v1.7 and above. The reason you need this current version is that it contains the Eve class that helps you not even have to rummage throuhg the EvE.hdf5 files itself. Off course you could just go through EvE with pandas but that’s not what we’re doing here.
If you have a question or a complain start an issue on the hoki github or send me an e-mail (hfstevance@gmail.com). I will do my best to help whilst I am still in science. If future me has left science, she might still be willing to help so it’s worth giving the e-mail a try.
Let’s go!
Initial imports and EvE.hdf5 structure¶
We will need some standard python libraries. Pandas is my favourite way to deal with tables and that is why it’s all over hoki and it is what the EvE.hdf5 file is made of. Let’s talk about the EvE.hdf5 structure to help you understand what we’ll be digging into.
[The ``EvE.hdf5`` file structure]
In my EvE.hdf5 each group is one of BPASS metallicities. If you don’t remember the BPASS metallicities and specifically what strings we like to use to name them, you can use the hoki.constants
module to help you
[1]:
from hoki import constants as hc
[3]:
hc.BPASS_METALLICITIES
[3]:
['zem5',
'zem4',
'z001',
'z002',
'z003',
'z004',
'z006',
'z008',
'z010',
'z014',
'z020',
'z030',
'z040']
[! TIP !]:in ``hoki v1.7.2`` I’ve added extra docs (amongst other things). You can then call ``hc?`` or ``hoki.constants?`` (depending on how you imported the module) and get a list of the constants in that module and a description.
So there are 13 groups in EvE.hdf5 each corresponding to a BPASS metallicity. Then each group contains the same tables (and we will look at those in just a second). Each of these tables is a pandas dataframe contained within a dataset of the hdf5 file. Now for those who work with hdf5 file you would be right to ask why not have sub-groups for each table and then each column in a dataset. And the answer to that is I like working with my pandas dataframes and I didn’t see the point in undoing them and redoing them again. It’s not the most data efficient thing but we’re not dealing with large volumes here.
[The ``hoki.eve.Eve`` class]
In most cases you are only looking through one metallicity at a time. I’ve created a very basic Eve
class in hoki
that reads in each of the table for a given metallicity, mostly to minimise how much copy pasting I had to do. The nifty thing about having this as a stand alone object though is that it gives you a lot of nice flexibility to mess with the data to your hearts content, add your own tables, and then save that object so that your hard work is easy to load later on without having
to retrace your steps. We’ll see a few examples of how I use this and I’ll show you how to pickle and load your Eve objects so that you can share your work with your future self and your colleagues.
[The imports]
Like I said we’re going to use and abuse pandas, we’ll need numpy and matplotlib, the hoki.eve module but also some of the tools in hoki.load
which will come in useful futher into the tutorial. The style sheet is the same as the one in all the other hoki tutorials
[4]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from hoki.load import dummy_manual, dummy_to_dataframe, MODELS_PATH
from hoki.eve import Eve
plt.style.use('tuto.mplstyle')
Let’s instanciate our Eve
object. We’ll need to specific a BPASS metallicity (must be contained in hc.BPASS_METALLICITIES
above), the location of our hdf5 file, and if we want we can give a name to identify which project we are working on. This is an optional parameter (default None).
[5]:
eve = Eve(met='z006', # the metallicity string
eve_path='./EvE.hdf5', # the location of the EvE.hdf5 file you downloaded
name='BLA') # an identifier for your project (optional)
So what tables have we made here? If you want a summary of the SCHEMA you can just summon the object you’ve instanciated
[8]:
eve
[8]:
<class 'hoki.eve.Eve'>
METALICITY: z006
PROJECT NAME: BLA
--------- SCHEMA -------
ID_TABLE
['filenames']
SUMMARY
['M1_ZAMS' 'M2_ZAMS' 'P_ZAMS' 'lifetime_MS' 'MT_bool' 'CEE_bool' 'AGE_end'
'M1_end' 'M2_end' 'P_end' 'modelimf' 'mixedimf' 'type']
CEE
['TIMESTEP_start' 'AGE_start' 'M1_start' 'M2_start' 'P_start' 'LOGA_start'
'TIMESTEP_end' 'AGE_end' 'M1_end' 'M2_end' 'P_end' 'LOGA_end'
'avgDM1R_msolpyr' 'avgDM2R_msolpyr' 'avgDM1W_msolpyr' 'avgDM2W_msolpyr'
'CASE']
MT
['TIMESTEP_start' 'AGE_start' 'M1_start' 'M2_start' 'P_start' 'LOGA_start'
'TIMESTEP_end' 'AGE_end' 'M1_end' 'M2_end' 'P_end' 'LOGA_end'
'avgDM1R_msolpyr' 'avgDM2R_msolpyr' 'avgDM1W_msolpyr' 'avgDM2W_msolpyr'
'CASE']
DEATH
['timestep' 'age' 'log(R1)' 'log(T1)' 'log(L1)' 'M1' 'He_core1' 'CO_core1'
'ONe_core1' 'Nan9' 'X' 'Y' 'C' 'N' 'O' 'Ne' 'MH1' 'MHe1' 'MC1' 'MN1'
'MO1' 'MNe1' 'MMg1' 'MSi1' 'MFe1' 'envelope_binding_E' 'star_binding_E'
'Mrem_weakSN' 'Mej_weakSN' 'Mrem_SN' 'Mej_SN' 'Mrem_superSN'
'Mej_superSN' 'AM_bin' 'P_bin' 'log(a)' 'Nan36' 'M2' 'MTOT' 'DM1W' 'DM2W'
'DM1A' 'DM2A' 'DM1R' 'DM2R' 'DAM' 'log(R2)' 'log(T2)' 'log(L2)' '?'
'modelimf' 'mixedimf' 'V-I' 'U' 'B' 'V' 'R' 'I' 'J']
The tables in EvE and key BPASS definitions¶
ID_TABLE
¶
[14]:
eve.ID_TABLE.tail()
[14]:
filenames | |
---|---|
MODEL_ID | |
160756 | NEWSINMODS/z006/sneplot-z006-1.1 |
160757 | NEWSINMODS/z006/sneplot-z006-1 |
160758 | NEWSINMODS/z006/sneplot-z006-0.9 |
160759 | NEWSINMODS/z006/sneplot-z006-0.8 |
160760 | NEWSINMODS/z006/sneplot-z006-0.6 |
As you can see above this relates the MODEL_ID
and filenames
properties. The filenames
are the paths to a specific stellar system within the BPASS stellar library. These filenames are themselves unique identifiers of the models, but the problem is that if you’re not working in FORTRAN using strings as unique identifiers is VERY TIME CONSUMING, e.g. if you want to check that a list of 300 models is (or is not) comprised in another list of 15,000 models. If all of those are strings
it will take orders of magnitudes longer than if you use integers.
The MODEL_ID
are these integers that are also unique identifiers of each model (unique across all 13 metallicities). In general we use the ``MODEL_ID`` to do model selection within our pandas dataframes (see below), then when we want to open a specific model in the BPASS stellar library we go fetch the file name string to load it in.
[? Q: WHAT MAKES A MODEL UNIQUE ?]Models are calculated on a of Mass of the primary, mass ratio and period (for binaries), and metallicity. Within a given metallicity, each model as a unique combintation of (M1, M2, P) at age=0 (which may be ZAMS or the age at rejuvination).
The SUMMARY
table (and some needed BPASS-hoki concepts)¶
[68]:
eve.SUMMARY.head()
[68]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
139237 | 65.0 | 1.0 | 39090200.0 | 3321112.0 | 0 | 0 | 4002222.0 | 19.94971 | 1.0 | 0.3879680E+09 | 0.077866 | 0.0 | -1 |
139238 | 64.0 | 1.0 | 39389750.0 | 3355019.0 | 0 | 0 | 4033544.0 | 19.77729 | 1.0 | 0.3855040E+09 | 0.080755 | 0.0 | -1 |
139239 | 63.0 | 1.0 | 39696290.0 | 3390314.0 | 0 | 0 | 4065838.0 | 19.62953 | 1.0 | 0.3820573E+09 | 0.083800 | 0.0 | -1 |
139240 | 62.0 | 1.0 | 40010100.0 | 3406536.0 | 0 | 0 | 4099226.0 | 19.50653 | 1.0 | 0.3776276E+09 | 0.087011 | 0.0 | -1 |
139241 | 61.0 | 1.0 | 40331470.0 | 3444347.0 | 0 | 0 | 4133877.0 | 19.39798 | 1.0 | 0.3726069E+09 | 0.090400 | 0.0 | -1 |
This table summarises information from both the stellar library and the population synthesis. EvE.hdf5 was created with the pop. synth from the fiducial models so if you want to use a different IMF you can’t use EvE.hdf5 and have to do things the old fashioned way (which usually means contacting one of the BPASS team members).
In SUMMARY
you will find some basic info about the initial state of the models such as the mass of the primary and secondary at birth, their separation. Note that single stars will have values in the M2_ZAMS and P_ZAMS columns but they are obviously nonesensical placeholders. In a future version I should replace those with np.NaN
, but there is a much simpler way to know whether a model is a single star or a binary.
One of the columns in SUMMARY
is type
. This contains the BPASS type of this specific models, here are the options: * -1: Single star (pure single star from birth) * 0: Merger has occured * 1: Primary model (see below) * 2: Secondary model (see below) * 3: Secondary Single secondary star (after first star has died) * 4: Quasi-homogenous evolution (only for low metallicities - see Eldridge et al. 2017 for details)
[Primary models Vs Secondary models]
In BPASS v2 the models are detailed… but only for one star at a time. The other star is evolved more similarly to what happens in a rapid code (again, check the instrument paper Eldridge et al. 2017). The primary models are those where the primary is evolved in detail, the secondary models are those where the secondary is evolved in detail AFTER THE FIRST STAR HAS DIED. This is convenient for computing time purposes (especially because the models where calcualted a few years back) and also if you’re looking at supernova kicks but that’s a whole other tutorial.
[! CAUTION !]In the stellar evolution library the properties of star 1 are ALWAYS those of the star that is being evolved in detail. That means that in primary models M1 is the mass of the primary, but in the secondary models M1 is actually the mass of the secondary and M2 could be the mass of the Black Hole or Neutron Star left behind after the death of the primary
Other properties in the SUMMARY
table relate to the final propeties of the model (_end
). Those are copy pasted from the last line in the stellar model table. For massive stars it’s indeed when the star dies. For white dwarves it’s at the end of universe according to BPASS or when the model crashes.
[``modelimf`` and ``mixedimf``]
The other crucial properties provided in this table are the pop. synth properties that tell you how many of each system you expect to arise in a 1 Million Msol population at the given metallicity. Without these properties you can find a progenitor but have no idea how likely it is to occur in the Universe.
modelimf
-> how many such models occur (NO REJUVINATION)mixedimf
-> how many such models occur as a result of rejuvination
Note that in the BPASS input files (should you wish to look at them despite the fact they are not human readable) the modelimf
is the TOTAL number (including mixedimf
). This is not something you should ever have to worry about, except maybe if you look into the entrails of hoki
(espcially the CMD class) and see in the comments that the definition is ever so slightly different. I chose to separate the two in the table because of personal preference - in hinsight consistency might
have been preferable but it is what it is.
[Mass transfer and Common Envelope Evolution] If you are specifically looking for systems that underwent mass transfer (MT) or common envelope evolution (CEE) you can check the MT_bool
and CEE_bool
columns. A 0 means ‘no’ whilst a ‘1’ means yes. But yes to what?
MT is programatically defined as the model having a period where there is mass loss through the roche lobe. CEE is defined as our star’s radius exceeded the separation of the the binary. Note that this is the CEE definition within the Cambridge STARS code for the onset of CEE so it is the only “correct” way to define it here even if you don’t agree about the physics of this definition
The CEE
and MT
tables¶
This is a lovely transition to talk about our CEE
and MT
tables which summarise the periods of (stable) mass transfer and common envelope that our models undergo
[18]:
eve.CEE.head()
[18]:
TIMESTEP_start | AGE_start | M1_start | M2_start | P_start | LOGA_start | TIMESTEP_end | AGE_end | M1_end | M2_end | P_end | LOGA_end | avgDM1R_msolpyr | avgDM2R_msolpyr | avgDM1W_msolpyr | avgDM2W_msolpyr | CASE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||||||
139363 | 10 | 32696.60 | 2.95 | 0.0 | 0.0 | -inf | 8350 | 9.742223e+10 | 0.74303 | 0.0 | 0.0 | -inf | 0.0 | 0.0 | 0.0 | 0.0 | A |
139365 | 10 | 35758.61 | 2.85 | 0.0 | 0.0 | -inf | 8260 | 9.746370e+10 | 0.71675 | 0.0 | 0.0 | -inf | 0.0 | 0.0 | 0.0 | 0.0 | A |
139367 | 10 | 39374.49 | 2.75 | 0.0 | 0.0 | -inf | 8190 | 9.751175e+10 | 0.69098 | 0.0 | 0.0 | -inf | 0.0 | 0.0 | 0.0 | 0.0 | A |
139369 | 10 | 43711.77 | 2.65 | 0.0 | 0.0 | -inf | 8130 | 9.756764e+10 | 0.66540 | 0.0 | 0.0 | -inf | 0.0 | 0.0 | 0.0 | 0.0 | A |
139371 | 10 | 48974.07 | 2.55 | 0.0 | 0.0 | -inf | 8090 | 9.763306e+10 | 0.64235 | 0.0 | 0.0 | -inf | 0.0 | 0.0 | 0.0 | 0.0 | A |
[16]:
eve.MT.head()
[16]:
TIMESTEP_start | AGE_start | M1_start | M2_start | P_start | LOGA_start | TIMESTEP_end | AGE_end | M1_end | M2_end | P_end | LOGA_end | avgDM1R_msolpyr | avgDM2R_msolpyr | avgDM1W_msolpyr | avgDM2W_msolpyr | CASE | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||||||
139478 | 600 | 1.640508e+03 | 299.3329 | 30.0 | 0.002748 | 1.463748 | 800 | 23047.62 | 302.26110 | 30.0 | 0.002748 | 1.463748 | -0.085665 | 0.0 | 0.000026 | 0.0 | A |
139478 | 4988 | 2.032127e+06 | 110.2153 | 30.0 | 0.002748 | 1.463748 | 11620 | 2448448.00 | 35.96710 | 30.0 | 0.002748 | 1.463748 | -0.085665 | 0.0 | 0.000026 | 0.0 | B |
139479 | 600 | 1.390236e+03 | 299.2373 | 60.0 | 0.002750 | 1.476344 | 900 | 46368.02 | 311.71300 | 60.0 | 0.002750 | 1.476344 | -0.100002 | 0.0 | 0.000026 | 0.0 | A |
139479 | 5000 | 1.980880e+06 | 113.6463 | 60.0 | 0.002750 | 1.476344 | 12432 | 2435873.00 | 32.84911 | 60.0 | 0.002750 | 1.476344 | -0.100002 | 0.0 | 0.000026 | 0.0 | B |
139480 | 500 | 7.313112e+02 | 298.6578 | 90.0 | 0.002750 | 1.487931 | 900 | 37422.93 | 315.46130 | 90.0 | 0.002750 | 1.487931 | -0.100002 | 0.0 | 0.000026 | 0.0 | A |
As you can see they both contain the same columns, which for the most part have self explenatory names. Note that the Periods are in units of log10(days). Also let’s talk about avgDM1R_msolpyr
and similarly named columns.
DM1R
is one of the columns in the stellar library tables, it is the mass loss through the roche lobe (or rather change in mass of the primary) in solar masses per second (not per 1.989 per second as shown in the BPASS manual). In these table I have taken the average of this mass loss and I report it in Msol per year not per second. This is because I think it’s more important here to be consistent with the units observers (or other astronomers) expect rather than internal consistency.
That being said if you see discrepancies between those average values and the numbers you see in the raw stellar library tables, check if it’s not a conversion from seconds to years.
DM1W
is the mass loss to winds (of the primary).
The other column names with 2 instead of one relate to the secondary.
[! WARNING !]I have tried to report whether the MT and CEE where Case A, B, or C. Similarly to how dificult and fuzzy, it is fuzzy to define these cases. They are there as first order approximations, if you want to do a good job you can check in the stellar evolution files and plot the mass of the cores (see below)
The DEATH
table¶
This is easy: I just copy pasted the last row of each stellar model into this table. It seems useless until you spend ages looking at those last rows searching for explosive transient progenitors. Speaking of which, TIME TO GO LOOK FOR SUPER-LUMINOUS SUPERNOVAE!!!
Use-case: Searching for a super-luminous supernova progenitor¶
We now have everything we need to start looking for matching models. But first let’s define what we will be looking for today.
[Criteria to be matched]
Let’s look for the progenitor of a SLSN-I, meanign no Hydrogen in its envelope and “no” helium. We also have some information about its ejecta mass, and we can use other peoples models to estimate how much hydrogen can be “hidden” in our stellar envelope.
Massive star that can explode as a SN (we typically use CO core>1.38 Msol)
M ejecta >7 & <15
No hydrogen at death (using the stuff in https://arxiv.org/abs/1205.5349)
as little as 0.001 M of hydrogen with surface mass fraction as low
as 0.01 can produce a strong Hα line
In order to check all these conditions we need to look through the eve.DEATH
table we mentioned above:
[25]:
eve.DEATH.head()
[25]:
timestep | age | log(R1) | log(T1) | log(L1) | M1 | He_core1 | CO_core1 | ONe_core1 | Nan9 | ... | ? | modelimf | mixedimf | V-I | U | B | V | R | I | J | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||||||||||
139237 | 7597.0 | 4002222.0 | -0.00374 | 5.23904 | 5.90192 | 19.94971 | 0.0 | 19.57384 | 2.19591 | 0.0 | ... | -0.40303 | 0.077866 | 0.0 | -0.804765 | -6.144496 | -5.124525 | -5.605848 | -5.492907 | -4.801082 | -4.960115 |
139238 | 7589.0 | 4033544.0 | -0.01400 | 5.24344 | 5.89899 | 19.77729 | 0.0 | 19.44443 | 2.21896 | 0.0 | ... | -0.40273 | 0.080755 | 0.0 | -0.801254 | -6.138891 | -5.120062 | -5.600776 | -5.488411 | -4.799521 | -4.957952 |
139239 | 7024.0 | 4065838.0 | -0.24850 | 5.36890 | 5.93182 | 19.62953 | 0.0 | 17.23459 | 0.00024 | 0.0 | ... | -0.40231 | 0.083800 | 0.0 | -0.275980 | -6.840992 | -5.846130 | -5.742734 | -5.720248 | -5.466754 | -5.671823 |
139240 | 7034.0 | 4099226.0 | -0.25057 | 5.36898 | 5.92804 | 19.50653 | 0.0 | 17.43372 | 0.00029 | 0.0 | ... | -0.40176 | 0.087011 | 0.0 | -0.276187 | -6.831222 | -5.836364 | -5.733389 | -5.710909 | -5.457203 | -5.662486 |
139241 | 7029.0 | 4133877.0 | -0.25589 | 5.37104 | 5.92561 | 19.39798 | 0.0 | 17.04446 | 0.00032 | 0.0 | ... | -0.40114 | 0.090400 | 0.0 | -0.276718 | -6.824322 | -5.829474 | -5.727585 | -5.705117 | -5.450867 | -5.656701 |
5 rows × 59 columns
As you can see there are a lot of columns, which correspond to those we can find in each stellar evolution model table in BPASSv2.2.1. You can check the BPASS manual to see a list, or you can use the dummy_manual
dictionary, which pairs the column names (keys) as they are in the pandas dataframe with the definitions (values).
[5]:
dummy_manual
[5]:
{'timestep': 'Time Step Number',
'age': 'Age in years',
'log(R1)': 'Log10(R/Rsun) of the primary',
'log(T1)': 'Effective log10 temperature of the primary',
'log(L1)': 'Log10(L/Lsun) of the primary',
'M1': 'M/Msun of the primary',
'He_core1': 'He core mass of the primary /Msun',
'CO_core1': 'CO core mass of the primary /Msun',
'ONe_core1': 'ONe core mass of the primary /Msun',
'X': 'Surface mass fractions for X (hydrogen)',
'Y': 'Surface mass fractions for Y (helium)',
'C': 'Surface mass fractions for C (carbon)',
'N': 'Surface mass fractions for N (nitrogem)',
'O': 'Surface mass fractions for O (oxygen)',
'Ne': 'Surface mass fractions for Ne (neon)',
'MH1': 'Mass of Hydrogen in primary /Msun',
'MHe1': 'Mass of Helium in primary /Msun',
'MC1': 'Mass of Carbon in primary /Msun',
'MN1': 'Mass of Nitrogen in primary /Msun',
'MO1': 'Mass of Oxygen in primary /Msun',
'MNe1': 'Mass of Neon in primary /Msun',
'MMg1': 'Mass of Hydrogen in primary /Msun',
'MSi1': 'Mass of Silicon in primary /Msun',
'MFe1': 'Mass of Iron in primary /Msun',
'envelope_binding_E': 'Binding Energy of the envelope in Joules',
'star_binding_E': 'Total star binding energy in Joules',
'Mrem_weakSN': 'Remnant Mass /Msun for a weakSN (1e43 J)',
'Mej_weakSN': 'Ejecta Mass /Msun for a weakSN (1e43 J)',
'Mrem_SN': 'Remnant Mass /Msun for a normal SN (1e44 J)',
'Mej_SN': 'Ejecta Mass /Msun for a normal SN (1e44 J)',
'Mrem_superSN': 'Remnant Mass /Msun for a high energy SN (1e45 J)',
'Mej_superSN': 'Ejecta Mass /Msun for a high energy SN (1e45 J)',
'AM_bin': 'Angular momentum of the binary',
'P_bin': 'Period of the binary in years',
'log(a)': 'Log10 of the binary separation/Rsun ',
'M2': 'Mass of the secondary /Msun',
'MTOT': 'Total Mass of the binary /Msun',
'DM1W': 'Wind mass loss rate of the primary (Msun/(1.989*s))',
'DM2W': 'Wind mass loss rate of the secondary (Msun/(1.989*s))',
'DM1A': 'Accretion onto primary (Msun/(1.989*s))',
'DM2A': 'Accretion onto secondary (Msun/(1.989*s))',
'DM1R': 'Roche Lobe overflow of the primary (Msun/(1.989*s))',
'DM2R': 'Roche Lobe overflow of the secondary (Msun/(1.989*s))',
'DAM': 'Angular momentum change',
'log(R2)': 'Log10 of estimated radius of the secondary /Rsun',
'log(T2)': 'Log10 of estimated effective Temperature of the secondary',
'log(L2)': 'Log10 of estimated Luminosity of the secondary /Lsun',
'?': 'Roche Lobe overflux of star 2',
'modelimf': 'Total IMF probability of stars',
'mixedimf': 'IMF probability of rejuvinated stars',
'V-I': 'V-I (absolute mag both stars)',
'U': 'U (absolute mag both stars)',
'B': 'B (absolute mag both stars)',
'V': 'V (absolute mag both stars)',
'R': 'R (absolute mag both stars)',
'I': 'I (absolute mag both stars)',
'J': 'J (absolute mag both stars)',
'H': 'H (absolute mag both stars)',
'K': 'K (absolute mag both stars)',
'u': 'u (absolute mag both stars)',
'g': 'g (absolute mag both stars)',
'r': 'r (absolute mag both stars)',
'i': 'i (absolute mag both stars)',
'z': 'z (absolute mag both stars)',
'f300w': ' f300w (absolute mag both stars)',
'f336w': 'f336w (absolute mag both stars)',
'f435w': 'f435w (absolute mag both stars)',
'f450w': 'f450w (absolute mag both stars)',
'f555w': 'f555w (absolute mag both stars)',
'f606w': 'f606w (absolute mag both stars)',
'f814w': 'f814w (absolute mag both stars)',
'U2': 'U (absolute mag secondary star)',
'B2': 'B (absolute mag secondary star)',
'V2': 'V (absolute mag secondary star)',
'R2': 'R (absolute mag secondary star)',
'I2': 'I (absolute mag secondary star)',
'J2': 'J (absolute mag secondary star)',
'H2': 'H (absolute mag secondary star)',
'K2': 'K (absolute mag secondary star)',
'u2': 'u (absolute mag secondary star)',
'g2': 'g (absolute mag secondary star)',
'r2': 'r (absolute mag secondary star)',
'i2': 'i (absolute mag secondary star)',
'z2': 'z (absolute mag secondary star)',
'f300w2': 'f300w (absolute mag secondary star)',
'f336w2': 'f336w (absolute mag secondary star)',
'f435w2': 'f435w (absolute mag secondary star)',
'f450w2': 'f450w (absolute mag secondary star)',
'f555w2': 'f555w (absolute mag secondary star)',
'f606w2': 'f606w (absolute mag secondary star)',
'f814w2': 'f814w (absolute mag secondary star)',
'Halpha': 'H alpha flux (log L erg/s)',
'FUV': 'UV flux (log L erg/s/A)',
'NUV': 'Near UV flux (log L erg/s/A)'}
[Why “dummy”?]
In the STARS code J.J. Eldridge wrote to output the data of the stellar library, the large array that contains the output is a variable called dummy
, and it is this array that is contained in each stellar model text file. This place-holder name has been in the code for nearly 2 decades and for consistency is used in other bits of code like TUI
and now hoki
. Evertime you see dummy
, there is a relation to the sneplot
files (i.e. the model files in the stellar library).
Selecting our desired models¶
Each model has a unique ID MODEL_ID
- it is unique across all 13 metallicities so it won’t start at 0 (unless you’re looking at the lowest metallicity: 10e-5).
Although you can just crop tables entierly I find the best approach is to store the sets of models IDs that correspond to specific properties of your search and then combine them and mask the full EvE tables. Let’s see how this works below
Finding CCSNe and Ibc (general)¶
We could start with the conditions stated above regarding the presence of hydrogen/helium and ejecta masses. That would be a faster way to crop down our sets of MODEL_ID
but I want to do it in an order that will be more natural if you go looking for other types of transients.
So first let’s find the IDs of all the stars that will explode as CCSNe. We want massive stars (to be conservative we select everything above 7 Msol) and we want them to go through iron core collapse so we need the CO core to be >1.38 Msol at death and the ONe core >0.1 Msol at death.
[32]:
# models of massive stars (loose definition)
id_massive = set(eve.SUMMARY[eve.SUMMARY.M1_ZAMS>7].index)
[Code break down] If you are not super familiar with pandas shenanigans here is a break down of the code above:
[33]:
eve.SUMMARY.M1_ZAMS>7 # creates a **mask** (a series of booleans (False, True))
[33]:
MODEL_ID
139237 True
139238 True
139239 True
139240 True
139241 True
...
160756 False
160757 False
160758 False
160759 False
160760 False
Name: M1_ZAMS, Length: 21117, dtype: bool
[34]:
eve.SUMMARY[eve.SUMMARY.M1_ZAMS>7] # selects all the rows of the SUMMARY tables where the mask says 'True'
[34]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
139237 | 65.0 | 1.0 | 39090200.0 | 3321112.0 | 0 | 0 | 4002222.0 | 19.94971 | 1.0 | 0.3879680E+09 | 0.077866 | 0.00000 | -1 |
139238 | 64.0 | 1.0 | 39389750.0 | 3355019.0 | 0 | 0 | 4033544.0 | 19.77729 | 1.0 | 0.3855040E+09 | 0.080755 | 0.00000 | -1 |
139239 | 63.0 | 1.0 | 39696290.0 | 3390314.0 | 0 | 0 | 4065838.0 | 19.62953 | 1.0 | 0.3820573E+09 | 0.083800 | 0.00000 | -1 |
139240 | 62.0 | 1.0 | 40010100.0 | 3406536.0 | 0 | 0 | 4099226.0 | 19.50653 | 1.0 | 0.3776276E+09 | 0.087011 | 0.00000 | -1 |
139241 | 61.0 | 1.0 | 40331470.0 | 3444347.0 | 0 | 0 | 4133877.0 | 19.39798 | 1.0 | 0.3726069E+09 | 0.090400 | 0.00000 | -1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
160727 | 9.5 | 1.0 | 98004320.0 | 24806290.0 | 0 | 0 | 29348150.0 | 9.15623 | 1.0 | 0.1047507E+09 | 41.799300 | 26.05064 | 3 |
160728 | 9.0 | 1.0 | 100424500.0 | 27140890.0 | 0 | 0 | 32336710.0 | 8.69743 | 1.0 | 0.1067887E+09 | 98.579450 | 19.05651 | 3 |
160729 | 8.5 | 1.0 | 103033400.0 | 30199880.0 | 0 | 0 | 35923690.0 | 8.24057 | 1.0 | 0.1088996E+09 | 56.428160 | 31.57097 | 3 |
160730 | 8.0 | 1.0 | 105856800.0 | 33624640.0 | 0 | 0 | 40273060.0 | 7.78239 | 1.0 | 0.1111671E+09 | 103.634900 | 16.64214 | 3 |
160731 | 7.5 | 1.0 | 108925700.0 | 38185990.0 | 0 | 0 | 45620450.0 | 7.32357 | 1.0 | 0.1135919E+09 | 96.289360 | 28.48787 | 3 |
11219 rows × 13 columns
[36]:
eve.SUMMARY[eve.SUMMARY.M1_ZAMS>7].index # returns the index of the selected rows
[36]:
Int64Index([139237, 139238, 139239, 139240, 139241, 139242, 139243, 139244,
139245, 139246,
...
160722, 160723, 160724, 160725, 160726, 160727, 160728, 160729,
160730, 160731],
dtype='int64', name='MODEL_ID', length=11219)
[37]:
set(eve.SUMMARY[eve.SUMMARY.M1_ZAMS>7].index) # returns a set
[37]:
{139237,
139238,
139239,
139240,
139241,
139242,
139243,
139244,
139245,
139246,
139247,
139248,
139249,
139250,
139251,
139252,
139253,
139254,
139255,
139256,
139257,
139258,
139259,
139260,
139261,
139262,
139263,
139264,
139265,
139266,
139267,
139268,
139269,
139270,
139271,
139272,
139273,
139274,
139275,
139276,
139277,
139278,
139279,
139280,
139281,
139282,
139283,
139284,
139285,
139286,
139287,
139288,
139289,
139290,
139291,
139292,
139293,
139294,
139295,
139296,
139297,
139298,
139299,
139300,
139301,
139302,
139303,
139304,
139305,
139306,
139307,
139308,
139309,
139310,
139311,
139312,
139313,
139314,
139315,
139316,
139317,
139318,
139319,
139320,
139321,
139478,
139479,
139480,
139481,
139482,
139483,
139484,
139485,
139486,
139487,
139488,
139489,
139490,
139491,
139492,
139493,
139494,
139495,
139496,
139497,
139498,
139499,
139500,
139501,
139502,
139503,
139504,
139505,
139506,
139507,
139508,
139509,
139510,
139511,
139512,
139513,
139514,
139515,
139516,
139517,
139518,
139519,
139520,
139521,
139522,
139523,
139524,
139525,
139526,
139527,
139528,
139529,
139530,
139531,
139532,
139533,
139534,
139535,
139536,
139537,
139538,
139539,
139540,
139541,
139542,
139543,
139544,
139545,
139546,
139547,
139548,
139549,
139550,
139551,
139552,
139553,
139554,
139555,
139556,
139557,
139558,
139559,
139560,
139561,
139562,
139563,
139564,
139565,
139566,
139567,
139568,
139569,
139570,
139571,
139572,
139573,
139574,
139575,
139576,
139577,
139578,
139579,
139580,
139581,
139582,
139583,
139584,
139585,
139586,
139587,
139588,
139589,
139590,
139591,
139592,
139593,
139594,
139595,
139596,
139597,
139598,
139599,
139600,
139601,
139602,
139603,
139604,
139605,
139606,
139607,
139608,
139609,
139610,
139611,
139612,
139613,
139614,
139615,
139616,
139617,
139618,
139619,
139620,
139621,
139622,
139623,
139624,
139625,
139626,
139627,
139628,
139629,
139630,
139631,
139632,
139633,
139634,
139635,
139636,
139637,
139638,
139639,
139640,
139641,
139642,
139643,
139644,
139645,
139646,
139647,
139648,
139649,
139650,
139651,
139652,
139653,
139654,
139655,
139656,
139657,
139658,
139659,
139660,
139661,
139662,
139663,
139664,
139665,
139666,
139667,
139668,
139669,
139670,
139671,
139672,
139673,
139674,
139675,
139676,
139677,
139678,
139679,
139680,
139681,
139682,
139683,
139684,
139685,
139686,
139687,
139688,
139689,
139690,
139691,
139692,
139693,
139694,
139695,
139696,
139697,
139698,
139699,
139700,
139701,
139702,
139703,
139704,
139705,
139706,
139707,
139708,
139709,
139710,
139711,
139712,
139713,
139714,
139715,
139716,
139717,
139718,
139719,
139720,
139721,
139722,
139723,
139724,
139725,
139726,
139727,
139728,
139729,
139730,
139731,
139732,
139733,
139734,
139735,
139736,
139737,
139738,
139739,
139740,
139741,
139742,
139743,
139744,
139745,
139746,
139747,
139748,
139749,
139750,
139751,
139752,
139753,
139754,
139755,
139756,
139757,
139758,
139759,
139760,
139761,
139762,
139763,
139764,
139765,
139766,
139767,
139768,
139769,
139770,
139771,
139772,
139773,
139774,
139775,
139776,
139777,
139778,
139779,
139780,
139781,
139782,
139783,
139784,
139785,
139786,
139787,
139788,
139789,
139790,
139791,
139792,
139793,
139794,
139795,
139796,
139797,
139798,
139799,
139800,
139801,
139802,
139803,
139804,
139805,
139806,
139807,
139808,
139809,
139810,
139811,
139812,
139813,
139814,
139815,
139816,
139817,
139818,
139819,
139820,
139821,
139822,
139823,
139824,
139825,
139826,
139827,
139828,
139829,
139830,
139831,
139832,
139833,
139834,
139835,
139836,
139837,
139838,
139839,
139840,
139841,
139842,
139843,
139844,
139845,
139846,
139847,
139848,
139849,
139850,
139851,
139852,
139853,
139854,
139855,
139856,
139857,
139858,
139859,
139860,
139861,
139862,
139863,
139864,
139865,
139866,
139867,
139868,
139869,
139870,
139871,
139872,
139873,
139874,
139875,
139876,
139877,
139878,
139879,
139880,
139881,
139882,
139883,
139884,
139885,
139886,
139887,
139888,
139889,
139890,
139891,
139892,
139893,
139894,
139895,
139896,
139897,
139898,
139899,
139900,
139901,
139902,
139903,
139904,
139905,
139906,
139907,
139908,
139909,
139910,
139911,
139912,
139913,
139914,
139915,
139916,
139917,
139918,
139919,
139920,
139921,
139922,
139923,
139924,
139925,
139926,
139927,
139928,
139929,
139930,
139931,
139932,
139933,
139934,
139935,
139936,
139937,
139938,
139939,
139940,
139941,
139942,
139943,
139944,
139945,
139946,
139947,
139948,
139949,
139950,
139951,
139952,
139953,
139954,
139955,
139956,
139957,
139958,
139959,
139960,
139961,
139962,
139963,
139964,
139965,
139966,
139967,
139968,
139969,
139970,
139971,
139972,
139973,
139974,
139975,
139976,
139977,
139978,
139979,
139980,
139981,
139982,
139983,
139984,
139985,
139986,
139987,
139988,
139989,
139990,
139991,
139992,
139993,
139994,
139995,
139996,
139997,
139998,
139999,
140000,
140001,
140002,
140003,
140004,
140005,
140006,
140007,
140008,
140009,
140010,
140011,
140012,
140013,
140014,
140015,
140016,
140017,
140018,
140019,
140020,
140021,
140022,
140023,
140024,
140025,
140026,
140027,
140028,
140029,
140030,
140031,
140032,
140033,
140034,
140035,
140036,
140037,
140038,
140039,
140040,
140041,
140042,
140043,
140044,
140045,
140046,
140047,
140048,
140049,
140050,
140051,
140052,
140053,
140054,
140055,
140056,
140057,
140058,
140059,
140060,
140061,
140062,
140063,
140064,
140065,
140066,
140067,
140068,
140069,
140070,
140071,
140072,
140073,
140074,
140075,
140076,
140077,
140078,
140079,
140080,
140081,
140082,
140083,
140084,
140085,
140086,
140087,
140088,
140089,
140090,
140091,
140092,
140093,
140094,
140095,
140096,
140097,
140098,
140099,
140100,
140101,
140102,
140103,
140104,
140105,
140106,
140107,
140108,
140109,
140110,
140111,
140112,
140113,
140114,
140115,
140116,
140117,
140118,
140119,
140120,
140121,
140122,
140123,
140124,
140125,
140126,
140127,
140128,
140129,
140130,
140131,
140132,
140133,
140134,
140135,
140136,
140137,
140138,
140139,
140140,
140141,
140142,
140143,
140144,
140145,
140146,
140147,
140148,
140149,
140150,
140151,
140152,
140153,
140154,
140155,
140156,
140157,
140158,
140159,
140160,
140161,
140162,
140163,
140164,
140165,
140166,
140167,
140168,
140169,
140170,
140171,
140172,
140173,
140174,
140175,
140176,
140177,
140178,
140179,
140180,
140181,
140182,
140183,
140184,
140185,
140186,
140187,
140188,
140189,
140190,
140191,
140192,
140193,
140194,
140195,
140196,
140197,
140198,
140199,
140200,
140201,
140202,
140203,
140204,
140205,
140206,
140207,
140208,
140209,
140210,
140211,
140212,
140213,
140214,
140215,
140216,
140217,
140218,
140219,
140220,
140221,
140222,
140223,
140224,
140225,
140226,
140227,
140228,
140229,
140230,
140231,
140232,
140233,
140234,
140235,
140236,
140237,
140238,
140239,
140240,
140241,
140242,
140243,
140244,
140245,
140246,
140247,
140248,
140249,
140250,
140251,
140252,
140253,
140254,
140255,
140256,
140257,
140258,
140259,
140260,
140261,
140262,
140263,
140264,
140265,
140266,
140267,
140268,
140269,
140270,
140271,
140272,
140273,
140274,
140275,
140276,
140277,
140278,
140279,
140280,
140281,
140282,
140283,
140284,
140285,
140286,
140287,
140288,
140289,
140290,
140291,
140292,
140293,
140294,
140295,
140296,
140297,
140298,
140299,
140300,
140301,
140302,
140303,
140304,
140305,
140306,
140307,
140308,
140309,
140310,
140311,
140312,
140313,
140314,
140315,
140316,
140317,
140318,
140319,
140320,
140321,
140322,
140323,
140324,
140325,
140326,
140327,
140328,
140329,
140330,
140331,
140332,
140333,
140334,
140335,
140336,
140337,
140338,
140339,
140340,
140341,
140342,
140343,
140344,
140345,
140346,
140347,
140348,
140349,
140350,
140351,
140352,
140353,
140354,
140355,
140356,
140357,
140358,
140359,
140360,
140361,
140362,
140363,
140364,
140365,
140366,
140367,
140368,
140369,
140370,
140371,
140372,
140373,
140374,
140375,
140376,
140377,
140378,
140379,
140380,
140381,
140382,
140383,
140384,
140385,
140386,
140387,
140388,
140389,
140390,
140391,
140392,
...}
SUMMARY table (only massive stars)
if we now want to use our set to view a cropped version of the table we can do:
[38]:
eve.SUMMARY.loc[id_massive]
[38]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
139237 | 65.0 | 1.0 | 39090200.0 | 3321112.0 | 0 | 0 | 4002222.0 | 19.94971 | 1.0 | 0.3879680E+09 | 0.077866 | 0.00000 | -1 |
139238 | 64.0 | 1.0 | 39389750.0 | 3355019.0 | 0 | 0 | 4033544.0 | 19.77729 | 1.0 | 0.3855040E+09 | 0.080755 | 0.00000 | -1 |
139239 | 63.0 | 1.0 | 39696290.0 | 3390314.0 | 0 | 0 | 4065838.0 | 19.62953 | 1.0 | 0.3820573E+09 | 0.083800 | 0.00000 | -1 |
139240 | 62.0 | 1.0 | 40010100.0 | 3406536.0 | 0 | 0 | 4099226.0 | 19.50653 | 1.0 | 0.3776276E+09 | 0.087011 | 0.00000 | -1 |
139241 | 61.0 | 1.0 | 40331470.0 | 3444347.0 | 0 | 0 | 4133877.0 | 19.39798 | 1.0 | 0.3726069E+09 | 0.090400 | 0.00000 | -1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
160727 | 9.5 | 1.0 | 98004320.0 | 24806290.0 | 0 | 0 | 29348150.0 | 9.15623 | 1.0 | 0.1047507E+09 | 41.799300 | 26.05064 | 3 |
160728 | 9.0 | 1.0 | 100424500.0 | 27140890.0 | 0 | 0 | 32336710.0 | 8.69743 | 1.0 | 0.1067887E+09 | 98.579450 | 19.05651 | 3 |
160729 | 8.5 | 1.0 | 103033400.0 | 30199880.0 | 0 | 0 | 35923690.0 | 8.24057 | 1.0 | 0.1088996E+09 | 56.428160 | 31.57097 | 3 |
160730 | 8.0 | 1.0 | 105856800.0 | 33624640.0 | 0 | 0 | 40273060.0 | 7.78239 | 1.0 | 0.1111671E+09 | 103.634900 | 16.64214 | 3 |
160731 | 7.5 | 1.0 | 108925700.0 | 38185990.0 | 0 | 0 | 45620450.0 | 7.32357 | 1.0 | 0.1135919E+09 | 96.289360 | 28.48787 | 3 |
11219 rows × 13 columns
Let’s create a set of IDs for the models that do meet the explosion criteria at death.
[39]:
# models that can explode
id_does_explode = set(eve.DEATH[(eve.DEATH.CO_core1>1.38) & (eve.DEATH.ONe_core1>0.1)].index)
The advantage of using sets is they have useful LOGIC such as intersections, so we can easily select the IDs that belong to several sets without having to use tedious loops!
[41]:
eve.SUMMARY.loc[id_massive.intersection(id_does_explode)]
[41]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
139237 | 65.0 | 1.0 | 39090200.0 | 3321112.0 | 0 | 0 | 4002222.0 | 19.94971 | 1.0 | 0.3879680E+09 | 0.077866 | 0.00000 | -1 |
139238 | 64.0 | 1.0 | 39389750.0 | 3355019.0 | 0 | 0 | 4033544.0 | 19.77729 | 1.0 | 0.3855040E+09 | 0.080755 | 0.00000 | -1 |
139242 | 60.0 | 1.0 | 40660710.0 | 3483503.0 | 0 | 0 | 4169864.0 | 19.30547 | 1.0 | 0.3669499E+09 | 0.093981 | 0.00000 | -1 |
139244 | 58.0 | 1.0 | 41344130.0 | 3545710.0 | 0 | 0 | 4246452.0 | 19.13785 | 1.0 | 0.3548877E+09 | 0.101774 | 0.00000 | -1 |
139245 | 57.0 | 1.0 | 41699020.0 | 3567365.0 | 0 | 0 | 4287724.0 | 19.03751 | 1.0 | 0.3493766E+09 | 0.106020 | 0.00000 | -1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
160727 | 9.5 | 1.0 | 98004320.0 | 24806290.0 | 0 | 0 | 29348150.0 | 9.15623 | 1.0 | 0.1047507E+09 | 41.799300 | 26.05064 | 3 |
160728 | 9.0 | 1.0 | 100424500.0 | 27140890.0 | 0 | 0 | 32336710.0 | 8.69743 | 1.0 | 0.1067887E+09 | 98.579450 | 19.05651 | 3 |
160729 | 8.5 | 1.0 | 103033400.0 | 30199880.0 | 0 | 0 | 35923690.0 | 8.24057 | 1.0 | 0.1088996E+09 | 56.428160 | 31.57097 | 3 |
160730 | 8.0 | 1.0 | 105856800.0 | 33624640.0 | 0 | 0 | 40273060.0 | 7.78239 | 1.0 | 0.1111671E+09 | 103.634900 | 16.64214 | 3 |
160731 | 7.5 | 1.0 | 108925700.0 | 38185990.0 | 0 | 0 | 45620450.0 | 7.32357 | 1.0 | 0.1135919E+09 | 96.289360 | 28.48787 | 3 |
7829 rows × 13 columns
Now let’s create more sets for our other conditions to find the Ib/c CCSNe and exclude the type II
[42]:
# models that are hydrogen poor at death
# here I create the mask separately to make the code easier to read and the line not too long
mask_hpoor = (eve.DEATH.X<0.01) & (eve.DEATH.MH1<0.001)
id_hpoor_at_death = set(eve.DEATH[mask_hpoor].index)
[43]:
eve.SUMMARY.loc[id_massive.intersection(id_does_explode).intersection(id_hpoor_at_death)]
[43]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
139264 | 38.0 | 1.00000 | 5.085194e+07 | 4740355.0 | 0 | 0 | 5654447.0 | 15.43550 | 1.000000 | 0.2863389E+09 | 1.059677 | 0.0 | -1 |
139269 | 33.0 | 3.30000 | 5.270922e+07 | 5356467.0 | 0 | 0 | 6374174.0 | 13.65394 | 3.300000 | 0.2416464E+09 | 1.721225 | 0.0 | -1 |
155699 | 15.0 | 1.99526 | 6.889769e-03 | 11693350.0 | 1 | 1 | 15929940.0 | 2.71254 | 3.674444 | 0.1258471E-02 | 0.012344 | 0.0 | 2 |
155720 | 13.0 | 1.99526 | 6.889769e-03 | 14289210.0 | 1 | 1 | 18806370.0 | 2.55130 | 3.459257 | 0.1370293E-02 | 0.015927 | 0.0 | 2 |
155764 | 10.0 | 1.99526 | 6.889769e-03 | 21717750.0 | 1 | 1 | 27907000.0 | 1.78449 | 2.580905 | 0.2114332E-02 | 0.006067 | 0.0 | 2 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
139259 | 43.0 | 1.00000 | 4.787552e+07 | 4314786.0 | 0 | 0 | 5151928.0 | 16.19231 | 1.000000 | 0.3135863E+09 | 0.792527 | 0.0 | -1 |
139260 | 42.0 | 1.00000 | 4.842901e+07 | 4396715.0 | 0 | 0 | 5241441.0 | 16.02714 | 1.000000 | 0.3088634E+09 | 0.837586 | 0.0 | -1 |
139261 | 41.0 | 1.00000 | 4.900216e+07 | 4483490.0 | 0 | 0 | 5335894.0 | 15.88997 | 1.000000 | 0.3030149E+09 | 0.886386 | 0.0 | -1 |
139262 | 40.0 | 1.00000 | 4.959615e+07 | 4575031.0 | 0 | 0 | 5435929.0 | 15.74946 | 1.000000 | 0.2971817E+09 | 0.939343 | 0.0 | -1 |
139263 | 39.0 | 1.00000 | 5.021227e+07 | 4672647.0 | 0 | 0 | 5541933.0 | 15.59117 | 1.000000 | 0.2918669E+09 | 0.996926 | 0.0 | -1 |
2677 rows × 13 columns
Matching ejecta mass and remnant mass¶
Here we want a neutron star so we will pick an remnant mass <3 Msol (take your pick). We also said earlier we want ejecta masses between 7 and 15 Msol.
One thing we need to keep in mind is that BPASS models give you remnant masses and ejecta masses for 3 SN energies: * 10e50 ergs (weakSN -> typically electron capture but can use it for partially failed SN) * 10e51 ergs (you’re average SN) * 10e52 ergs (superSN -> useful for superluminous SNe like we have here).
We’ll also use a low Helium mass criteria at the end of the life of the star since we’re looking for a SLSN-Ic: See Hachinger et al. 2012
[44]:
# If you have several conditions to write into your masks
# not that you can go to the next line so the conditions sit on top of each other
# this makes the code easier to read.
id_ns_matchmej = (eve.DEATH[ (eve.DEATH.Mej_superSN>8)
& (eve.DEATH.Mej_superSN<13)
& (eve.DEATH.Mrem_superSN<3) # it's a neutron star
& (eve.DEATH.MHe1<0.3) # not much helium left
].index)
Specific Angular momentum (gotta go fast to make a pulsar!)¶
Since we said we wanted a Superluminous supernova, we have a good idea that the compact remnant needs to be fast rotating. We can do a back of the envelope calculation to estimate the specific angular momentum j of our remnant and then select only the models that reach a certain (fist spinning) value.
[45]:
# first we need the radius of our stars in kilometers
Rsun=696340 # radius of the sun in km
eve.DEATH['R1km']=(10**eve.DEATH['log(R1)'])*Rsun # in km
Note that here we are adding columns to our tables (in the above case DEATH
) - WE ARE NOT ADDING COLUMNS TO THE EVE.HDF5 DATABASE only to the copy of the data that is contained in our eve
object. Furthermore if you had another instance, say eve2
that was created with the same data, these new columns would not appear in eve2
, they are specific to this one object we are working with. This is very practical because you can mess with the data as much as you want, add, remove,
change columns, to suit your science case. You can then (as we’ll see later) save this work by pickling this hoki.eve.Eve
instance. All of this without messing with the original data, or with other hoki.eve.Eve
instances you might be running in the same notbok looking for some other object.
Anyway, let’s look at the periods… There is an issue with some of the period columns in that they are not numeric because some values of infinity has made their way in and had been recognised by pandas as strings, making the columns a mix of types (i.e. an object). I only noticed that after I’d compiled the .hdf5 file and left it - in future versions I can clean up the type issue. For now we need to use pands.to_numeric
[46]:
eve.DEATH.P_bin=pd.to_numeric(eve.DEATH.P_bin, errors='coerce')
Assuming that the rotational velocity of the star is synched with the period (which is okay if they’ve interacted), then we can calculate the rotational velocity in km/s
[47]:
eve.DEATH['vrot_kms']=(2*np.pi*eve.DEATH.R1km.values)/(eve.DEATH.P_bin.values*365*24*3600)
<ipython-input-47-5a731fa27368>:1: RuntimeWarning: divide by zero encountered in true_divide
eve.DEATH['vrot_kms']=(2*np.pi*eve.DEATH.R1km.values)/(eve.DEATH.P_bin.values*365*24*3600)
[49]:
eve.DEATH.vrot_kms
[49]:
MODEL_ID
139237 3.545347e-10
139238 3.484703e-10
139239 2.049114e-10
139240 2.063293e-10
139241 2.065636e-10
...
160756 inf
160757 inf
160758 inf
160759 inf
160760 inf
Name: vrot_kms, Length: 21117, dtype: float64
[51]:
# and we turn the rotational velocity into a specific AM
eve.DEATH['j_cm2s']=eve.DEATH['vrot_kms']*eve.DEATH.R1km * 1e10 #conversion to cm^2
[55]:
# we also create and ID set that is the intersection of the sets we created above
# that is to make the code easier to read and shorter
id_best_sofar = id_massive.intersection(id_does_explode).intersection(id_hpoor_at_death).intersection(id_ns_matchmej)
[54]:
eve.DEATH.loc[id_best_sofar].j_cm2s
[54]:
MODEL_ID
159747 1.967440e+16
159748 1.419265e+16
159750 1.438781e+16
159751 9.292407e+15
159752 6.008772e+15
...
158713 2.681758e+16
158714 1.591317e+16
158715 9.968024e+15
158716 6.323594e+15
158717 4.702891e+15
Name: j_cm2s, Length: 116, dtype: float64
Now we are going to use the properties of our imagined SLSN-I (it’s actually using the values of SN 2017gci) to estimate a value of j that our remnants need to reach:
[56]:
P=2.8*1e-3 #2.8ms
R=10*1e3*1e2 #10km is a good approx, in cm though
[62]:
j_17gci = (2/5) * (R**2) * 2*np.pi/P
j_17gci/1e14
[62]:
8.975979010256552
so something around 1e15 and above, that’s nice since (from the print out above) a lot of our models already have exceeding values and we’re in the same ballpark in terms of orders of magnitude. once again we create a set of MODEL_ID
[64]:
id_enough_rotation = set(eve.DEATH[eve.DEATH.j_cm2s>j_17gci].index)
[65]:
id_best = id_best_sofar.intersection(id_enough_rotation)
[66]:
eve.DEATH.loc[id_best]
[66]:
timestep | age | log(R1) | log(T1) | log(L1) | M1 | He_core1 | CO_core1 | ONe_core1 | Nan9 | ... | V-I | U | B | V | R | I | J | R1km | vrot_kms | j_cm2s | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||||||||||
159747 | 10928.0 | 5618206.0 | -0.22646 | 5.25413 | 5.51683 | 10.53407 | 0.0 | 10.20924 | 1.47597 | 0.0 | ... | -0.426910 | -5.593392 | -4.584808 | -4.654883 | -4.602030 | -4.227973 | -4.405664 | 413391.310173 | 4.759268 | 1.967440e+16 |
159748 | 10787.0 | 5488492.0 | -0.21599 | 5.25719 | 5.55003 | 11.03129 | 0.0 | 10.73932 | 1.44532 | 0.0 | ... | -0.610628 | -5.452509 | -4.432625 | -4.714235 | -4.630044 | -4.103607 | -4.261867 | 423478.477630 | 3.351446 | 1.419265e+16 |
159750 | 10916.0 | 5429943.0 | -0.21712 | 5.26568 | 5.58173 | 11.71055 | 0.0 | 11.47110 | 1.63243 | 0.0 | ... | -0.599104 | -5.543197 | -4.523274 | -4.792562 | -4.710203 | -4.193458 | -4.351852 | 422378.052252 | 3.406383 | 1.438781e+16 |
159751 | 11344.0 | 5427022.0 | -0.20820 | 5.26706 | 5.60508 | 12.19142 | 0.0 | 12.00032 | 1.86693 | 0.0 | ... | -0.652923 | -5.547994 | -4.528258 | -4.855170 | -4.764397 | -4.202248 | -4.360003 | 431143.003804 | 2.155296 | 9.292407e+15 |
159752 | 11716.0 | 5427732.0 | -0.19781 | 5.27005 | 5.63783 | 12.82921 | 0.0 | 12.69262 | 2.04972 | 0.0 | ... | -0.671042 | -5.611740 | -4.592069 | -4.938427 | -4.844900 | -4.267385 | -4.424918 | 441581.980700 | 1.360738 | 6.008772e+15 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
158713 | 10523.0 | 5433841.0 | -0.22290 | 5.26152 | 5.55354 | 11.19408 | 0.0 | 10.92697 | 1.51714 | 0.0 | ... | -0.548907 | -5.522329 | -4.502241 | -4.717961 | -4.643772 | -4.169053 | -4.328015 | 416793.889396 | 6.434254 | 2.681758e+16 |
158714 | 10931.0 | 5430873.0 | -0.21776 | 5.26448 | 5.57564 | 11.60518 | 0.0 | 11.36546 | 1.66942 | 0.0 | ... | -0.590261 | -5.536736 | -4.516783 | -4.776623 | -4.695680 | -4.186361 | -4.344857 | 421756.071356 | 3.773074 | 1.591317e+16 |
158715 | 11255.0 | 5427329.0 | -0.21172 | 5.26760 | 5.60019 | 12.07276 | 0.0 | 11.86242 | 1.74400 | 0.0 | ... | -0.629136 | -5.559499 | -4.539679 | -4.841098 | -4.754000 | -4.211962 | -4.370004 | 427662.670125 | 2.330815 | 9.968024e+15 |
158716 | 11684.0 | 5427097.0 | -0.20212 | 5.27051 | 5.63103 | 12.68744 | 0.0 | 12.53888 | 1.98375 | 0.0 | ... | -0.677210 | -5.588558 | -4.568909 | -4.921893 | -4.827437 | -4.244683 | -4.402140 | 437221.332166 | 1.446314 | 6.323594e+15 |
158717 | 12170.0 | 5430072.0 | -0.15624 | 5.25498 | 5.66070 | 13.46907 | 0.0 | 13.29260 | 2.06366 | 0.0 | ... | -0.376628 | -6.022578 | -5.018670 | -5.029058 | -4.985591 | -4.652429 | -4.837749 | 485938.538481 | 0.967795 | 4.702891e+15 |
116 rows × 62 columns
And it looks like we have selected 116 models out of the >21k we could see in the original SUMMARY table (see below)
[69]:
eve.SUMMARY.shape[0]
[69]:
21117
Let’s explore the BPASS models!¶
Firstly we’ll need to know where to look. The MODELS_PATH
in hoki.constants
contains the local path to the BPASS models if you have set it up. You can just temporarily create a MODELS_PATH variable with the path to the model library on your machine, or you can set it up permanently using the hoki.constants.set_models_path
function (see its documentation for me info. For now you can see that by default it is set to the correct path on my own machine:
[71]:
hc.MODELS_PATH
[71]:
'/home/fste075/BPASS_hoki_dev/bpass-v2.2-newmodels/'
[Reading in a model (sneplot) file]
Within hoki.load
there is a function called dummy_to_dataframe
which will read in a model file into a dataframe with column names (the same ones we saw above with the DEATH
table).
Using this we can load in our matching models and plot them on an HR Diagram!
[72]:
plt.figure(figsize=(4,5))
for _id in id_best: # id is a keyword in python, using _id avoids overwriting that keyword
# As we saw much earlier, ID_TABLE is used to turn integer IDs
# into the filename strings we need.
_fname = eve.ID_TABLE.loc[_id].filenames
# Then we create a temporary dataframe containing the data for that one model
# We can just add MODELS_PATH to the filename we just retrieved (make sure MODELS_PATH
# ends with a / otherwise it won't be valid)
_df = dummy_to_dataframe(MODELS_PATH+_fname)
# finally we can plot our HRD data. Note that a low alpha is used
# so that we don't have an illegible plot.
plt.plot(_df['log(T1)'], _df['log(L1)'], color='k', alpha=0.1)
plt.gca().invert_xaxis()
nifty! but we’re going to want do to a lot more than this. First of all plotting our stellar tracks in low alpha tells us where most of the models fall, but not where most of the probability falls. Each stellar model is more or less likely to occur (see the section on modelimf
) and we have to take that into account if we want to do the stellar population synthesis bit correctly.
First of all let’s create a new SUMMARY
table with our favourite models so we don’t need to keep doing .loc[id_best]
(this is another example of why handling this with an object is super flexible! we can add whatever attribute we want as we go through the analysis)
[73]:
eve.SUMMARY_best = eve.SUMMARY.loc[id_best]
To get a quick idea of which models are best we can sort using modelimf
[75]:
eve.SUMMARY_best.sort_values('modelimf', ascending=False).head(10)
[75]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | |||||||||||||
141269 | 40.0 | 4.0 | 0.274287 | 4470888.0 | 1 | 1 | 5429815.0 | 13.79834 | 4.000171 | 0.1266157E+00 | 1.767013 | 0.0 | 1 |
141270 | 40.0 | 8.0 | 0.274287 | 4470888.0 | 1 | 1 | 5429342.0 | 13.39695 | 8.001817 | 0.1049087E+00 | 1.706822 | 0.0 | 1 |
141271 | 40.0 | 12.0 | 0.274287 | 4470888.0 | 1 | 1 | 5429529.0 | 13.58817 | 12.047250 | 0.1121516E+00 | 1.672568 | 0.0 | 1 |
141260 | 40.0 | 4.0 | 0.173063 | 4470888.0 | 1 | 1 | 5427357.0 | 12.95953 | 4.000201 | 0.7404644E-01 | 1.641982 | 0.0 | 1 |
141261 | 40.0 | 8.0 | 0.173063 | 4450443.0 | 1 | 1 | 5427467.0 | 12.75270 | 8.002334 | 0.6476529E-01 | 1.619376 | 0.0 | 1 |
141262 | 40.0 | 12.0 | 0.173063 | 4470888.0 | 1 | 1 | 5426833.0 | 12.88541 | 12.053630 | 0.7003154E-01 | 1.606297 | 0.0 | 1 |
141253 | 40.0 | 12.0 | 0.109195 | 4450443.0 | 1 | 1 | 5426638.0 | 12.25425 | 12.059850 | 0.4262797E-01 | 1.538057 | 0.0 | 1 |
141251 | 40.0 | 4.0 | 0.109195 | 4450443.0 | 1 | 1 | 5426505.0 | 12.30724 | 4.000213 | 0.4360660E-01 | 1.521252 | 0.0 | 1 |
141244 | 40.0 | 12.0 | 0.068898 | 4450443.0 | 1 | 1 | 5429384.0 | 11.76606 | 12.068530 | 0.2658655E-01 | 1.468233 | 0.0 | 1 |
141226 | 40.0 | 12.0 | 0.027429 | 4470888.0 | 1 | 1 | 5435845.0 | 11.06886 | 12.092340 | 0.1040865E-01 | 1.325502 | 0.0 | 1 |
We can also get a broad view of the models we picked out with pandas tools like describe()
. Although note all this is for preliminary data analysis, you wouldn’t use those raw numbers to report in a paper, the progenitor isn’t 43 Msol +/- 12. DO NOT DO THIS PLEASE. If you need me to explain in more details why YOU CANNOT USE THESE NUMBERS RAW TO REPORT YOUR PROGENITOR CHARACTERISTICS feel free to send me an email.
[28]:
eve010.SUMMARY_best.M1_ZAMS.describe()
[28]:
count 116.000000
mean 43.577586
std 12.065150
min 20.000000
25% 40.000000
50% 40.000000
75% 40.000000
max 120.000000
Name: M1_ZAMS, dtype: float64
Here is one reason: describe is useful but it can be misleading! Look at the unique values of M1 possible for example…
[29]:
eve.SUMMARY_best.M1_ZAMS.unique()
[29]:
array([ 40., 60., 35., 80., 70., 50., 20., 120.])
Clearly a discrete set, because that is the BPASS grid. A standard deviation is a notion valid for Normal distributions, not for our bespoke grid. Also the means in describe
don’t take into account our pop. synth. So let’s do this now:
Most likely masses (by N_imf)¶
Much earlier in the notebook I talked about modelimf
and mixedimf
. Well here we need to put them together into a new column we will call N_imf
because it is the number of each model we can expect in a 1 Million Msol population.
[76]:
eve.SUMMARY_best['Nimf']=eve.SUMMARY_best.modelimf+eve.SUMMARY_best.mixedimf
eve.SUMMARY_best.groupby('M1_ZAMS').sum().Nimf.sort_values(ascending=False)
[76]:
M1_ZAMS
40.0 58.860495
35.0 0.898797
20.0 0.710178
60.0 0.003268
50.0 0.002970
70.0 0.000364
80.0 0.000216
120.0 0.000045
Name: Nimf, dtype: float64
Now we can once figure out how likely each primary is to occur:
[78]:
total_nimf = eve.SUMMARY_best.Nimf.sum()
# groupby does what it says on the tin, it groups all rows according to their values in a chosen column
# in this case M1_ZAMS. We chose how it is grouped (mean, sum, count etc..)
# then I select the Nimf column as that is the only one I care about reporting
# and finally I sort it from largest to smallest before normalising it by total_nimf and making it percent
eve.SUMMARY_best.groupby('M1_ZAMS').sum().Nimf.sort_values(ascending=False)/total_nimf*100
[78]:
M1_ZAMS
40.0 97.328148
35.0 1.486197
20.0 1.174307
60.0 0.005403
50.0 0.004911
70.0 0.000602
80.0 0.000357
120.0 0.000075
Name: Nimf, dtype: float64
So 97% of our matching models in this population have M1 = 40 Msol at birth, there are no models below 20 Msol (and even those only account for 1.1%) and negligible porbabilities for models above 10 Msol although we find some matches at 50, 60, 70, 80 and 120 Msol. THAT IS HOW YOU WANT TO REPORT THE FINDINGS I know we are used to error bars, but that is TERRIBLE WAY to summarise these analyses.
Now that I’ve beat my dead horse let’s keep going - we are now going to take a look at the evolution of one model with a close eye. This is where most of these system searches will lead you. First you narrow down which systems are interesting using Eve and the methods shown above, then you go look at the BPASS stellar evolution directly.
Looking at individual models.¶
Let’s pick a model at random (not at random: I picked a weird looking one for fun)
[79]:
eve.SUMMARY_best.sort_values('Nimf', ascending=False)
[79]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | Nimf | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | ||||||||||||||
141269 | 40.0 | 4.00000 | 0.274287 | 4470888.0 | 1 | 1 | 5429815.0 | 13.79834 | 4.000171 | 0.1266157E+00 | 1.767013 | 0.0 | 1 | 1.767013 |
141270 | 40.0 | 8.00000 | 0.274287 | 4470888.0 | 1 | 1 | 5429342.0 | 13.39695 | 8.001817 | 0.1049087E+00 | 1.706822 | 0.0 | 1 | 1.706822 |
141271 | 40.0 | 12.00000 | 0.274287 | 4470888.0 | 1 | 1 | 5429529.0 | 13.58817 | 12.047250 | 0.1121516E+00 | 1.672568 | 0.0 | 1 | 1.672568 |
141260 | 40.0 | 4.00000 | 0.173063 | 4470888.0 | 1 | 1 | 5427357.0 | 12.95953 | 4.000201 | 0.7404644E-01 | 1.641982 | 0.0 | 1 | 1.641982 |
141261 | 40.0 | 8.00000 | 0.173063 | 4450443.0 | 1 | 1 | 5427467.0 | 12.75270 | 8.002334 | 0.6476529E-01 | 1.619376 | 0.0 | 1 | 1.619376 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
160049 | 70.0 | 31.62392 | 0.004073 | 4371940.0 | 1 | 0 | 5440977.0 | 10.20070 | 82.294470 | 0.1917270E-01 | 0.000046 | 0.0 | 2 | 0.000046 |
158621 | 120.0 | 12.58930 | 0.027429 | 2533937.0 | 1 | 0 | 3440047.0 | 10.57277 | 30.691660 | 0.2393484E-02 | 0.000045 | 0.0 | 2 | 0.000045 |
160020 | 80.0 | 31.62328 | 0.004362 | 4118972.0 | 1 | 0 | 5144425.0 | 10.65417 | 90.112690 | 0.1836079E-01 | 0.000034 | 0.0 | 2 | 0.000034 |
160048 | 70.0 | 31.62392 | 0.004073 | 4371940.0 | 1 | 0 | 5440977.0 | 10.20070 | 82.294470 | 0.1917270E-01 | 0.000030 | 0.0 | 2 | 0.000030 |
160021 | 80.0 | 31.62328 | 0.004362 | 4118972.0 | 1 | 0 | 5144425.0 | 10.65417 | 90.112690 | 0.1836079E-01 | 0.000011 | 0.0 | 2 | 0.000011 |
116 rows × 14 columns
[80]:
id_model = eve.SUMMARY_best.sort_values('Nimf', ascending=False).index.values[0]
Loading a model from the stellar library requires knowing its path, we can convert from MODEL_ID to filename using the ID_TABLE
.
[81]:
eve.ID_TABLE.loc[id_model].values[0]
[81]:
'NEWBINMODS/NEWBINMODS/z006/sneplot-z006-40-0.1-2'
[82]:
# we load our data into a dataframe with the right columns using hoki.load.dummy_to_dataframe
dummy_df = dummy_to_dataframe(MODELS_PATH+eve.ID_TABLE.loc[id_model].values[0])
[83]:
dummy_df
[83]:
timestep | age | log(R1) | log(T1) | log(L1) | M1 | He_core1 | CO_core1 | ONe_core1 | Nan9 | ... | f300w2 | f336w2 | f435w2 | f450w2 | f555w2 | f606w2 | f814w2 | Halpha | FUV | NUV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0 | 0.000 | 0.97038 | 4.61220 | 5.34281 | 40.00000 | 0.0 | 0.00001 | 0.00000 | 0.0 | ... | -1.237489 | -1.015627 | 0.010051 | 0.045032 | 0.167154 | 0.207036 | 0.351422 | 49.01473 | 36.70769 | 36.22317 |
1 | 100.0 | 3627.553 | 0.91835 | 4.64589 | 5.37351 | 39.99897 | 0.0 | 0.00000 | 0.00000 | 0.0 | ... | -1.237514 | -1.015652 | 0.010026 | 0.045007 | 0.167129 | 0.207011 | 0.351397 | 49.11522 | 36.67072 | 36.17228 |
2 | 200.0 | 39673.240 | 0.89581 | 4.65121 | 5.34971 | 39.98932 | 0.0 | 0.00000 | 0.00000 | 0.0 | ... | -1.237590 | -1.015727 | 0.009951 | 0.044931 | 0.167053 | 0.206935 | 0.351321 | 49.09683 | 36.63593 | 36.13750 |
3 | 300.0 | 539810.300 | 0.92718 | 4.64130 | 5.37281 | 39.84777 | 0.0 | 0.00000 | 0.00000 | 0.0 | ... | -1.238756 | -1.016837 | 0.009015 | 0.044003 | 0.166157 | 0.206049 | 0.350466 | 49.10769 | 36.68012 | 36.18160 |
4 | 400.0 | 1345856.000 | 0.96097 | 4.63452 | 5.41327 | 39.57804 | 0.0 | 0.00000 | 0.00000 | 0.0 | ... | -1.240647 | -1.018639 | 0.007486 | 0.042488 | 0.164691 | 0.204597 | 0.349063 | 49.13902 | 36.73828 | 36.23923 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
125 | 12500.0 | 5429815.000 | -0.13999 | 5.25100 | 5.67727 | 13.79835 | 0.0 | 13.46089 | 1.19353 | 0.0 | ... | -1.250536 | -1.028079 | -0.000566 | 0.034503 | 0.156958 | 0.196937 | 0.341650 | 49.54843 | 37.43567 | 36.16653 |
126 | 12600.0 | 5429815.000 | -0.13355 | 5.24735 | 5.67553 | 13.79834 | 0.0 | 13.46342 | 1.55636 | 0.0 | ... | -1.250536 | -1.028079 | -0.000566 | 0.034503 | 0.156958 | 0.196937 | 0.341650 | 49.54507 | 37.43893 | 36.16934 |
127 | 12700.0 | 5429815.000 | -0.12842 | 5.24440 | 5.67401 | 13.79834 | 0.0 | 13.46331 | 1.87427 | 0.0 | ... | -1.250536 | -1.028079 | -0.000566 | 0.034503 | 0.156958 | 0.196937 | 0.341650 | 49.54211 | 37.44044 | 36.17529 |
128 | 12764.0 | 5429815.000 | -0.12487 | 5.24235 | 5.67289 | 13.79834 | 0.0 | 13.46613 | 2.07038 | 0.0 | ... | -1.250536 | -1.028079 | -0.000566 | 0.034503 | 0.156958 | 0.196937 | 0.341650 | 49.54033 | 37.44062 | 36.17820 |
129 | 12764.0 | 5429815.000 | -0.12487 | 5.24235 | 5.67289 | 13.79834 | 0.0 | 13.46613 | 2.07038 | 0.0 | ... | -1.250536 | -1.028079 | -0.000566 | 0.034503 | 0.156958 | 0.196937 | 0.341650 | 49.54033 | 37.44062 | 36.17820 |
130 rows × 96 columns
In the plots we are going to make we will want to show the episodes of mass transfer and common envelope. Using the same criteria as mentioned in the introduction we create masks for our dataframe that will allow us to select only these steps of the evolution for some of our plotting. Note I’ve added most of the explanation of what each plot does in the comments of the code because I feel that this could end up being copy-pasted straight into other scripts: this way you have the meaning and goal of each plot explained in your code.
[85]:
cee_mask = (dummy_df['log(R1)']>dummy_df['log(a)'])
mt_mask = (dummy_df['DM1R']<0)
[86]:
# We want 3 plots in a row - I picked a convenient size for the notebook
# feel free to amend for your own plotting needs.
f, ax0 = plt.subplots(ncols=3, nrows=1, figsize=(12,4))
# I decided to name each axis in the array to type fewer square brackets - very optional
ax, ax1, ax2 = ax0[0], ax0[1] , ax0[2]
# PLOT 0
# this plot shows the radius and period evolution over the life of the stars
# it also shows the mass as it's interesting to see where most of the mass is lost
# especially with respect to the stages of mass transfer.
ax.plot(dummy_df['timestep'], dummy_df['log(a)'], label='log(a/R$_{\odot}$)',
color='magenta', lw=1)
ax.plot(dummy_df['timestep'], dummy_df['log(R1)'], label='log(R/R$_{\odot}$)', color='k', lw=1)
ax.plot(dummy_df.timestep, dummy_df.P_bin, label='P (years)', color='darkred', lw=1)
ax.plot(dummy_df['timestep'], dummy_df['MH1'], label='MH1 (M$_{\odot}$)', color='b', lw=1)
# Highlighting the common envelope evolution and RLOF
ax.axvspan(dummy_df[mt_mask].timestep.min(),
dummy_df[mt_mask].timestep.max(), color='orange',
label='RLOF', alpha=0.3)
ax.axvspan(dummy_df[cee_mask].timestep.min(),
dummy_df[cee_mask].timestep.max(), color='red',
label='CE', alpha=0.3)
ax.legend()
ax.set_xlabel('Timestep', loc='right')
# PLOT 1
# this plot shows the evolution of the cores' mass coordinates and the mass of the two companions.
# Note that when He_core1 == M1 then the value of He_core1 drops to 0. That is because
# when the helium core mass cordinate reaches the outside of the star it's no longer a core... it's
# just a helium star. You could fix the plotting by just plotting M1 as He_core1 beyond that.
# This plot is useful to know where the mass transfer and CEE occurs with respect to the
# main sequence and post main sequence evolution.
ax1.plot(dummy_df['timestep'], dummy_df['M1'], label='M1 (M$_{\odot}$)', color='k')
ax1.plot(dummy_df['timestep'], dummy_df['M2'], label='M2 (M$_{\odot}$)', color='k', ls='--')
ax1.plot(dummy_df['timestep'], dummy_df['He_core1'], label='He core (M$_{\odot}$)')
ax1.plot(dummy_df['timestep'], dummy_df['CO_core1'], label='CO core (M$_{\odot}$)')
ax1.plot(dummy_df['timestep'], dummy_df['ONe_core1'], label='ONe core (M$_{\odot}$)')
# Highlighting the common envelope evolution and RLOF
ax1.axvspan(dummy_df[mt_mask].timestep.min(),
dummy_df[mt_mask].timestep.max(), color='orange',
alpha=0.3)
ax1.axvspan(dummy_df[cee_mask].timestep.min(),
dummy_df[cee_mask].timestep.max(), color='red',
alpha=0.3)
ax1.set_ylim([0,51])
ax1.legend()
ax1.set_xlabel('Timestep', loc='right')
# PLOT2
# This is just your HR Diagram! I like to plot the evolutionary track as a continuous line and overplot
# in large markers a scatter plot so we can see where each timestep (that recorded the data of the plots 0
# and 1) is - as we can see those timesteps are denser in areas that change more rapidly.
ax2.plot(dummy_df['log(T1)'], dummy_df['log(L1)'], color='grey', alpha=0.5, lw=3, zorder=0.1)
ax2.scatter(dummy_df['log(T1)'], dummy_df['log(L1)'], color='grey')
# plotting the common envelope evolution time steps in a different colour
ax2.scatter(dummy_df[cee_mask]['log(T1)'], dummy_df[cee_mask]['log(L1)'],
zorder=10, color='crimson', marker='h',s=10)
# plotting the stable mass transfer time steps in a different colour
ax2.scatter(dummy_df[mt_mask]['log(T1)'], dummy_df[mt_mask]['log(L1)'],
color='orange', marker='h',s=10)
# YOU MIGHT WANT TO ADJUST THESE RANGES FOR OTHER MODELS
ax2.set_ylim([5.2001, 5.9])
ax2.set_xlim([5.4, 3.5])
# This is just a mroe convenient location for the labels. Padding will need to change if size changes
ax2.set_ylabel('log(L/L$_{\odot}$)', loc='top', labelpad=-50)
ax2.set_xlabel('log(T)', loc='right', labelpad=-35)
ax2.set_xlabel('log(T)',loc='center',labelpad=0)
[86]:
Text(1, 0, 'log(T)')
[89]:
# just checking M2 does increase in mass at least a bit.. it's a weird model
# but if it stayed at 4.0 the whole time it would be worryingly weird
dummy_df.M2.values
[89]:
array([4. , 4. , 4. , 4. , 4. , 4. ,
4. , 4. , 4. , 4. , 4. , 4. ,
4. , 4. , 4. , 4. , 4. , 4. ,
4. , 4. , 4. , 4. , 4. , 4. ,
4. , 4. , 4. , 4. , 4. , 4. ,
4. , 4. , 4. , 4. , 4. , 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171, 4.000171, 4.000171,
4.000171, 4.000171, 4.000171, 4.000171])
Okay I did say I picked a weirdo model, apparently this secondary gains very little mass and the mass -> probably because most of the RLOF timesteps are CEE and that leads to mostly mass ejection.
If you want to look at some “real life” models that came up in publications recently you can check the SN 2017gci paper (SLSN-I), the NGC 1851-BH1 paper (quiescent black hole binary.. or not), the VFTS 243 paper (quiescent black hole binary, for real).
Preserve your results with pickle!¶
Finally let us save our Eve
object with all of our extra columns and the new table so that we don’t have to rerun all this when we continue our analysis tomorrow.
[91]:
import pickle
file = open('myeve.pkl', 'wb') # open a file, where you ant to store the data
pickle.dump(eve, file) # dump information to that file
file.close() # close the file
And if you want to open your object again you can do:
[92]:
file = open('myeve.pkl', 'rb')
eve_again = pickle.load(file)
file.close()
[93]:
eve_again.SUMMARY_best
[93]:
M1_ZAMS | M2_ZAMS | P_ZAMS | lifetime_MS | MT_bool | CEE_bool | AGE_end | M1_end | M2_end | P_end | modelimf | mixedimf | type | Nimf | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
MODEL_ID | ||||||||||||||
159747 | 40.0 | 25.1189 | 0.006890 | 4660114.0 | 1 | 0 | 5618206.0 | 10.53407 | 46.20547 | 0.1730591E-01 | 0.000821 | 0.000000 | 2 | 0.000821 |
159748 | 40.0 | 25.1189 | 0.010920 | 4585610.0 | 1 | 0 | 5488492.0 | 11.03129 | 45.24818 | 0.2517517E-01 | 0.001601 | 0.000000 | 2 | 0.001601 |
159750 | 40.0 | 25.1189 | 0.027429 | 4454813.0 | 1 | 1 | 5429943.0 | 11.71055 | 27.49449 | 0.2470479E-01 | 0.002769 | 0.000000 | 2 | 0.002769 |
159751 | 40.0 | 25.1189 | 0.043472 | 4454813.0 | 1 | 1 | 5427022.0 | 12.19142 | 27.17696 | 0.3985545E-01 | 0.003708 | 0.013488 | 2 | 0.017196 |
159752 | 40.0 | 25.1189 | 0.068898 | 4454813.0 | 1 | 1 | 5427732.0 | 12.82921 | 26.93096 | 0.6465621E-01 | 0.005269 | 0.296793 | 2 | 0.302062 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
158713 | 40.0 | 12.5893 | 0.017306 | 4454813.0 | 1 | 1 | 5433841.0 | 11.19408 | 14.40241 | 0.1290614E-01 | 0.003516 | 0.116958 | 2 | 0.120474 |
158714 | 40.0 | 12.5893 | 0.027429 | 4454813.0 | 1 | 1 | 5430873.0 | 11.60518 | 13.67144 | 0.2227098E-01 | 0.008946 | 0.376418 | 2 | 0.385365 |
158715 | 40.0 | 12.5893 | 0.043472 | 4454813.0 | 1 | 1 | 5427329.0 | 12.07276 | 13.54084 | 0.3655669E-01 | 0.023674 | 0.476126 | 2 | 0.499800 |
158716 | 40.0 | 12.5893 | 0.068898 | 4454813.0 | 1 | 1 | 5427097.0 | 12.68744 | 13.43443 | 0.6022988E-01 | 0.104141 | 0.604571 | 2 | 0.708711 |
158717 | 40.0 | 12.5893 | 0.109195 | 4454813.0 | 1 | 1 | 5430072.0 | 13.46907 | 13.34467 | 0.1000394E+00 | 0.275734 | 0.529478 | 2 | 0.805212 |
116 rows × 14 columns
And as you can see it contains the new attributes that we created like SUMMARY_best
!
If you have a question or a complain…¶
I’ve said it already but it is worth repeating. Let me know if you have questions or issues! You can start an issue on the hoki github or send me an e-mail (hfstevance@gmail.com).
Now go and find your stars!