diff --git a/binarycpython/utils/functions.py b/binarycpython/utils/functions.py index b15dcc5d9e6fa5c9da04855641e6e32a9bdd5aa2..5e401986f9c7f810d1e944dbbbc208e7efd47425 100644 --- a/binarycpython/utils/functions.py +++ b/binarycpython/utils/functions.py @@ -363,6 +363,22 @@ def get_help_all(print_help=True, return_dict=False): else: return None +def filter_arg_dict(arg_dict): + """ + Function to filter out keys that contain values included in ['NULL', 'Function', ''] + """ + + old_dict = arg_dict.copy() + new_dict = {} + + for key in old_dict.keys(): + if not old_dict[key] in ["NULL", "Function"]: + if not old_dict[key] == "": + new_dict[key] = old_dict[key] + + return new_dict + + def create_arg_string(arg_dict, sort=False, filter_values=False): """ @@ -375,18 +391,12 @@ def create_arg_string(arg_dict, sort=False, filter_values=False): """ arg_string = "" - # - keys = sorted(arg_dict.keys()) if sort else arg_dict.keys() + if filter_values: + arg_dict = filter_values(arg_dict) - # + keys = sorted(arg_dict.keys()) if sort else arg_dict.keys() for key in keys: - # Filter out NULLS (not compiled anyway) - if filter_values: - if not arg_dict[key] in ["NULL", "Function"]: - if not arg_dict[key] == "": - arg_string += "{key} {value} ".format(key=key, value=arg_dict[key]) - else: - arg_string += "{key} {value} ".format(key=key, value=arg_dict[key]) + arg_string += "{key} {value} ".format(key=key, value=arg_dict[key]) arg_string = arg_string.strip() return arg_string @@ -405,16 +415,10 @@ def get_defaults(filter_values=False): for default in default_output.split("\n"): if not default in ["__ARG_BEGIN", "__ARG_END", ""]: key, value = default.split(" = ") + default_dict[key] = value - # 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 + if filter_values: + default_dict = filter_arg_dict(default_dict) return default_dict diff --git a/binarycpython/utils/grid.py b/binarycpython/utils/grid.py index 41e77311dcd2e352b942db779edd492f7fcd5a84..5a3953a22643fda4048d7324db85458d0d543f9c 100644 --- a/binarycpython/utils/grid.py +++ b/binarycpython/utils/grid.py @@ -27,6 +27,7 @@ from binarycpython.utils.functions import ( parse_binary_c_version_info, output_lines, remove_file, + filter_arg_dict, ) @@ -1258,14 +1259,12 @@ class Population(object): - "NULL" - "" - "Function" - + + Uses the function from utils.functions """ - cleaned_dict = {} binary_c_defaults = self.return_binary_c_defaults().copy() - for key in binary_c_defaults: - if not binary_c_defaults[key] in ["NULL", "", "Function"]: - cleaned_dict[key] = binary_c_defaults[key] + cleaned_dict = filter_arg_dict(binary_c_defaults) return cleaned_dict diff --git a/binarycpython/utils/plot_functions.py b/binarycpython/utils/plot_functions.py new file mode 100644 index 0000000000000000000000000000000000000000..0529702932f4fc1c82f853d24bcafc3fe42a9b56 --- /dev/null +++ b/binarycpython/utils/plot_functions.py @@ -0,0 +1,162 @@ +""" +Module that contains plotting routines for single systems. + +The idea to do this is to provide the user with some quick +commands to plot the evolution of a system + +There is no preloaded matplotlib rc, you should do that yourself +""" + +import pandas as pd +import numpy as np + +import matplotlib.pyplot as plt +from david_phd_functions.plotting.plot_functions import plot_orbit, plot_masses, plot_HR_diagram + +from binarycpython.utils.functions import get_arg_keys, output_lines +from binarycpython.utils.run_system_wrapper import run_system +from binarycpython.utils.custom_logging_functions import binary_c_log_code + +# Define the custom_logging_strings. These are kept to the minimum necessary for each plotting routine. + +custom_logging_string_masses = "" +custom_logging_string_orbit = "" + +custom_logging_string_HR_diagram = """ +Printf("HR_PLOTTING %30.12e %d %d %g %g %g %g %g %g\\n", + // + stardata->model.time, // 1 + + // stellar types + stardata->star[0].stellar_type, //2 + stardata->star[1].stellar_type, //3 + + // luminosity and radii + stardata->star[0].luminosity, // 4 + stardata->star[1].luminosity, // 5 + stardata->star[0].radius, // 6 + stardata->star[1].radius, // 7 + + // masses + stardata->star[0].pms_mass, // 8 + stardata->star[1].pms_mass // 9 + ); +""" + + + + + + + + +# Define the parse functions for the plotting routines +def dummy(): + pass + + + +def parse_function_hr_diagram(output): + """ + Parsing function for the HR plotting routine + """ + + # extract info from the single evolution + + values_list = [] + + parameters = ['time', + 'stellar_type_1', 'stellar_type_2', + 'luminosity_1', 'luminosity_2', + 'radius_1', 'radius_2', 'pms_mass_1', 'pms_mass_2'] + + # Go over the output. + for el in output_lines(output): + headerline = el.split()[0] + + # Check the header and act accordingly + if (headerline=='HR_PLOTTING'): + values = el.split()[1:] + values_list.append(values) + + df = pd.DataFrame(values_list) + df.columns = parameters + + + df = df.astype(np.float64) + df['stellar_type_1'] = df['stellar_type_1'].astype(np.int64) + df['stellar_type_2'] = df['stellar_type_2'].astype(np.int64) + + return df + +def plot_system(plot_type, **kwargs): + """ + TODO: Complex Function! + TODO: make sure this way of passing args works correctly. + TODO: make the plotting specific keywords available via the inspect stuff + Function to plot the evolution of the system. + + This goes (in general) via the following steps: + - a preset custom logging for a specific plotting routine is loaded. + - This is used for the run_system call + - The output of this run_system is loaded into a dataframe by parsing it with a corresponding parsing function + - The dataframe is passed to the plotting routine + - plot is shown or returned. + + There are several pre-set plots to choose from + + All keywords are considered kwargs, except for plot_type + input: + plot_type: string input should be one of the following types: ['mass_evolution', 'orbit_evolution', 'hr_diagram']. + Input will be matched against this, and then go through a dictionary to pick the correct plotting function. + return_fig: boolean whether to return the fig object instead of plotting the plot (makes so that you can customize it) + show_stellar_types: whether to plot the stellar type evolution on a second pane. This is not included in all the plotting routines. + Other input: other kwargs that are passed to run_system (inspect the docstring of run_system for more info) + """ + + # set defaults and options + return_fig = False + show_stellar_types = False + + plot_types_dict = { + 'mass_evolution': {'plot_function': plot_masses, 'custom_logging_string': custom_logging_string_masses, 'parse_function': dummy}, + 'orbit_evolution': {'plot_function': plot_orbit, 'custom_logging_string': custom_logging_string_orbit, 'parse_function': dummy}, + 'hr_diagram': {'plot_function': plot_HR_diagram, 'custom_logging_string': custom_logging_string_HR_diagram, 'parse_function': parse_function_hr_diagram}, + } + plot_system_specific_keywords = ['plot_type', 'show_plot', 'show_stellar_types'] + + # First check on the plot_type input + if not plot_type in plot_types_dict.keys(): + print("Warning, the provided plot type is not known. Please choose one from the following:\n\t{}".format(plot_types_dict.keys())) + raise ValueError + + # First: check all the arguments. Chosen to not check all the keywords for run_system and binary_c specifically, but just to pick out the ones needed for this routine. run_system will handle the rest + run_system_arg_dict = {} + + for key in kwargs.keys(): + if key == 'show_plot': + show_plot = kwargs[key] + elif key == 'show_stellar_types': + show_stellar_types = kwargs[key] + + # The rest will be passed to run_system + else: + run_system_arg_dict[key] = kwargs[key] + + # TODO: When a list of plot_types is passed, make it so that the strings are chained, and that the output of the binary_c call is handled by multiple parsers + custom_logging_code = binary_c_log_code(plot_types_dict[plot_type]['custom_logging_string']) + run_system_arg_dict['custom_logging_code'] = custom_logging_code + + run_system_arg_dict['parse_function'] = plot_types_dict[plot_type]['parse_function'] + + # Run and get the output of the parse function + binary_c_output_df = run_system(**run_system_arg_dict) + + + fig = plot_types_dict[plot_type]['plot_function'](binary_c_output_df, show_plot=show_plot, show_stellar_types=show_stellar_types) + + if not show_plot: + return fig + + +plot_system(plot_type='hr_diagram', M_1=10, M_2=5, orbital_period=100000, max_evolution_time=15000, show_plot=True) \ No newline at end of file diff --git a/binarycpython/utils/run_system_wrapper.py b/binarycpython/utils/run_system_wrapper.py index 7166b031811c181f4da685f5b16343336a458224..0a247f1f0074c7568445dad536bacbefa3a63bdf 100644 --- a/binarycpython/utils/run_system_wrapper.py +++ b/binarycpython/utils/run_system_wrapper.py @@ -40,8 +40,6 @@ def run_system(**kwargs): other_keywords = ['custom_logging_code', 'log_filename', 'parse_function'] - - # Set default values func_memaddr = -1 write_logfile = 0 diff --git a/requirements.txt b/requirements.txt index 6329c5c64a0c110f6df6626ff18ee3d6d2e842d0..1c79312a35c83aecc26abf7f38a7855e4a2b43c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,57 +1,64 @@ -astropy==3.2.1 -attrs==19.1.0 +alabaster==0.7.12 +astropy==4.0.1 +Babel==2.7.0 backcall==0.1.0 -bleach==3.1.0 +binarycpython==0.1 +certifi==2019.9.11 +chardet==3.0.4 +clang==6.0.0.2 cycler==0.10.0 -decorator==4.4.0 -defusedxml==0.6.0 +decorator==4.4.1 dill==0.3.1.1 -entrypoints==0.3 +docutils==0.15.2 h5py==2.10.0 -ipykernel==5.1.2 -ipython==7.7.0 +hawkmoth==0.4 +idna==2.8 +imagesize==1.1.0 +ipython==7.9.0 ipython-genutils==0.2.0 -ipywidgets==7.5.1 -ivs-sse==0.0 jedi==0.15.1 -Jinja2==2.10.1 -jsonschema==3.0.2 -jupyter==1.0.0 -jupyter-client==5.3.1 -jupyter-console==6.0.0 -jupyter-core==4.5.0 +Jinja2==2.10.3 kiwisolver==1.1.0 +lxml==4.5.0 +m2r==0.2.1 MarkupSafe==1.1.1 +matplotlib==3.1.2 mistune==0.8.4 multiprocess==0.70.9 -nbconvert==5.6.0 -nbformat==4.4.0 -notebook==6.0.0 -numpy==1.17.0 -#pandas==0.25.0 -pandocfilters==1.4.2 +mypy==0.770 +mypy-extensions==0.4.3 +numpy==1.17.4 +packaging==19.2 +pandas==0.25.3 parso==0.5.1 pathos==0.2.5 pexpect==4.7.0 pickleshare==0.7.5 pox==0.2.7 ppft==1.6.6.1 -prometheus-client==0.7.1 -prompt-toolkit==2.0.9 +prompt-toolkit==2.0.10 +psutil==5.6.7 ptyprocess==0.6.0 Pygments==2.4.2 -pyparsing==2.4.2 -pyrsistent==0.15.4 -python-dateutil==2.8.0 -pytz==2019.2 -pyzmq==18.1.0 -qtconsole==4.5.2 -Send2Trash==1.5.0 -six==1.12.0 -terminado==0.8.2 -testpath==0.4.2 -tornado==6.0.3 -traitlets==4.3.2 +pyparsing==2.4.5 +python-dateutil==2.8.1 +pytz==2019.3 +requests==2.22.0 +scipy==1.4.1 +seaborn==0.10.0 +setproctitle==1.1.10 +six==1.13.0 +snowballstemmer==2.0.0 +Sphinx==2.2.1 +sphinx-rtd-theme==0.4.3 +sphinxcontrib-applehelp==1.0.1 +sphinxcontrib-devhelp==1.0.1 +sphinxcontrib-htmlhelp==1.0.2 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.2 +sphinxcontrib-serializinghtml==1.1.3 +traitlets==4.3.3 +typed-ast==1.4.1 +typing-extensions==3.7.4.1 +urllib3==1.25.7 wcwidth==0.1.7 -webencodings==0.5.1 -widgetsnbextension==3.5.1