diff --git a/install.sh b/install.sh
index b81adec9d44fd049d1fa0974e440ccc271e9dc3a..42f91d61275ba2e570618dc5aaf7f08a45d9f5c3 100755
--- a/install.sh
+++ b/install.sh
@@ -5,8 +5,15 @@
 VERSION_NUMBER=$(cat "VERSION")
 echo "installing binarcpython version $VERSION_NUMBER"
 
-python setup.py clean
-pip uninstall binarycpython
-python setup.py build --force
-python setup.py sdist
-pip install -v dist/binarycpython-$VERSION_NUMBER.tar.gz
+# we can only use python3 and python3, but allow
+# the user to set these in environment variables
+# PYTHON and PIP.
+: "${PYTHON:="python3"}"
+: "${PIP:="pip3"}"
+
+# do stuff...
+$PYTHON setup.py clean
+$PIP uninstall binarycpython
+$PYTHON setup.py build --force
+$PYTHON setup.py sdist
+$PIP install -v dist/binarycpython-$VERSION_NUMBER.tar.gz
diff --git a/src/binary_c_python.c b/src/binary_c_python.c
index c10f8dfd030c0ea6823b6c76c1ba10ff5197db94..d3a9a374dbe64a72f881bb8cde19ccec9bb37b55 100644
--- a/src/binary_c_python.c
+++ b/src/binary_c_python.c
@@ -13,13 +13,13 @@
  * binary_c/PYTHON API interface functions
  *
  * This module will be available as _binary_c_bindings, as a part of the binarycpython package.
- * 
- * The first section contains the functions that will be available 
+ *
+ * The first section contains the functions that will be available
  * to python as part of the submodule _binary_c_bindings
- * 
- * The second section is composed of the functions that interface with the binary_c API 
  *
- * Written by David Hendriks (davidhendriks93@gmail.com), Robert Izzard (r.izzard@surrey.ac.uk). 
+ * The second section is composed of the functions that interface with the binary_c API
+ *
+ * Written by David Hendriks (davidhendriks93@gmail.com), Robert Izzard (r.izzard@surrey.ac.uk).
  * Based on initial work of Jeff Andrews
  * Remember: variables must be passed by references
  * (i.e. as pointers).
@@ -41,13 +41,13 @@
  * https://www.geeksforgeeks.org/c-api-from-extension-module-in-python-set-1/
  * http://pageperso.lif.univ-mrs.fr/~francois.denis/IAAM1/python-3.6.5rc1-docs-html/howto/cporting.html
  * http://python3porting.com/cextensions.html
- * 
- * 
+ *
+ *
  * Open tasks for the Extension:
  * TODO: Put in clear debug statements
  * TODO: properly return stderr
  * TODO: describe all functions with docstrings
- * TODO: properly pass through all the pointers using Capsules:  
+ * TODO: properly pass through all the pointers using Capsules:
  */
 
 
@@ -70,34 +70,34 @@ static char module_docstring[] MAYBE_UNUSED =
     "This module is a python3 wrapper around binary_c";
 
 // Evolution function docstrings
-static char run_system_docstring[] = 
+static char run_system_docstring[] =
     "Function to run a system. This is a general function that will be able to handle different kinds of situations: single system run with different settings, population run with different settings, etc. To avoid having too many functions doing slightly different things.\n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) custom_logging_func_memaddr: memory address value for custom logging function. Default = -1 (None)\n\t(opt) store_memaddr: memory adress of the store. Default = -1 (None)\n\t(opt) write_logfile: Boolean (in int form) for whether to enable the writing of the log function. Default = 0\n\t(opt) population: Boolean (in int form) for whether this system is part of a population run. Default = 0.";
 
 // Utility function docstrings
 static char return_arglines_docstring[] =
     "Return the default args for a binary_c system\n\nArguments:\n\tNo arguments.";
-static char return_help_info_docstring[] = 
+static char return_help_info_docstring[] =
     "Return the help info for a given parameter\n\nArguments:\n\tparameter: parameter name.";
-static char return_help_all_info_docstring[] = 
+static char return_help_all_info_docstring[] =
     "Return an overview of all the parameters, their description, categorized in sections\n\nArguments:\n\tNo arguments.";
-static char return_version_info_docstring[] = 
+static char return_version_info_docstring[] =
     "Return the version information of the used binary_c build\n\nArguments:\n\tNo arguments.";
-static char return_minimum_orbit_for_RLOF_docstring[] = 
+static char return_minimum_orbit_for_RLOF_docstring[] =
     "Returns a string containing the minimum orbit and separation for which a binary system does not RLOF at ZAMS. Please use the wrapper functions in utils for this except when you know what you're doing.\n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) store_capsule: capsule containing memory adress for the store object.unction. Default = Null";
-static char return_maximum_mass_ratio_for_RLOF_docstring[] = 
+static char return_maximum_mass_ratio_for_RLOF_docstring[] =
     "Returns a string containing the maximum mass ratio for which a binary system does not RLOF at ZAMS. Please use the wrapper functions in utils for this except when you know what you're doing.\n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) store_capsule: capsule containing memory adress for the store object.unction. Default = Null";
 
 // other functionality
-static char return_store_memaddr_docstring[] = 
+static char return_store_memaddr_docstring[] =
     "Return the store memory adress that will be passed to run_population\n\nArguments:\n\tNo arguments.";
-static char return_persistent_data_memaddr_docstring[] = 
+static char return_persistent_data_memaddr_docstring[] =
     "Return the store memory adress that will be passed to run_population\n\nArguments:\n\tNo arguments.";
 
-static char free_persistent_data_memaddr_and_return_json_output_docstring[] = 
+static char free_persistent_data_memaddr_and_return_json_output_docstring[] =
     "Frees the persistent_data memory and returns the json output.\n\nArguments:\n\tstore capsule: capsule containing the memory adress of the persistent data object (contains the ensemble)";
-static char free_store_memaddr_docstring[] = 
+static char free_store_memaddr_docstring[] =
     "Frees the store memaddr.\n\nArguments:\n\tstore capsule: capsule containing the memory adress of the store object";
-static char test_func_docstring[] = 
+static char test_func_docstring[] =
     "Function that contains random snippets. Do not expect this to remain available, or reliable. i.e. dont use it. ";
 
 /* Initialize pyobjects */
@@ -125,7 +125,7 @@ static PyObject* python_test_func(PyObject *self, PyObject *args);
 /* Set the module functions */
 static PyMethodDef module_methods[] = {
     // Wierdly, this casting to a PyCFunction, which usually takes only 2 args, now works when giving keywords. See https://stackoverflow.com/q/10264080
-    {"run_system", (PyCFunction)python_run_system, METH_VARARGS|METH_KEYWORDS, run_system_docstring}, 
+    {"run_system", (PyCFunction)python_run_system, METH_VARARGS|METH_KEYWORDS, run_system_docstring},
 
     //
     {"return_arglines", python_return_arglines, METH_VARARGS, return_arglines_docstring},
@@ -220,8 +220,8 @@ static PyObject* python_run_system(PyObject *self, PyObject *args, PyObject *kwa
         if (PyCapsule_IsValid(persistent_data_capsule, "PERSISTENT_DATA"))
         {
             if (!(persistent_data = (struct libbinary_c_persistent_data_t *) PyCapsule_GetPointer(persistent_data_capsule, "PERSISTENT_DATA")))
-                return NULL;   
-            debug_printf("Unpacked persistent_data pointer %p from capsule\n", persistent_data);                
+                return NULL;
+            debug_printf("Unpacked persistent_data pointer %p from capsule\n", persistent_data);
         }
     }
 
@@ -232,8 +232,8 @@ static PyObject* python_run_system(PyObject *self, PyObject *args, PyObject *kwa
         if (PyCapsule_IsValid(store_capsule, "STORE"))
         {
             if (!(store = (struct libbinary_c_store_t *) PyCapsule_GetPointer(store_capsule, "STORE")))
-                return NULL;   
-            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);            
+                return NULL;
+            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);
         }
     }
 
@@ -303,7 +303,7 @@ static PyObject* python_return_help_info(PyObject *self, PyObject *args)
 {
     /* Parse the input tuple */
     char *argstring;
-    
+
     if(!PyArg_ParseTuple(args, "s", &argstring))
     {
         return NULL;
@@ -327,7 +327,7 @@ static PyObject* python_return_help_info(PyObject *self, PyObject *args)
                 "Error (in function: binary_c_return_help_info): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -353,7 +353,7 @@ static PyObject* python_return_help_all_info(PyObject *self, PyObject *args)
                 "Error (in function: binary_c_return_help_all_info): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -379,7 +379,7 @@ static PyObject* python_return_version_info(PyObject *self, PyObject *args)
                 "Error (in function: binary_c_return_version_info): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -408,8 +408,8 @@ static PyObject* python_return_minimum_orbit_for_RLOF(PyObject *self, PyObject *
         if (PyCapsule_IsValid(store_capsule, "STORE"))
         {
             if (!(store = (struct libbinary_c_store_t *) PyCapsule_GetPointer(store_capsule, "STORE")))
-                return NULL;   
-            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);            
+                return NULL;
+            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);
         }
     }
 
@@ -465,8 +465,8 @@ static PyObject* python_return_maximum_mass_ratio_for_RLOF(PyObject *self, PyObj
         if (PyCapsule_IsValid(store_capsule, "STORE"))
         {
             if (!(store = (struct libbinary_c_store_t *) PyCapsule_GetPointer(store_capsule, "STORE")))
-                return NULL;   
-            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);            
+                return NULL;
+            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);
         }
     }
 
@@ -525,11 +525,11 @@ int return_maximum_mass_ratio_for_RLOF(char * argstring,
                         NULL,
                         NULL,
                         &store,
-                        NULL,   
+                        NULL,
                         &argstring,
                         -1);
 
-    // Set preferences. 
+    // Set preferences.
     stardata->preferences->show_maximum_mass_ratio_for_instant_RLOF = TRUE;
     snprintf(stardata->preferences->log_filename,
              STRING_LENGTH-1,"%s","/dev/null");
@@ -539,14 +539,14 @@ int return_maximum_mass_ratio_for_RLOF(char * argstring,
     stardata->preferences->batchmode = BATCHMODE_LIBRARY;
 
     /* Actually show the instant_rlof */
-    binary_c_show_instant_RLOF(stardata); // prints to the buffer. 
+    binary_c_show_instant_RLOF(stardata); // prints to the buffer.
 
     /* put results in buffer */
     binary_c_buffer_info(stardata, buffer, nbytes);
 
     /* Put errors in error buffer */
     binary_c_error_buffer(stardata, error_buffer);
- 
+
     Boolean free_persistent_data = TRUE;
 
     /* free stardata (except the buffer) */
@@ -590,7 +590,7 @@ static PyObject* python_return_store_memaddr(PyObject *self, PyObject *args)
         printf("Error (in function: binary_c_return_store_memaddr): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -622,7 +622,7 @@ static PyObject* python_return_persistent_data_memaddr(PyObject *self, PyObject
         printf("Error (in function: binary_c_return_persistent_data_memaddr): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -641,13 +641,13 @@ static PyObject* python_free_persistent_data_memaddr_and_return_json_output(PyOb
         fprintf(stderr,
                 "Error (in function: binary_c_free_persistent_data_memaddr_and_return_json_output): Got a bad input\n");
         printf("Error (in function: binary_c_free_persistent_data_memaddr_and_return_json_output): Got a bad input\n");
-        return NULL; // Add message for input        
+        return NULL; // Add message for input
     }
 
     // Unpack the capsule
     struct libbinary_c_persistent_data_t * persistent_data = NULL;
     if (!(persistent_data = (struct libbinary_c_persistent_data_t *) PyCapsule_GetPointer(persistent_data_memaddr_capsule, "PERSISTENT_DATA")))
-        return NULL;   
+        return NULL;
     debug_printf("Unpacked persistent_data pointer %p from capsule\n", persistent_data);
 
     // Interface with binary_c API
@@ -672,7 +672,7 @@ static PyObject* python_free_persistent_data_memaddr_and_return_json_output(PyOb
         printf("Error (in function: binary_c_free_persistent_data_memaddr_and_return_json_output): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -692,7 +692,7 @@ static PyObject* python_free_store_memaddr(PyObject *self, PyObject *args)
         fprintf(stderr,
                 "Error (in function: binary_c_free_store_memaddr): Got a bad input\n");
         printf("Error (in function: binary_c_free_store_memaddr): Got a bad input\n");
-        return NULL; // Add message for input        
+        return NULL; // Add message for input
     }
     // TODO: Add checks for validity of capsule
 
@@ -700,7 +700,7 @@ static PyObject* python_free_store_memaddr(PyObject *self, PyObject *args)
     // Unpack the capsule
     struct libbinary_c_store_t * store = NULL;
     if (!(store = (struct libbinary_c_store_t *) PyCapsule_GetPointer(store_memaddr_capsule, "STORE")))
-        return NULL;   
+        return NULL;
     debug_printf("Unpacked store pointer %p from capsule\n", store);
 
     int out MAYBE_UNUSED = free_store_memaddr(store,
@@ -720,7 +720,7 @@ static PyObject* python_free_store_memaddr(PyObject *self, PyObject *args)
         printf("Error (in function: binary_c_free_store_memaddr): %s\n",
                 error_buffer);
     }
-    
+
     Safe_free(buffer);
     Safe_free(error_buffer);
 
@@ -741,14 +741,14 @@ static PyObject* python_test_func(PyObject *self, PyObject *args)
  ************************************************************
  ** Section 2: binary_c interfacing functions
  **
- ** These functions call the binary_c API 
+ ** These functions call the binary_c API
  ************************************************************
  ************************************************************/
 
-/* Binary_c python API 
+/* Binary_c python API
  * Set of c-functions that interface with the binary_c api.
- * These functions are called by python, through the functions defined above. 
- * 
+ * These functions are called by python, through the functions defined above.
+ *
  * Contains several functions:
  * // evolution functions:
  * run_system
@@ -763,9 +763,9 @@ static PyObject* python_test_func(PyObject *self, PyObject *args)
  * // memory allocating functions:
  * return_store_memaddr
  * free_persistent_data_memaddr_and_return_json_output
- * 
+ *
  * // Memory freeing functions:
- * free_store_memaddr 
+ * free_store_memaddr
  * free_persistent_data_memaddr_and_return_json_output
  */
 
@@ -783,7 +783,7 @@ int stdoutwas;
 /* Functions to evolve systems                                         */
 /* =================================================================== */
 
-/* 
+/*
 Function that runs a system. Has multiple input parameters:
 Big function. Takes several arguments. See binary_c_python.c docstring.
 TODO: Describe each input
@@ -858,10 +858,10 @@ int run_system(char * argstring,
     /* do binary evolution */
     binary_c_evolve_for_dt(stardata,
                            stardata->model.max_evolution_time);
-        
+
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
 
@@ -919,10 +919,10 @@ int return_arglines(char ** const buffer,
 
     /* get buffer pointer */
     binary_c_buffer_info(stardata,buffer,nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata,error_buffer);
-    
+
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -931,7 +931,7 @@ int return_arglines(char ** const buffer,
         FALSE,                      // free_raw_buffer
         TRUE                        // free_persistent
     );
-    
+
     return 0;
 }
 
@@ -960,13 +960,13 @@ int return_help_info(char * argstring,
 
     /* Ask the help api */
     binary_c_help(stardata, argstring);
-        
+
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
-        
+
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -1004,13 +1004,13 @@ int return_help_all_info(char ** const buffer,
 
     /* Ask the help api */
     binary_c_help_all(stardata);
-        
+
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
-        
+
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -1048,13 +1048,13 @@ int return_version_info(char ** const buffer,
 
     /* Ask the help api */
     binary_c_version(stardata);
-        
+
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
-    
+
     /* free stardata (except the buffer) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -1075,7 +1075,7 @@ int return_minimum_orbit_for_RLOF(char * argstring,
 {
     /*
      * Return the binary_c minimum orbit (separation or period)
-     * that leads to RLOF 
+     * that leads to RLOF
      */
 
 
@@ -1091,16 +1091,16 @@ int return_minimum_orbit_for_RLOF(char * argstring,
         free_store = TRUE;
     }
 
-    // 
+    //
     binary_c_new_system(&stardata,
                         NULL,
                         NULL,
                         &store,
-                        NULL,   
+                        NULL,
                         &argstring,
                         -1);
 
-    // Set preferences. 
+    // Set preferences.
     stardata->preferences->show_minimum_separation_for_instant_RLOF = TRUE;
     stardata->preferences->show_minimum_orbital_period_for_instant_RLOF = TRUE;
     snprintf(stardata->preferences->log_filename,
@@ -1111,14 +1111,14 @@ int return_minimum_orbit_for_RLOF(char * argstring,
     stardata->preferences->batchmode = BATCHMODE_LIBRARY;
 
     /* Actually show the instant_rlof */
-    binary_c_show_instant_RLOF(stardata); // prints to the buffer. 
+    binary_c_show_instant_RLOF(stardata); // prints to the buffer.
 
     /* put results in buffer */
     binary_c_buffer_info(stardata, buffer, nbytes);
 
     /* Put errors in error buffer */
     binary_c_error_buffer(stardata, error_buffer);
- 
+
     //
     Boolean free_persistent_data = FALSE;
 
@@ -1163,10 +1163,10 @@ struct libbinary_c_store_t * return_store_memaddr(char ** const buffer,
 
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
-        
+
     /* free stardata (except the buffer and the store) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -1206,10 +1206,10 @@ struct persistent_data_t * return_persistent_data_memaddr(char ** const buffer,
 
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
-        
+
     /* free stardata (except the buffer and the persistent data) */
     binary_c_free_memory(&stardata, // Stardata
         TRUE,                       // free_preferences
@@ -1250,8 +1250,8 @@ int free_persistent_data_memaddr_and_return_json_output(struct persistent_data_t
     );
     debug_printf("Freed persistent_data pointer.\n");
 
-    /* Set the model hash (usually done internally but we're not evolving a system here */
-    stardata->model.ensemble_hash = stardata->persistent_data->ensemble_hash;
+    /* Set the model cdict (usually done internally but we're not evolving a system here */
+    stardata->model.ensemble_cdict = stardata->persistent_data->ensemble_cdict;
 
     /* output to strings */
     stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
@@ -1262,7 +1262,7 @@ int free_persistent_data_memaddr_and_return_json_output(struct persistent_data_t
 
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);
 
@@ -1308,7 +1308,7 @@ int free_store_memaddr(struct libbinary_c_store_t * store,
 
     /* get buffer pointer */
     binary_c_buffer_info(stardata, buffer, nbytes);
-    
+
     /* get error buffer pointer */
     binary_c_error_buffer(stardata, error_buffer);