From 37dc93033ec3c167fd20ebb22c5ca7dafcf3fc17 Mon Sep 17 00:00:00 2001 From: David Hendriks <davidhendriks93@gmail.com> Date: Sun, 8 Aug 2021 17:48:54 +0100 Subject: [PATCH] updating population notebook --- examples/notebook_extra_features.ipynb | 33 + examples/notebook_population.ipynb | 830 +++++++++++++++++++++---- 2 files changed, 731 insertions(+), 132 deletions(-) create mode 100644 examples/notebook_extra_features.ipynb diff --git a/examples/notebook_extra_features.ipynb b/examples/notebook_extra_features.ipynb new file mode 100644 index 000000000..4827ad5e2 --- /dev/null +++ b/examples/notebook_extra_features.ipynb @@ -0,0 +1,33 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "1e1f31c5-dfa0-43a9-8505-3e1b279b7f2e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebook_population.ipynb b/examples/notebook_population.ipynb index b121d0f55..1e21fe3a8 100644 --- a/examples/notebook_population.ipynb +++ b/examples/notebook_population.ipynb @@ -6,44 +6,85 @@ "metadata": {}, "source": [ "# Setting up populations\n", - "This notebook will show you how to evolve a population of stars\n" + "This notebook will show you how to evolve a population of stars\n", + "\n", + "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. \n", + "\n", + "At the bottom of this notebook there are some complete example scripts" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "id": "bf6b8673-a2b5-4b50-ad1b-e90671f57470", "metadata": {}, "outputs": [], "source": [ "import os\n", + "from binarycpython.utils.custom_logging_functions import temp_dir\n", "from binarycpython.utils.grid import Population\n", - "from binarycpython.utils.functions import (\n", - " get_help_all,\n", - " get_help,\n", - " create_hdf5,\n", - " output_lines,\n", - ")\n", - "from binarycpython.utils.custom_logging_functions import temp_dir" + "\n", + "# help(Population) # Uncomment to see the public functions of this object" + ] + }, + { + "cell_type": "markdown", + "id": "a081ab23-7822-4971-aa82-991548534714", + "metadata": {}, + "source": [ + "- adding custom logging\n", + "- setting up a parse function\n", + "\n", + "- running ensemble\n", + "- using the output\n", + "- using M&S grid" + ] + }, + { + "cell_type": "markdown", + "id": "f268eff3-4e08-4f6b-8b59-f22dba4d2074", + "metadata": {}, + "source": [ + "## Setting up the Population object\n", + "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.\n", + "\n", + "There are three categories of options that the Population object can set:\n", + "- 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. You can access these through `population.bse_options['<bse option name>']` after you have set them. \n", + "\n", + "- 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. They can be accessed via `population.grid_options['<grid option name>']` after you have set them. \n", + "\n", + "- 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", - "execution_count": null, + "execution_count": 37, "id": "79ab50b7-591f-4883-af09-116d1835a751", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "adding: M_1=10 to BSE_options\n", + "adding: orbital_period=45000000080 to BSE_options\n", + "adding: max_evolution_time=15000 to BSE_options\n", + "adding: eccentricity=0.02 to BSE_options\n", + "adding: amt_cores=2 to grid_options\n", + "<<<< Warning: Key does not match previously known parameter: adding: data_dir=/tmp/binary_c_python/example_python_population_result to custom_options >>>>\n", + "<<<< Warning: Key does not match previously known parameter: adding: base_filename=example_pop.dat to custom_options >>>>\n", + "1\n", + "example_pop.dat\n", + "10\n" + ] + } + ], "source": [ - "#########################################################\n", - "# This file serves as an example for running a population.\n", - "# The use of help(<function>) is a good way to inspect what parameters are there to use\n", - "#########################################################\n", - "\n", "# Create population object\n", "example_pop = Population()\n", "\n", "# If you want verbosity, set this before other things\n", - "example_pop.set(verbose=1)\n", + "example_pop.set(verbosity=1)\n", "\n", "# Setting values can be done via .set(<parameter_name>=<value>)\n", "# Values that are known to be binary_c_parameters are loaded into bse_options.\n", @@ -52,115 +93,222 @@ "example_pop.set(\n", " # binary_c physics options\n", " M_1=10, # bse_options\n", - " separation=0, # bse_options\n", " orbital_period=45000000080, # bse_options\n", " max_evolution_time=15000, # bse_options\n", " eccentricity=0.02, # bse_options\n", - " # Set companion to low mass\n", - " M_2=0.08, # Since in the example we run a single system, we should set the companion mass here. If we donm't do this, the code will complain.\n", + "\n", + "\n", " # grid_options\n", " amt_cores=2, # grid_options\n", - " verbose=1, # verbosity. Not fully configured correctly yet but having it value of 1 prints alot of stuff\n", + " \n", " # Custom options # TODO: need to be set in grid_options probably\n", " data_dir=os.path.join(\n", " temp_dir(), \"example_python_population_result\"\n", " ), # custom_options\n", " base_filename=\"example_pop.dat\", # custom_options\n", - ")" + ")\n", + "\n", + "# We can use the options through\n", + "print(example_pop.grid_options['verbosity'])\n", + "print(example_pop.custom_options['base_filename'])\n", + "print(example_pop.bse_options['M_1'])" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "0c986215-93b1-4e30-ad79-f7c397e9ff7d", + "cell_type": "markdown", + "id": "f8d46d19-633d-4911-821d-a59daed31816", "metadata": {}, - "outputs": [], "source": [ - "def parse_function(self, output):\n", - " # EXAMPLE PARSE_FUNCTION\n", - "\n", - " # extract info from the population instance\n", + "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()`.\n", "\n", - " # Get some information from the\n", - " data_dir = self.custom_options[\"data_dir\"]\n", - " base_filename = self.custom_options[\"base_filename\"]\n", - "\n", - " # Check directory, make if necessary\n", - " os.makedirs(data_dir, exist_ok=True)\n", - "\n", - " seperator = \" \"\n", - "\n", - " # Create filename\n", - " outfilename = os.path.join(data_dir, base_filename)\n", - "\n", - " parameters = [\"time\", \"mass\", \"zams_mass\", \"probability\", \"radius\", \"stellar_type\"]\n", - "\n", - " # Go over the output.\n", - " for el in output_lines(output):\n", - " headerline = el.split()[0]\n", - "\n", - " # CHeck the header and act accordingly\n", - " if headerline == \"MY_STELLAR_DATA\":\n", - " values = el.split()[1:]\n", - " print(values)\n", - "\n", - " if not len(parameters) == len(values):\n", - " print(\"Amount of column names isnt equal to amount of columns\")\n", - " raise ValueError\n", + "On default this exports everything, each of the sections can be disabled:\n", + " - population settings (bse_options, grid_options, custom_options), turn off with include_population\n", + " settings=False\n", + " - binary_c_defaults (all the commandline arguments that binary c accepts, and their defaults).\n", + " turn off with include_binary_c_defaults=False\n", + " - include_binary_c_version_info (all the compilation info, and information about the compiled\n", + " parameters), turn off with include_binary_c_version_info=False\n", + " - include_binary_c_help_all (all the help information for all the binary_c parameters),\n", + " turn off with include_binary_c_help_all=Fase\n", + " \n", + "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", + "execution_count": 38, + "id": "b9c2471a-a5b0-48b7-a50b-2f0d22100926", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing settings to /tmp/binary_c_python/example_python_population_result/example_pop_settings.json\n" + ] + }, + { + "data": { + "text/plain": [ + "'/tmp/binary_c_python/example_python_population_result/example_pop_settings.json'" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "example_pop.export_all_info()" + ] + }, + { + "cell_type": "markdown", + "id": "f9a65554-36ab-4a04-96ca-9f1422c307fd", + "metadata": {}, + "source": [ + "## Adding grid variables\n", + "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.\n", "\n", - " if not os.path.exists(outfilename):\n", - " with open(outfilename, \"w\") as f:\n", - " f.write(seperator.join(parameters) + \"\\n\")\n", + "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. \n", "\n", - " with open(outfilename, \"a\") as f:\n", - " f.write(seperator.join(values) + \"\\n\")\n", + "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) \n", "\n", "\n", + "A notable special type of grid variable is that of the Moe & di Stefano 2017 dataset (see further down in the notebook).\n", "\n", - "# Creating a parsing function\n", - "example_pop.set(\n", - " parse_function=parse_function, # Setting the parse function thats used in the evolve_population\n", - ")" + "To add a grid variable to the population object we use `example_pop.add_grid_variable` (see next cell)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "2fa5188e-312f-4a05-aeda-0bd4c00629c8", + "execution_count": 39, + "id": "68c84521-9ae8-4020-af7a-5334173db969", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on method add_grid_variable in module binarycpython.utils.grid:\n", + "\n", + "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\n", + " Function to add grid variables to the grid_options.\n", + " \n", + " The execution of the grid generation will be through a nested for loop.\n", + " Each of the grid variables will get create a deeper for loop.\n", + " \n", + " The real function that generates the numbers will get written to a new file in the TMP_DIR,\n", + " and then loaded imported and evaluated.\n", + " beware that if you insert some destructive piece of code, it will be executed anyway.\n", + " Use at own risk.\n", + " \n", + " Tasks:\n", + " - TODO: Fix this complex function.\n", + " \n", + " Args:\n", + " name:\n", + " name of parameter. This is evaluated as a parameter and you can use it throughout\n", + " the rest of the function\n", + " \n", + " Examples:\n", + " name = 'lnm1'\n", + " longname:\n", + " Long name of parameter\n", + " \n", + " Examples:\n", + " longname = 'Primary mass'\n", + " range:\n", + " Range of values to take. Does not get used really, the spacingfunction is used to\n", + " get the values from\n", + " \n", + " Examples:\n", + " range = [math.log(m_min), math.log(m_max)]\n", + " resolution:\n", + " Resolution of the sampled range (amount of samples).\n", + " TODO: check if this is used anywhere\n", + " \n", + " Examples: \n", + " resolution = resolution[\"M_1\"]\n", + " spacingfunction:\n", + " Function determining how the range is sampled. You can either use a real function,\n", + " or a string representation of a function call. Will get written to a file and\n", + " then evaluated.\n", + " \n", + " Examples:\n", + " spacingfunction = \"const(math.log(m_min), math.log(m_max), {})\".format(resolution['M_1'])\n", + " \n", + " precode:\n", + " Extra room for some code. This code will be evaluated within the loop of the\n", + " sampling function (i.e. a value for lnm1 is chosen already)\n", + " \n", + " Examples:\n", + " precode = 'M_1=math.exp(lnm1);'\n", + " probdist:\n", + " Function determining the probability that gets assigned to the sampled parameter\n", + " \n", + " Examples:\n", + " probdist = 'Kroupa2001(M_1)*M_1'\n", + " dphasevol:\n", + " part of the parameter space that the total probability is calculated with. Put to -1\n", + " if you want to ignore any dphasevol calculations and set the value to 1\n", + " Examples:\n", + " dphasevol = 'dlnm1'\n", + " condition:\n", + " condition that has to be met in order for the grid generation to continue\n", + " Examples:\n", + " condition = 'self.grid_options['binary']==1'\n", + " gridtype:\n", + " Method on how the value range is sampled. Can be either 'edge' (steps starting at\n", + " the lower edge of the value range) or 'center'\n", + " (steps starting at lower edge + 0.5 * stepsize).\n", + "\n" + ] + } + ], "source": [ - "### Custom logging\n", - "# Log the moment when the star turns into neutron\n", - "example_pop.set(\n", - " C_logging_code=\"\"\"\n", - "if(stardata->star[0].stellar_type >= 13) \n", - "{\n", - " if (stardata->model.time < stardata->model.max_evolution_time)\n", - " {\n", - " Printf(\"MY_STELLAR_DATA %30.12e %g %g %g %g %d\\\\n\",\n", - " // \n", - " stardata->model.time, // 1\n", - " stardata->star[0].mass, // 2\n", - " stardata->common.zero_age.mass[0], // 4\n", - " stardata->model.probability, // 5\n", - " stardata->star[0].radius, // 6\n", - " stardata->star[0].stellar_type // 7\n", - " );\n", - " };\n", - " /* Kill the simulation to save time */\n", - " stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;\n", - "};\n", - "\"\"\"\n", - ")" + "help(example_pop.add_grid_variable)" + ] + }, + { + "cell_type": "markdown", + "id": "1b3a007b-5c17-42a7-a981-7e268e6f545c", + "metadata": {}, + "source": [ + "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", - "execution_count": null, - "id": "fd197154-a8ce-4865-8929-008d3483101a", + "execution_count": 40, + "id": "47979841-2c26-4b26-8945-603d013dc93a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Added grid variable: {\n", + " \"name\": \"lnm1\",\n", + " \"longname\": \"Primary mass\",\n", + " \"valuerange\": [\n", + " 2,\n", + " 150\n", + " ],\n", + " \"resolution\": \"20\",\n", + " \"spacingfunc\": \"const(math.log(2), math.log(150), 20)\",\n", + " \"precode\": \"M_1=math.exp(lnm1)\",\n", + " \"probdist\": \"three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1\",\n", + " \"dphasevol\": \"dlnm1\",\n", + " \"parameter_name\": \"M_1\",\n", + " \"condition\": \"\",\n", + " \"gridtype\": \"edge\",\n", + " \"branchpoint\": 0,\n", + " \"grid_variable_number\": 0\n", + "}\n" + ] + } + ], "source": [ "# Add grid variables\n", "resolution = {\"M_1\": 20, \"q\": 20, \"per\": 40}\n", @@ -212,88 +360,331 @@ }, { "cell_type": "markdown", - "id": "8c96b151-8c3b-4479-969f-6c2f898497a5", + "id": "163f13ae-fec1-4ee8-b9d4-c1b75c19ff39", "metadata": {}, "source": [ - "Exporting of all the settings can be done with .export_all_info()\n", - "on default it exports everything, but can be supressed by turning it off:\n", - " population settings (bse_options, grid_options, custom_options), turn off with include_population\n", - " settings=False\n", - " binary_c_defaults (all the commandline arguments that binary c accepts, and their defaults).\n", - " turn off with include_binary_c_defaults=False\n", - " include_binary_c_version_info (all the compilation info, and information about the compiled\n", - " parameters), turn off with include_binary_c_version_info=False\n", - " include_binary_c_help_all (all the help information for all the binary_c parameters),\n", - " turn off with include_binary_c_help_all=Fase\n", - "On default it will write this to the custom_options['data_dir'], but that can be overriden by\n", - " setting use_datadir=False and providing an outfile=<>" + "## Setting logging and handling the output\n", + "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. \n", + "\n", + "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`). \n", + "\n", + "In the code below we will set up both the custom logging, and a parse function to handle that output" ] }, { "cell_type": "code", - "execution_count": 5, - "id": "ba83443c-64b4-4126-90b3-b1ca76c0f73d", + "execution_count": 41, + "id": "0c986215-93b1-4e30-ad79-f7c397e9ff7d", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "'/tmp/binary_c_python/example_python_population_result/example_pop_settings.json'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "adding: C_logging_code=\n", + "if(stardata->star[0].stellar_type >= 13) \n", + "{\n", + " if (stardata->model.time < stardata->model.max_evolution_time)\n", + " {\n", + " Printf(\"EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\\n\",\n", + " // \n", + " stardata->model.time, // 1\n", + " stardata->star[0].mass, // 2\n", + " stardata->common.zero_age.mass[0], // 3\n", + " stardata->model.probability, // 4\n", + " stardata->star[0].stellar_type // 5\n", + " );\n", + " };\n", + " /* Kill the simulation to save time */\n", + " stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;\n", + "};\n", + " to grid_options\n" + ] } ], "source": [ - "example_pop.export_all_info()" + "# Create custom logging statement: in this case we will log when the star turns into a compact object, and then terminate the evolution.\n", + "custom_logging_statement = \"\"\"\n", + "if(stardata->star[0].stellar_type >= 13) \n", + "{\n", + " if (stardata->model.time < stardata->model.max_evolution_time)\n", + " {\n", + " Printf(\"EXAMPLE_COMPACT_OBJECT %30.12e %g %g %g %d\\\\n\",\n", + " // \n", + " stardata->model.time, // 1\n", + " stardata->star[0].mass, // 2\n", + " stardata->common.zero_age.mass[0], // 3\n", + " stardata->model.probability, // 4\n", + " stardata->star[0].stellar_type // 5\n", + " );\n", + " };\n", + " /* Kill the simulation to save time */\n", + " stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;\n", + "};\n", + "\"\"\"\n", + "\n", + "example_pop.set(\n", + " C_logging_code=custom_logging_statement\n", + ")" ] }, { "cell_type": "markdown", - "id": "ef5b51a1-e56d-4bec-a5c7-b9d5bceeceba", + "id": "ae1f1f0c-1f8b-42d8-b051-cbf8c6b51514", "metadata": {}, "source": [ - "Executing a single system\n", - "This uses the M_1 orbital period etc set with the set function" + "The parse function must now catch lines that start with \"EXAMPLE_COMPACT_OBJECT\", and write that line to a file" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "c0a9aed7-1fc9-4fe3-8bcf-4e987bfc00a9", + "execution_count": 42, + "id": "fd197154-a8ce-4865-8929-008d3483101a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Creating the code for the shared library for the custom logging\n", - "['2.773586668293e+01', '1.33526', '10', '1', '1.72498e-05', '13']\n", - "None\n" + "adding: parse_function=<function parse_function at 0x7f1ef99d1f28> to grid_options\n" ] } ], "source": [ - "output = example_pop.evolve_single()\n", - "print(output)" + "def parse_function(self, output):\n", + " \"\"\"\n", + " Example parse function\n", + " \"\"\"\n", + " \n", + " # get info from the population instance\n", + " data_dir = self.custom_options[\"data_dir\"]\n", + " base_filename = self.custom_options[\"base_filename\"]\n", + "\n", + " # Check directory, make if necessary\n", + " os.makedirs(data_dir, exist_ok=True)\n", + "\n", + " seperator = \" \"\n", + "\n", + " # Create filename\n", + " outfilename = os.path.join(data_dir, base_filename)\n", + "\n", + " parameters = [\"time\", \"mass\", \"zams_mass\", \"probability\", \"stellar_type\"]\n", + "\n", + " # Go over the output.\n", + " for line in output_lines(output):\n", + " headerline = line.split()[0]\n", + "\n", + " # CHeck the header and act accordingly\n", + " if headerline == \"EXAMPLE_COMPACT_OBJECT\":\n", + " values = line.split()[1:]\n", + " print(line)\n", + " \n", + " if not len(parameters) == len(values):\n", + " print(\"Amount of column names isnt equal to amount of columns\")\n", + " raise ValueError\n", + "\n", + " if not os.path.exists(outfilename):\n", + " with open(outfilename, \"w\") as f:\n", + " f.write(seperator.join(parameters) + \"\\n\")\n", + "\n", + " with open(outfilename, \"a\") as f:\n", + " f.write(seperator.join(values) + \"\\n\")\n", + "\n", + "# Add the parsing function\n", + "example_pop.set(\n", + " parse_function=parse_function,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "91509ce5-ffe7-4937-aa87-6d7baac9ac04", + "metadata": {}, + "source": [ + "## Evolving the grid\n", + "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()`\n", + "\n", + "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." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "id": "8ea376c1-1e92-45af-8cab-9d7fdca564eb", "metadata": { "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "adding: verbosity=0 to grid_options\n", + "Generating grid code\n", + "Constructing/adding: lnm1\n", + "Grid has handled 20 stars\n", + "with a total probability of 0.05150046619238192\n", + "Total starcount for this run will be: 20\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-08-08 17:48:00,496 DEBUG MainProcess] --- setting up the system_queue_filler now\n", + "[2021-08-08 17:48:00,498 DEBUG Process-38] --- Setting up processor: process-0[2021-08-08 17:48:00,499 DEBUG Process-39] --- Setting up processor: process-1\n", + "[2021-08-08 17:48:00,505 DEBUG MainProcess] --- Signaling stop to processes\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Process 1 started at 2021-08-08T17:48:00.506077.\tUsing store memaddr <capsule object \"STORE\" at 0x7f1efb31cd20>\n", + "Process 0 started at 2021-08-08T17:48:00.516098.\tUsing store memaddr <capsule object \"STORE\" at 0x7f1efb31ce70>\n", + "Generating grid code\n", + "Constructing/adding: lnm1\n", + "EXAMPLE_COMPACT_OBJECT 2.867655467480e+01 1.33079 9.81391 0.00167028 13\n", + "EXAMPLE_COMPACT_OBJECT 4.439623364590e+01 1.38004 7.81906 0.00224431 13\n", + "EXAMPLE_COMPACT_OBJECT 1.931266944719e+01 1.3933 12.3177 0.00124307 13\n", + "EXAMPLE_COMPACT_OBJECT 1.364277535630e+01 1.47961 15.4603 0.000925128 13\n", + "EXAMPLE_COMPACT_OBJECT 1.017435498578e+01 1.59052 19.4046 0.000688507 13\n", + "EXAMPLE_COMPACT_OBJECT 8.294870923827e+00 1.7197 24.3552 0.000512406 13\n", + "EXAMPLE_COMPACT_OBJECT 6.802132608769e+00 1.84162 30.5689 0.000381347 13\n", + "EXAMPLE_COMPACT_OBJECT 5.723570798020e+00 1.99471 38.3678 0.00028381 13\n", + "EXAMPLE_COMPACT_OBJECT 4.933751523833e+00 2.15875 48.1564 0.000211219 13\n", + "EXAMPLE_COMPACT_OBJECT 4.337250536639e+00 2.35209 60.4424 0.000157195 14\n", + "EXAMPLE_COMPACT_OBJECT 3.862081089332e+00 2.56776 75.8628 0.000116989 14\n", + "EXAMPLE_COMPACT_OBJECT 3.449960890183e+00 2.80457 95.2174 8.70668e-05 14\n", + "EXAMPLE_COMPACT_OBJECT 3.172196856333e+00 3.05193 119.51 6.47976e-05 14\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-08-08 17:48:01,097 DEBUG Process-39] --- Process-1 is finishing.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Process 1 finished:\n", + "\tgenerator started at 2021-08-08T17:48:00.499672, done at 2021-08-08T17:48:01.114081 (total: 0.614409s of which 0.5701460838317871s interfacing with binary_c).\n", + "\tRan 10 systems with a total probability of 0.026044641717704063.\n", + "\tThis thread had 0 failing systems with a total probability of 0.\n", + "\tSkipped a total of 0 systems because they had 0 probability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-08-08 17:48:01,127 DEBUG Process-39] --- Process-1 is finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "EXAMPLE_COMPACT_OBJECT 3.069627290216e+00 3.27563 150 4.82242e-05 14\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-08-08 17:48:01,152 DEBUG Process-38] --- Process-0 is finishing.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Process 0 finished:\n", + "\tgenerator started at 2021-08-08T17:48:00.498331, done at 2021-08-08T17:48:01.161255 (total: 0.662924s of which 0.6246497631072998s interfacing with binary_c).\n", + "\tRan 10 systems with a total probability of 0.025455824474677844.\n", + "\tThis thread had 0 failing systems with a total probability of 0.\n", + "\tSkipped a total of 0 systems because they had 0 probability\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[2021-08-08 17:48:01,170 DEBUG Process-38] --- Process-0 is finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Population-4f23670fd94b48cbb6590a4e503782ca finished! The total probability was: 0.05150046619238191. It took a total of 0.864509105682373s to run 20 systems on 2 cores\n", + "There were no errors found in this run.\n" + ] + } + ], "source": [ + "# change verbosity\n", + "example_pop.set(verbosity=0)\n", + "\n", "## Executing a population\n", "## This uses the values generated by the grid_variables\n", - "example_pop.evolve() # TODO: update this function call" + "analytics = example_pop.evolve() # TODO: update this function call" + ] + }, + { + "cell_type": "markdown", + "id": "91ab45c7-7d31-4543-aee4-127ab58e891f", + "metadata": {}, + "source": [ + "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", + "execution_count": 44, + "id": "e1f0464b-0424-4022-b34b-5b744bc2c59d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'population_name': '4f23670fd94b48cbb6590a4e503782ca', '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': 1628441280.4808269, 'end_timestamp': 1628441281.345336, 'total_mass_run': 730.1048014407227, 'total_probability_weighted_mass_run': 0.2983275843337705, 'zero_prob_stars_skipped': 0}\n" + ] + } + ], + "source": [ + "print(analytics)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a10760f-f94e-496f-923c-89dbd450b65c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6108170-2055-48ba-9732-d39f46baf16a", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "348ba1d2-4cea-47b8-a94c-677e43c9247a", + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "id": "ce937b07-7292-4bb1-b2e7-d69e51bdff6e", @@ -309,7 +700,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 45, "id": "ad444138-f854-4fdb-8e18-49e35ac9c7e2", "metadata": {}, "outputs": [ @@ -321,6 +712,20 @@ "Adding settings to HDF5 file\n", "Adding data to HDF5 file\n" ] + }, + { + "ename": "ValueError", + "evalue": "Wrong number of columns at line 17", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m<ipython-input-45-9734fbb7432e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcreate_hdf5\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata_dir\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mexample_pop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcustom_options\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"data_dir\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"example_pop.hdf5\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/.pyenv/versions/3.6.4/envs/dev-binarycpython3.6.4/lib/python3.6/site-packages/binarycpython/utils/functions.py\u001b[0m in \u001b[0;36mcreate_hdf5\u001b[0;34m(data_dir, name)\u001b[0m\n\u001b[1;32m 482\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 483\u001b[0m \u001b[0;31m# Add data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 484\u001b[0;31m \u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloadtxt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfull_path\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mskiprows\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 485\u001b[0m \u001b[0mdata_grp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_dataset\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbase_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 486\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/numpy/lib/npyio.py\u001b[0m in \u001b[0;36mloadtxt\u001b[0;34m(fname, dtype, comments, delimiter, converters, skiprows, usecols, unpack, ndmin, encoding, max_rows)\u001b[0m\n\u001b[1;32m 1137\u001b[0m \u001b[0;31m# converting the data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1138\u001b[0m \u001b[0mX\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1139\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mread_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_loadtxt_chunksize\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 1140\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mX\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1141\u001b[0m \u001b[0mX\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\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/numpy/lib/npyio.py\u001b[0m in \u001b[0;36mread_data\u001b[0;34m(chunk_size)\u001b[0m\n\u001b[1;32m 1062\u001b[0m \u001b[0mline_num\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mi\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mskiprows\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1063\u001b[0m raise ValueError(\"Wrong number of columns at line %d\"\n\u001b[0;32m-> 1064\u001b[0;31m % line_num)\n\u001b[0m\u001b[1;32m 1065\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1066\u001b[0m \u001b[0;31m# Convert each value according to its column and store\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Wrong number of columns at line 17" + ] } ], "source": [ @@ -537,6 +942,167 @@ "# and packing them into an hdf5 file, which is then written into the same data_dir directory\n", "create_hdf5(data_dir=example_pop.custom_options[\"data_dir\"], name=\"example_pop.hdf5\")\n" ] + }, + { + "cell_type": "markdown", + "id": "60359eb1-4d0c-4d2d-8265-ec5171b944a2", + "metadata": {}, + "source": [ + "# Full example Population of single stars\n", + "Below is a full setup for a population of single stars" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7212b6be-9787-4122-a7f1-86538cf38179", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from binarycpython.utils.grid import Population\n", + "from binarycpython.utils.custom_logging_functions import temp_dir\n", + "\n", + "def parse_function(self, output):\n", + " \"\"\"\n", + " Example parsing function\n", + " \"\"\"\n", + " \n", + " # extract info from the population instance\n", + "\n", + " # Get some information from the\n", + " data_dir = self.custom_options[\"data_dir\"]\n", + " base_filename = self.custom_options[\"base_filename\"]\n", + "\n", + " # Check directory, make if necessary\n", + " os.makedirs(data_dir, exist_ok=True)\n", + "\n", + " #\n", + " seperator = \" \"\n", + "\n", + " # Create filename\n", + " outfilename = os.path.join(data_dir, base_filename)\n", + "\n", + " # The header columns matching this \n", + " parameters = [\"time\", \"mass\", \"zams_mass\", \"probability\", \"radius\", \"stellar_type\"]\n", + "\n", + " # Go over the output.\n", + " for el in output_lines(output):\n", + " headerline = el.split()[0]\n", + "\n", + " # CHeck the header and act accordingly\n", + " if headerline == \"MY_STELLAR_DATA\":\n", + " values = el.split()[1:]\n", + "\n", + " if not len(parameters) == len(values):\n", + " print(\"Amount of column names isnt equal to amount of columns\")\n", + " raise ValueError\n", + "\n", + " if not os.path.exists(outfilename):\n", + " with open(outfilename, \"w\") as f:\n", + " f.write(seperator.join(parameters) + \"\\n\")\n", + "\n", + " with open(outfilename, \"a\") as f:\n", + " f.write(seperator.join(values) + \"\\n\")\n", + "\n", + "\n", + "# Create population object\n", + "example_pop = Population()\n", + "\n", + "# If you want verbosity, set this before other things\n", + "example_pop.set(verbosity=0)\n", + "\n", + "# Setting values can be done via .set(<parameter_name>=<value>)\n", + "example_pop.set(\n", + " # binary_c physics options\n", + " M_1=10, # bse_options\n", + " separation=0, # bse_options\n", + " orbital_period=45000000080, # bse_options\n", + " max_evolution_time=15000, # bse_options\n", + " eccentricity=0.02, # bse_options\n", + " \n", + " # grid_options\n", + " amt_cores=2, # grid_options\n", + "\n", + " # Custom options: the data directory and the output filename\n", + " data_dir=os.path.join(\n", + " temp_dir(), \"example_python_population_result\"\n", + " ), # custom_options\n", + " base_filename=\"example_pop.dat\", # custom_options\n", + ")\n", + "\n", + "# Creating a parsing function\n", + "example_pop.set(\n", + " parse_function=parse_function, # Setting the parse function thats used in the evolve_population\n", + ")\n", + "\n", + "### Custom logging\n", + "# Log the moment when the star turns into neutron\n", + "example_pop.set(\n", + " C_logging_code=\"\"\"\n", + "if(stardata->star[0].stellar_type >= 13) \n", + "{\n", + " if (stardata->model.time < stardata->model.max_evolution_time)\n", + " {\n", + " Printf(\"MY_STELLAR_DATA %30.12e %g %g %g %g %d\\\\n\",\n", + " // \n", + " stardata->model.time, // 1\n", + " stardata->star[0].mass, // 2\n", + " stardata->common.zero_age.mass[0], // 4\n", + " stardata->model.probability, // 5\n", + " stardata->star[0].radius, // 6\n", + " stardata->star[0].stellar_type // 7\n", + " );\n", + " };\n", + " /* Kill the simulation to save time */\n", + " stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;\n", + "};\n", + "\"\"\"\n", + ")\n", + "\n", + "# Add grid variables\n", + "resolution = {\"M_1\": 20}\n", + "\n", + "# Mass\n", + "example_pop.add_grid_variable(\n", + " name=\"lnm1\",\n", + " longname=\"Primary mass\",\n", + " valuerange=[2, 150],\n", + " resolution=\"{}\".format(resolution[\"M_1\"]),\n", + " spacingfunc=\"const(math.log(2), math.log(150), {})\".format(resolution[\"M_1\"]),\n", + " precode=\"M_1=math.exp(lnm1)\",\n", + " probdist=\"three_part_powerlaw(M_1, 0.1, 0.5, 1.0, 150, -1.3, -2.3, -2.3)*M_1\",\n", + " dphasevol=\"dlnm1\",\n", + " parameter_name=\"M_1\",\n", + " condition=\"\",\n", + ")\n", + "\n", + "# Exporting of all the settings can be done with .export_all_info()\n", + "example_pop.export_all_info()\n", + "\n", + "# remove the result file if it exists\n", + "if os.path.isfile(os.path.join(temp_dir(), \"example_python_population_result\", \"example_pop.dat\")):\n", + " os.remove(os.path.join(temp_dir(), \"example_python_population_result\", \"example_pop.dat\"))\n", + "\n", + "\n", + "# Evolve the population\n", + "example_pop.evolve()\n", + "\n", + "# \n", + "with open(os.path.join(temp_dir(), \"example_python_population_result\", \"example_pop.dat\"), 'r') as f:\n", + " output = f.read()\n", + "print(\"\\n\")\n", + "print(output)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c8f4d66-536a-44a9-b044-d284784536ec", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { -- GitLab