From 77cef2b18ce12f80b00b9290b77dfc1858125b52 Mon Sep 17 00:00:00 2001 From: David Hendriks <davidhendriks93@gmail.com> Date: Wed, 20 Nov 2019 23:56:34 +0000 Subject: [PATCH] made the parse output a bit more functional --- .../custom_logging_functions.py | 30 ++++++---- binaryc_python_utils/functions.py | 38 ++++++++---- examples/examples.py | 28 ++++++--- setup.py | 59 ++++++++++--------- 4 files changed, 93 insertions(+), 62 deletions(-) diff --git a/binaryc_python_utils/custom_logging_functions.py b/binaryc_python_utils/custom_logging_functions.py index 3bb4d7f48..cd37988bc 100644 --- a/binaryc_python_utils/custom_logging_functions.py +++ b/binaryc_python_utils/custom_logging_functions.py @@ -122,7 +122,7 @@ def from_binary_c_config(config_file, flag): return res -def return_compilation_dict(): +def return_compilation_dict(verbose=False): """ Function to build the compile command for the shared library @@ -206,21 +206,23 @@ def return_compilation_dict(): ] 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() + + if verbose: + 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 + 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): +def compile_shared_lib(code, sourcefile_name, outfile_name, verbose=False): """ Function to write the custom logging code to a file and then compile it. """ @@ -245,11 +247,13 @@ def compile_shared_lib(code, sourcefile_name, outfile_name): command = " ".join(command.split()) # Execute compilation - print("Executing following command:\n{command}".format(command=command)) + if verbose: + 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)) + if verbose: + if res: + print("Output of compilation command:\n{}".format(res)) def temp_custom_logging_dir(): diff --git a/binaryc_python_utils/functions.py b/binaryc_python_utils/functions.py index c0b9ee155..cc7e3b954 100644 --- a/binaryc_python_utils/functions.py +++ b/binaryc_python_utils/functions.py @@ -136,16 +136,20 @@ def run_system_with_log(**kwargs): 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 + Function that parses output of binary_c: + + This function works in two cases: + if the caught line contains output like 'example_header time=12.32 mass=0.94 ..' + or if the line contains output like 'example_header 12.32 0.94' 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 - + + TODO: Think about exporting to numpy array or pandas instead of a defaultdict """ - value_dicts = [] - val_lists = [] + + value_dicts = [] + val_lists = [] # split output on newlines for i, line in enumerate(output.split("\n")): @@ -155,17 +159,25 @@ def parse_output(output, selected_header): # Select parts header = split_line[0] - value_array = split_line[1:] + values_list = split_line[1:] + # print(values_list) # Catch line starting with selected header if header == selected_header: - # print(value_array) - # Make a dict + # Check if the line contains '=' symbols: value_dict = {} - for el in value_array: - key, val = el.split("=") - value_dict[key] = val - value_dicts.append(value_dict) + if all('=' in el for el in values_list): + for el in values_list: + key, val = el.split("=") + value_dict[key.strip()] = val.strip() + value_dicts.append(value_dict) + else: + if any('=' in el for el in values_list): + raise ValueError('Caught line contains some = symbols but not all of them do. aborting run') + else: + for i, val in enumerate(values_list): + value_dict[i] = val + value_dicts.append(value_dict) if len(value_dicts) == 0: print( diff --git a/examples/examples.py b/examples/examples.py index a8609771c..7df0e0287 100644 --- a/examples/examples.py +++ b/examples/examples.py @@ -20,7 +20,6 @@ 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 @@ -46,7 +45,6 @@ def run_example_binary(): output = binary_c.run_binary(argstring) print(output) - # run_example_binary() @@ -60,6 +58,8 @@ def run_example_binary_with_run_system(): 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 + + The parsing of the output only works correctly if either all of the values are described inline like `mass=<number>' or none of them are. """ import pandas as pd @@ -68,16 +68,31 @@ def run_example_binary_with_run_system(): # Run system. all arguments can be given as optional arguments. output = run_system(M_1=10, M_2=20, separation=0, orbital_period=100000000000) + # print(output) + # 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") + result_example_header_1 = parse_output(output, selected_header="example_header_1") + result_example_header_2 = parse_output(output, selected_header="example_header_2") + + # print(result_example_header_1) #### 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') + # Or put them into a pandas array + + # Cast the data into a dataframe. - df = pd.DataFrame.from_dict(result_example_header, dtype=np.float64) + # This example automatically catches the column names because the binary_c output line is constructed as 'example_header_1 time=<number>..' + df = pd.DataFrame.from_dict(result_example_header_1, dtype=np.float64) + print(df) + + # This example has column headers which are numbered, but we can override that with custom headers. + df2 = pd.DataFrame.from_dict(result_example_header_2, dtype=np.float64) + df2.columns=['time', 'mass_1', 'mass_2', 'st1', 'st2', 'sep', 'ecc'] + print(df2) # print(df) # sliced_df = df[df.t < 1000] # Cut off late parts of evolution @@ -85,8 +100,7 @@ def run_example_binary_with_run_system(): # Some routine to plot. -# run_example_binary_with_run_system() - +run_example_binary_with_run_system() def run_example_binary_with_custom_logging(): """ @@ -166,4 +180,4 @@ def run_example_binary_with_writing_logfile(): # Some routine to plot. -# run_example_binary_with_writing_logfile() +# run_example_binary_with_writing_logfile() \ No newline at end of file diff --git a/setup.py b/setup.py index c2e18e378..88648bed4 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ -# from distutils.core import setup, Extension +from distutils.core import setup, Extension # from setuptools import find_packages -from setuptools import setup, find_packages, Extension +# from setuptools import setup, find_packages, Extension import os import subprocess import re @@ -57,11 +57,37 @@ API_h = os.environ["BINARY_C"] + "/src/API/binary_c_API.h" binary_c_define_macros.extend([("BINARY_C_API_H", API_h)]) +binary_c_python_api_module = Extension( + "binary_c", + ["src/binary_c_python.c"], + include_dirs=[ + os.environ["BINARY_C"] + "/src", + os.environ["BINARY_C"] + "/src/API", + "include", + ] + + binary_c_incdirs, + libraries=["binary_c"] + binary_c_libs + ["binary_c_api"], + library_dirs=[ + os.environ["BINARY_C"] + "/src", + "./", + os.path.join(CWD, "lib/"), + ] + + binary_c_libdirs, + runtime_library_dirs=[ + os.environ["BINARY_C"] + "/src", + "./", + os.path.join(CWD, "lib/"), + ] + + binary_c_libdirs, + define_macros=[] + binary_c_define_macros, + extra_objects=[], + extra_compile_args=[], +) + def readme(): with open('README.md') as f: return f.read() - setup( name="binary_c", version="1.0", @@ -72,31 +98,6 @@ setup( url="https://gitlab.eps.surrey.ac.uk/ri0005/binary_c-python", license="", ext_modules=[ - Extension( - "binary_c", - ["src/binary_c_python.c"], - include_dirs=[ - os.environ["BINARY_C"] + "/src", - os.environ["BINARY_C"] + "/src/API", - "include", - ] - + binary_c_incdirs, - libraries=["binary_c"] + binary_c_libs + ["binary_c_api"], - library_dirs=[ - os.environ["BINARY_C"] + "/src", - "./", - os.path.join(CWD, "lib/"), - ] - + binary_c_libdirs, - runtime_library_dirs=[ - os.environ["BINARY_C"] + "/src", - "./", - os.path.join(CWD, "lib/"), - ] - + binary_c_libdirs, - define_macros=[] + binary_c_define_macros, - extra_objects=[], - extra_compile_args=[], - ) + binary_c_python_api_module ], # binary_c must be loaded ) -- GitLab