import textwrap # Functions for the automatic logging of stuff # https://stackoverflow.com/questions/41954269/create-c-function-pointers-structure-in-python # https://stackabuse.com/enhancing-python-with-custom-c-extensions/ Read # https://stackoverflow.com/questions/49941617/runtime-generation-and-compilation-of-cython-functions # https://realpython.com/cpython-source-code-guide/ # https://docs.python.org/3.6/c-api/index.html # https://stackoverflow.com/questions/6626167/build-a-pyobject-from-a-c-function # https://docs.python.org/3.6/extending/newtypes_tutorial.html?highlight=pointer # https://realpython.com/cpython-source-code-guide/ # https://diseraluca.github.io/blog/2019/03/21/wetting-feet-with-python-c-api # https://docs.python.org/3/c-api/function.html # See example_perl.pm autologging def autogen_C_logging_code(logging_dict): """ 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 autogen_C_logging_code( { 'MY_STELLAR_DATA': ['model.time', 'star[0].mass'], 'my_sss2': ['model.time', 'star[1].mass'] } ) #################################################################################### # see example_perl.pm binary_c_log_code def binary_c_log_code(code): """ Function to construct the code to construct the custom logging function """ custom_logging_function_string = """ #pragma push_macro(\"MAX\") #pragma push_macro(\"MIN\") #undef MAX #undef MIN #include \"binary_c.h\" void custom_output_function(SV * x); SV * custom_output_function_pointer(void); SV * custom_output_function_pointer() {{ /* * use PTR2UV to convert the function pointer * &custom_output_function to an unsigned int, * which is then converted to a Perl SV */ return (SV*)newSVuv(PTR2UV(custom_output_function)); }} void custom_output_function(SV * x) {{ struct stardata_t * stardata = (struct stardata_t *)x; {code}; }} #undef MAX #undef MIN #pragma pop_macro(\"MIN\") #pragma pop_macro(\"MAX\") """.format(code=code) print(textwrap.dedent(custom_logging_function_string)) # return custom_logging_function_string code = autogen_C_logging_code( { 'MY_STELLAR_DATA': ['model.time', 'star[0].mass'], 'my_sss2': ['model.time', 'star[1].mass'] } ) binary_c_log_code(code)