Skip to content
Snippets Groups Projects
Commit 1bd7acd8 authored by David Hendriks's avatar David Hendriks
Browse files

minor change in notebook output

parent c6e3f007
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:bbbaafbb-fd7d-4b73-a970-93506ba35d71 tags: %% Cell type:markdown id:bbbaafbb-fd7d-4b73-a970-93506ba35d71 tags:
# Tutorial: Running populations with binary_c-python # Tutorial: Running populations with binary_c-python
This notebook will show you how to evolve a population of stars This notebook will show you how to evolve a population of stars
Much of the code in the binarycpython package is written to evolve a population of stars through the Population object, rather than running a single system. Let's go through the functionality of this object step by step and set up some example populations. Much of the code in the binarycpython package is written to evolve a population of stars through the Population object, rather than running a single system. Let's go through the functionality of this object step by step and set up some example populations.
At the bottom of this notebook there are some complete example scripts At the bottom of this notebook there are some complete example scripts
%% Cell type:code id:bf6b8673-a2b5-4b50-ad1b-e90671f57470 tags: %% Cell type:code id:bf6b8673-a2b5-4b50-ad1b-e90671f57470 tags:
``` python ``` python
import os import os
from binarycpython.utils.custom_logging_functions import temp_dir from binarycpython.utils.custom_logging_functions import temp_dir
from binarycpython import Population from binarycpython import Population
TMP_DIR = temp_dir("notebooks", "notebook_population") TMP_DIR = temp_dir("notebooks", "notebook_population")
# help(Population) # Uncomment to see the public functions of this object # help(Population) # Uncomment to see the public functions of this object
``` ```
%% Cell type:code id:cf687b99-04f7-4d33-9f74-3d9d66d0b530 tags: %% Cell type:code id:cf687b99-04f7-4d33-9f74-3d9d66d0b530 tags:
``` python ``` python
from binarycpython import Population from binarycpython import Population
``` ```
%% Cell type:markdown id:f268eff3-4e08-4f6b-8b59-f22dba4d2074 tags: %% Cell type:markdown id:f268eff3-4e08-4f6b-8b59-f22dba4d2074 tags:
## Setting up the Population object ## Setting up the Population object
To set up and configure the population object we need to make an object instance of the `Population` object, and add configuration via the `.set()` function. To set up and configure the population object we need to make an object instance of the `Population` object, and add configuration via the `.set()` function.
There are three categories of options that the Population object can set: There are three categories of options that the Population object can set:
- BSE options: these options will be used for the binary_c calls, and are recognized by comparing the arguments to a known list of available arguments of binary_c. To see which options are available, see section [`binary_c parameters` in the documentation](https://ri0005.pages.surrey.ac.uk/binary_c-python/binary_c_parameters.html). You can access these through `population.bse_options['<bse option name>']` after you have set them. - BSE options: these options will be used for the binary_c calls, and are recognized by comparing the arguments to a known list of available arguments of binary_c. To see which options are available, see section [`binary_c parameters` in the documentation](https://ri0005.pages.surrey.ac.uk/binary_c-python/binary_c_parameters.html). You can access these through `population.bse_options['<bse option name>']` after you have set them.
- Grid options: these options will be used to configure the behaviour of the Population object. To see which options are available, see section [`Population grid code options` in the documentation](https://ri0005.pages.surrey.ac.uk/binary_c-python/grid_options_descriptions.html). They can be accessed via `population.grid_options['<grid option name>']` after you have set them. - Grid options: these options will be used to configure the behaviour of the Population object. To see which options are available, see section [`Population grid code options` in the documentation](https://ri0005.pages.surrey.ac.uk/binary_c-python/grid_options_descriptions.html). They can be accessed via `population.grid_options['<grid option name>']` after you have set them.
- Custom options: these options are not recognized as either of the above, so they will be stored in the custom_options, and can be accessed via `population.custom_options['<custom option name>']` - Custom options: these options are not recognized as either of the above, so they will be stored in the custom_options, and can be accessed via `population.custom_options['<custom option name>']`
%% Cell type:code id:79ab50b7-591f-4883-af09-116d1835a751 tags: %% Cell type:code id:79ab50b7-591f-4883-af09-116d1835a751 tags:
``` python ``` python
# Create population object # Create population object
example_pop = Population() example_pop = Population()
# If you want verbosity, set this before other things # If you want verbosity, set this before other things
example_pop.set(verbosity=1) example_pop.set(verbosity=1)
# Setting values can be done via .set(<parameter_name>=<value>) # Setting values can be done via .set(<parameter_name>=<value>)
# Values that are known to be binary_c_parameters are loaded into bse_options. # Values that are known to be binary_c_parameters are loaded into bse_options.
# Those that are present in the default grid_options are set in grid_options # Those that are present in the default grid_options are set in grid_options
# All other values that you set are put in a custom_options dict # All other values that you set are put in a custom_options dict
example_pop.set( example_pop.set(
# binary_c physics options # binary_c physics options
M_1=10, # bse_options M_1=10, # bse_options
orbital_period=45000000080, # bse_options orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options eccentricity=0.02, # bse_options
# grid_options # grid_options
num_cores=2, num_cores=2,
tmp_dir=TMP_DIR, tmp_dir=TMP_DIR,
# Custom options # TODO: need to be set in grid_options probably # Custom options # TODO: need to be set in grid_options probably
data_dir=os.path.join( data_dir=os.path.join(
TMP_DIR, "example_python_population_result" TMP_DIR, "example_python_population_result"
), # custom_options ), # custom_options
base_filename="example_pop.dat", # custom_options base_filename="example_pop.dat", # custom_options
) )
# We can use the options through # We can use the options through
print(example_pop.grid_options['verbosity']) print(example_pop.grid_options['verbosity'])
print(example_pop.custom_options['base_filename']) print(example_pop.custom_options['base_filename'])
print(example_pop.bse_options['M_1']) print(example_pop.bse_options['M_1'])
``` ```
%% Output %% Output
adding: num_cores=2 to grid_options adding: num_cores=2 to grid_options
adding: tmp_dir=/tmp/binary_c_python-david/notebooks/notebook_population to grid_options adding: tmp_dir=/tmp/binary_c_python-david/notebooks/notebook_population to grid_options
<<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result to custom_options >>>> <<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result to custom_options >>>>
<<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>> <<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>>
1 1
example_pop.dat example_pop.dat
10 10
%% Cell type:markdown id:f8d46d19-633d-4911-821d-a59daed31816 tags: %% Cell type:markdown id:f8d46d19-633d-4911-821d-a59daed31816 tags:
After configuring the population, but before running the actual population, its usually a good idea to export the full configuration (including version info of binary_c and all the parameters) to a file. To do this we use `example_pop.export_all_info()`. After configuring the population, but before running the actual population, its usually a good idea to export the full configuration (including version info of binary_c and all the parameters) to a file. To do this we use `example_pop.export_all_info()`.
On default this exports everything, each of the sections can be disabled: On default this exports everything, each of the sections can be disabled:
- population settings (bse_options, grid_options, custom_options), turn off with include_population - population settings (bse_options, grid_options, custom_options), turn off with include_population
settings=False settings=False
- binary_c_defaults (all the commandline arguments that binary c accepts, and their defaults). - binary_c_defaults (all the commandline arguments that binary c accepts, and their defaults).
turn off with include_binary_c_defaults=False turn off with include_binary_c_defaults=False
- include_binary_c_version_info (all the compilation info, and information about the compiled - include_binary_c_version_info (all the compilation info, and information about the compiled
parameters), turn off with include_binary_c_version_info=False parameters), turn off with include_binary_c_version_info=False
- include_binary_c_help_all (all the help information for all the binary_c parameters), - include_binary_c_help_all (all the help information for all the binary_c parameters),
turn off with include_binary_c_help_all=Fase turn off with include_binary_c_help_all=Fase
On default it will write this to the custom_options['data_dir'], but that can be overriden by setting use_datadir=False and providing an outfile=<> On default it will write this to the custom_options['data_dir'], but that can be overriden by setting use_datadir=False and providing an outfile=<>
%% Cell type:code id:b9c2471a-a5b0-48b7-a50b-2f0d22100926 tags: %% Cell type:code id:b9c2471a-a5b0-48b7-a50b-2f0d22100926 tags:
``` python ``` python
example_pop.export_all_info() example_pop.export_all_info()
``` ```
%% Output %% Output
ok ok
lockfile=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock lockfile=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock
post-lock: <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [unlocked: 0:00:15] pid=147908 at 0x7f5278ecd970x> post-lock: <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [unlocked: 0:00:15] pid=147908 at 0x7f5278ecd970x>
try to lock <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [unlocked: 0:01:00] pid=147908 at 0x7f5278ecd970x> try to lock <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [unlocked: 0:01:00] pid=147908 at 0x7f5278ecd970x>
locked <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x> locked <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x>
/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz is locked by <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x> to /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz is locked by <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x> to /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock
Try to open file at /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz Try to open file at /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz
Return locked file <_io.TextIOWrapper name='/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz' encoding='utf-8'>, <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x> Return locked file <_io.TextIOWrapper name='/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz' encoding='utf-8'>, <Lock /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz.lock [locked: 0:01:00] pid=147908 at 0x7f5278ecd970x>
ok ok
Writing settings to /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz Writing settings to /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz
'/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz' '/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz'
%% Cell type:markdown id:f9a65554-36ab-4a04-96ca-9f1422c307fd tags: %% Cell type:markdown id:f9a65554-36ab-4a04-96ca-9f1422c307fd tags:
## Adding grid variables ## Adding grid variables
The main purpose of the Population object is to handle the population synthesis side of running a set of stars. The main method to do this with binarycpython, as is the case with Perl binarygrid, is to use grid variables. These are loops over a predefined range of values, where a probability will be assigned to the systems based on the chosen probability distributions. The main purpose of the Population object is to handle the population synthesis side of running a set of stars. The main method to do this with binarycpython, as is the case with Perl binarygrid, is to use grid variables. These are loops over a predefined range of values, where a probability will be assigned to the systems based on the chosen probability distributions.
Usually we use either 1 mass grid variable, or a trio of mass, mass ratio and period (See below for full examples of all of these). We can, however, also add grid sampling for e.g. eccentricity, metallicity or other parameters. Usually we use either 1 mass grid variable, or a trio of mass, mass ratio and period (See below for full examples of all of these). We can, however, also add grid sampling for e.g. eccentricity, metallicity or other parameters.
In some cases it could be easier to set up a for loop that sets that parameter and calls the evolve function several times, e.g. when you want to vary a prescription (usually a discrete, unweighted parameter) In some cases it could be easier to set up a for loop that sets that parameter and calls the evolve function several times, e.g. when you want to vary a prescription (usually a discrete, unweighted parameter)
A notable special type of grid variable is that of the Moe & di Stefano 2017 dataset (see further down in the notebook). A notable special type of grid variable is that of the Moe & di Stefano 2017 dataset (see further down in the notebook).
To add a grid variable to the population object we use `example_pop.add_grid_variable` (see next cell) To add a grid variable to the population object we use `example_pop.add_grid_variable` (see next cell)
%% Cell type:code id:68c84521-9ae8-4020-af7a-5334173db969 tags: %% Cell type:code id:68c84521-9ae8-4020-af7a-5334173db969 tags:
``` python ``` python
help(example_pop.add_grid_variable) help(example_pop.add_grid_variable)
``` ```
%% Output %% Output
Help on method add_grid_variable in module binarycpython.utils.population_extensions.gridcode: Help on method add_grid_variable in module binarycpython.utils.population_extensions.gridcode:
add_grid_variable(name: str, parameter_name: str, longname: str, valuerange: Union[list, str], samplerfunc: str, probdist: str, dphasevol: Union[str, int] = -1, gridtype: str = 'centred', branchpoint: int = 0, branchcode: Optional[str] = None, precode: Optional[str] = None, postcode: Optional[str] = None, topcode: Optional[str] = None, bottomcode: Optional[str] = None, condition: Optional[str] = None, index: Optional[int] = None, dry_parallel: Optional[bool] = False) -> None method of binarycpython.utils.grid.Population instance add_grid_variable(name: str, parameter_name: str, longname: str, valuerange: Union[list, str], samplerfunc: str, probdist: str, dphasevol: Union[str, int] = -1, gridtype: str = 'centred', branchpoint: int = 0, branchcode: Optional[str] = None, precode: Optional[str] = None, postcode: Optional[str] = None, topcode: Optional[str] = None, bottomcode: Optional[str] = None, condition: Optional[str] = None, index: Optional[int] = None, dry_parallel: Optional[bool] = False) -> None method of binarycpython.utils.grid.Population instance
Function to add grid variables to the grid_options. Function to add grid variables to the grid_options.
The execution of the grid generation will be through a nested for loop. The execution of the grid generation will be through a nested for loop.
Each of the grid variables will get create a deeper for loop. Each of the grid variables will get create a deeper for loop.
The real function that generates the numbers will get written to a new file in the TMP_DIR, The real function that generates the numbers will get written to a new file in the TMP_DIR,
and then loaded imported and evaluated. and then loaded imported and evaluated.
beware that if you insert some destructive piece of code, it will be executed anyway. beware that if you insert some destructive piece of code, it will be executed anyway.
Use at own risk. Use at own risk.
Args: Args:
name: name:
name of parameter used in the grid Python code. name of parameter used in the grid Python code.
This is evaluated as a parameter and you can use it throughout This is evaluated as a parameter and you can use it throughout
the rest of the function the rest of the function
Examples:: Examples::
name = 'lnM_1' name = 'lnM_1'
parameter_name: parameter_name:
name of the parameter in binary_c name of the parameter in binary_c
This name must correspond to a Python variable of the same name, This name must correspond to a Python variable of the same name,
which is automatic if parameter_name == name. which is automatic if parameter_name == name.
Note: if parameter_name != name, you must set a Note: if parameter_name != name, you must set a
variable in "precode" or "postcode" to define a Python variable variable in "precode" or "postcode" to define a Python variable
called parameter_name called parameter_name
longname: longname:
Long name of parameter Long name of parameter
Examples:: Examples::
longname = 'Primary mass' longname = 'Primary mass'
range: range:
Range of values to take. Does not get used really, the samplerfunc is used to Range of values to take. Does not get used really, the samplerfunc is used to
get the values from get the values from
Examples:: Examples::
range = [math.log(m_min), math.log(m_max)] range = [math.log(m_min), math.log(m_max)]
samplerfunc: samplerfunc:
Function returning a list or numpy array of samples spaced appropriately. Function returning a list or numpy array of samples spaced appropriately.
You can either use a real function, or a string representation of a function call. You can either use a real function, or a string representation of a function call.
Examples:: Examples::
samplerfunc = "self.const_linear(math.log(m_min), math.log(m_max), {})".format(resolution['M_1']) samplerfunc = "self.const_linear(math.log(m_min), math.log(m_max), {})".format(resolution['M_1'])
precode: precode:
Extra room for some code. This code will be evaluated within the loop of the Extra room for some code. This code will be evaluated within the loop of the
sampling function (i.e. a value for lnM_1 is chosen already) sampling function (i.e. a value for lnM_1 is chosen already)
Examples:: Examples::
precode = 'M_1=math.exp(lnM_1);' precode = 'M_1=math.exp(lnM_1);'
postcode: postcode:
Code executed after the probability is calculated. Code executed after the probability is calculated.
probdist: probdist:
Function determining the probability that gets assigned to the sampled parameter Function determining the probability that gets assigned to the sampled parameter
Examples:: Examples::
probdist = 'self.Kroupa2001(M_1)*M_1' probdist = 'self.Kroupa2001(M_1)*M_1'
dphasevol: dphasevol:
part of the parameter space that the total probability is calculated with. Put to -1 part of the parameter space that the total probability is calculated with. Put to -1
if you want to ignore any dphasevol calculations and set the value to 1 if you want to ignore any dphasevol calculations and set the value to 1
Examples:: Examples::
dphasevol = 'dlnM_1' dphasevol = 'dlnM_1'
condition: condition:
condition that has to be met in order for the grid generation to continue condition that has to be met in order for the grid generation to continue
Examples:: Examples::
condition = "self.grid_options['binary']==1" condition = "self.grid_options['binary']==1"
gridtype: gridtype:
Method on how the value range is sampled. Can be either 'edge' (steps starting at Method on how the value range is sampled. Can be either 'edge' (steps starting at
the lower edge of the value range) or 'centred' the lower edge of the value range) or 'centred'
(steps starting at ``lower edge + 0.5 * stepsize``). (steps starting at ``lower edge + 0.5 * stepsize``).
dry_parallel: dry_parallel:
If True, try to parallelize this variable in dry runs. If True, try to parallelize this variable in dry runs.
topcode: topcode:
Code added at the very top of the block. Code added at the very top of the block.
bottomcode: bottomcode:
Code added at the very bottom of the block. Code added at the very bottom of the block.
%% Cell type:markdown id:bd75cebe-2152-4025-b680-dc020b80889b tags: %% Cell type:markdown id:bd75cebe-2152-4025-b680-dc020b80889b tags:
All the distribution functions that we can use are stored in the `binarycpython.utils.distribution_functions` or `binarycpython/utils/distribution_functions.py` on git. If you uncomment the help statement below you can see which functions are available now: All the distribution functions that we can use are stored in the `binarycpython.utils.distribution_functions` or `binarycpython/utils/distribution_functions.py` on git. If you uncomment the help statement below you can see which functions are available now:
%% Cell type:code id:048db541-3e92-4c5d-a25c-9c5a34b9c857 tags: %% Cell type:code id:048db541-3e92-4c5d-a25c-9c5a34b9c857 tags:
``` python ``` python
# import binarycpython.utils.distribution_functions # import binarycpython.utils.distribution_functions
# help(binarycpython.utils.distribution_functions) # help(binarycpython.utils.distribution_functions)
``` ```
%% Cell type:markdown id:1b3a007b-5c17-42a7-a981-7e268e6f545c tags: %% Cell type:markdown id:1b3a007b-5c17-42a7-a981-7e268e6f545c tags:
The next cell contains an example of adding the mass grid variable, but sampling in log mass. The commented grid variables are examples of the mass ratio sampling and the period sampling. The next cell contains an example of adding the mass grid variable, but sampling in log mass. The commented grid variables are examples of the mass ratio sampling and the period sampling.
%% Cell type:code id:47979841-2c26-4b26-8945-603d013dc93a tags: %% Cell type:code id:47979841-2c26-4b26-8945-603d013dc93a tags:
``` python ``` python
# Add grid variables # Add grid variables
resolution = {"M_1": 20} resolution = {"M_1": 20}
# Mass # Mass
example_pop.add_grid_variable( example_pop.add_grid_variable(
name="lnm1", name="lnm1",
longname="Primary mass", longname="Primary mass",
valuerange=[2, 150], valuerange=[2, 150],
samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]), samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)", precode="M_1=math.exp(lnm1)",
probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1", probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1", dphasevol="dlnm1",
parameter_name="M_1", parameter_name="M_1",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
) )
# # Mass ratio # # Mass ratio
# test_pop.add_grid_variable( # test_pop.add_grid_variable(
# name="q", # name="q",
# longname="Mass ratio", # longname="Mass ratio",
# valuerange=["0.1/M_1", 1], # valuerange=["0.1/M_1", 1],
# samplerfunc="self.const_linear(0.1/M_1, 1, {})".format(resolution['q']), # samplerfunc="self.const_linear(0.1/M_1, 1, {})".format(resolution['q']),
# probdist="self.flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])", # probdist="self.flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])",
# dphasevol="dq", # dphasevol="dq",
# precode="M_2 = q * M_1", # precode="M_2 = q * M_1",
# parameter_name="M_2", # parameter_name="M_2",
# condition="", # Impose a condition on this grid variable. Mostly for a check for yourself # condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
# ) # )
# # # #
# test_pop.add_grid_variable( # test_pop.add_grid_variable(
# name="log10per", # in days # name="log10per", # in days
# longname="log10(Orbital_Period)", # longname="log10(Orbital_Period)",
# valuerange=[0.15, 5.5], # valuerange=[0.15, 5.5],
# samplerfunc="self.const_linear(0.15, 5.5, {})".format(resolution["per"]), # samplerfunc="self.const_linear(0.15, 5.5, {})".format(resolution["per"]),
# precode="""orbital_period = 10** log10per # precode="""orbital_period = 10** log10per
# sep = calc_sep_from_period(M_1, M_2, orbital_period) # sep = calc_sep_from_period(M_1, M_2, orbital_period)
# sep_min = calc_sep_from_period(M_1, M_2, 10**0.15) # sep_min = calc_sep_from_period(M_1, M_2, 10**0.15)
# sep_max = calc_sep_from_period(M_1, M_2, 10**5.5)""", # sep_max = calc_sep_from_period(M_1, M_2, 10**5.5)""",
# probdist="self.sana12(M_1, M_2, sep, orbital_period, sep_min, sep_max, math.log10(10**0.15), math.log10(10**5.5), -0.55)", # probdist="self.sana12(M_1, M_2, sep, orbital_period, sep_min, sep_max, math.log10(10**0.15), math.log10(10**5.5), -0.55)",
# parameter_name="orbital_period", # parameter_name="orbital_period",
# dphasevol="dlog10per", # dphasevol="dlog10per",
# ) # )
``` ```
%% Cell type:markdown id:163f13ae-fec1-4ee8-b9d4-c1b75c19ff39 tags: %% Cell type:markdown id:163f13ae-fec1-4ee8-b9d4-c1b75c19ff39 tags:
## Setting logging and handling the output ## Setting logging and handling the output
On default, binary_c will not output anything (except for 'SINGLE STAR LIFETIME'). It is up to us to determine what will be printed. We can either do that by hardcoding the print statements into `binary_c` (see documentation binary_c). Or, we can use the custom logging functionality of binarycpython (see notebook `notebook_custom_logging.ipynb`), which is faster to set up and requires no recompilation of binary_c, but is somewhat more limited in its functionality. On default, binary_c will not output anything (except for 'SINGLE STAR LIFETIME'). It is up to us to determine what will be printed. We can either do that by hardcoding the print statements into `binary_c` (see documentation binary_c). Or, we can use the custom logging functionality of binarycpython (see notebook `notebook_custom_logging.ipynb`), which is faster to set up and requires no recompilation of binary_c, but is somewhat more limited in its functionality.
After configuring what will be printed, we need to make a function to parse the output. This can be done by setting the parse_function parameter in the population object (see also notebook `notebook_individual_systems.ipynb`). After configuring what will be printed, we need to make a function to parse the output. This can be done by setting the parse_function parameter in the population object (see also notebook `notebook_individual_systems.ipynb`).
In the code below we will set up both the custom logging, and a parse function to handle that output In the code below we will set up both the custom logging, and a parse function to handle that output
%% Cell type:code id:0c986215-93b1-4e30-ad79-f7c397e9ff7d tags: %% Cell type:code id:0c986215-93b1-4e30-ad79-f7c397e9ff7d tags:
``` python ``` python
# Create custom logging statement: in this case we will log when the star turns into a compact object, and then terminate the evolution. # Create custom logging statement: in this case we will log when the star turns into a compact object, and then terminate the evolution.
custom_logging_code = """ custom_logging_code = """
if(stardata->star[0].stellar_type >= 13) if(stardata->star[0].stellar_type >= 13)
{ {
if (stardata->model.time < stardata->model.max_evolution_time) if (stardata->model.time < stardata->model.max_evolution_time)
{ {
Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\\n", Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\\n",
// //
stardata->model.time, // 1 stardata->model.time, // 1
stardata->star[0].mass, // 2 stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 3 stardata->common.zero_age.mass[0], // 3
stardata->model.probability, // 4 stardata->model.probability, // 4
stardata->star[0].stellar_type // 5 stardata->star[0].stellar_type // 5
); );
}; };
/* Kill the simulation to save time */ /* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm; stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
}; };
""" """
example_pop.set( example_pop.set(
C_logging_code=custom_logging_code C_logging_code=custom_logging_code
) )
``` ```
%% Output %% Output
adding: C_logging_code= adding: C_logging_code=
if(stardata->star[0].stellar_type >= 13) if(stardata->star[0].stellar_type >= 13)
{ {
if (stardata->model.time < stardata->model.max_evolution_time) if (stardata->model.time < stardata->model.max_evolution_time)
{ {
Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\n", Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\n",
// //
stardata->model.time, // 1 stardata->model.time, // 1
stardata->star[0].mass, // 2 stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 3 stardata->common.zero_age.mass[0], // 3
stardata->model.probability, // 4 stardata->model.probability, // 4
stardata->star[0].stellar_type // 5 stardata->star[0].stellar_type // 5
); );
}; };
/* Kill the simulation to save time */ /* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm; stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
}; };
to grid_options to grid_options
%% Cell type:markdown id:ae1f1f0c-1f8b-42d8-b051-cbf8c6b51514 tags: %% Cell type:markdown id:ae1f1f0c-1f8b-42d8-b051-cbf8c6b51514 tags:
The parse function must now catch lines that start with "EXAMPLE_COMPACT_OBJECT", and write that line to a file The parse function must now catch lines that start with "EXAMPLE_COMPACT_OBJECT", and write that line to a file
%% Cell type:code id:fd197154-a8ce-4865-8929-008d3483101a tags: %% Cell type:code id:fd197154-a8ce-4865-8929-008d3483101a tags:
``` python ``` python
def parse_function(self, output): def parse_function(self, output):
""" """
Example parse function Example parse function
""" """
# get info from the population instance # get info from the population instance
data_dir = self.custom_options["data_dir"] data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"] base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary # Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True) os.makedirs(data_dir, exist_ok=True)
seperator = " " seperator = " "
# Create filename # Create filename
outfilename = os.path.join(data_dir, base_filename) outfilename = os.path.join(data_dir, base_filename)
parameters = ["time", "mass", "zams_mass", "probability", "stellar_type"] parameters = ["time", "mass", "zams_mass", "probability", "stellar_type"]
# Go over the output. # Go over the output.
for line in output.splitlines(): for line in output.splitlines():
headerline = line.split()[0] headerline = line.split()[0]
# CHeck the header and act accordingly # CHeck the header and act accordingly
if headerline == "EXAMPLE_COMPACT_OBJECT": if headerline == "EXAMPLE_COMPACT_OBJECT":
values = line.split()[1:] values = line.split()[1:]
print(line) print(line)
if not len(parameters) == len(values): if not len(parameters) == len(values):
print("Number of column names isnt equal to number of columns") print("Number of column names isnt equal to number of columns")
raise ValueError raise ValueError
if not os.path.exists(outfilename): if not os.path.exists(outfilename):
with open(outfilename, "w") as f: with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n") f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f: with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n") f.write(seperator.join(values) + "\n")
# Add the parsing function # Add the parsing function
example_pop.set( example_pop.set(
parse_function=parse_function, parse_function=parse_function,
) )
``` ```
%% Output %% Output
adding: parse_function=<function parse_function at 0x7f523208e280> to grid_options adding: parse_function=<function parse_function at 0x7f523208e280> to grid_options
%% Cell type:markdown id:91509ce5-ffe7-4937-aa87-6d7baac9ac04 tags: %% Cell type:markdown id:91509ce5-ffe7-4937-aa87-6d7baac9ac04 tags:
## Evolving the grid ## Evolving the grid
Now that we configured all the main parts of the population object, we can actually run the population! Doing this is straightforward: `example_pop.evolve()` Now that we configured all the main parts of the population object, we can actually run the population! Doing this is straightforward: `example_pop.evolve()`
This will start up the processing of all the systems. We can control how many cores are used by settings `num_cores`. By setting the `verbosity` of the population object to a higher value we can get a lot of verbose information about the run, but for now we will set it to 0. This will start up the processing of all the systems. We can control how many cores are used by settings `num_cores`. By setting the `verbosity` of the population object to a higher value we can get a lot of verbose information about the run, but for now we will set it to 0.
There are many grid_options that can lead to different behaviour of the evolution of the grid. Please do have a look at those: [grid options docs](https://ri0005.pages.surrey.ac.uk/binary_c-python/grid_options_descriptions.html), and try There are many grid_options that can lead to different behaviour of the evolution of the grid. Please do have a look at those: [grid options docs](https://ri0005.pages.surrey.ac.uk/binary_c-python/grid_options_descriptions.html), and try
%% Cell type:code id:8ea376c1-1e92-45af-8cab-9d7fdca564eb tags: %% Cell type:code id:8ea376c1-1e92-45af-8cab-9d7fdca564eb tags:
``` python ``` python
# change verbosity # change verbosity
example_pop.set(verbosity=0) example_pop.set(verbosity=0)
## Executing a population ## Executing a population
## This uses the values generated by the grid_variables ## This uses the values generated by the grid_variables
analytics = example_pop.evolve() # TODO: update this function call analytics = example_pop.evolve() # TODO: update this function call
``` ```
%% Output %% Output
adding: verbosity=0 to grid_options adding: verbosity=0 to grid_options
Do dry run? True Do dry run? True
Doing dry run to calculate total starcount and probability Doing dry run to calculate total starcount and probability
Grid has handled 19 stars with a total probability of 0.0443872 Grid has handled 19 stars with a total probability of 0.0443872
********************************** **********************************
* Dry run * * Dry run *
* Total starcount is 19 * * Total starcount is 19 *
* Total probability is 0.0443872 * * Total probability is 0.0443872 *
********************************** **********************************
EXAMPLE_COMPACT_OBJECT 3.598268106261e+01 1.30592 8.75988 0.00193614 13 EXAMPLE_COMPACT_OBJECT 3.598268106261e+01 1.30592 8.75988 0.00193614 13
EXAMPLE_COMPACT_OBJECT 2.436983545179e+01 1.35842 10.9948 0.00144093 13 EXAMPLE_COMPACT_OBJECT 2.436983545179e+01 1.35842 10.9948 0.00144093 13
EXAMPLE_COMPACT_OBJECT 1.690157943854e+01 1.43124 13.7998 0.00107238 13 EXAMPLE_COMPACT_OBJECT 1.690157943854e+01 1.43124 13.7998 0.00107238 13
EXAMPLE_COMPACT_OBJECT 1.242397939734e+01 1.52416 17.3205 0.000798096 13 EXAMPLE_COMPACT_OBJECT 1.242397939734e+01 1.52416 17.3205 0.000798096 13
EXAMPLE_COMPACT_OBJECT 9.758088010684e+00 1.6691 21.7394 0.000593966 13 EXAMPLE_COMPACT_OBJECT 9.758088010684e+00 1.6691 21.7394 0.000593966 13
EXAMPLE_COMPACT_OBJECT 8.484238931453e+00 1.66351 27.2857 0.000442046 13 EXAMPLE_COMPACT_OBJECT 8.484238931453e+00 1.66351 27.2857 0.000442046 13
EXAMPLE_COMPACT_OBJECT 7.699271848690e+00 1.64817 34.247 0.000328983 13 EXAMPLE_COMPACT_OBJECT 7.699271848690e+00 1.64817 34.247 0.000328983 13
EXAMPLE_COMPACT_OBJECT 7.568274926111e+00 1.64805 42.9844 0.000244839 13 EXAMPLE_COMPACT_OBJECT 7.568274926111e+00 1.64805 42.9844 0.000244839 13
EXAMPLE_COMPACT_OBJECT 7.569952912843e+00 1.64805 53.9508 0.000182216 13 EXAMPLE_COMPACT_OBJECT 7.569952912843e+00 1.64805 53.9508 0.000182216 13
Do join of subprocesses ... Do join of subprocesses ...
EXAMPLE_COMPACT_OBJECT 7.571923249967e+00 1.64787 67.7151 0.00013561 13 EXAMPLE_COMPACT_OBJECT 7.571923249967e+00 1.64787 67.7151 0.00013561 13
EXAMPLE_COMPACT_OBJECT 7.612944004713e+00 1.64836 84.9909 0.000100925 13 EXAMPLE_COMPACT_OBJECT 7.612944004713e+00 1.64836 84.9909 0.000100925 13
EXAMPLE_COMPACT_OBJECT 7.620339349962e+00 1.64833 106.674 7.51114e-05 13 EXAMPLE_COMPACT_OBJECT 7.620339349962e+00 1.64833 106.674 7.51114e-05 13
EXAMPLE_COMPACT_OBJECT 7.622200536471e+00 1.64833 133.89 5.59e-05 13 EXAMPLE_COMPACT_OBJECT 7.622200536471e+00 1.64833 133.89 5.59e-05 13
Joined all subprocesses. Joined all subprocesses.
********************************************************** **********************************************************
* Population-0339fb6d69f146188239ec3595eb47d5 finished! * * Population-0339fb6d69f146188239ec3595eb47d5 finished! *
* The total probability is 0.0443872. * * The total probability is 0.0443872. *
* It took a total of 2.76s to run 19 systems on 2 cores * * It took a total of 2.76s to run 19 systems on 2 cores *
* = 5.53s of CPU time. * * = 5.53s of CPU time. *
* Maximum memory use 488.414 MB * * Maximum memory use 488.414 MB *
********************************************************** **********************************************************
No failed systems were found in this run. No failed systems were found in this run.
Do analytics Do analytics
Added analytics to metadata Added analytics to metadata
%% Cell type:markdown id:91ab45c7-7d31-4543-aee4-127ab58e891f tags: %% Cell type:markdown id:91ab45c7-7d31-4543-aee4-127ab58e891f tags:
After the run is complete, some technical report on the run is returned. I stored that in `analytics`. As we can see below, this dictionary is like a status report of the evolution. Useful for e.g. debugging. After the run is complete, some technical report on the run is returned. I stored that in `analytics`. As we can see below, this dictionary is like a status report of the evolution. Useful for e.g. debugging.
%% Cell type:code id:e1f0464b-0424-4022-b34b-5b744bc2c59d tags: %% Cell type:code id:e1f0464b-0424-4022-b34b-5b744bc2c59d tags:
``` python ``` python
print(analytics) print(analytics)
``` ```
%% Cell type:markdown id:6460df56-9fba-4817-9a1e-593ef15d98c1 tags: %% Cell type:markdown id:6460df56-9fba-4817-9a1e-593ef15d98c1 tags:
## Noteworthy functionality ## Noteworthy functionality
Some extra features that are available from via the population object are: Some extra features that are available from via the population object are:
- write_binary_c_calls_to_file: Function to write the calls that would be passed to binary_c to a file - write_binary_c_calls_to_file: Function to write the calls that would be passed to binary_c to a file
%% Cell type:code id:83f8e519-4f7c-474a-ad95-f175a34fae81 tags: %% Cell type:code id:83f8e519-4f7c-474a-ad95-f175a34fae81 tags:
``` python ``` python
help(example_pop.write_binary_c_calls_to_file) help(example_pop.write_binary_c_calls_to_file)
``` ```
%% Cell type:code id:dacfed75-dfe3-4afd-a0ff-a4be17746021 tags: %% Cell type:code id:dacfed75-dfe3-4afd-a0ff-a4be17746021 tags:
``` python ``` python
example_pop.set(verbosity=1) example_pop.set(verbosity=1)
calls_filename = example_pop.write_binary_c_calls_to_file() calls_filename = example_pop.write_binary_c_calls_to_file()
print(calls_filename) print(calls_filename)
with open(calls_filename, 'r') as f: with open(calls_filename, 'r') as f:
print('\n'.join(f.read().splitlines()[:4])) print('\n'.join(f.read().splitlines()[:4]))
print("(abridged)") print("(abridged)")
``` ```
%% Cell type:markdown id:60359eb1-4d0c-4d2d-8265-ec5171b944a2 tags: %% Cell type:markdown id:60359eb1-4d0c-4d2d-8265-ec5171b944a2 tags:
## Full examples of population scripts ## Full examples of population scripts
%% Cell type:markdown id:1ee279d6-e120-4aef-9e57-845e534f5c6a tags: %% Cell type:markdown id:1ee279d6-e120-4aef-9e57-845e534f5c6a tags:
### Single star population ### Single star population
Below is a full setup for a population of single stars Below is a full setup for a population of single stars
%% Cell type:code id:7212b6be-9787-4122-a7f1-86538cf38179 tags: %% Cell type:code id:7212b6be-9787-4122-a7f1-86538cf38179 tags:
``` python ``` python
def parse_function(self, output): def parse_function(self, output):
""" """
Example parsing function Example parsing function
""" """
# extract info from the population instance # extract info from the population instance
# Get some information from the # Get some information from the
data_dir = self.custom_options["data_dir"] data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"] base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary # Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True) os.makedirs(data_dir, exist_ok=True)
# #
seperator = " " seperator = " "
# Create filename # Create filename
outfilename = os.path.join(data_dir, base_filename) outfilename = os.path.join(data_dir, base_filename)
# The header columns matching this # The header columns matching this
parameters = ["time", "mass", "zams_mass", "probability", "radius", "stellar_type"] parameters = ["time", "mass", "zams_mass", "probability", "radius", "stellar_type"]
# Go over the output. # Go over the output.
for el in output.splitlines(): for el in output.splitlines():
headerline = el.split()[0] headerline = el.split()[0]
# CHeck the header and act accordingly # CHeck the header and act accordingly
if headerline == "MY_STELLAR_DATA": if headerline == "MY_STELLAR_DATA":
values = el.split()[1:] values = el.split()[1:]
if not len(parameters) == len(values): if not len(parameters) == len(values):
print("Number of column names isnt equal to number of columns") print("Number of column names isnt equal to number of columns")
raise ValueError raise ValueError
if not os.path.exists(outfilename): if not os.path.exists(outfilename):
with open(outfilename, "w") as f: with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n") f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f: with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n") f.write(seperator.join(values) + "\n")
# Create population object # Create population object
example_pop = Population() example_pop = Population()
# If you want verbosity, set this before other things # If you want verbosity, set this before other things
example_pop.set(verbosity=0) example_pop.set(verbosity=0)
# Setting values can be done via .set(<parameter_name>=<value>) # Setting values can be done via .set(<parameter_name>=<value>)
example_pop.set( example_pop.set(
# binary_c physics options # binary_c physics options
M_1=10, # bse_options M_1=10, # bse_options
separation=0, # bse_options separation=0, # bse_options
orbital_period=45000000080, # bse_options orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options eccentricity=0.02, # bse_options
# grid_options # grid_options
num_cores=2, num_cores=2,
tmp_dir=TMP_DIR, tmp_dir=TMP_DIR,
# Custom options: the data directory and the output filename # Custom options: the data directory and the output filename
data_dir=os.path.join( data_dir=os.path.join(
TMP_DIR, "example_python_population_result" TMP_DIR, "example_python_population_result"
), # custom_options ), # custom_options
base_filename="example_pop.dat", # custom_options base_filename="example_pop.dat", # custom_options
) )
# Creating a parsing function # Creating a parsing function
example_pop.set( example_pop.set(
parse_function=parse_function, # Setting the parse function thats used in the evolve_population parse_function=parse_function, # Setting the parse function thats used in the evolve_population
) )
### Custom logging ### Custom logging
# Log the moment when the star turns into neutron # Log the moment when the star turns into neutron
example_pop.set( example_pop.set(
C_logging_code=""" C_logging_code="""
if(stardata->star[0].stellar_type >= 13) if(stardata->star[0].stellar_type >= 13)
{ {
if (stardata->model.time < stardata->model.max_evolution_time) if (stardata->model.time < stardata->model.max_evolution_time)
{ {
Printf("MY_STELLAR_DATA %30.12e %g %g %g %g %d\\n", Printf("MY_STELLAR_DATA %30.12e %g %g %g %g %d\\n",
// //
stardata->model.time, // 1 stardata->model.time, // 1
stardata->star[0].mass, // 2 stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 4 stardata->common.zero_age.mass[0], // 4
stardata->model.probability, // 5 stardata->model.probability, // 5
stardata->star[0].radius, // 6 stardata->star[0].radius, // 6
stardata->star[0].stellar_type // 7 stardata->star[0].stellar_type // 7
); );
}; };
/* Kill the simulation to save time */ /* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm; stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
}; };
""" """
) )
# Add grid variables # Add grid variables
resolution = {"M_1": 20} resolution = {"M_1": 20}
# Mass # Mass
example_pop.add_grid_variable( example_pop.add_grid_variable(
name="lnm1", name="lnm1",
longname="Primary mass", longname="Primary mass",
valuerange=[2, 150], valuerange=[2, 150],
samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]), samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)", precode="M_1=math.exp(lnm1)",
probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1", probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1", dphasevol="dlnm1",
parameter_name="M_1", parameter_name="M_1",
condition="", condition="",
) )
# Exporting of all the settings can be done with .export_all_info() # Exporting of all the settings can be done with .export_all_info()
example_pop.export_all_info() example_pop.export_all_info()
# remove the result file if it exists # remove the result file if it exists
if os.path.isfile(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")): if os.path.isfile(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")):
os.remove(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")) os.remove(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"))
# Evolve the population # Evolve the population
example_pop.evolve() example_pop.evolve()
# #
with open(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"), 'r') as f: with open(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"), 'r') as f:
output = f.read() output = f.read()
print("\n") print("\n")
print(output) print(output)
``` ```
%% Output %% Output
<<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result to custom_options >>>> <<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result to custom_options >>>>
<<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>> <<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>>
ok ok
File at /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz already exists: cannot write to it File at /tmp/binary_c_python-david/notebooks/notebook_population/example_python_population_result/example_pop_settings.json.gz already exists: cannot write to it
ok ok
Do dry run? True Do dry run? True
Doing dry run to calculate total starcount and probability Doing dry run to calculate total starcount and probability
Grid has handled 19 stars with a total probability of 0.0443872 Grid has handled 19 stars with a total probability of 0.0443872
********************************** **********************************
* Dry run * * Dry run *
* Total starcount is 19 * * Total starcount is 19 *
* Total probability is 0.0443872 * * Total probability is 0.0443872 *
********************************** **********************************
Do join of subprocesses ... Do join of subprocesses ...
Joined all subprocesses. Joined all subprocesses.
********************************************************** **********************************************************
* Population-19273c7d83674b89902b735e67ae3ae3 finished! * * Population-d56f97fb060a4bb69b3d30bcba0d01d4 finished! *
* The total probability is 0.0443872. * * The total probability is 0.0443872. *
* It took a total of 4.23s to run 19 systems on 2 cores * * It took a total of 3.75s to run 19 systems on 2 cores *
* = 8.46s of CPU time. * * = 7.50s of CPU time. *
* Maximum memory use 493.797 MB * * Maximum memory use 493.797 MB *
********************************************************** **********************************************************
No failed systems were found in this run. No failed systems were found in this run.
Do analytics Do analytics
Added analytics to metadata Added analytics to metadata
time mass zams_mass probability radius stellar_type time mass zams_mass probability radius stellar_type
2.436983545179e+01 1.35842 10.9948 0.00144093 1.72498e-05 13
3.598268106261e+01 1.30592 8.75988 0.00193614 1.72498e-05 13 3.598268106261e+01 1.30592 8.75988 0.00193614 1.72498e-05 13
2.436983545179e+01 1.35842 10.9948 0.00144093 1.72498e-05 13
1.690157943854e+01 1.43124 13.7998 0.00107238 1.72498e-05 13 1.690157943854e+01 1.43124 13.7998 0.00107238 1.72498e-05 13
1.242397939734e+01 1.52416 17.3205 0.000798096 1.72498e-05 13 1.242397939734e+01 1.52416 17.3205 0.000798096 1.72498e-05 13
9.758088010684e+00 1.6691 21.7394 0.000593966 1.72498e-05 13 9.758088010684e+00 1.6691 21.7394 0.000593966 1.72498e-05 13
8.484238931453e+00 1.66351 27.2857 0.000442046 1.72498e-05 13 8.484238931453e+00 1.66351 27.2857 0.000442046 1.72498e-05 13
7.699271848690e+00 1.64817 34.247 0.000328983 1.72498e-05 13 7.699271848690e+00 1.64817 34.247 0.000328983 1.72498e-05 13
7.568274926111e+00 1.64805 42.9844 0.000244839 1.72498e-05 13 7.568274926111e+00 1.64805 42.9844 0.000244839 1.72498e-05 13
7.569952912843e+00 1.64805 53.9508 0.000182216 1.72498e-05 13 7.569952912843e+00 1.64805 53.9508 0.000182216 1.72498e-05 13
7.571923249967e+00 1.64787 67.7151 0.00013561 1.72498e-05 13 7.571923249967e+00 1.64787 67.7151 0.00013561 1.72498e-05 13
7.612944004713e+00 1.64836 84.9909 0.000100925 1.72498e-05 13 7.612944004713e+00 1.64836 84.9909 0.000100925 1.72498e-05 13
7.620339349962e+00 1.64833 106.674 7.51114e-05 1.72498e-05 13 7.620339349962e+00 1.64833 106.674 7.51114e-05 1.72498e-05 13
7.622200536471e+00 1.64833 133.89 5.59e-05 1.72498e-05 13 7.622200536471e+00 1.64833 133.89 5.59e-05 1.72498e-05 13
%% Cell type:markdown id:c2ab0979-6575-481d-9c1c-ca98517b2437 tags: %% Cell type:markdown id:c2ab0979-6575-481d-9c1c-ca98517b2437 tags:
### Binary star population ### Binary star population
We can also set up a population that samples binary systems, by adding extra grid variables. Below is an example of a full script that runs a binary population and registers when a double compact object is formed. The logging is rather compact and should be expanded to be more useful. Also note that we run very little systems in the following example, as its just intended to show how the code works. We can also set up a population that samples binary systems, by adding extra grid variables. Below is an example of a full script that runs a binary population and registers when a double compact object is formed. The logging is rather compact and should be expanded to be more useful. Also note that we run very little systems in the following example, as its just intended to show how the code works.
%% Cell type:code id:79acdbb2-7dd6-45c4-9609-80994f03619a tags: %% Cell type:code id:79acdbb2-7dd6-45c4-9609-80994f03619a tags:
``` python ``` python
def parse_function(self, output): def parse_function(self, output):
""" """
Example parsing function Example parsing function
""" """
# extract info from the population instance # extract info from the population instance
# Get some information from the # Get some information from the
data_dir = self.custom_options["data_dir"] data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"] base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary # Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True) os.makedirs(data_dir, exist_ok=True)
# #
seperator = " " seperator = " "
# Create filename # Create filename
outfilename = os.path.join(data_dir, base_filename) outfilename = os.path.join(data_dir, base_filename)
# The header columns matching this # The header columns matching this
parameters = [ parameters = [
"time", "time",
"mass_1", "zams_mass_1", "mass_2", "zams_mass_2", "mass_1", "zams_mass_1", "mass_2", "zams_mass_2",
"stellar_type_1", "prev_stellar_type_1", "stellar_type_2", "prev_stellar_type_2", "stellar_type_1", "prev_stellar_type_1", "stellar_type_2", "prev_stellar_type_2",
"metallicity", "probability" "metallicity", "probability"
] ]
# Go over the output. # Go over the output.
for el in output.splitlines(): for el in output.splitlines():
headerline = el.split()[0] headerline = el.split()[0]
# CHeck the header and act accordingly # CHeck the header and act accordingly
if headerline == "EXAMPLE_DCO": if headerline == "EXAMPLE_DCO":
values = el.split()[1:] values = el.split()[1:]
if not len(parameters) == len(values): if not len(parameters) == len(values):
print("Number of column names isnt equal to number of columns") print("Number of column names isnt equal to number of columns")
raise ValueError raise ValueError
if not os.path.exists(outfilename): if not os.path.exists(outfilename):
with open(outfilename, "w") as f: with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n") f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f: with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n") f.write(seperator.join(values) + "\n")
# Create population object # Create population object
example_pop = Population() example_pop = Population()
# If you want verbosity, set this before other things # If you want verbosity, set this before other things
example_pop.set(verbosity=0) example_pop.set(verbosity=0)
# Setting values can be done via .set(<parameter_name>=<value>) # Setting values can be done via .set(<parameter_name>=<value>)
example_pop.set( example_pop.set(
# binary_c physics options # binary_c physics options
M_1=10, # bse_options M_1=10, # bse_options
separation=0, # bse_options separation=0, # bse_options
orbital_period=45000000080, # bse_options orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options eccentricity=0.02, # bse_options
# grid_options # grid_options
num_cores=2, # grid_options num_cores=2, # grid_options
tmp_dir=TMP_DIR, tmp_dir=TMP_DIR,
# Custom options: the data directory and the output filename # Custom options: the data directory and the output filename
data_dir=os.path.join( data_dir=os.path.join(
TMP_DIR, "example_python_population_result" TMP_DIR, "example_python_population_result"
), # custom_options ), # custom_options
base_filename="example_pop.dat", # custom_options base_filename="example_pop.dat", # custom_options
) )
# Creating a parsing function # Creating a parsing function
example_pop.set( example_pop.set(
parse_function=parse_function, # Setting the parse function thats used in the evolve_population parse_function=parse_function, # Setting the parse function thats used in the evolve_population
) )
### Custom logging ### Custom logging
# Log the moment when the star turns into neutron # Log the moment when the star turns into neutron
example_pop.set( example_pop.set(
C_logging_code=""" C_logging_code="""
// logger to find gravitational wave progenitors // logger to find gravitational wave progenitors
if(stardata->star[0].stellar_type>=NS && stardata->star[1].stellar_type>=NS) if(stardata->star[0].stellar_type>=NS && stardata->star[1].stellar_type>=NS)
{ {
if (stardata->model.time < stardata->model.max_evolution_time) if (stardata->model.time < stardata->model.max_evolution_time)
{ {
Printf("EXAMPLE_DCO %30.12e " // 1 Printf("EXAMPLE_DCO %30.12e " // 1
"%g %g %g %g " // 2-5 "%g %g %g %g " // 2-5
"%d %d %d %d " // 6-9 "%d %d %d %d " // 6-9
"%g %g\\n", // 10-11 "%g %g\\n", // 10-11
stardata->model.time, // 1 stardata->model.time, // 1
stardata->star[0].mass, //2 stardata->star[0].mass, //2
stardata->common.zero_age.mass[0], //3 stardata->common.zero_age.mass[0], //3
stardata->star[1].mass, //4 stardata->star[1].mass, //4
stardata->common.zero_age.mass[1], //5 stardata->common.zero_age.mass[1], //5
stardata->star[0].stellar_type, //6 stardata->star[0].stellar_type, //6
stardata->previous_stardata->star[0].stellar_type, //7 stardata->previous_stardata->star[0].stellar_type, //7
stardata->star[1].stellar_type, //8 stardata->star[1].stellar_type, //8
stardata->previous_stardata->star[1].stellar_type, //9 stardata->previous_stardata->star[1].stellar_type, //9
// model stuff // model stuff
stardata->common.metallicity, //10 stardata->common.metallicity, //10
stardata->model.probability //11 stardata->model.probability //11
); );
} }
/* Kill the simulation to safe time */ /* Kill the simulation to safe time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm; stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
} }
""" """
) )
# Add grid variables # Add grid variables
resolution = {"M_1": 3, "q": 3, "per": 3} resolution = {"M_1": 3, "q": 3, "per": 3}
# Mass # Mass
example_pop.add_grid_variable( example_pop.add_grid_variable(
name="lnm1", name="lnm1",
longname="Primary mass", longname="Primary mass",
valuerange=[2, 150], valuerange=[2, 150],
samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]), samplerfunc="self.const_linear(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)", precode="M_1=math.exp(lnm1)",
probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1", probdist="self.three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1", dphasevol="dlnm1",
parameter_name="M_1", parameter_name="M_1",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
) )
# Mass ratio # Mass ratio
example_pop.add_grid_variable( example_pop.add_grid_variable(
name="q", name="q",
longname="Mass ratio", longname="Mass ratio",
valuerange=["0.1/M_1", 1], valuerange=["0.1/M_1", 1],
samplerfunc="self.const_linear(0.1/M_1, 1, {})".format(resolution['q']), samplerfunc="self.const_linear(0.1/M_1, 1, {})".format(resolution['q']),
probdist="self.flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])", probdist="self.flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])",
dphasevol="dq", dphasevol="dq",
precode="M_2 = q * M_1", precode="M_2 = q * M_1",
parameter_name="M_2", parameter_name="M_2",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
) )
# #
example_pop.add_grid_variable( example_pop.add_grid_variable(
name="log10per", # in days name="log10per", # in days
longname="log10(Orbital_Period)", longname="log10(Orbital_Period)",
valuerange=[0.15, 5.5], valuerange=[0.15, 5.5],
samplerfunc="self.const_linear(0.15, 5.5, {})".format(resolution["per"]), samplerfunc="self.const_linear(0.15, 5.5, {})".format(resolution["per"]),
precode="""orbital_period = 10** log10per precode="""orbital_period = 10** log10per
sep = calc_sep_from_period(M_1, M_2, orbital_period) sep = calc_sep_from_period(M_1, M_2, orbital_period)
sep_min = calc_sep_from_period(M_1, M_2, 10**0.15) sep_min = calc_sep_from_period(M_1, M_2, 10**0.15)
sep_max = calc_sep_from_period(M_1, M_2, 10**5.5)""", sep_max = calc_sep_from_period(M_1, M_2, 10**5.5)""",
probdist="self.sana12(M_1, M_2, sep, orbital_period, sep_min, sep_max, math.log10(10**0.15), math.log10(10**5.5), -0.55)", probdist="self.sana12(M_1, M_2, sep, orbital_period, sep_min, sep_max, math.log10(10**0.15), math.log10(10**5.5), -0.55)",
parameter_name="orbital_period", parameter_name="orbital_period",
dphasevol="dlog10per", dphasevol="dlog10per",
) )
# Exporting of all the settings can be done with .export_all_info() # Exporting of all the settings can be done with .export_all_info()
example_pop.export_all_info() example_pop.export_all_info()
# remove the result file if it exists # remove the result file if it exists
if os.path.isfile(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")): if os.path.isfile(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")):
os.remove(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat")) os.remove(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"))
# Evolve the population # Evolve the population
example_pop.evolve() example_pop.evolve()
# #
with open(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"), 'r') as f: with open(os.path.join(TMP_DIR, "example_python_population_result", "example_pop.dat"), 'r') as f:
output = f.read() output = f.read()
print("\n") print("\n")
print(output) print(output)
``` ```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment