import copy import json from collections import defaultdict import binary_c_python_api from binarycpython.utils.custom_logging_functions import ( create_and_load_logging_function, ) def get_help_all(print_help=True, return_dict=False): """ Function that reads out the output of the help_all api call to binary_c prints all the parameters and their descriptions. return_dict: returns a dictionary """ # Call function help_all = binary_c_python_api.return_help_all() # String manipulation split = help_all.split( "############################################################\n" ) cleaned = [el for el in split if not el == "\n"] section_nums = [i for i in range(len(cleaned)) if cleaned[i].startswith("#####")] # Create dicts help_all_dict = {} # Select the section name and the contents of that section. Note, not all sections have content! for i in range(len(section_nums)): if not i == len(section_nums) - 1: params = cleaned[section_nums[i] + 1 : section_nums[i + 1]] else: params = cleaned[section_nums[i] + 1 : len(cleaned)] section_name = ( cleaned[section_nums[i]] .lstrip("#####") .strip() .replace("Section ", "") .lower() ) # params_dict = {} if params: # Clean it, replace in-text newlines with a space and then split on newlines. split_params = params[0].strip().replace("\n ", " ").split("\n") # Process params and descriptions per section for el in split_params: split_param_info = el.split(" : ") if not len(split_param_info) == 3: # there are ocassions where the semicolon is used in the description text itself. if len(split_param_info) == 4: split_param_info = [ split_param_info[0], ": ".join([split_param_info[1], split_param_info[2]]), split_param_info[3], ] # other occassions? # Put the information in a dict param_name = split_param_info[0] param_description = split_param_info[1] rest = split_param_info[2] params_dict[param_name] = { "param_name": param_name, "description": param_description, "rest": rest, } # make section_dict section_dict = { "section_name": section_name, "parameters": params_dict.copy(), } # Put in the total dict help_all_dict[section_name] = section_dict.copy() # Print things if print_help: for section in sorted(help_all_dict.keys()): print( "##################\n###### Section {}\n##################".format( section ) ) section_dict = help_all_dict[section] for param_name in sorted(section_dict["parameters"].keys()): param = section_dict["parameters"][param_name] print( "\n{}:\n\t{}: {}".format( param["param_name"], param["description"], param["rest"] ) ) # Loop over all the parameters an call the help() function on it. Takes a long time but this is for testing # for section in help_all_dict.keys(): # section_dict = help_all_dict[section] # for param in section_dict['parameters'].keys(): # get_help(param) if return_dict: return help_all_dict else: return None 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(filter_values=False): """ Function that calls the binaryc get args function and cast it into a dictionary All the values are strings filter_values: whether to filter out NULL and Function defaults. """ default_output = binary_c_python_api.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 filter_values: if not value in ["NULL", "Function"]: if not value == "": default_dict[key] = value # On default, just show everything else: 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 get_help(param_name, return_dict=False): """ Function that returns the help info for a given parameter. Binary_c will output things in the following order; - Did you mean? - binary_c help for variable - default - available macros This function reads out that structure and catches the different components of this output Will print a dict return_dict: wether to return the help info dictionary """ available_arg_keys = get_arg_keys() if param_name in available_arg_keys: help_info = binary_c_python_api.return_help(param_name) cleaned = [el for el in help_info.split("\n") if not el == ""] # Get line numbers did_you_mean_nr = [ i for i, el in enumerate(cleaned) if el.startswith("Did you mean") ] parameter_line_nr = [ i for i, el in enumerate(cleaned) if el.startswith("binary_c help") ] default_line_nr = [ i for i, el in enumerate(cleaned) if el.startswith("Default") ] macros_line_nr = [ i for i, el in enumerate(cleaned) if el.startswith("Available") ] help_info_dict = {} # Get alternatives if did_you_mean_nr: alternatives = cleaned[did_you_mean_nr[0] + 1 : parameter_line_nr[0]] alternatives = [el.strip() for el in alternatives] help_info_dict["alternatives"] = alternatives # Information about the parameter parameter_line = cleaned[parameter_line_nr[0]] parameter_name = parameter_line.split(":")[1].strip().split(" ")[0] parameter_value_input_type = ( " ".join(parameter_line.split(":")[1].strip().split(" ")[1:]) .replace("<", "") .replace(">", "") ) help_info_dict["parameter_name"] = parameter_name help_info_dict["parameter_value_input_type"] = parameter_value_input_type description_line = " ".join( cleaned[parameter_line_nr[0] + 1 : default_line_nr[0]] ) help_info_dict["description"] = description_line # Default: default_line = cleaned[default_line_nr[0]] default_value = default_line.split(":")[-1].strip() help_info_dict["default"] = default_value # Get Macros: if macros_line_nr: macros = cleaned[macros_line_nr[0] + 1 :] help_info_dict["macros"] = macros # for key in help_info_dict.keys(): # print("{}:\n\t{}".format(key, help_info_dict[key])) if return_dict: return help_info_dict else: print( "{} is not a valid parameter name. Please choose from the following parameters:\n\t{}".format( param_name, list(available_arg_keys) ) ) return None # get_help("RLOF_method") 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_python_api.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_python_api.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_python_api.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 output = binary_c_python_api.run_binary_with_logfile(arg_string) return output # run_system_with_log() def parse_output(output, selected_header): """ 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 instead of a defaultdict """ 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] values_list = split_line[1:] # print(values_list) # Catch line starting with selected header if header == selected_header: # Check if the line contains '=' symbols: 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( "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 def load_logfile(logfile): with open(logfile, "r") as f: logfile_data = f.readlines() time_list = [] m1_list = [] m2_list = [] k1_list = [] k2_list = [] sep_list = [] ecc_list = [] rel_r1_list = [] rel_r2_list = [] event_list = [] random_seed = logfile_data[0].split()[-2] random_count = logfile_data[0].split()[-1] probability = logfile_data[-1].split() for line in logfile_data[1:-1]: split_line = line.split() time_list.append(split_line[0]) m1_list.append(split_line[1]) m2_list.append(split_line[2]) k1_list.append(split_line[3]) k2_list.append(split_line[4]) sep_list.append(split_line[5]) ecc_list.append(split_line[6]) rel_r1_list.append(split_line[7]) rel_r2_list.append(split_line[8]) event_list.append(" ".join(split_line[9:])) print(event_list) # load_logfile()