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

resolved merge conflicts

parents a9718c02 57d5ced2
No related branches found
No related tags found
No related merge requests found
Python module for binary_c # Python module for binary_c
Based on a original work by Jeff Andrews, updated and extended Based on a original work by Jeff Andrews (can be found in old_solution/ directory)
for Python3 by Robert Izzard updated and extended for Python3 by Robert Izzard, David hendriks
Warning : THIS CODE IS EXPERIMENTAL! Warning : THIS CODE IS EXPERIMENTAL!
...@@ -9,41 +9,42 @@ r.izzard@surrey.ac.uk ...@@ -9,41 +9,42 @@ r.izzard@surrey.ac.uk
http://personal.ph.surrey.ac.uk/~ri0005/binary_c.html http://personal.ph.surrey.ac.uk/~ri0005/binary_c.html
09/06/2019 09/06/2019
------------------------------------------------------------ Requirements
--------------------- ---------------------
- Python3
- binary_c version 2.1+
- requirements.txt (no?)
Environment variables Environment variables
--------------------- ---------------------
Before compilation you should set the following 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 - 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: 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 Build instructions
--------------------- ---------------------
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:
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: ```
---
make clean make clean
make make
--- ```
Then to test the Python module:
then to test the Python module ```
---
python3 ./python_API_test.py 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). 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.
File added
#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;
}
#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
#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
...@@ -223,9 +223,9 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar ...@@ -223,9 +223,9 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar
{ {
/* Parse the input tuple */ /* Parse the input tuple */
char *argstring; 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; return NULL;
} }
...@@ -235,7 +235,7 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar ...@@ -235,7 +235,7 @@ static PyObject* binary_c_run_binary_custom_logging(PyObject *self, PyObject *ar
char * error_buffer; char * error_buffer;
size_t nbytes; size_t nbytes;
int out MAYBE_UNUSED = run_binary_custom_logging(argstring, int out MAYBE_UNUSED = run_binary_custom_logging(argstring,
str_1, func_memaddr,
&buffer, &buffer,
&error_buffer, &error_buffer,
&nbytes); &nbytes);
......
...@@ -20,7 +20,7 @@ int run_binary_with_logfile (char * argstring, ...@@ -20,7 +20,7 @@ int run_binary_with_logfile (char * argstring,
size_t * const nbytes); size_t * const nbytes);
int run_binary_custom_logging(char * argstring, int run_binary_custom_logging(char * argstring,
long int str_1, long int func_memaddr,
char ** const buffer, char ** const buffer,
char ** const error_buffer, char ** const error_buffer,
size_t * const nbytes); size_t * const nbytes);
......
...@@ -97,7 +97,7 @@ int run_binary(char * argstring, ...@@ -97,7 +97,7 @@ int run_binary(char * argstring,
} }
int run_binary_custom_logging(char * argstring, int run_binary_custom_logging(char * argstring,
long int str_1, long int func_memaddr,
char ** const buffer, char ** const buffer,
char ** const error_buffer, char ** const error_buffer,
size_t * const nbytes) size_t * const nbytes)
...@@ -127,7 +127,7 @@ int run_binary_custom_logging(char * argstring, ...@@ -127,7 +127,7 @@ int run_binary_custom_logging(char * argstring,
/* output to strings */ /* output to strings */
stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE; stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
stardata->preferences->batchmode = BATCHMODE_LIBRARY; 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 */ /* do binary evolution */
binary_c_evolve_for_dt(stardata, binary_c_evolve_for_dt(stardata,
......
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
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
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
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
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
#!/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
...@@ -7,8 +7,6 @@ import binary_c ...@@ -7,8 +7,6 @@ import binary_c
# module. # module.
############################################################ ############################################################
def run_test_binary(): def run_test_binary():
m1 = 15.0 # Msun m1 = 15.0 # Msun
m2 = 14.0 # Msun m2 = 14.0 # Msun
......
...@@ -19,6 +19,7 @@ binary_c_define_macros = [] ...@@ -19,6 +19,7 @@ binary_c_define_macros = []
defines = subprocess.run([binary_c_config,'define_macros'],stdout=subprocess.PIPE).stdout.decode('utf-8').split() defines = subprocess.run([binary_c_config,'define_macros'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
lone = re.compile('^-D(.+)$') lone = re.compile('^-D(.+)$')
partner = re.compile('^-D(.+)=(.+)$') partner = re.compile('^-D(.+)=(.+)$')
for x in defines: for x in defines:
y = partner.match(x) y = partner.match(x)
if(y): if(y):
...@@ -35,15 +36,15 @@ setup( ...@@ -35,15 +36,15 @@ setup(
name='binary_c', name='binary_c',
version='1.0', version='1.0',
description='This is a python API for binary_c by Rob Izzard and collaborators', description='This is a python API for binary_c by Rob Izzard and collaborators',
author='Jeff Andrews and Robert Izzard', 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', author_email='andrews@physics.uoc.gr and r.izzard@surrey.ac.uk and rob.izzard@gmail.com and dhendriks93@gmail.com',
license='', license='',
ext_modules=[Extension("binary_c", ext_modules=[Extension("binary_c",
["binary_c_python.c"], ["binary_c_python.c"],
libraries = ['binary_c']+binary_c_libs+['binary_c_api'], 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, 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, library_dirs = [os.environ['BINARY_C'] + '/src', './'] + binary_c_libdirs,
runtime_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, define_macros = [] + binary_c_define_macros,
extra_objects = [], extra_objects = [],
extra_compile_args = [], extra_compile_args = [],
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment