diff --git a/README.md b/README.md
index 8b5bbbd078609889117b1bed918296c1fff92c09..98ab80fe34b1093817757a896feb58e43dfbf38f 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-Python module for binary_c
+# Python module for binary_c
 
-Based on a original work by Jeff Andrews, updated and extended
-for Python3 by Robert Izzard
+Based on a original work by Jeff Andrews (can be found in old_solution/ directory)
+updated and extended for Python3 by Robert Izzard, David hendriks
 
 Warning : THIS CODE IS EXPERIMENTAL!
 
@@ -9,41 +9,42 @@ r.izzard@surrey.ac.uk
 http://personal.ph.surrey.ac.uk/~ri0005/binary_c.html
 09/06/2019
 
-------------------------------------------------------------
-
+Requirements
 ---------------------
+- Python3
+- binary_c version 2.1+
+- requirements.txt (no?)
+
 Environment variables
 ---------------------
-
 Before compilation you should set the following environment variables:
 
-required: BINARY_C should point to the root directory of your binary_c installation
-
-recommended: LD_LIBRARY_PATH should include $BINARY_C/src and whatever directories are required to run binary_c (e.g. locations of libgsl, libmemoize, librinterpolate, etc.)
+- required: `BINARY_C` should point to the root directory of your binary_c installation
+- recommended: `LD_LIBRARY_PATH` should include $BINARY_C/src and whatever directories are required to run binary_c (e.g. locations of libgsl, libmemoize, librinterpolate, etc.)
+- recommended: `LIBRARY_PATH` should include whatever directories are required to build binary_c (e.g. locations of libgsl, libmemoize, librinterpolate, etc.)
 
-recommended: LIBRARY_PATH should include whatever directories are required to build binary_c (e.g. locations of libgsl, libmemoize, librinterpolate, etc.)
-
-
-
----------------------
 Build instructions
 ---------------------
-
-To build the module, make sure you have built binary_c (with "make" in the binar_c root directory), its shared library (with "make libbinary_c.so" in the binary_c root directory), and set environment variables as described above, then run:
-
----
+To build the module, make sure you have built binary_c (with `make` in the binary_c root directory), its shared library (with `make libbinary_c.so` in the binary_c root directory), and set environment variables as described above, then run the following code in t:
+```
  make clean
  make
----
+```
+Then to test the Python module:
 
-then to test the Python module
-
----
+```
  python3 ./python_API_test.py
----
-
-
+```
 You will require whatever libraries with which binary_c was compiled, as well as the compiler with which Python was built (usually gcc, which is easily installed on most systems).
 
+If you want to be able to import the binary_c module correctly for child directories (or anywhere for that matter), execute or put the following code in your .bashrc/.zshrc: 
+```
+export LD_LIBRARY_PATH=<full path to directory containing libbinary_c_api.so>:$LD_LIBRARY_PATH
+export PYTHONPATH=<full path to directory containing libbinary_c_api.so>:$PYTHONPATH
+```
+
+Usage notes
+---------------------
+When running a jupyter notebook and importing binary_c, it might happen that the module binary_c cannot be found. I experienced this when I executed Jupyter Notebook from a virtual environment which didnt use the same python (version/binary/shim) as the one I built this library with. Make sure jupyter does use the same underlying python version/binary/shim. That resolved the issue for me.
 
-------------------------------------------------------------
+Also: I figured that having binaryc output the log like "<LOG HEADER> t=10e4 ..." (i.e. printing the parameter names as well as their values) would be useful because in that way one can easily have python read that out automatically instead of having to manually copy the list of parameter names.
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/__pycache__/defaults.cpython-36.pyc b/__pycache__/defaults.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..16d2a1e2a2eebed842457dfebe2c60d92cc79c8d
Binary files /dev/null and b/__pycache__/defaults.cpython-36.pyc differ
diff --git a/binary_c_api.c b/binary_c_api.c
deleted file mode 100644
index 487b3989e388353f0ee705bee5477765a99f4f22..0000000000000000000000000000000000000000
--- a/binary_c_api.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "binary_c_python.h"
-//#include "binary_c_api.h"
-#include "binary_c_API.h"
-#include "binary_c_API_prototypes.h"
-#include <time.h>
-#include <sys/timeb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-/*
- * apitest
- *
- * Short test programme to throw random binary systems at binary_c's
- * library via its API.
- *
- * Note that it looks more complicated than it is because I have included
- * code to capture binary_c's stdout stream and output it here.
- *
- * This code sends output to stderr : you should use apitest.sh to run it
- * and hence force output to your terminal's stdout.
- *
- * Output lines:
- *
- * APITEST ....  is information about what this code is doing.
- * STATUS  ....  is information about the binary system.
- * BINARY_C .... is output from binary_c (see iterate_logging.c etc.)
- *               which would have gone to stdout
- *
- * If you define the NO_OUTPUT macro, there will be no output except
- * the memory allocation and test system information. This is useful for speed tests,
- * but note that you may end up in a race condition where the pipe which replaces
- * stdout's buffer fills and hence the code stops.
- *
- * Note:
- * I have tested this with gcc 4.7.2 (Ubuntu 12.10) only.
- */
-
-
-// #define _CAPTURE
-#ifdef _CAPTURE
-static void show_stdout(void);
-static void capture_stdout(void);
-#endif
-
-
-/* global variables */
-int out_pipe[2];
-int stdoutwas;
-
-int main(int argc,
-         char * argv[])
-{
-    char * argstring = MALLOC(sizeof(char) * (size_t)STRING_LENGTH);
-    snprintf(argstring,
-             STRING_LENGTH,
-             "binary_c M_1 %g M_2 %g separation %g orbital_period %g metallicity %g max_evolution_time %g\n",
-             20.0,
-             15.0,
-             0.0,
-             3.0,
-             0.02,
-             15000.0);
-
-    char * buffer ;
-    size_t nbytes;
-    int out = run_binary(argstring,
-                     &buffer,
-                     &nbytes);
-
-    printf("output (binary_c returned %d)\n%s\n",out,buffer);
-
-    free(buffer);
-    
-    return out;
-}
-
-
-int run_binary(char * argstring,
-               char ** buffer,
-               size_t * nbytes)
-{
-    /* memory for N binary systems */
-    struct libbinary_c_stardata_t *stardata;
-    struct libbinary_c_store_t * store = NULL;
-
-    printf("argstring : %s\n",argstring);
-    fflush(stdout);
-
-    stardata = NULL;
-    binary_c_new_system(&stardata,
-                        NULL,
-                        NULL,
-                        &store,
-                        &argstring,
-                        -1);
-    snprintf(stardata->preferences->log_filename,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    snprintf(stardata->preferences->api_log_filename_prefix,
-             STRING_LENGTH-1,
-             "%s",
-             "/dev/null");
-    stardata->preferences->internal_buffering = 2;
-    stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-
-    binary_c_evolve_for_dt(stardata,
-                           stardata->model.max_evolution_time);
-
-    /*
-     * Save the buffer pointer
-     */
-    binary_c_buffer_info(stardata,&buffer,nbytes);
-
-    /*
-     * And free everything else
-     */    
-    binary_c_free_memory(&stardata,TRUE,TRUE,FALSE);
-    binary_c_free_store_contents(store);
-    
-    return 0;
-}
diff --git a/binary_c_api.h b/binary_c_api.h
deleted file mode 100644
index ef9f2ccdbb9d5f28b9d822d12ec7a9da432af606..0000000000000000000000000000000000000000
--- a/binary_c_api.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#ifndef BINARY_C_PYTHON_API_H
-#define BINARY_C_PYTHON_API_H
-
-/* local function prototypes */
-static void APIprintf(char * format,...);
-
-int run_binary(char * argstring,
-               char ** buffer,
-               size_t * nbytes);
-
-/* C macros */
-#define BINARY_C_APITEST_VERSION 0.1
-#define APIprint(...) APIprintf(__VA_ARGS__);
-#define NO_OUTPUT
-
-#endif // BINARY_C_PYTHON_API_H
diff --git a/binary_c_api_python.h b/binary_c_api_python.h
deleted file mode 100644
index ef9f2ccdbb9d5f28b9d822d12ec7a9da432af606..0000000000000000000000000000000000000000
--- a/binary_c_api_python.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-#ifndef BINARY_C_PYTHON_API_H
-#define BINARY_C_PYTHON_API_H
-
-/* local function prototypes */
-static void APIprintf(char * format,...);
-
-int run_binary(char * argstring,
-               char ** buffer,
-               size_t * nbytes);
-
-/* C macros */
-#define BINARY_C_APITEST_VERSION 0.1
-#define APIprint(...) APIprintf(__VA_ARGS__);
-#define NO_OUTPUT
-
-#endif // BINARY_C_PYTHON_API_H
diff --git a/binary_c_python.c b/binary_c_python.c
index 00f4abd5efb1d98f7411855d4c1c7a80258244ee..7a96ccc4d29f09a963d071ec5c049fd8c8e57454 100644
--- a/binary_c_python.c
+++ b/binary_c_python.c
@@ -223,9 +223,9 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar
 {
     /* Parse the input tuple */
     char *argstring;
-    long int str_1;
+    long int func_memaddr;
 
-    if(!PyArg_ParseTuple(args, "sl", &argstring, &str_1))
+    if(!PyArg_ParseTuple(args, "sl", &argstring, &func_memaddr))
     {
         return NULL;
     }
@@ -235,7 +235,7 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar
         char * error_buffer;
         size_t nbytes;
         int out MAYBE_UNUSED = run_binary_custom_logging(argstring,
-                                            str_1, 
+                                          func_memaddr, 
                                           &buffer,
                                           &error_buffer,
                                           &nbytes);
diff --git a/binary_c_python.h b/binary_c_python.h
index 152c6e51428f473cddf2f61f84c9128d5f00bcad..29979236ed26c9929c013c4f34a8b6fb5d75f2f0 100644
--- a/binary_c_python.h
+++ b/binary_c_python.h
@@ -20,7 +20,7 @@ int run_binary_with_logfile (char * argstring,
                 size_t * const nbytes);
 
 int run_binary_custom_logging(char * argstring,
-               long int str_1,
+               long int func_memaddr,
                char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes);
diff --git a/binary_c_python_api.c b/binary_c_python_api.c
index 04a0a9a8a442faa2f82eb5fbd47de8cb49c304d1..98aa26883644956eba1f5902b6c9e5d1a10091e8 100644
--- a/binary_c_python_api.c
+++ b/binary_c_python_api.c
@@ -97,7 +97,7 @@ int run_binary(char * argstring,
 }
 
 int run_binary_custom_logging(char * argstring,
-               long int str_1,
+               long int func_memaddr,
                char ** const buffer,
                char ** const error_buffer,
                size_t * const nbytes)
@@ -127,7 +127,7 @@ int run_binary_custom_logging(char * argstring,
     /* output to strings */
     stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
     stardata->preferences->batchmode = BATCHMODE_LIBRARY;
-    stardata->preferences->custom_output_function = str_1;
+    stardata->preferences->custom_output_function = (void*)(struct stardata_t *)func_memaddr;
 
     /* do binary evolution */
     binary_c_evolve_for_dt(stardata,
diff --git a/binaryc_python_utils/custom_logging_functions.py b/binaryc_python_utils/custom_logging_functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d82f67b1839ab4d7c23b5b01790c3f1f5c2fbc1
--- /dev/null
+++ b/binaryc_python_utils/custom_logging_functions.py
@@ -0,0 +1,276 @@
+import os
+import textwrap
+import subprocess
+import socket
+import tempfile
+import ctypes
+
+# Functions for the automatic logging of stuff
+def autogen_C_logging_code(logging_dict):
+    # See example_perl.pm autologging
+    """
+    Function that autogenerates PRINTF statements for binaryc
+
+    Input:
+        dictionary where the key is the header of that logging line and items which are lists of parameters that will be put in that logging line
+
+        example: {'MY_STELLAR_DATA': 
+        [
+            'model.time',
+            'star[0].mass',
+            'model.probability',
+            'model.dt'
+        ']}
+    """
+
+    # Check if the input is of the correct form 
+    if not type(logging_dict)==dict:
+        print("Error: please use a dictionary as input")
+        return None
+
+    code = ''
+    # Loop over dict keys
+    for key in logging_dict:
+        logging_dict_entry = logging_dict[key]
+
+        # Check if item is of correct type:
+        if type(logging_dict_entry)==list:
+
+            # Construct print statement
+            code += 'Printf("{}'.format(key)
+            code += ' {}'.format('%g '*len(logging_dict_entry))
+            code = code.strip()
+            code += '\\n"'
+
+            # Add format keys
+            for param in logging_dict_entry:
+                code += ',((double)stardata->{})'.format(param)
+            code += ');\n'
+
+        else:
+            print('Error: please use a list for the list of parameters that you want to have logged')
+    code = code.strip()
+    # print("MADE AUTO CODE\n\n{}\n\n{}\n\n{}\n".format('*'*60, repr(code), '*'*60))
+
+    return code
+
+####################################################################################
+def binary_c_log_code(code):
+    """
+    Function to construct the code to construct the custom logging function
+    # see example_perl.pm binary_c_log_code in perl
+    """
+    custom_logging_function_string = """\
+#pragma push_macro(\"MAX\")
+#pragma push_macro(\"MIN\")
+#undef MAX
+#undef MIN
+#include \"binary_c.h\"
+
+// add visibility __attribute__ ((visibility ("default"))) to it 
+void binary_c_API_function custom_output_function(struct stardata_t * stardata);
+void binary_c_API_function custom_output_function(struct stardata_t * stardata)
+{{
+    // struct stardata_t * stardata = (struct stardata_t *)x;
+    {};
+}}
+
+#undef MAX 
+#undef MIN
+#pragma pop_macro(\"MIN\")
+#pragma pop_macro(\"MAX\")\
+    """.format(code)
+     
+    # print(repr(textwrap.dedent(custom_logging_function_string)))
+    return textwrap.dedent(custom_logging_function_string)
+
+def binary_c_write_log_code(code, filename):
+    """
+    Function to write the generated logging code to a file
+    """
+
+    cwd = os.getcwd()
+
+    filePath = os.path.join(cwd, filename)
+    if os.path.exists(filePath):
+        try:
+            os.remove(filePath)
+        except:
+            print("Error while deleting file {}".format(filePath))
+
+    with open(filePath, 'w') as f:
+        f.write(code)
+
+def from_binary_c_config(config_file, flag):
+    """
+    Function to run the binaryc_config command with flags
+    """
+
+    res = subprocess.check_output('{config_file} {flag}'.format(config_file=config_file, flag=flag),
+        shell=True, stderr=subprocess.STDOUT)
+
+    # convert and chop off newline
+    res = res.decode('utf').rstrip()
+    return res
+
+def return_compilation_dict():
+    """
+    Function to build the compile command for the shared library
+
+    inspired by binary_c_inline_config command in perl
+
+    TODO: this function still has some cleaning up to do wrt default values for the compile command
+    # https://developers.redhat.com/blog/2018/03/21/compiler-and-linker-flags-gcc/
+
+
+    returns:
+     - string containing the command to build the shared library
+    """    
+
+    # use binary_c-config to get necessary flags
+    BINARY_C_DIR = os.getenv('BINARY_C')
+    if BINARY_C_DIR:
+        BINARY_C_CONFIG = os.path.join(BINARY_C_DIR, 'binary_c-config')
+        BINARY_C_SRC_DIR = os.path.join(BINARY_C_DIR, 'src')
+        # TODO: build in check to see whether the file exists
+    else:
+        raise NameError('Envvar BINARY_C doesnt exist')
+        return None
+
+    # TODO: make more options for the compiling
+    cc = from_binary_c_config(BINARY_C_CONFIG, 'cc')
+
+    # Check for binary_c
+    BINARY_C_EXE = os.path.join(BINARY_C_DIR, 'binary_c')
+    if not os.path.isfile(BINARY_C_EXE):
+        print("We require  binary_c executable; have you built binary_c?")
+        raise NameError('BINARY_C executable doesnt exist')
+
+    # TODO: debug
+    libbinary_c = '-lbinary_c'
+    binclibs = from_binary_c_config(BINARY_C_CONFIG, 'libs')
+    libdirs = "{} -L{}".format(from_binary_c_config(BINARY_C_CONFIG, 'libdirs'), BINARY_C_SRC_DIR)
+    bincflags = from_binary_c_config(BINARY_C_CONFIG, 'cflags')
+    bincincdirs = from_binary_c_config(BINARY_C_CONFIG, 'incdirs')
+
+    # combine 
+    binclibs = ' {} {} {}'.format(libdirs, libbinary_c, binclibs)
+
+    # setup defaults:
+    defaults = {
+        'cc': 'gcc', # default compiler
+        'ccflags': bincflags,
+        'ld': 'ld',         # 'ld': $Config{ld}, # default linker
+        'debug': 0,
+        'inc': '{} -I{}'.format(bincincdirs, BINARY_C_SRC_DIR),
+        # inc => ' '.($Config{inc}//' ').' '.$bincincdirs." -I$srcdir ", # include the defaults plus # GSL and binary_c
+        # 'libname': libname, # libname is usually just binary_c corresponding to libbinary_c.so
+        'libs': binclibs,
+    }
+
+    # set values with defaults. TODO: make other input possile.
+    ld = defaults['ld']
+    debug = defaults['debug']
+    inc = defaults['inc'] # = ($ENV{BINARY_GRID2_INC} // $defaults{inc}).' '.($ENV{BINARY_GRID2_EXTRAINC} // '');
+    libs = defaults['libs'] # = ($ENV{BINARY_GRID2_LIBS} // $defaults{libs}).' '.($ENV{BINARY_GRID2_EXTRALIBS}//'');
+    ccflags = defaults['ccflags'] #  = $ENV{BINARY_GRID2_CCFLAGS} // ($defaults{ccflags}) . ($ENV{BINARY_GRID2_EXTRACCFLAGS} // '');
+  
+    # you must define _SEARCH_H to prevent it being loaded twice
+    ccflags += ' -shared -D_SEARCH_H'
+
+    # remove the visibility=hidden for this compilation
+    ccflags = ccflags.replace('-fvisibility=hidden', '')
+
+
+    # ensure library paths to the front of the libs:
+    libs_content = libs.split(' ')
+    library_paths = [el for el in libs_content if el.startswith('-L')]
+    non_library_paths = [el for el in libs_content if (not el.startswith('-L') and not el=='')]
+    libs = "{} {}".format(' '.join(library_paths), ' '.join(non_library_paths))
+
+    print("Building shared library for custom logging with (binary_c.h) at {} on {}\n".format(BINARY_C_SRC_DIR, socket.gethostname()))
+    print("With options:\n\tcc = {cc}\n\tccflags = {ccflags}\n\tld = {ld}\n\tlibs = {libs}\n\tinc = {inc}\n\n".format(
+        cc=cc, ccflags=ccflags, ld=ld, libs=libs, inc=inc)
+    )
+
+    return {
+        'cc': cc,
+        'ld': ld,
+        'ccflags': ccflags,
+        'libs': libs,
+        'inc': inc
+        }
+
+def compile_shared_lib(code, sourcefile_name, outfile_name):
+    """
+    Function to write the custom logging code to a file and then compile it.
+    """
+
+    # Write code to file
+    binary_c_write_log_code(code, sourcefile_name)
+
+    # create compilation command
+    compilation_dict = return_compilation_dict()
+
+    # Construct full command
+    command = "{cc} {ccflags} {libs} -o {outfile_name} {sourcefile_name} {inc}".format(
+        cc=compilation_dict['cc'],
+        ccflags=compilation_dict['ccflags'],
+        libs=compilation_dict['libs'],
+        outfile_name=outfile_name,
+        sourcefile_name=sourcefile_name,
+        inc=compilation_dict['inc'])
+
+    # remove extra whitespaces:
+    command = ' '.join(command.split())
+
+    # Execute compilation
+    print('Executing following command:\n{command}'.format(command=command))
+    res = subprocess.check_output('{command}'.format(command=command),
+        shell=True)
+
+    if res:
+        print('Output of compilation command:\n{}'.format(res))
+
+
+def temp_custom_logging_dir():
+    """
+    Function to return the path the custom logging library shared object and script will be written to.
+
+    Makes use of os.makedirs exist_ok which requires python 3.2+
+    """
+
+    tmp_dir = tempfile.gettempdir()
+    path = os.path.join(tmp_dir, 'binary_c_python')
+
+    # 
+    os.makedirs(path, exist_ok=True)
+
+    return path
+
+
+def create_and_load_logging_function(custom_logging_code):
+    """
+    Function to automatically compile the shared library with the given custom logging code and load it with ctypes
+
+    returns:
+        memory adress of the custom logging function in a int type.
+    """
+
+    # 
+    compile_shared_lib(custom_logging_code, 
+            sourcefile_name=os.path.join(temp_custom_logging_dir(), 'custom_logging.c'), 
+            outfile_name=os.path.join(temp_custom_logging_dir(), 'libcustom_logging.so')
+        )
+
+    # Loading library
+    dll1 = ctypes.CDLL('libgslcblas.so', mode=ctypes.RTLD_GLOBAL)
+    dll2 = ctypes.CDLL('libgsl.so', mode=ctypes.RTLD_GLOBAL)
+    dll3 = ctypes.CDLL('libbinary_c.so', mode=ctypes.RTLD_GLOBAL)
+    libmean = ctypes.CDLL(os.path.join(temp_custom_logging_dir(), 'libcustom_logging.so'),
+        mode=ctypes.RTLD_GLOBAL) # loads the shared library
+
+    # Get memory adress of function. mimicking a pointer
+    func_memaddr = ctypes.cast(libmean.custom_output_function, ctypes.c_void_p).value
+
+    return func_memaddr
diff --git a/binaryc_python_utils/functions.py b/binaryc_python_utils/functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..be648e1bf4a496f1a58b89c393bfc6f6f076b2d8
--- /dev/null
+++ b/binaryc_python_utils/functions.py
@@ -0,0 +1,174 @@
+from collections import defaultdict
+
+import binary_c
+from binaryc_python_utils.custom_logging_functions import create_and_load_logging_function
+
+def create_arg_string(arg_dict):
+    """
+    Function that creates the arg string
+    """
+    arg_string = '' 
+    for key in arg_dict.keys():
+        arg_string += "{key} {value} ".format(key=key, value=arg_dict[key])
+    arg_string = arg_string.strip()
+    return arg_string
+
+def get_defaults():
+    """
+    Function that calls the binaryc get args function and cast it into a dictionary
+    All the values are strings
+    """
+    default_output = binary_c.return_arglines()
+    default_dict = {}
+
+    for default in default_output.split('\n'):
+        if not default  in ['__ARG_BEGIN', '__ARG_END', '']:
+            key, value = default.split(' = ')
+
+            # Filter out NULLS (not compiled anyway)
+            if not value in ['NULL', 'Function']:
+                if not value=='':
+                    default_dict[key] = value
+    return default_dict
+
+def get_arg_keys():
+    """
+    Function that return the list of possible keys to give in the arg string
+    """
+
+    return get_defaults().keys()
+
+def run_system(**kwargs):
+    """
+    Wrapper to run a system with settings 
+    
+    This function determines which underlying python-c api function will be called based upon the arguments that are passed via kwargs.
+
+    - if custom_logging_code or custom_logging_dict is included in the kwargs then it will     
+    - if 
+
+    """
+
+    # Load default args
+    args = get_defaults()
+    if 'custom_logging_code' in kwargs:
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            if not key=='custom_logging_code':
+                args[key] = kwargs[key]
+
+        # Generate library and get memaddr
+        func_memaddr = create_and_load_logging_function(kwargs['custom_logging_code'])
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = 'binary_c {}'.format(arg_string)
+
+        # Run it and get output
+        output = binary_c.run_binary_custom_logging(arg_string, func_memaddr)
+        return output
+
+    elif 'log_filename' in kwargs:
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            args[key] = kwargs[key]
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = 'binary_c {}'.format(arg_string)
+
+        # Run it and get output
+        output = binary_c.run_binary_with_logfile(arg_string)
+        return output
+
+    else: # run the plain basic type
+
+        # Use kwarg value to override defaults and add new args
+        for key in kwargs.keys():
+            args[key] = kwargs[key]
+
+        # Construct arguments string and final execution string
+        arg_string = create_arg_string(args)
+        arg_string = 'binary_c {}'.format(arg_string)
+
+        # Run it and get output
+        output = binary_c.run_binary(arg_string)
+
+        return output
+
+def run_system_with_log(**kwargs):
+    """
+    Wrapper to run a system with settings AND logs the files to a designated place defined by the log_filename parameter.
+    """
+
+    # Load default args
+    args = get_defaults()
+    # args = {}
+
+    # For example
+    # physics_args['M_1'] = 20
+    # physics_args['separation'] = 0 # 0 = ignored, use period
+    # physics_args['orbital_period'] = 100000000000 # To make it single
+
+    # Use kwarg value to override defaults and add new args
+    for key in kwargs.keys():
+        args[key] = kwargs[key]
+
+    # Construct arguments string and final execution string
+    arg_string = create_arg_string(args)
+    arg_string = 'binary_c {}'.format(arg_string) 
+    
+    # print(arg_string)
+
+    # Run it and get output
+    buffer = ""
+    output = binary_c.run_binary_with_log(arg_string)
+
+    return output
+
+def parse_output(output, selected_header):
+    """
+    Function that parses output of binaryc when it is construction like this:
+    DAVID_SINGLE_ANALYSIS t=0 mass=20 
+
+    You can give a 'selected_header' to catch any line that starts with that. 
+    Then the values will be put into a dictionary.
+    TODO: Think about exporting to numpy array or pandas
+
+    """
+    value_dicts = []
+    val_lists = []
+
+    # split output on newlines
+    for i, line in enumerate(output.split('\n')):
+        # Skip any blank lines
+        if not line=='':
+            split_line = line.split()
+
+            # Select parts
+            header = split_line[0]
+            value_array = split_line[1:]
+
+            # Catch line starting with selected header
+            if header==selected_header:
+                # print(value_array)
+                # Make a dict 
+                value_dict = {}
+                for el in value_array:
+                    key, val = el.split('=')
+                    value_dict[key] = val
+                value_dicts.append(value_dict)
+
+    if len(value_dicts)==0:
+        print('Sorry, didnt find any line matching your header {}'.format(selected_header))
+        return None
+
+    keys = value_dicts[0].keys()
+
+    # Construct final dict.
+    final_values_dict = defaultdict(list)
+    for value_dict in value_dicts:
+        for key in keys:
+            final_values_dict[key].append(value_dict[key])
+
+    return final_values_dict
\ No newline at end of file
diff --git a/binaryc_python_utils/stellar_types.py b/binaryc_python_utils/stellar_types.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f947f28bca95043af541510d840b79429d1e6d1
--- /dev/null
+++ b/binaryc_python_utils/stellar_types.py
@@ -0,0 +1,18 @@
+stellar_type = {
+    0: 'low mass main sequence', 
+    1: 'Main Sequence',
+    2: 'Hertzsprung Gap',
+    3: 'First Giant Branch', 
+    4: 'Core Helium Burning',
+    5: 'Early Asymptotic Giant Branch',
+    6: 'Thermally Pulsing', 
+    7: 'NAKED_MAIN_SEQUENCE_HELIUM_STAR',
+    8: 'NAKED_HELIUM_STAR_HERTZSPRUNG_GAP',
+    9: 'NAKED_HELIUM_STAR_GIANT_BRANCH',
+    10: 'HELIUM_WHITE_DWARF', 
+    11: 'CARBON_OXYGEN_WHITE_DWARF',
+    12: 'OXYGEN_NEON_WHITE_DWARF',
+    13: 'NEUTRON_STAR', 
+    14: 'BLACK_HOLE', 
+    15: 'MASSLESS REMNANT'
+}
\ No newline at end of file
diff --git a/compile_script.txt b/compile_script.txt
deleted file mode 100644
index db54dea283afd4f9e9c5c5ec801d0498c51021e2..0000000000000000000000000000000000000000
--- a/compile_script.txt
+++ /dev/null
@@ -1,61 +0,0 @@
-Jeff's instructions
-
-please see README.md instead!
-
-
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
-
-
-
-
-
-----
-
-First, we need to compile binary_c_api.c into a shared library. We can do this by either the short way
-
-make all
-
-or the long way
-
-gcc binary_c_api.c -c -lbinary_c -lm -lc -fpic
-gcc -shared -o libbinary_c_api.so binary_c_api.o
-
-####
-
-export BINARY_C=...
-export LD_LIBRARY_PATY=$BINARY_C/src
-
-gcc `$BINARY_C/binary_c-config --flags` binary_c_api.c -c 
-
-
-####
-
-Next, we need to make sure that the current directory (that containing libbinary_c_api.so) is included in $LD_LIBRARY_PATH
-export LD_LIBRARY_PATH=....
-
-
-Next, we compile the python setup.py script:
-python setup.py build_ext --inplace
-
-Within python, you should be able to now run:
-python python_API_test.py
-
-
-Or access the python functions within an ipython notebook:
-import binary_c
-binary_c.function_name()
-
-
-To remake, first, start by running
-make clean
-
diff --git a/examples/example_run_binary_with_custom_logging.py b/examples/example_run_binary_with_custom_logging.py
new file mode 100644
index 0000000000000000000000000000000000000000..02336da32feb64a334bcea5efcf601e9c635b5ee
--- /dev/null
+++ b/examples/example_run_binary_with_custom_logging.py
@@ -0,0 +1,32 @@
+import ctypes
+import tempfile
+import os
+
+from binaryc_python_utils.custom_logging_functions import autogen_C_logging_code, binary_c_log_code, compile_shared_lib, temp_custom_logging_dir, create_and_load_logging_function
+import binary_c
+
+# generate logging lines
+logging_line = autogen_C_logging_code(
+    {
+        'MY_STELLAR_DATA': ['model.time', 'star[0].mass'], 
+        'my_sss2': ['model.time', 'star[1].mass']
+    }
+)
+
+# Generate code around logging lines
+custom_logging_code = binary_c_log_code(logging_line)
+
+# Generate library and get memaddr
+func_memaddr = create_and_load_logging_function(custom_logging_code)
+
+# 
+m1 = 15.0 # Msun
+m2 = 14.0 # Msun
+separation = 0 # 0 = ignored, use period
+orbital_period = 4530.0 # days
+eccentricity = 0.0
+metallicity = 0.02
+max_evolution_time = 15000
+argstring = "binary_c M_1 {0:g} M_2 {1:g} separation {2:g} orbital_period {3:g} eccentricity {4:g} metallicity {5:g} max_evolution_time {6:g}".format(m1,m2,separation,orbital_period,eccentricity,metallicity,max_evolution_time)
+output = binary_c.run_binary_custom_logging(argstring, func_memaddr)
+print(output)
\ No newline at end of file
diff --git a/examples/examples_run_binary.py b/examples/examples_run_binary.py
new file mode 100644
index 0000000000000000000000000000000000000000..2bd18c2cb728a5bec53cf2f8efa450b2ef6f45e5
--- /dev/null
+++ b/examples/examples_run_binary.py
@@ -0,0 +1,144 @@
+#!/usr/bin/python3
+import os
+import sys
+
+import binary_c
+
+from binaryc_python_utils.functions import run_system, parse_output
+from binaryc_python_utils.custom_logging_functions import autogen_C_logging_code, binary_c_log_code
+
+"""
+Very basic scripts to run a binary system and print the output.
+
+Use these as inspiration/base
+"""
+
+def run_example_binary():
+    """
+    Function to run a binary system. Very basic approach which directly adresses the run_binary(..) python-c wrapper function. 
+
+    """
+
+    m1 = 15.0 # Msun
+    m2 = 14.0 # Msun
+    separation = 0 # 0 = ignored, use period
+    orbital_period = 4530.0 # days
+    eccentricity = 0.0
+    metallicity = 0.02
+    max_evolution_time = 15000 # Myr. You need to include this argument.
+
+    # 
+    argstring = "binary_c M_1 {m1} M_2 {m2} separation {separation} orbital_period {orbital_period} \
+        eccentricity {eccentricity} metallicity {metallicity} \
+        max_evolution_time {max_evolution_time}".format(m1=m1, m2=m2, separation=separation, orbital_period=orbital_period, eccentricity=eccentricity, metallicity=metallicity, max_evolution_time=max_evolution_time)
+    output = binary_c.run_binary(argstring)
+    print (output)
+
+run_example_binary()
+
+def run_example_binary_with_run_system():
+    """
+    This function serves as an example on the function run_system and parse_output. 
+    There is more functionality with this method and several tasks are done behind the scene.
+
+    Requires pandas, numpy to run.
+
+    run_system: mostly just makes passing arguments to the function easier. It also loads all the necessary defaults in the background
+    parse_output: Takes the raw output of binary_c and selects those lines that start with the given header. 
+    Note, if you dont use the custom_logging functionality binary_c should be configured to have output that starts with that given header
+    """
+
+    import pandas as pd
+    import numpy as np
+
+    # Run system. all arguments can be given as optional arguments.
+    output = run_system(M_1=10, M_2=20, separation=0, orbital_period=100000000000)
+
+    # Catch results that start with a given header. (Mind that binary_c has to be configured to print them if your not using a custom logging function)
+    result_example_header = parse_output(output, 'example_header')
+
+    #### Now do whatever you want with it: 
+    # Put it in numpy arrays
+    #t_res = np.asarray(result_example_header['t'], dtype=np.float64, order='C')
+    #m_res = np.asarray(result_example_header['mass'], dtype=np.float64, order='C')
+
+    # Cast the data into a dataframe. 
+    df = pd.DataFrame.from_dict(result_example_header, dtype=np.float64)
+
+    # print(df) 
+    # sliced_df = df[df.t < 1000] # Cut off late parts of evolution
+    # print(sliced_df[["t","m1"]])
+
+    # Some routine to plot.
+
+run_example_binary_with_run_system()
+
+
+def run_example_binary_with_custom_logging():
+    """
+    Function that will use a automatically generated piece of logging code. Compile it, load it 
+    into memory and run a binary system. See run_system on how several things are done in the background here.
+    """
+
+    import pandas as pd
+    import numpy as np
+
+    # generate logging lines. Here you can choose whatever you want to have logged, and with what header
+    # this generates working print statements
+    logging_line = autogen_C_logging_code(
+        {
+            'MY_STELLAR_DATA': ['model.time', 'star[0].mass'], 
+        }
+    )
+    # OR
+    # You can also decide to `write` your own logging_line, which allows you to write a more complex logging statement with conditionals.
+    logging_line = 'Printf("MY_STELLAR_DATA time=%g mass=%g\\n", stardata->model.time, stardata->star[0].mass)'
+
+    # Generate entire shared lib code around logging lines
+    custom_logging_code = binary_c_log_code(logging_line)
+
+    # Run system. all arguments can be given as optional arguments. the custom_logging_code is one of them and will be processed automatically.
+    output = run_system(M_1=1, metallicity=0.002, M_2=0.1, separation=0, orbital_period=100000000000, custom_logging_code=custom_logging_code)
+
+    # Catch results that start with a given header. (Mind that binary_c has to be configured to print them if your not using a custom logging function)
+    # DOESNT WORK YET if you have the line autogenerated.
+    result_example_header = parse_output(output, 'MY_STELLAR_DATA')
+
+    # Cast the data into a dataframe. 
+    df = pd.DataFrame.from_dict(result_example_header, dtype=np.float64)
+
+    # Do whatever you like with the dataframe.
+    print(df)
+
+run_example_binary_with_custom_logging()
+
+def run_example_binary_with_writing_logfile():
+    """
+    Same as above but when giving the log_filename argument the log filename will be written
+    """
+
+    import pandas as pd
+    import numpy as np
+    import tempfile
+
+    # Run system. all arguments can be given as optional arguments.
+    output = run_system(M_1=10, M_2=20, separation=0, orbital_period=100000000000, log_filename=tempfile.gettempdir()+'/test_log.txt')
+
+    # Catch results that start with a given header. (Mind that binary_c has to be configured to print them if your not using a custom logging function)
+    result_example_header = parse_output(output, 'example_header')
+
+    #### Now do whatever you want with it: 
+    # Put it in numpy arrays
+    #t_res = np.asarray(result_example_header['t'], dtype=np.float64, order='C')
+    #m_res = np.asarray(result_example_header['mass'], dtype=np.float64, order='C')
+
+    # Cast the data into a dataframe. 
+    df = pd.DataFrame.from_dict(result_example_header, dtype=np.float64)
+
+    # print(df) 
+    # sliced_df = df[df.t < 1000] # Cut off late parts of evolution
+    # print(sliced_df[["t","m1"]])
+
+    # Some routine to plot.
+
+run_example_binary_with_writing_logfile()
\ No newline at end of file
diff --git a/python_API_test.py b/python_API_test.py
index bbba1d945e24ed8fd0df2c60dd33fcf2cea920f0..fb77ec234976cdeb13e76c336c7563842eb6c97d 100755
--- a/python_API_test.py
+++ b/python_API_test.py
@@ -7,8 +7,6 @@ import binary_c
 # module.
 ############################################################
 
-
-
 def run_test_binary():
     m1 = 15.0 # Msun
     m2 = 14.0 # Msun
diff --git a/setup.py b/setup.py
index cbd77df3804dce2ca919f783908d14803dc9cdd1..db7f9600e8603b1e903964e451f7187161f81f03 100644
--- a/setup.py
+++ b/setup.py
@@ -19,6 +19,7 @@ binary_c_define_macros = []
 defines = subprocess.run([binary_c_config,'define_macros'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
 lone = re.compile('^-D(.+)$')
 partner = re.compile('^-D(.+)=(.+)$')
+
 for x in defines:
     y = partner.match(x)
     if(y):
@@ -35,15 +36,15 @@ setup(
     name='binary_c',
     version='1.0',
     description='This is a python API for binary_c by Rob Izzard and collaborators',
-    author='Jeff Andrews and Robert Izzard',
-    author_email='andrews@physics.uoc.gr and r.izzard@surrey.ac.uk and rob.izzard@gmail.com',
+    author='Jeff Andrews and Robert Izzard and David Hendriks',
+    author_email='andrews@physics.uoc.gr and r.izzard@surrey.ac.uk and rob.izzard@gmail.com and dhendriks93@gmail.com',
 license='',
     ext_modules=[Extension("binary_c",
                            ["binary_c_python.c"],
-                           libraries = ['binary_c']+binary_c_libs+['binary_c_api'],
-                           include_dirs = [os.environ['BINARY_C']+'/src',os.environ['BINARY_C']+'/src/API']+binary_c_incdirs,
-                           library_dirs = [os.environ['BINARY_C']+'/src', './'] + binary_c_libdirs,
-                           runtime_library_dirs = [os.environ['BINARY_C']+'/src', './']+binary_c_libdirs,
+                           libraries = ['binary_c'] + binary_c_libs + ['binary_c_api'],
+                           include_dirs = [os.environ['BINARY_C'] + '/src', os.environ['BINARY_C'] + '/src/API'] + binary_c_incdirs,
+                           library_dirs = [os.environ['BINARY_C'] + '/src', './'] + binary_c_libdirs,
+                           runtime_library_dirs = [os.environ['BINARY_C']+'/src', './'] + binary_c_libdirs,
                            define_macros = [] + binary_c_define_macros,
                            extra_objects = [],
                            extra_compile_args = [],