Skip to content
Snippets Groups Projects
Commit 8cc082a4 authored by Izzard, Robert Dr (Maths & Physics)'s avatar Izzard, Robert Dr (Maths & Physics)
Browse files

add a first, experimental, version of binary_c-python

parents
No related branches found
No related tags found
No related merge requests found
Makefile 0 → 100644
# Makefile for Rapid Binary Star Evolution program
# you will need to set the BINARY_C variable to point
# to the root binary_c directory
CC := gcc
LD := gcc
PROGRAM := binary_c_python_api
MAKE := /usr/bin/make
LIBS := -lbinary_c `$(BINARY_C)/binary_c-config --libs`
C_SRC := binary_c_python_api.c
OBJECTS := $(C_SRC:.c=.o)
OBJ_FLAGS := -c
CFLAGS := -fPIC `$(BINARY_C)/binary_c-config --flags` -I$(BINARY_C)/src/ -I$(BINARY_C)/src/API
SO_FLAGS := -shared -o
SO_NAME := libbinary_c_api.so
# To create python shared library
PY_EXEC := python3
PY_SETUP := setup.py
PY_OPTIONS := build_ext --inplace
all: $(OBJECTS)
$(CC) -DBINARY_C=$(BINARY_C) $(CFLAGS) $(INCDIRS) $(C_SRC) $(OBJ_FLAGS) $(INCDIRS) $(LIBS)
$(CC) -DBINARY_C=$(BINARY_C) $(SO_FLAGS) $(SO_NAME) $(OBJECTS)
$(PY_EXEC) $(PY_SETUP) $(PY_OPTIONS)
clean:
rm -f *.o *.so
Python module for binary_c
Based on a original work by Jeff Andrews, updated and extended
for Python3 by Robert Izzard
>>> THIS CODE IS VERY EXPERIMENTAL AND PROBABLY WILL NOT WORK <<<
r.izzard@surrey.ac.uk
http://personal.ph.surrey.ac.uk/~ri0005/binary_c.html
09/06/2019
------------------------------------------------------------
---------------------
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.)
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:
---
make clean
make
---
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).
------------------------------------------------------------
#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->internal_buffering_compression = 0;
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
#include <Python.h>
#include "binary_c_python.h"
/*
* binary_c/PYTHON API interface functions
*
* Remember: variables must be passed by references
* (i.e. as pointers).
*
* See apitest.py for an expmple of how to use these functions.
*
* See also
* http://www-h.eng.cam.ac.uk/help/tpl/languages/mixinglanguages.html
*/
/* list of variables used in the Py<>C interface */
/************************************************************/
/*
* function prototypes : these are the functions
* called by PYTHON code, without the trailing underscore.
*/
/************************************************************/
static char module_docstring[] MAYBE_UNUSED =
"This module is a python wrapper around binary_c";
#ifdef __DEPRECATED
static char create_binary_docstring[] =
"Allocate memory for a binary";
#endif
static char run_binary_docstring[] =
"Run one binary using binary_c";
static char new_binary_system_docstring[] =
"Return an object containing a binary, ready for evolution";
static char function_prototype_docstring[] =
"The prototype for a binary_c python function";
static struct libbinary_c_store_t *store = NULL;
#ifdef __DEPRECATED
static PyObject* binary_c_create_binary(PyObject *self, PyObject *args);
#endif
static PyObject* binary_c_run_binary(PyObject *self, PyObject *args);
static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args);
static PyObject* binary_c_new_binary_system(PyObject *self, PyObject *args);
/*
* Python 3 interface is described at
*
* http://scipy-lectures.org/advanced/interfacing_with_c/interfacing_with_c.html
*/
static PyMethodDef module_methods[] = {
#ifdef __DEPRECATED
{"create_binary", binary_c_create_binary, METH_VARARGS, create_binary_docstring},
#endif
{"run_binary", binary_c_run_binary, METH_VARARGS, run_binary_docstring},
{"function_prototype", binary_c_function_prototype, METH_VARARGS, function_prototype_docstring},
{"new_system", binary_c_new_binary_system, METH_VARARGS, new_binary_system_docstring},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION >= 3
/* Python 3+ */
static struct PyModuleDef Py_binary_c =
{
PyModuleDef_HEAD_INIT,
"binary_c", /* name of module */
"binary_c docs", /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
module_methods
};
PyMODINIT_FUNC PyInit_binary_c(void)
{
return PyModule_Create(&Py_binary_c);
}
#else
/*
* Python pre-V3
*
* NOT TESTED THOROUGHLY!
*/
PyMODINIT_FUNC initbinary_c(void)
{
PyObject *m = Py_InitModule3("binary_c", module_methods, module_docstring);
if(m == NULL)
return;
}
#endif // Python version check
#ifdef __DEPRECATED
static PyObject* binary_c_create_binary(PyObject *self, PyObject *args){
double var1, var2;
char * empty_str = "";
int i;
const int N = 1;
/* Parse the input tuple */
if(!PyArg_ParseTuple(args, "dd", &var1, &var2))
return NULL;
/* Binary structures */
struct libbinary_c_stardata_t *stardata[N];
struct libbinary_c_store_t *store = NULL;
/* Allocate memory for binaries */
for(i=0;i<N;i++){
stardata[i] = NULL;
binary_c_new_system(&stardata[i], NULL, NULL, &store, &empty_str, -1);
}
/* Return the evolved binary */
PyObject *ret = Py_BuildValue("");
return ret;
}
#endif
static PyObject* binary_c_new_binary_system(PyObject *self, PyObject *args)
{
/* Binary structures */
struct libbinary_c_stardata_t *stardata;
/* Allocate memory for binaries */
char * empty_str = "";
stardata = NULL;
binary_c_new_system(&stardata, NULL, NULL, &store, &empty_str, -1);
/* Return an object containing the stardata */
PyObject *ret = Py_BuildValue("");
return ret;
}
static PyObject* binary_c_function_prototype(PyObject *self, PyObject *args)
{
double var1, var2;
/* Parse the input tuple */
if(!PyArg_ParseTuple(args, "dd", &var1, &var2))
{
return NULL;
}
else
{
/* Return the evolved binary */
PyObject *ret = Py_BuildValue("");
return ret;
}
}
static PyObject* binary_c_run_binary(PyObject *self, PyObject *args)
{
/* Parse the input tuple */
char *argstring;
if(!PyArg_ParseTuple(args, "s", &argstring))
{
return NULL;
}
else
{
char * buffer;
int nbytes;
int out MAYBE_UNUSED = run_binary(argstring,
&buffer,
&nbytes);
/* copy the buffer to a python string */
PyObject * ret = Py_BuildValue("s", buffer);
free(buffer);
return ret;
}
}
#pragma once
#ifndef BINARY_C_PYTHON_H
#define BINARY_C_PYTHON_H
/*
* Include binary_C's API
*/
#include "binary_c_API.h"
#include "binary_c_API_prototypes.h"
/* Binary_c's python API prototypes */
int run_binary (char * argstring,
char ** outstring,
int * nbytes);
/* C macros */
#define BINARY_C_APITEST_VERSION 0.1
#define APIprint(...) APIprintf(__VA_ARGS__);
#define NO_OUTPUT
#endif // BINARY_C_C_PYTHON_H
#include "binary_c_python.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 ;
int 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,
int * nbytes)
{
/* memory for N binary systems */
struct libbinary_c_stardata_t *stardata;
struct libbinary_c_store_t * store = NULL;
/* make new stardata */
stardata = NULL;
binary_c_new_system(&stardata,
NULL,
NULL,
&store,
&argstring,
-1);
/* disable logging */
snprintf(stardata->preferences->log_filename,
STRING_LENGTH-1,
"%s",
"/dev/null");
snprintf(stardata->preferences->api_log_filename_prefix,
STRING_LENGTH-1,
"%s",
"/dev/null");
/* output to strings */
stardata->preferences->internal_buffering = 2;
stardata->preferences->internal_buffering_compression = 0;
stardata->preferences->batchmode = BATCHMODE_LIBRARY;
/* do binary evolution */
binary_c_evolve_for_dt(stardata,
stardata->model.max_evolution_time);
/* get buffer pointer */
binary_c_buffer_info(stardata,buffer,nbytes);
/* set raw_buffer_size = -1 to prevent it being freed */
stardata->tmpstore->raw_buffer_size = -1;
/* free stardata (except the buffer) */
binary_c_free_memory(&stardata,TRUE,TRUE,FALSE);
binary_c_free_store_contents(store);
return 0;
}
File added
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
#!/usr/bin/python3
import binary_c
############################################################
# Test script to run a binary using the binary_c Python
# module.
############################################################
def run_test_binary():
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
buffer = ""
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(argstring)
print ("\n\nBinary_c output:\n\n")
print (output)
binary_star=binary_c.new_system()
print(binary_star)
run_test_binary()
setup.py 0 → 100644
from distutils.core import setup, Extension
import os
import subprocess
import re
import sys
# binary_c must be installed.
binary_c_config = os.environ['BINARY_C']+'/binary_c-config'
binary_c_incdirs = subprocess.run([binary_c_config,'incdirs_list'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
binary_c_libdirs = subprocess.run([binary_c_config,'libdirs'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
binary_c_cflags = subprocess.run([binary_c_config,'cflags'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
binary_c_libs = subprocess.run([binary_c_config,'libs_list'],stdout=subprocess.PIPE).stdout.decode('utf-8').split()
# create list of tuples of defined macros
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):
binary_c_define_macros.extend([(y.group(1),y.group(2))])
else:
y = lone.match(x)
if(y):
binary_c_define_macros.extend([(y.group(1),None)])
# add API header file
API_h = os.environ['BINARY_C'] + '/src/API/binary_c_API.h'
binary_c_define_macros.extend([('BINARY_C_API_H',API_h)])
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',
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,
define_macros = [] + binary_c_define_macros,
extra_objects = [],
extra_compile_args = [],
)] # binary_c must be loaded
)
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