From ee872b09b45ce5a163ab43dc34ad1445583ddf4d Mon Sep 17 00:00:00 2001
From: David Hendriks <davidhendriks93@gmail.com>
Date: Tue, 14 Jan 2020 23:36:35 +0000
Subject: [PATCH] added store loading function and added run_population
 function and add_grid_variable function

---
 .../utils/custom_logging_functions.py         |   2 +
 binarycpython/utils/grid.py                   | 163 +++++++++++++-----
 binarycpython/utils/grid_options_defaults.py  |  28 ++-
 src/binary_c_python_api.c                     |  13 +-
 tests/population/grid_tests.py                |  12 +-
 tests/python_API_test.py                      |   3 +-
 6 files changed, 154 insertions(+), 67 deletions(-)

diff --git a/binarycpython/utils/custom_logging_functions.py b/binarycpython/utils/custom_logging_functions.py
index b966f6eae..9f58b705a 100644
--- a/binarycpython/utils/custom_logging_functions.py
+++ b/binarycpython/utils/custom_logging_functions.py
@@ -5,6 +5,7 @@ import socket
 import tempfile
 import ctypes
 
+
 def autogen_C_logging_code(logging_dict):
     """
     Function that autogenerates PRINTF statements for binaryc. intput is a dictionary where the key is the header of that logging line and items which are lists of parameters\
@@ -220,6 +221,7 @@ def return_compilation_dict(verbose=False):
 
     return {"cc": cc, "ld": ld, "ccflags": ccflags, "libs": libs, "inc": inc}
 
+
 def compile_shared_lib(code, sourcefile_name, outfile_name, verbose=False):
     """
     Function to write the custom logging code to a file and then compile it.
diff --git a/binarycpython/utils/grid.py b/binarycpython/utils/grid.py
index c846fcbd2..c8b66521e 100644
--- a/binarycpython/utils/grid.py
+++ b/binarycpython/utils/grid.py
@@ -7,11 +7,14 @@ import binary_c_python_api
 
 import binarycpython
 from binarycpython.utils.grid_options_defaults import grid_options_defaults_dict
-from binarycpython.utils.custom_logging_functions import autogen_C_logging_code, binary_c_log_code, create_and_load_logging_function
+from binarycpython.utils.custom_logging_functions import (
+    autogen_C_logging_code,
+    binary_c_log_code,
+    create_and_load_logging_function,
+)
 from binarycpython.utils.functions import get_defaults
 
 
-
 # TODO list
 # TODO: add functionality to parse cmdline args
 # TODO: add functionality to 'on-init' set arguments
@@ -27,11 +30,10 @@ from binarycpython.utils.functions import get_defaults
 # TODO: add functionality to return the ensemble_list
 
 # DONE: add functionality to return the evcode_version_string
-    # Make this function also an API call. Doest seem to get written to a buffer that is stored into a python object. rather its just written to stdout
+# Make this function also an API call. Doest seem to get written to a buffer that is stored into a python object. rather its just written to stdout
 # DONE: add functionality to return the evcode_args_list
 
 
-
 class Population(object):
     def __init__(self):
         """
@@ -41,30 +43,30 @@ class Population(object):
         self.defaults = get_defaults()
 
         # Different sections of options
-        self.bse_options = {} # bse_options is just empty. Setting stuff will check against the defaults to see if the input is correct. 
+        self.bse_options = (
+            {}
+        )  # bse_options is just empty. Setting stuff will check against the defaults to see if the input is correct.
         self.grid_options = grid_options_defaults_dict.copy()
         self.custom_options = {}
 
         # Argline dict
         self.argline_dict = {}
 
-
     ###################################################
     # Argument functions
     ###################################################
 
     # General flow of generating the arguments for the binary_c call:
     # - user provides parameter and value via set (or manually but that is risky)
-    # - The parameter names of these input get compared to the parameter names in the self.defaults; with this, we know that its a valid 
-    # parameter to give to binary_c. 
+    # - The parameter names of these input get compared to the parameter names in the self.defaults; with this, we know that its a valid
+    # parameter to give to binary_c.
     # - For a single system, the bse_options will be written as a arg line
-    # - For a population the bse_options will get copied to a temp_bse_options file and updated with all the parameters generated by the grid
+    # - For a population the bse_options will get copied to a temp_bse_options dict and updated with all the parameters generated by the grid
 
-
-    # I will NOT create the argument line by fully writing ALL the defaults and overriding user input, that seems not necessary 
+    # I will NOT create the argument line by fully writing ALL the defaults and overriding user input, that seems not necessary
     # because by using the get_defaults() function we already know for sure which parameter names are valid for the binary_c version
-    # And because binary_c uses internal defaults, its not necessary to explicitly pass them
-    # I do however suggest everyone to export the binary_c defaults to a file, so that you know exactly which values were the defaults
+    # And because binary_c uses internal defaults, its not necessary to explicitly pass them.
+    # I do however suggest everyone to export the binary_c defaults to a file, so that you know exactly which values were the defaults.
 
     def set(self, **kwargs):
         """
@@ -80,7 +82,7 @@ class Population(object):
         for key in kwargs.keys():
             # Filter out keys for the bse_options
             if key in self.defaults.keys():
-                print('adding: {}={} to BSE_options'.format(key,kwargs[key]))
+                print("adding: {}={} to BSE_options".format(key, kwargs[key]))
                 self.bse_options[key] = kwargs[key]
 
             # Filter out keys for the grid_options
@@ -111,6 +113,71 @@ class Population(object):
 
         pass
 
+    def add_grid_variable(
+        self,
+        name,
+        longname,
+        range,
+        resolution,
+        spacingfunc,
+        precode,
+        probdist,
+        dphasevol,
+        condition,
+    ):
+        """
+        Function to add grid variables to the grid_options.
+
+        TODO: Fix this complex function.
+
+        The execution of the grid generation will be through a nested forloop, 
+        and will rely heavily on the eval() functionality of python. Which, in terms of safety is very bad, but in terms of flexibility is very good.
+
+        name: 
+            name of parameter
+            example: name = 'lnm1'            
+        longname: 
+            Long name of parameter
+            example: longname = 'Primary mass'
+        range: 
+            Range of values to take
+            example: range = [log($mmin),log($mmax)]
+        resolution: 
+            Resolution of the sampled range (amount of samples)
+            example: resolution = $resolution->{m1}
+        spacingfunction: 
+            Function determining how the range is sampled
+            example: spacingfunction = "const(log($mmin),log($mmax),$resolution->{m1})"
+        precode: 
+            # TODO: think of good description.
+            example: precode = '$m1=exp($lnm1);'
+        probdist: 
+            FUnction determining the probability that gets asigned to the sampled parameter
+            example: probdist = 'Kroupa2001($m1)*$m1'
+        dphasevol: 
+            part of the parameter space that the total probability is calculated with
+            example: dphasevol = '$dlnm1'
+        condition: 
+            condition that has to be met in order for the grid generation to continue
+            example: condition = '$self->{_grid_options}{binary}==1'
+        """
+
+        # Add grid_variable
+        grid_variable = {
+            "name": name,
+            "longname": longname,
+            "range": range,  # TODO: change name
+            "resolution": resolution,
+            "spacingfunction": spacingfunction,
+            "precode": precode,
+            "probdist": probdist,
+            "dphasevol": dphasevol,
+            "condition": condition,
+            "grid_variable_number": len(self.grid_options["grid_variables"]),
+        }
+
+        # Load it into the grid_options
+        self.grid_options["grid_variables"][grid_variable["name"]] = grid_variable
 
     ###################################################
     # Return functions
@@ -124,9 +191,9 @@ class Population(object):
         """
 
         options = {
-            'bse_options': self.bse_options,
-            'grid_options': self.grid_options,
-            'custom_options': self.custom_options,
+            "bse_options": self.bse_options,
+            "grid_options": self.grid_options,
+            "custom_options": self.custom_options,
         }
 
         return options
@@ -162,10 +229,10 @@ class Population(object):
         binary_c_help_all_info = get_help_all(print_help=False, return_dict=True)
 
         all_info = {}
-        all_info['population_settings'] = population_settings
-        all_info['binary_c_defaults'] = binary_c_defaults
-        all_info['binary_c_version_info'] = binary_c_version_info
-        all_info['binary_c_help_all'] = binary_c_help_all_info
+        all_info["population_settings"] = population_settings
+        all_info["binary_c_defaults"] = binary_c_defaults
+        all_info["binary_c_version_info"] = binary_c_version_info
+        all_info["binary_c_help_all"] = binary_c_help_all_info
 
         return all_info
 
@@ -180,7 +247,7 @@ class Population(object):
         all_info = self.return_all_info()
 
         # if not outfile.endswith('json'):
-        with open(outfile, 'w') as f:
+        with open(outfile, "w") as f:
             f.write(json.dumps(all_info, indent=4))
 
     ###################################################
@@ -192,9 +259,7 @@ class Population(object):
         Function to run a single system
         """
 
-
         argline = self.return_argline(self.bse_options)
-return_binary_c_version_info
         out = binary_c_python_api.run_binary(argline)
         # out = binary_c_python_api.run_binary('binary_c M_1 15 M_2 14 separation 0 orbital_period 4530 eccentricity 0 metallicity 0.02 max_evolution_time 15000')
         return out
@@ -206,27 +271,39 @@ return_binary_c_version_info
 
         ### Custom logging code:
         # C_logging_code gets priority of C_autogen_code
-        if self.grid_options['C_auto_logging']:
+        if self.grid_options["C_auto_logging"]:
             # Generate real logging code
-            logging_line = autogen_C_logging_code(
-                    self.grid_options['C_auto_logging']
-                )
+            logging_line = autogen_C_logging_code(self.grid_options["C_auto_logging"])
 
             # Generate entire shared lib code around logging lines
             custom_logging_code = binary_c_log_code(logging_line)
 
             # Load memory adress
-            self.grid_options['custom_logging_func_memaddr'] = create_and_load_logging_function(custom_logging_code)
-        # 
-        if self.grid_options['C_logging_code']:
+            self.grid_options[
+                "custom_logging_func_memaddr"
+            ] = create_and_load_logging_function(custom_logging_code)
+        #
+        if self.grid_options["C_logging_code"]:
             # Generate entire shared lib code around logging lines
-            custom_logging_code = binary_c_log_code(self.grid_options['C_logging_code'])
+            custom_logging_code = binary_c_log_code(self.grid_options["C_logging_code"])
 
             # Load memory adress
-            self.grid_options['custom_logging_func_memaddr'] = create_and_load_logging_function(custom_logging_code)
-        ###
+            self.grid_options[
+                "custom_logging_func_memaddr"
+            ] = create_and_load_logging_function(custom_logging_code)
 
-        ### Arguments 
+        ### Load store
+        store = binary_c_python_api.return_store("")
+
+        print("ho")
+
+        print(self.return_argline())
+
+        out = binary_c_python_api.run_population(self.return_argline(), 12, store)
+        print(out)
+        quit()
+
+        ### Arguments
         # If user inputs a file containing arg lines then use that
         if custom_arg_file:
             # check if file exists
@@ -237,14 +314,14 @@ return_binary_c_version_info
                     temp = f.read().splitlines()
 
                     # Filter out all the lines that dont start with binary_c
-                    population_arglines = [line for line in temp if line.startswith('binary_c')]
+                    population_arglines = [
+                        line for line in temp if line.startswith("binary_c")
+                    ]
 
         else:
-            # generate population from options 
-
+            # generate population from options
 
-
-            print('ho')
+            print("ho")
 
             pass
 
@@ -253,12 +330,8 @@ return_binary_c_version_info
         for line in population_arglines:
             print(line)
 
-
-
-
         pass
 
-
     ###################################################
     # Testing functions
     ###################################################
@@ -287,4 +360,4 @@ return_binary_c_version_info
         print(output)
 
 
-################################################################################################ 
+################################################################################################
diff --git a/binarycpython/utils/grid_options_defaults.py b/binarycpython/utils/grid_options_defaults.py
index d45f0a53b..8c99fec7d 100644
--- a/binarycpython/utils/grid_options_defaults.py
+++ b/binarycpython/utils/grid_options_defaults.py
@@ -1,25 +1,21 @@
 grid_options_defaults_dict = {
-    # 
-    'amt_cores': 1, # total amount of cores used to evolve the population
-    'verbose': 0, # Level of verbosity of the simulation
-
+    #
+    "amt_cores": 1,  # total amount of cores used to evolve the population
+    "verbose": 0,  # Level of verbosity of the simulation
     # Custom logging
-    'C_auto_logging': None, # Should contain a dictionary where the kes are they headers and the values are lists of parameters that should be logged. This will get parsed by autogen_C_logging_code in custom_loggion_functions.py
-    'C_logging_code': None, # Should contain a string which holds the logging code.
-    'custom_logging_func_memaddr': -1, # Contains the custom_logging functions memory address
-
-    # Log args: logging of arguments 
-    'log_args': 0, #
-    'log_args_dir': '/tmp/',
-
-    
+    "C_auto_logging": None,  # Should contain a dictionary where the kes are they headers and the values are lists of parameters that should be logged. This will get parsed by autogen_C_logging_code in custom_loggion_functions.py
+    "C_logging_code": None,  # Should contain a string which holds the logging code.
+    "custom_logging_func_memaddr": -1,  # Contains the custom_logging functions memory address
+    # Log args: logging of arguments
+    "log_args": 0,  #
+    "log_args_dir": "/tmp/",
+    # Grid variables: instructions to generate the values of the parameters
+    "grid_variables": {},
     # return_array_refs=>1, # quicker data parsing mode
     # sort_args=>1,
     # save_args=>1,
-    # nice=>'nice -n +20',  # nice command e.g. 'nice -n +10' or '' 
+    # nice=>'nice -n +20',  # nice command e.g. 'nice -n +10' or ''
     # timeout=>15, # seconds until timeout
     # log_filename=>"/scratch/davidh/results_simulations/tmp/log.txt",
     # # current_log_filename=>"/scratch/davidh/results_simulations/tmp/grid_errors.log",
-        
 }
-
diff --git a/src/binary_c_python_api.c b/src/binary_c_python_api.c
index e8922c589..603f89d5c 100644
--- a/src/binary_c_python_api.c
+++ b/src/binary_c_python_api.c
@@ -229,7 +229,11 @@ int run_population(char * argstring,
 
     // load the store
     // struct libbinary_c_store_t * store = (void*)store_memaddr;
-    struct libbinary_c_store_t * store = NULL;
+    struct libbinary_c_store_t * store = (void*)store_memaddr;
+    // struct libbinary_c_store_t * store = (void*)(struct stardata_t *)custom_logging_func_memaddr;
+    // struct libbinary_c_store_t * store = (void*)(struct stardata_t *)custom_logging_func_memaddr;
+    // struct libbinary_c_store_t * store = (void*)(struct stardata_t *)custom_logging_func_memaddr;
+    // struct libbinary_c_store_t * store = NULL;
 
     /* make new stardata */
     stardata = NULL;
@@ -253,7 +257,7 @@ int run_population(char * argstring,
     /* output to strings */
     stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
     stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-    stardata->preferences->custom_output_function = (void*)(struct stardata_t *)custom_logging_func_memaddr;
+    // stardata->preferences->custom_output_function = (void*)(struct stardata_t *)custom_logging_func_memaddr;
 
     /* do binary evolution */
     binary_c_evolve_for_dt(stardata,
@@ -491,6 +495,11 @@ long int return_store(char * argstring,
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata, TRUE, TRUE, FALSE, FALSE);
 
+    // int store_ptr;
+    // store_ptr = (void *)store; 
+
+
     // binary_c_free_store_contents(store);
+    // return store_ptr;
     return store;
 }
\ No newline at end of file
diff --git a/tests/population/grid_tests.py b/tests/population/grid_tests.py
index a8d8ec1e8..666bf9b39 100644
--- a/tests/population/grid_tests.py
+++ b/tests/population/grid_tests.py
@@ -13,7 +13,13 @@ test_pop = Population()
 # test_pop.set(M_1=10, M_2=500)
 # print(test_pop.bse_options['M_1'])
 # print(test_pop.bse_options['M_2'])
-test_pop.set(M_1=10, separation=0, orbital_period=4580, max_evolution_time=15000, eccentricity=0.02, )
+test_pop.set(
+    M_1=10,
+    separation=0,
+    orbital_period=4580,
+    max_evolution_time=15000,
+    eccentricity=0.02,
+)
 # print(test_pop.bse_options)
 
 ## Testing single evolution
@@ -55,7 +61,7 @@ test_pop.set(M_1=10, separation=0, orbital_period=4580, max_evolution_time=15000
 
 # return all info:
 # print(json.dumps(test_pop.return_all_info(), indent=4))
-test_pop.export_all_info(outfile=os.path.join(os.getcwd(), 'test_output.txt'))
-
+test_pop.export_all_info(outfile=os.path.join(os.getcwd(), "test_output.txt"))
 
 
+test_pop.evolve_population()
diff --git a/tests/python_API_test.py b/tests/python_API_test.py
index 8d295b57f..9ef833b0c 100755
--- a/tests/python_API_test.py
+++ b/tests/python_API_test.py
@@ -121,13 +121,14 @@ def test_return_help_all():
     out = binary_c_python_api.return_help_all("M_1")
     print(out)
 
+
 def test_return_version_info():
     out = binary_c_python_api.return_version_info()
     print(out)
 
 
 def test_return_store():
-    out = binary_c_python_api.return_store("binary_c M_1 10")
+    out = binary_c_python_api.return_store("")
     print(out)
 
 
-- 
GitLab