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

updated population notebook

parent 0b646fdf
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:bbbaafbb-fd7d-4b73-a970-93506ba35d71 tags:
# Setting up populations
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
%% Cell type:code id:bf6b8673-a2b5-4b50-ad1b-e90671f57470 tags:
``` python
import os
from binarycpython.utils.custom_logging_functions import temp_dir
from binarycpython.utils.grid import Population
# help(Population) # Uncomment to see the public functions of this object
```
%% Cell type:markdown id:a081ab23-7822-4971-aa82-991548534714 tags:
- running ensemble
- using the output
- using M&S grid
%% Cell type:markdown id:f268eff3-4e08-4f6b-8b59-f22dba4d2074 tags:
## 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.
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>']`
%% Cell type:code id:79ab50b7-591f-4883-af09-116d1835a751 tags:
``` python
# Create population object
example_pop = Population()
# If you want verbosity, set this before other things
example_pop.set(verbosity=1)
# Setting values can be done via .set(<parameter_name>=<value>)
# 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
# All other values that you set are put in a custom_options dict
example_pop.set(
# binary_c physics options
M_1=10, # bse_options
orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options
# grid_options
amt_cores=2, # grid_options
# Custom options # TODO: need to be set in grid_options probably
data_dir=os.path.join(
temp_dir(), "example_python_population_result"
), # custom_options
base_filename="example_pop.dat", # custom_options
)
# We can use the options through
print(example_pop.grid_options['verbosity'])
print(example_pop.custom_options['base_filename'])
print(example_pop.bse_options['M_1'])
```
%% Output
adding: M_1=10 to BSE_options
adding: orbital_period=45000000080 to BSE_options
adding: max_evolution_time=15000 to BSE_options
adding: eccentricity=0.02 to BSE_options
adding: amt_cores=2 to grid_options
<<<< 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 >>>>
1
example_pop.dat
10
%% 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()`.
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=<>
%% Cell type:code id:b9c2471a-a5b0-48b7-a50b-2f0d22100926 tags:
``` python
example_pop.export_all_info()
```
%% Output
Writing settings to /tmp/binary_c_python/example_python_population_result/example_pop_settings.json
'/tmp/binary_c_python/example_python_population_result/example_pop_settings.json'
%% Cell type:markdown id:f9a65554-36ab-4a04-96ca-9f1422c307fd tags:
## 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.
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)
%% Cell type:code id:68c84521-9ae8-4020-af7a-5334173db969 tags:
``` python
help(example_pop.add_grid_variable)
```
%% Output
Help on method add_grid_variable in module binarycpython.utils.grid:
add_grid_variable(name:str, longname:str, valuerange:Union[list, str], resolution:str, spacingfunc:str, probdist:str, dphasevol:Union[str, int], parameter_name:str, gridtype:str='edge', branchpoint:int=0, precode:Union[str, NoneType]=None, condition:Union[str, NoneType]=None) -> None method of binarycpython.utils.grid.Population instance
Function to add grid variables to the grid_options.
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.
The real function that generates the numbers will get written to a new file in the TMP_DIR,
and then loaded imported and evaluated.
beware that if you insert some destructive piece of code, it will be executed anyway.
Use at own risk.
Tasks:
- TODO: Fix this complex function.
Args:
name:
name of parameter. This is evaluated as a parameter and you can use it throughout
the rest of the function
Examples:
name = 'lnm1'
longname:
Long name of parameter
Examples:
longname = 'Primary mass'
range:
Range of values to take. Does not get used really, the spacingfunction is used to
get the values from
Examples:
range = [math.log(m_min), math.log(m_max)]
resolution:
Resolution of the sampled range (amount of samples).
TODO: check if this is used anywhere
Examples:
resolution = resolution["M_1"]
spacingfunction:
Function determining how the range is sampled. You can either use a real function,
or a string representation of a function call. Will get written to a file and
then evaluated.
Examples:
spacingfunction = "const(math.log(m_min), math.log(m_max), {})".format(resolution['M_1'])
precode:
Extra room for some code. This code will be evaluated within the loop of the
sampling function (i.e. a value for lnm1 is chosen already)
Examples:
precode = 'M_1=math.exp(lnm1);'
probdist:
Function determining the probability that gets assigned to the sampled parameter
Examples:
probdist = 'Kroupa2001(M_1)*M_1'
dphasevol:
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
Examples:
dphasevol = 'dlnm1'
condition:
condition that has to be met in order for the grid generation to continue
Examples:
condition = 'self.grid_options['binary']==1'
gridtype:
Method on how the value range is sampled. Can be either 'edge' (steps starting at
the lower edge of the value range) or 'center'
(steps starting at lower edge + 0.5 * stepsize).
%% 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:
%% Cell type:code id:048db541-3e92-4c5d-a25c-9c5a34b9c857 tags:
``` python
# import binarycpython.utils.distribution_functions
# help(binarycpython.utils.distribution_functions)
```
%% 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.
%% Cell type:code id:47979841-2c26-4b26-8945-603d013dc93a tags:
``` python
# Add grid variables
resolution = {"M_1": 20, "q": 20, "per": 40}
# Mass
example_pop.add_grid_variable(
name="lnm1",
longname="Primary mass",
valuerange=[2, 150],
resolution="{}".format(resolution["M_1"]),
spacingfunc="const(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)",
probdist="three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1",
parameter_name="M_1",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
)
# # Mass ratio
# test_pop.add_grid_variable(
# name="q",
# longname="Mass ratio",
# valuerange=["0.1/M_1", 1],
# resolution="{}".format(resolution['q']),
# spacingfunc="const(0.1/M_1, 1, {})".format(resolution['q']),
# probdist="flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])",
# dphasevol="dq",
# precode="M_2 = q * M_1",
# parameter_name="M_2",
# condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
# )
# #
# test_pop.add_grid_variable(
# name="log10per", # in days
# longname="log10(Orbital_Period)",
# valuerange=[0.15, 5.5],
# resolution="{}".format(resolution["per"]),
# spacingfunc="const(0.15, 5.5, {})".format(resolution["per"]),
# precode="""orbital_period = 10** log10per
# 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_max = calc_sep_from_period(M_1, M_2, 10**5.5)""",
# probdist="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",
# dphasevol="dlog10per",
# )
```
%% Output
Added grid variable: {
"name": "lnm1",
"longname": "Primary mass",
"valuerange": [
2,
150
],
"resolution": "20",
"spacingfunc": "const(math.log(2), math.log(150), 20)",
"precode": "M_1=math.exp(lnm1)",
"probdist": "three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
"dphasevol": "dlnm1",
"parameter_name": "M_1",
"condition": "",
"gridtype": "edge",
"branchpoint": 0,
"grid_variable_number": 0
}
%% Cell type:markdown id:163f13ae-fec1-4ee8-b9d4-c1b75c19ff39 tags:
## 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.
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
%% Cell type:code id:0c986215-93b1-4e30-ad79-f7c397e9ff7d tags:
``` python
# 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_statement = """
if(stardata->star[0].stellar_type >= 13)
{
if (stardata->model.time < stardata->model.max_evolution_time)
{
Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\\n",
//
stardata->model.time, // 1
stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 3
stardata->model.probability, // 4
stardata->star[0].stellar_type // 5
);
};
/* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
};
"""
example_pop.set(
C_logging_code=custom_logging_statement
)
```
%% Output
adding: C_logging_code=
if(stardata->star[0].stellar_type >= 13)
{
if (stardata->model.time < stardata->model.max_evolution_time)
{
Printf("EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\n",
//
stardata->model.time, // 1
stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 3
stardata->model.probability, // 4
stardata->star[0].stellar_type // 5
);
};
/* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
};
to grid_options
%% 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
%% Cell type:code id:fd197154-a8ce-4865-8929-008d3483101a tags:
``` python
def parse_function(self, output):
"""
Example parse function
"""
# get info from the population instance
data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True)
seperator = " "
# Create filename
outfilename = os.path.join(data_dir, base_filename)
parameters = ["time", "mass", "zams_mass", "probability", "stellar_type"]
# Go over the output.
for line in output.splitlines():
headerline = line.split()[0]
# CHeck the header and act accordingly
if headerline == "EXAMPLE_COMPACT_OBJECT":
values = line.split()[1:]
print(line)
if not len(parameters) == len(values):
print("Amount of column names isnt equal to amount of columns")
raise ValueError
if not os.path.exists(outfilename):
with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n")
# Add the parsing function
example_pop.set(
parse_function=parse_function,
)
```
%% Output
adding: parse_function=<function parse_function at 0x7f54b3a21a60> to grid_options
adding: parse_function=<function parse_function at 0x7ff3bdf79620> to grid_options
%% Cell type:markdown id:91509ce5-ffe7-4937-aa87-6d7baac9ac04 tags:
## 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()`
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
%% Cell type:code id:8ea376c1-1e92-45af-8cab-9d7fdca564eb tags:
``` python
# change verbosity
example_pop.set(verbosity=0)
## Executing a population
## This uses the values generated by the grid_variables
analytics = example_pop.evolve() # TODO: update this function call
```
%% Output
adding: verbosity=0 to grid_options
Generating grid code
Constructing/adding: lnm1
Grid has handled 20 stars
with a total probability of 0.05150046619238192
Total starcount for this run will be: 20
EXAMPLE_COMPACT_OBJECT 2.867655467480e+01 1.33079 9.81391 0.00167028 13
Generating grid code
Constructing/adding: lnm1
EXAMPLE_COMPACT_OBJECT 2.867655467480e+01 1.33079 9.81391 0.00167028 13
EXAMPLE_COMPACT_OBJECT 4.439623364590e+01 1.38004 7.81906 0.00224431 13
EXAMPLE_COMPACT_OBJECT 1.931266944719e+01 1.3933 12.3177 0.00124307 13
EXAMPLE_COMPACT_OBJECT 4.439623364590e+01 1.38004 7.81906 0.00224431 13
EXAMPLE_COMPACT_OBJECT 1.364277535630e+01 1.47961 15.4603 0.000925128 13
EXAMPLE_COMPACT_OBJECT 1.017435498578e+01 1.59052 19.4046 0.000688507 13
EXAMPLE_COMPACT_OBJECT 8.294870923827e+00 1.7197 24.3552 0.000512406 13
EXAMPLE_COMPACT_OBJECT 6.802132608769e+00 1.84162 30.5689 0.000381347 13
EXAMPLE_COMPACT_OBJECT 5.723570798020e+00 1.99471 38.3678 0.00028381 13
EXAMPLE_COMPACT_OBJECT 4.933751523833e+00 2.15875 48.1564 0.000211219 13
EXAMPLE_COMPACT_OBJECT 4.337250536639e+00 2.35209 60.4424 0.000157195 14
EXAMPLE_COMPACT_OBJECT 3.862081089332e+00 2.56776 75.8628 0.000116989 14
EXAMPLE_COMPACT_OBJECT 3.449960890183e+00 2.80457 95.2174 8.70668e-05 14
EXAMPLE_COMPACT_OBJECT 3.172196856333e+00 3.05193 119.51 6.47976e-05 14
EXAMPLE_COMPACT_OBJECT 3.069627290216e+00 3.27563 150 4.82242e-05 14
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
There were no errors found in this run.
%% 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.
%% Cell type:code id:e1f0464b-0424-4022-b34b-5b744bc2c59d tags:
``` python
print(analytics)
```
%% Output
{'population_name': 'c8a5c8285f6047bfa420a68ccc89a04f', 'evolution_type': 'grid', 'failed_count': 0, 'failed_prob': 0, 'failed_systems_error_codes': [], 'errors_exceeded': False, 'errors_found': False, 'total_probability': 0.05150046619238191, 'total_count': 20, 'start_timestamp': 1628442540.4302576, 'end_timestamp': 1628442541.2622445, 'total_mass_run': 730.1048014407228, 'total_probability_weighted_mass_run': 0.2983275843337705, 'zero_prob_stars_skipped': 0}
{'population_name': '2a7732d03e594ef4b5dfe9051b41d9c0', 'evolution_type': 'grid', 'failed_count': 0, 'failed_prob': 0, 'failed_systems_error_codes': [], 'errors_exceeded': False, 'errors_found': False, 'total_probability': 0.05150046619238191, 'total_count': 20, 'start_timestamp': 1628444120.234709, 'end_timestamp': 1628444121.0144107, 'total_mass_run': 730.1048014407228, 'total_probability_weighted_mass_run': 0.2983275843337705, 'zero_prob_stars_skipped': 0}
%% Cell type:markdown id:6460df56-9fba-4817-9a1e-593ef15d98c1 tags:
## Noteworthy functionality
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
%% Cell type:code id:83f8e519-4f7c-474a-ad95-f175a34fae81 tags:
``` python
help(example_pop.write_binary_c_calls_to_file)
```
%% Output
Help on method write_binary_c_calls_to_file in module binarycpython.utils.grid:
write_binary_c_calls_to_file(output_dir:Union[str, NoneType]=None, output_filename:Union[str, NoneType]=None, include_defaults:bool=False) -> None method of binarycpython.utils.grid.Population instance
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
%% Cell type:code id:dacfed75-dfe3-4afd-a0ff-a4be17746021 tags:
``` python
example_pop.set(verbosity=10)
calls_filename = example_pop.write_binary_c_calls_to_file()
print(calls_filename)
with open(calls_filename, 'r') as f:
print('\n'.join(f.read().splitlines()[:4]))
```
%% Output
adding: verbosity=10 to grid_options
Generating grid code
Generating grid code
Constructing/adding: lnm1
Saving grid code to grid_options
Writing grid code to /tmp/binary_c_python/binary_c_grid_2a7732d03e594ef4b5dfe9051b41d9c0.py
Loading grid code function from /tmp/binary_c_python/binary_c_grid_2a7732d03e594ef4b5dfe9051b41d9c0.py
Grid code loaded
Writing binary_c calls to /tmp/binary_c_python/example_python_population_result/binary_c_calls.txt
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
_calculate_multiplicity_fraction: Chosen not to use any multiplicity fraction.
Grid has handled 20 stars
with a total probability of 0.25750233096190955
with a total probability of 0.05150046619238192
/tmp/binary_c_python/example_python_population_result/binary_c_calls.txt
binary_c M_1 2.0 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.013208238029791246 separation 0
binary_c M_1 2.5102526289471614 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.009829948023831718 separation 0
binary_c M_1 3.1506841305680684 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.0073157281034221516 separation 0
binary_c M_1 3.9545065608702976 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.005444573822104362 separation 0
binary_c M_1 2.0 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.013208238029791246
binary_c M_1 2.5102526289471614 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.009829948023831718
binary_c M_1 3.1506841305680684 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.0073157281034221516
binary_c M_1 3.9545065608702976 eccentricity 0.02 max_evolution_time 15000 orbital_period 45000000080 phasevol 0.22723621650191106 probability 0.005444573822104362
%% Cell type:markdown id:60359eb1-4d0c-4d2d-8265-ec5171b944a2 tags:
# Full example 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:
``` python
import os
from binarycpython.utils.grid import Population
from binarycpython.utils.custom_logging_functions import temp_dir
def parse_function(self, output):
"""
Example parsing function
"""
# extract info from the population instance
# Get some information from the
data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True)
#
seperator = " "
# Create filename
outfilename = os.path.join(data_dir, base_filename)
# The header columns matching this
parameters = ["time", "mass", "zams_mass", "probability", "radius", "stellar_type"]
# Go over the output.
for el in output.splitlines():
headerline = el.split()[0]
# CHeck the header and act accordingly
if headerline == "MY_STELLAR_DATA":
values = el.split()[1:]
if not len(parameters) == len(values):
print("Amount of column names isnt equal to amount of columns")
raise ValueError
if not os.path.exists(outfilename):
with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n")
# Create population object
example_pop = Population()
# If you want verbosity, set this before other things
example_pop.set(verbosity=0)
# Setting values can be done via .set(<parameter_name>=<value>)
example_pop.set(
# binary_c physics options
M_1=10, # bse_options
separation=0, # bse_options
orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options
# grid_options
amt_cores=2, # grid_options
# Custom options: the data directory and the output filename
data_dir=os.path.join(
temp_dir(), "example_python_population_result"
), # custom_options
base_filename="example_pop.dat", # custom_options
)
# Creating a parsing function
example_pop.set(
parse_function=parse_function, # Setting the parse function thats used in the evolve_population
)
### Custom logging
# Log the moment when the star turns into neutron
example_pop.set(
C_logging_code="""
if(stardata->star[0].stellar_type >= 13)
{
if (stardata->model.time < stardata->model.max_evolution_time)
{
Printf("MY_STELLAR_DATA %30.12e %g %g %g %g %d\\n",
//
stardata->model.time, // 1
stardata->star[0].mass, // 2
stardata->common.zero_age.mass[0], // 4
stardata->model.probability, // 5
stardata->star[0].radius, // 6
stardata->star[0].stellar_type // 7
);
};
/* Kill the simulation to save time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
};
"""
)
# Add grid variables
resolution = {"M_1": 20}
# Mass
example_pop.add_grid_variable(
name="lnm1",
longname="Primary mass",
valuerange=[2, 150],
resolution="{}".format(resolution["M_1"]),
spacingfunc="const(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)",
probdist="three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1",
parameter_name="M_1",
condition="",
)
# Exporting of all the settings can be done with .export_all_info()
example_pop.export_all_info()
# remove the result file if it exists
if os.path.isfile(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat")):
os.remove(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat"))
# Evolve the population
example_pop.evolve()
#
with open(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat"), 'r') as f:
output = f.read()
print("\n")
print(output)
```
%% Output
Generating grid code
Constructing/adding: lnm1
Grid has handled 20 stars
with a total probability of 0.05150046619238192
Total starcount for this run will be: 20
Process Process-5:
Traceback (most recent call last):
Process Process-6:
Traceback (most recent call last):
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
2.867655467480e+01 1.33079 9.81391 0.00167028 1.72498e-05 13
1.931266944719e+01 1.3933 12.3177 0.00124307 1.72498e-05 13
4.439623364590e+01 1.38004 7.81906 0.00224431 1.72498e-05 13
1.364277535630e+01 1.47961 15.4603 0.000925128 1.72498e-05 13
1.017435498578e+01 1.59052 19.4046 0.000688507 1.72498e-05 13
8.294870923827e+00 1.7197 24.3552 0.000512406 1.72498e-05 13
6.802132608769e+00 1.84162 30.5689 0.000381347 1.72498e-05 13
5.723570798020e+00 1.99471 38.3678 0.00028381 1.72498e-05 13
4.933751523833e+00 2.15875 48.1564 0.000211219 1.72498e-05 13
4.337250536639e+00 2.35209 60.4424 0.000157195 9.97286e-06 14
3.862081089332e+00 2.56776 75.8628 0.000116989 1.08873e-05 14
3.449960890183e+00 2.80457 95.2174 8.70668e-05 1.18914e-05 14
3.172196856333e+00 3.05193 119.51 6.47976e-05 1.29402e-05 14
3.069627290216e+00 3.27563 150 4.82242e-05 1.38887e-05 14
%% Cell type:markdown id:c2ab0979-6575-481d-9c1c-ca98517b2437 tags:
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
<ipython-input-12-6a22064fcbfb> in <module>
127
128 # Evolve the population
--> 129 example_pop.evolve()
130
131 #
~/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py in evolve(self)
766 else:
767 # Execute population evolution subroutines
--> 768 self.evolve_population()
769
770 # Put all interesting stuff in a variable and output that afterwards, as analytics of the run.
~/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py in evolve_population(self)
826 ):
827 if self.grid_options["evolution_type"] == "grid":
--> 828 self._evolve_population_grid()
829 # elif self.grid_options["evolution_type"] == "mc":
830 # # TODO: add MC option
~/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/grid.py in _evolve_population_grid(self)
1037
1038 sentinel = object()
-> 1039 for output_dict in iter(result_queue.get, sentinel):
1040 combined_output_dict = merge_dicts(combined_output_dict, output_dict)
1041 if result_queue.empty():
<string> in get(self, *args, **kwds)
~/.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
%% Cell type:code id:1c8f4d66-536a-44a9-b044-d284784536ec tags:
%% Cell type:code id:79acdbb2-7dd6-45c4-9609-80994f03619a tags:
``` python
import os
from binarycpython.utils.grid import Population
from binarycpython.utils.custom_logging_functions import temp_dir
def parse_function(self, output):
"""
Example parsing function
"""
# extract info from the population instance
# Get some information from the
data_dir = self.custom_options["data_dir"]
base_filename = self.custom_options["base_filename"]
# Check directory, make if necessary
os.makedirs(data_dir, exist_ok=True)
#
seperator = " "
# Create filename
outfilename = os.path.join(data_dir, base_filename)
# The header columns matching this
parameters = [
"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"
]
# Go over the output.
for el in output.splitlines():
headerline = el.split()[0]
# CHeck the header and act accordingly
if headerline == "EXAMPLE_DCO":
values = el.split()[1:]
if not len(parameters) == len(values):
print("Amount of column names isnt equal to amount of columns")
raise ValueError
if not os.path.exists(outfilename):
with open(outfilename, "w") as f:
f.write(seperator.join(parameters) + "\n")
with open(outfilename, "a") as f:
f.write(seperator.join(values) + "\n")
# Create population object
example_pop = Population()
# If you want verbosity, set this before other things
example_pop.set(verbosity=0)
# Setting values can be done via .set(<parameter_name>=<value>)
example_pop.set(
# binary_c physics options
M_1=10, # bse_options
separation=0, # bse_options
orbital_period=45000000080, # bse_options
max_evolution_time=15000, # bse_options
eccentricity=0.02, # bse_options
# grid_options
amt_cores=2, # grid_options
# Custom options: the data directory and the output filename
data_dir=os.path.join(
temp_dir(), "example_python_population_result"
), # custom_options
base_filename="example_pop.dat", # custom_options
)
# Creating a parsing function
example_pop.set(
parse_function=parse_function, # Setting the parse function thats used in the evolve_population
)
### Custom logging
# Log the moment when the star turns into neutron
example_pop.set(
C_logging_code="""
// logger to find gravitational wave progenitors
if(stardata->star[0].stellar_type>=NS && stardata->star[1].stellar_type>=NS)
{
if (stardata->model.time < stardata->model.max_evolution_time)
{
Printf("EXAMPLE_DCO %30.12e " // 1
"%g %g %g %g " // 2-5
"%d %d %d %d " // 6-9
"%g %g\\n", // 10-11
stardata->model.time, // 1
stardata->star[0].mass, //2
stardata->common.zero_age.mass[0], //3
stardata->star[1].mass, //4
stardata->common.zero_age.mass[1], //5
stardata->star[0].stellar_type, //6
stardata->previous_stardata->star[0].stellar_type, //7
stardata->star[1].stellar_type, //8
stardata->previous_stardata->star[1].stellar_type, //9
// model stuff
stardata->common.metallicity, //10
stardata->model.probability //11
);
}
/* Kill the simulation to safe time */
stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
}
"""
)
# Add grid variables
resolution = {"M_1": 5, "q": 5, "per": 5}
# Mass
example_pop.add_grid_variable(
name="lnm1",
longname="Primary mass",
valuerange=[2, 150],
resolution="{}".format(resolution["M_1"]),
spacingfunc="const(math.log(2), math.log(150), {})".format(resolution["M_1"]),
precode="M_1=math.exp(lnm1)",
probdist="three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1",
dphasevol="dlnm1",
parameter_name="M_1",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
)
# Mass ratio
example_pop.add_grid_variable(
name="q",
longname="Mass ratio",
valuerange=["0.1/M_1", 1],
resolution="{}".format(resolution['q']),
spacingfunc="const(0.1/M_1, 1, {})".format(resolution['q']),
probdist="flatsections(q, [{'min': 0.1/M_1, 'max': 1.0, 'height': 1}])",
dphasevol="dq",
precode="M_2 = q * M_1",
parameter_name="M_2",
condition="", # Impose a condition on this grid variable. Mostly for a check for yourself
)
#
example_pop.add_grid_variable(
name="log10per", # in days
longname="log10(Orbital_Period)",
valuerange=[0.15, 5.5],
resolution="{}".format(resolution["per"]),
spacingfunc="const(0.15, 5.5, {})".format(resolution["per"]),
precode="""orbital_period = 10** log10per
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_max = calc_sep_from_period(M_1, M_2, 10**5.5)""",
probdist="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",
dphasevol="dlog10per",
)
# Exporting of all the settings can be done with .export_all_info()
example_pop.export_all_info()
# remove the result file if it exists
if os.path.isfile(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat")):
os.remove(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat"))
# Evolve the population
example_pop.evolve()
#
with open(os.path.join(temp_dir(), "example_python_population_result", "example_pop.dat"), 'r') as f:
output = f.read()
print("\n")
print(output)
```
%% Output
Generating grid code
Constructing/adding: lnm1
Constructing/adding: q
Constructing/adding: log10per
Grid has handled 125 stars
with a total probability of 0.0862478164626921
Total starcount for this run will be: 125
Generating grid code
Constructing/adding: lnm1
Constructing/adding: q
Constructing/adding: log10per
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
8.863377990313e+01 1.29444 5.88566 0 2.99283 13 5 15 15 0.02 0.000627913
1.146421815741e+02 0 5.88566 1.33062 4.43925 15 15 13 5 0.02 0.000627913
7.222715508467e+01 1.34922 5.88566 0 5.88566 13 5 15 15 0.02 0.000627913
1.350021848285e+01 1.48488 17.3205 0 0.1 13 5 15 15 0.02 0.000154349
1.171108213270e+01 1.53113 17.3205 0 0.1 13 5 15 15 0.02 0.000154349
1.171086983243e+01 1.53177 17.3205 0 0.1 13 9 15 15 0.02 0.000154349
1.170770599495e+01 1.53176 17.3205 0 4.40513 13 5 15 15 0.02 0.000172877
1.230407246199e+01 1.59499 17.3205 0 4.40513 13 5 15 15 0.02 0.000610573
1.108751340926e+01 1.70319 17.3205 0 8.71025 13 4 15 15 0.02 0.000610573
1.941017702765e+01 1.34903 17.3205 1.65097 8.71025 13 13 13 5 0.02 0.000172877
1.980988739731e+01 1.36979 17.3205 1.60808 8.71025 13 13 13 5 0.02 0.000121486
3.571858031651e+01 1.53174 17.3205 1.30504 8.71025 13 13 13 5 0.02 8.42148e-05
3.459153942631e+01 1.53176 17.3205 1.31004 8.71025 13 13 13 5 0.02 9.8162e-05
1.687368550125e+01 1.34937 17.3205 1.73856 13.0154 13 13 13 8 0.02 0.000172877
1.194842917007e+01 1.78096 17.3205 0 13.0154 13 8 15 15 0.02 0.000610573
1.733614170983e+01 1.53184 17.3205 1.42375 13.0154 13 13 13 5 0.02 9.8162e-05
1.723547465714e+01 1.38403 17.3205 1.71288 13.0154 13 13 13 8 0.02 0.000121486
1.764340254985e+01 1.53174 17.3205 1.41264 13.0154 13 13 13 5 0.02 8.42148e-05
1.170425790780e+01 1.52963 17.3205 0 17.3205 13 5 15 15 0.02 0.000172877
8.922967341481e+00 1.85486 17.3205 0 17.3205 13 8 15 15 0.02 0.000610573
1.232906623449e+01 1.41074 17.3205 1.34281 17.3205 13 13 13 8 0.02 0.000121486
1.170775828562e+01 1.53183 17.3205 1.53183 17.3205 13 5 13 5 0.02 9.8162e-05
1.170770422321e+01 1.53175 17.3205 1.53175 17.3205 13 5 13 5 0.02 8.42148e-05
5.075844624794e+00 2.12303 50.9713 0 0.1 13 8 15 15 0.02 3.79411e-05
4.766606588165e+00 2.20484 50.9713 0 0.1 14 8 15 15 0.02 3.79411e-05
4.768305081494e+00 2.18838 50.9713 0 0.1 13 8 15 15 0.02 3.79411e-05
4.458869865939e+00 2.29864 50.9713 0 12.8178 14 8 15 15 0.02 0.000150087
1.806014211040e+01 2.10446 50.9713 1.40749 12.8178 13 13 13 5 0.02 2.9863e-05
4.797342083485e+00 2.10328 50.9713 0 12.8178 13 13 15 1 0.02 4.24954e-05
1.721374713429e+01 2.21673 50.9713 1.42212 12.8178 14 14 13 5 0.02 2.41295e-05
4.055645404546e+00 2.47276 50.9713 0 25.5357 14 7 15 15 0.02 0.000150087
1.806123543037e+01 2.21893 50.9713 1.40745 12.8178 14 14 13 5 0.02 2.07011e-05
8.117519147635e+00 2.10433 50.9713 2.21473 25.5357 13 13 14 8 0.02 4.24954e-05
8.315554923168e+00 2.15343 50.9713 2.08519 25.5357 13 13 13 8 0.02 2.9863e-05
7.917420996633e+00 2.21892 50.9713 1.7431 25.5357 14 14 13 8 0.02 2.07011e-05
7.693213405973e+00 2.21805 50.9713 1.78384 25.5357 14 14 13 8 0.02 2.41295e-05
3.753837732894e+00 2.62517 50.9713 0 38.2535 14 7 15 15 0.02 0.000150087
7.087296558990e+00 2.10417 50.9713 2.40935 38.2535 13 13 14 8 0.02 4.24954e-05
7.007109286263e+00 2.15854 50.9713 2.28672 38.2535 13 13 14 8 0.02 2.9863e-05
5.653200958306e+00 2.21878 50.9713 2.0587 38.2535 14 14 13 8 0.02 2.41295e-05
5.733794947644e+00 2.21892 50.9713 1.99255 38.2535 14 14 13 8 0.02 2.07011e-05
3.513216011269e+00 2.76647 50.9713 0 50.9713 14 7 15 15 0.02 0.000150087
4.750574783854e+00 2.27442 50.9713 0 50.9713 14 8 15 15 0.02 4.24954e-05
7.278384712062e+00 1.29678 50.9713 2.09216 50.9713 13 8 13 13 0.02 2.9863e-05
4.765996194699e+00 2.20787 50.9713 2.20787 50.9713 14 8 14 8 0.02 2.07011e-05
4.765535914728e+00 2.21331 50.9713 2.21331 50.9713 14 8 14 8 0.02 2.41295e-05
3.104706358826e+00 3.17639 150 0 0.1 14 7 15 15 0.02 9.32641e-06
3.069363482023e+00 3.27572 150 0 0.1 14 7 15 15 0.02 9.32641e-06
3.047074050271e+00 3.3836 150 0 37.575 14 7 15 15 0.02 3.68933e-05
5.974759306305e+00 3.23604 150 2.53922 37.575 14 14 14 7 0.02 1.04459e-05
6.074084349384e+00 3.30145 150 2.13876 37.575 14 14 13 8 0.02 7.34071e-06
5.733865371895e+00 3.29994 150 2.00498 37.575 14 14 13 8 0.02 5.93135e-06
3.027099358410e+00 3.53631 150 0 75.05 14 7 15 15 0.02 3.68933e-05
5.807147339697e+00 3.30197 150 1.9791 37.575 14 14 13 8 0.02 5.08861e-06
4.862942347290e+00 3.25294 150 2.97823 75.05 14 14 14 7 0.02 1.04459e-05
4.556479830908e+00 3.29942 150 2.73221 75.05 14 14 14 7 0.02 7.34071e-06
3.853070305680e+00 3.29977 150 2.62486 75.05 14 14 14 7 0.02 5.93135e-06
3.881529045940e+00 3.30149 150 2.55924 75.05 14 14 14 7 0.02 5.08861e-06
3.015033359333e+00 3.64419 150 0 112.525 14 7 15 15 0.02 3.68933e-05
4.126828648362e+00 3.32047 150 0 112.525 14 14 15 3 0.02 1.04459e-05
3.990017992944e+00 3.3032 150 2.94027 112.525 14 14 14 7 0.02 7.34071e-06
3.206771867883e+00 3.07671 150 3.11282 112.525 14 14 14 7 0.02 5.93135e-06
3.006827156705e+00 3.72638 150 0 150 14 7 15 15 0.02 3.68933e-05
3.218786094847e+00 3.30337 150 3.01344 112.525 14 14 14 7 0.02 5.08861e-06
4.527722847382e+00 1.42238 150 0 150 13 5 15 15 0.02 1.04459e-05
3.069567332611e+00 3.27804 150 3.27804 150 14 7 14 7 0.02 5.93135e-06
5.726405299909e+00 1.29746 150 3.22759 150 13 8 14 14 0.02 7.34071e-06
3.069626478211e+00 3.27565 150 3.27565 150 14 7 14 7 0.02 5.08861e-06
......
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