"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:"
"Population-c8a5c8285f6047bfa420a68ccc89a04f finished! The total probability was: 0.05150046619238191. It took a total of 0.8319869041442871s to run 20 systems on 2 cores\n",
"Population-2a7732d03e594ef4b5dfe9051b41d9c0 finished! The total probability was: 0.05150046619238191. It took a total of 0.7797017097473145s to run 20 systems on 2 cores\n",
"with a total probability of 0.05150046619238192\n",
"Total starcount for this run will be: 20\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Process Process-5:\n",
"Traceback (most recent call last):\n",
"Process Process-6:\n",
"Traceback (most recent call last):\n",
" File \"/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py\", line 258, in _bootstrap\n",
" self.run()\n",
" File \"/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py\", line 93, in run\n",
" self._target(*self._args, **self._kwargs)\n",
" File \"/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py\", line 258, in _bootstrap\n",
" self.run()\n",
" File \"/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py\", line 1312, in _process_run_population_grid\n",
" self._evolve_system_mp(full_system_dict)\n",
" File \"/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py\", line 93, in run\n",
" self._target(*self._args, **self._kwargs)\n",
" File \"/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py\", line 1312, in _process_run_population_grid\n",
" self._evolve_system_mp(full_system_dict)\n",
" File \"/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py\", line 1128, in _evolve_system_mp\n",
" File \"<ipython-input-12-6a22064fcbfb>\", line 30, in parse_function\n",
" for el in output_lines(output):\n",
"NameError: name 'output_lines' is not defined\n",
" File \"/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py\", line 1128, in _evolve_system_mp\n",
"\u001b[0;32m<ipython-input-12-6a22064fcbfb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 127\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 128\u001b[0m \u001b[0;31m# Evolve the population\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 129\u001b[0;31m \u001b[0mexample_pop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mevolve\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 130\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 131\u001b[0m \u001b[0;31m#\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py\u001b[0m in \u001b[0;36mevolve\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 766\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 767\u001b[0m \u001b[0;31m# Execute population evolution subroutines\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 768\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mevolve_population\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 769\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 770\u001b[0m \u001b[0;31m# Put all interesting stuff in a variable and output that afterwards, as analytics of the run.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"Population-3680f3882c0a449c944462abffea2447 finished! The total probability was: 0.05150046619238191. It took a total of 0.6246354579925537s to run 20 systems on 2 cores\n",
"There were no errors found in this run.\n",
"\n",
"\n",
"time mass zams_mass probability radius stellar_type\n",
"We can also set up a population that samples biinary 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 top be more useful"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1c8f4d66-536a-44a9-b044-d284784536ec",
"execution_count": 14,
"id": "79acdbb2-7dd6-45c4-9609-80994f03619a",
"metadata": {},
"outputs": [],
"source": []
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generating grid code\n",
"Constructing/adding: lnm1\n",
"Constructing/adding: q\n",
"Constructing/adding: log10per\n",
"Grid has handled 125 stars\n",
"with a total probability of 0.0862478164626921\n",
"Total starcount for this run will be: 125\n",
"Generating grid code\n",
"Constructing/adding: lnm1\n",
"Constructing/adding: q\n",
"Constructing/adding: log10per\n",
"Population-d20a4c74d20a43b881c0c9e5def5f76c finished! The total probability was: 0.08624781646269201. It took a total of 8.561265707015991s to run 125 systems on 2 cores\n",
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.
At the bottom of this notebook there are some complete example scripts
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:
- 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.
- 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>']`
<<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python/example_python_population_result to custom_options >>>>
<<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>>
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:
- population settings (bse_options, grid_options, custom_options), turn off with include_population
settings=False
- binary_c_defaults (all the commandline arguments that binary c accepts, and their defaults).
turn off with include_binary_c_defaults=False
- include_binary_c_version_info (all the compilation info, and information about the compiled
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),
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=<>
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.
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).
To add a grid variable to the population object we use `example_pop.add_grid_variable` (see next cell)
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:
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.
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`).
In the code below we will set up both the custom logging, and a parse function to handle that output
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 `amt_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
Population-c8a5c8285f6047bfa420a68ccc89a04f finished! The total probability was: 0.05150046619238191. It took a total of 0.8319869041442871s to run 20 systems on 2 cores
Population-2a7732d03e594ef4b5dfe9051b41d9c0 finished! The total probability was: 0.05150046619238191. It took a total of 0.7797017097473145s to run 20 systems on 2 cores
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.
Function that loops over the grid code and writes the generated parameters to a file.
In the form of a command line call
Only useful when you have a variable grid as system_generator. MC wouldn't be that useful
Also, make sure that in this export there are the basic parameters
like m1,m2,sep, orb-per, ecc, probability etc.
On default this will write to the datadir, if it exists
Tasks:
- TODO: test this function
- TODO: make sure the binary_c_python .. output file has a unique name
Args:
output_dir: (optional, default = None) directory where to write the file to. If custom_options['data_dir'] is present, then that one will be used first, and then the output_dir
output_filename: (optional, default = None) filename of the output. If not set it will be called "binary_c_calls.txt"
include_defaults: (optional, default = None) whether to include the defaults of binary_c in the lines that are written. Beware that this will result in very long lines, and it might be better to just export the binary_c defaults and keep them in a separate file.
Returns:
filename: filename that was used to write the calls to
File "/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py", line 1312, in _process_run_population_grid
self._evolve_system_mp(full_system_dict)
File "/home/david/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py", line 1312, in _process_run_population_grid
self._evolve_system_mp(full_system_dict)
File "/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py", line 1128, in _evolve_system_mp
self.grid_options["parse_function"](self, out)
File "<ipython-input-12-6a22064fcbfb>", line 30, in parse_function
for el in output_lines(output):
NameError: name 'output_lines' is not defined
File "/home/david/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py", line 1128, in _evolve_system_mp
self.grid_options["parse_function"](self, out)
File "<ipython-input-12-6a22064fcbfb>", line 30, in parse_function
for el in output_lines(output):
NameError: name 'output_lines' is not defined
Generating grid code
Constructing/adding: lnm1
Population-3680f3882c0a449c944462abffea2447 finished! The total probability was: 0.05150046619238191. It took a total of 0.6246354579925537s to run 20 systems on 2 cores
There were no errors found in this run.
time mass zams_mass probability radius stellar_type
~/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/managers.py in _callmethod(self, methodname, args, kwds)
755
756 conn.send((self._id, methodname, args, kwds))
--> 757 kind, result = conn.recv()
758
759 if kind == '#RETURN':
~/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/connection.py in recv(self)
248 self._check_closed()
249 self._check_readable()
--> 250 buf = self._recv_bytes()
251 return _ForkingPickler.loads(buf.getbuffer())
252
~/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/connection.py in _recv_bytes(self, maxsize)
405
406 def _recv_bytes(self, maxsize=None):
--> 407 buf = self._recv(4)
408 size, = struct.unpack("!i", buf.getvalue())
409 if maxsize is not None and size > maxsize:
~/.pyenv/versions/3.6.4/lib/python3.6/multiprocessing/connection.py in _recv(self, size, read)
377 remaining = size
378 while remaining > 0:
--> 379 chunk = read(handle, remaining)
380 n = len(chunk)
381 if n == 0:
KeyboardInterrupt:
We can also set up a population that samples biinary 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 top be more useful
Population-d20a4c74d20a43b881c0c9e5def5f76c finished! The total probability was: 0.08624781646269201. It took a total of 8.561265707015991s to run 125 systems on 2 cores
There were no errors found in this run.
time mass_1 zams_mass_1 mass_2 zams_mass_2 stellar_type_1 prev_stellar_type_1 stellar_type_2 prev_stellar_type_2 metallicity probability