From 698842eadb04d7a9c8381542a640906f69141c3b Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:35:31 -0500 Subject: [PATCH 01/13] fix conftest fixture so it creates new recipe object on each call --- tests/conftest.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 45c6308a..411f70dc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -150,19 +150,23 @@ def _capturestdout(f, *args, **kwargs): @pytest.fixture() def build_recipe_one_contribution(): "helper to build a simple recipe" - profile = Profile() - x = linspace(0, pi, 10) - y = sin(x) - profile.set_observed_profile(x, y) - contribution = FitContribution("c1") - contribution.set_profile(profile) - contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") - recipe = FitRecipe() - recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 1) - recipe.add_variable(contribution.wave_number, 1) - recipe.add_variable(contribution.phase_shift, 1) - return recipe + + def _build_recipe(): + profile = Profile() + x = linspace(0, pi, 10) + y = sin(x) + profile.set_observed_profile(x, y) + contribution = FitContribution("c1") + contribution.set_profile(profile) + contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") + recipe = FitRecipe() + recipe.add_contribution(contribution) + recipe.add_variable(contribution.amplitude, 1) + recipe.add_variable(contribution.wave_number, 1) + recipe.add_variable(contribution.phase_shift, 1) + return recipe + + return _build_recipe @pytest.fixture() From 12ee91c51cc0de38f63e5376754693bfbf7b4a7c Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:43:43 -0500 Subject: [PATCH 02/13] update fixture initial values to be more different --- tests/conftest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 411f70dc..6b5b39c7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -161,9 +161,9 @@ def _build_recipe(): contribution.set_equation("amplitude*sin(wave_number*x + phase_shift)") recipe = FitRecipe() recipe.add_contribution(contribution) - recipe.add_variable(contribution.amplitude, 1) - recipe.add_variable(contribution.wave_number, 1) - recipe.add_variable(contribution.phase_shift, 1) + recipe.add_variable(contribution.amplitude, 4) + recipe.add_variable(contribution.wave_number, 3) + recipe.add_variable(contribution.phase_shift, 2) return recipe return _build_recipe From 0d6e1beedc9a21ad138b408b2c772d582a81207f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 14:48:46 -0500 Subject: [PATCH 03/13] update expected to accound for the slight difference now --- tests/test_fitresults.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index b9fb7492..4a2fde67 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -38,10 +38,7 @@ Restraints 0.00000000 Chi2 0.00000000 Reduced Chi2 0.00000000 -Rw 0.00000000 - -Variables (Uncertainties invalid) ------------------------------------------------------------------------------- +Rw 0.00000007 """ expected_refined_variables = ["amplitude", "wave_number", "phase_shift"] @@ -54,9 +51,10 @@ def optimize_recipe(recipe): def test_formatResults(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) + results.save_results("res.res") actual_results_string = results.formatResults(header="My Custom header") # Because slight variations in refinement, just check # that the header of the results are the same. @@ -67,7 +65,7 @@ def test_formatResults(build_recipe_one_contribution): def test_get_results_string(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_string = results.get_results_string( @@ -82,7 +80,7 @@ def test_get_results_string(build_recipe_one_contribution): def test_printResults(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) results.printResults(header="My Custom header") @@ -96,7 +94,7 @@ def test_printResults(build_recipe_one_contribution, capsys): def test_print_results(build_recipe_one_contribution, capsys): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) results.print_results(header="My Custom header") @@ -110,7 +108,7 @@ def test_print_results(build_recipe_one_contribution, capsys): def test_saveResults(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -127,7 +125,7 @@ def test_saveResults(build_recipe_one_contribution, tmp_path): def test_save_results(build_recipe_one_contribution, tmp_path): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_file = tmp_path / "fit_results.txt" @@ -146,7 +144,7 @@ def test_save_results(build_recipe_one_contribution, tmp_path): def test_get_results_dictionary(build_recipe_one_contribution): # Case: user gets results dictionary after optimization # expected: results dictionary contains expected keys and values - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) results = FitResults(recipe) actual_results_dict = results.get_results_dictionary() From 474b32e6169c3fcc40e004483dffe0f2e9fab3d4 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:23:33 -0500 Subject: [PATCH 04/13] feat: initialize FitRecipe from a results file or object --- src/diffpy/srfit/fitbase/fitrecipe.py | 70 +++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index c44eb6d9..ca3d34a8 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -35,11 +35,13 @@ __all__ = ["FitRecipe"] from collections import OrderedDict +from pathlib import Path import matplotlib.pyplot as plt from bg_mpl_stylesheets.styles import all_styles from numpy import array, concatenate, dot, sqrt +import diffpy.srfit.util.inpututils as utils from diffpy.srfit.fitbase.fithook import PrintFitHook from diffpy.srfit.fitbase.parameter import ParameterProxy from diffpy.srfit.fitbase.recipeorganizer import RecipeOrganizer @@ -1184,6 +1186,74 @@ def initialize_recipe_with_recipe(self, recipe_object): if restraint not in self._restraints: self._restraints.add(restraint) + def _pretty_print_results_dict(self, params_dict): + """Pretty print a dictionary of parameter names and values.""" + sorted_params = sorted(params_dict.items()) + width = max(len(name) for name, _ in sorted_params) + for name, value in sorted_params: + if isinstance(value, float): + value_str = f"{value:.6g}" + else: + value_str = str(value) + print(f" {name:<{width}} = {value_str}") + + def _set_parameters_from_dict(self, params_dict): + """Set the parameters of the FitRecipe from a dictionary of + parameter names and values.""" + for param_name, param_value in params_dict.items(): + if param_name in self._parameters: + self._parameters[param_name].setValue(param_value) + else: + print( + f"Warning: Parameter '{param_name}' from results " + "not found in FitRecipe and will be ignored." + ) + + def initialize_recipe_with_results(self, results, verbose=True): + """Initialize a FitRecipe with a FitResults object or a results + file. + + Note that at least one FitContribution must already exist in + the FitRecipe. + + Parameters + ---------- + results : FitResults, pathlib.Path, or str + The FitResults object or path to results file to initialize with. + verbose : bool, optional + If True, print warnings for any parameters in the results that are + not in the FitRecipe. Default is True. + + Raises + ------ + ValueError + If the input results is not a FitResults object or a path to a + results file. + """ + if hasattr(results, "print_results"): + params_dict = utils.get_dict_from_results_object(results) + elif isinstance(results, (str, Path)): + params_dict = utils.get_dict_from_results_file(results) + else: + raise ValueError( + "The input results must be a FitResults object or a path to a " + f"results file, but got {type(results)}." + ) + self._set_parameters_from_dict(params_dict) + if verbose: + print() + print("Parameters found in Results:") + print("=" * 30) + self._pretty_print_results_dict(params_dict) + print() + print("Parameters set in FitRecipe:") + print("=" * 30) + set_parameters_dict = { + param.name: param.getValue() + for param in self._parameters.values() + } + self._pretty_print_results_dict(set_parameters_dict) + def set_plot_defaults(self, **kwargs): """Set default plotting options for all future plots. From 96ac076387ed6a0253460e204e7c90199fec627d Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:24:22 -0500 Subject: [PATCH 05/13] test: tests for the new feature --- tests/test_fitrecipe.py | 132 +++++++++++++++++++++++++++++++++++----- 1 file changed, 118 insertions(+), 14 deletions(-) diff --git a/tests/test_fitrecipe.py b/tests/test_fitrecipe.py index 6deb1cad..21ce1113 100644 --- a/tests/test_fitrecipe.py +++ b/tests/test_fitrecipe.py @@ -527,11 +527,115 @@ def test_initialize_recipe_from_recipe_bad(build_recipe_two_contributions): recipe2.initialize_recipe_with_recipe(recipe_bad) -# def test_initialize_recipe_from_results(build_recipe_one_contribution): -# # Case: User initializes a FitRecipe from a FitResults object or -# # results file -# # expected: recipe is initialized with variables from previous fit -# assert False +def test_initialize_recipe_from_results_object(build_recipe_one_contribution): + # Case: User initializes a FitRecipe from a FitResults object + # expected: recipe is initialized with variables from previous fit + recipe1 = build_recipe_one_contribution() + optimize_recipe(recipe1) + results1 = FitResults(recipe1) + expected_values = np.round(results1.varvals, 5) + expected_names = results1.varnames + + recipe2 = build_recipe_one_contribution() + recipe2.create_new_variable( + "extra_var", 5 + ) # should be included in the initialized recipe + actual_values_before_init = [val for val in recipe2.get_values()] + actual_names_before_init = recipe2.get_names() + expected_names_before_init = [ + "amplitude", + "extra_var", + "phase_shift", + "wave_number", + ] + expected_values_before_init = [ + 4, + 3, + 2, + 5, + ] # the three variables + the extra_var + + assert actual_values_before_init == expected_values_before_init + assert sorted(actual_names_before_init) == sorted( + expected_names_before_init + ) + + recipe2.initialize_recipe_with_results(results1) + optimize_recipe(recipe2) + results2 = FitResults(recipe2) + actual_values = np.round(results2.varvals, 5) + actual_names = results2.varnames + + expected_names = expected_names + [ + "extra_var" + ] # add the new variable name to expected names + expected_values = list(expected_values) + [ + 5 + ] # add the value of the new variable to expected values + assert sorted(expected_names) == sorted(actual_names) + assert sorted(expected_values) == sorted(list(actual_values)) + + +def test_initialize_recipe_from_results_file( + build_recipe_one_contribution, temp_data_files +): + # Case: User initializes a FitRecipe from a FitResults file + # expected: recipe is initialized with variables from previous fit + results_file = temp_data_files / "fit_results.res" + expected_names = ["amplitude", "phase_shift", "wave_number"] + expected_values = [1, 1, 0] + + recipe = build_recipe_one_contribution() + recipe.initialize_recipe_with_results(results_file) + results = FitResults(recipe) + actual_values = np.round(results.varvals, 5) + actual_names = results.varnames + + assert sorted(expected_names) == sorted(actual_names) + assert list(expected_values) == list(actual_values) + + +def test_initialize_recipe_from_results_file_bad( + build_recipe_one_contribution, +): + # Case: User tries to initialize a recipe with something that + # isn't a path, str, or FitResults object + # Expected: raised ValueError with message + recipe = build_recipe_one_contribution() + bad_input = 12345 # not a valid input type + msg = ( + "The input results must be a FitResults object or a path to a " + "results file, but got ." + ) + with pytest.raises(ValueError, match=msg): + recipe.initialize_recipe_with_results(bad_input) + + +def test_initialize_recipe_from_results_file_wrong( + build_recipe_two_contributions, temp_data_files, capsys +): + # Case: User tries to initialize a FitRecipe from a results file + # that does not match params in the recipe + # expected: Warning message is printed and things proceed as + # usual with the variables in the recipe + + results_file_from_single_contrib = temp_data_files / "fit_results.res" + recipe = build_recipe_two_contributions + recipe.initialize_recipe_with_results(results_file_from_single_contrib) + captured = capsys.readouterr() + actual_print_msg = captured.out # .strip() + + results_file_param_names = ["amplitude", "phase_shift", "wave_number"] + expected_print_messages = [] + for param_name in results_file_param_names: + msg = ( + f"Warning: Parameter '{param_name}' from results not found " + "in FitRecipe and will be ignored." + ) + expected_print_messages.append(msg) + + for expected_print_msg in expected_print_messages: + assert expected_print_msg in actual_print_msg def get_labels_and_linecount(ax): @@ -591,7 +695,7 @@ def build_recipe_from_datafile_deprecated(datafile): def test_plot_recipe_bad_display(build_recipe_one_contribution): - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() # Case: All plots are disabled # expected: raised ValueError with message plt.close("all") @@ -621,7 +725,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): # Case: User tries to plot recipe before refinement # expected: Data plotted without fit line or difference curve # and warning message printed - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() plt.close("all") before = set(plt.get_fignums()) # include fit_label="nothing" to make sure fit line is not plotted @@ -649,7 +753,7 @@ def test_plot_recipe_before_refinement(capsys, build_recipe_one_contribution): def test_plot_recipe_after_refinement(build_recipe_one_contribution): # Case: User refines recipe and then plots # expected: Plot generates with no problem - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -686,7 +790,7 @@ def test_plot_recipe_two_contributions(build_recipe_two_contributions): def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): # Case: User passes axes to plot_recipe to plot on existing figure # expected: User modifications are present in the final figure - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") fig, ax = plt.subplots() @@ -706,7 +810,7 @@ def test_plot_recipe_on_existing_plot(build_recipe_one_contribution): def test_plot_recipe_add_new_data(build_recipe_one_contribution): # Case: User wants to add data to figure generated by plot_recipe # Expected: New data is added to existing figure (check with labels) - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") before = set(plt.get_fignums()) @@ -750,7 +854,7 @@ def test_plot_recipe_add_new_data_two_figs(build_recipe_two_contributions): def test_plot_recipe_set_title(build_recipe_one_contribution): # Case: User sets title via plot_recipe # Expected: Title is set correctly - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") expected_title = "Custom Recipe Title" @@ -764,7 +868,7 @@ def test_plot_recipe_set_title(build_recipe_one_contribution): def test_plot_recipe_set_defaults(build_recipe_one_contribution): # Case: user sets default plot options with set_plot_defaults # Expected: plot_recipe uses the default options for all calls - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") # set new defaults @@ -792,7 +896,7 @@ def test_plot_recipe_set_defaults(build_recipe_one_contribution): def test_plot_recipe_set_defaults_bad(capsys, build_recipe_one_contribution): # Case: user tries to set kwargs that are not valid plot_recipe options # Expected: Plot is shown and warning is printed - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") recipe.set_plot_defaults( @@ -902,7 +1006,7 @@ def test_plot_recipe_reset_all_defaults(build_recipe_one_contribution): "show": True, } - recipe = build_recipe_one_contribution + recipe = build_recipe_one_contribution() optimize_recipe(recipe) plt.close("all") From 66a658d4255a39d8090d91284976e1f7adddbf33 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:24:57 -0500 Subject: [PATCH 06/13] add utils objects to get dict from results object or file --- src/diffpy/srfit/util/inpututils.py | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index b5dfa2ac..9eb2e067 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -17,6 +17,7 @@ __all__ = ["inputToString"] import os.path +from pathlib import Path def inputToString(input): @@ -51,4 +52,65 @@ def inputToString(input): return inptstr +def get_dict_from_results_file( + results_filepath: Path | str, +) -> dict[str, float]: + """Get a dictionary of parameter names and values from a results + file. + + The file should have lines in the format: + "parameter_name value +/- uncertainty". Lines that do not match this + format will be ignored. + + Parameters + ---------- + results_filepath : pathlib.Path or str + The path to the results file. + + Returns + ------- + parsed_results_dict : dict + The dictionary where keys are parameter names and values are the + corresponding parameter values as floats. + """ + with open(results_filepath, "r") as f: + results_string = f.read() + parsed_results_dict = {} + for raw_line in results_string.splitlines(): + line = raw_line.strip() + # skip blank lines and lines that are just dashes + if not line or set(line) == {"-"}: + continue + line_items = line.split() + if len(line_items) < 2: + continue + if len(line_items) >= 4 and line_items[2] == "+/-": + try: + parsed_results_dict[line_items[0]] = float(line_items[1]) + except ValueError: + pass + return parsed_results_dict + + +def get_dict_from_results_object(results_object) -> dict[str, float]: + """Get a dictionary of parameter names and values from a FitResults + object. + + Parameters + ---------- + results_object : FitResults + The FitResults object containing the parameter names and values. + + Returns + ------- + params_dict : dict + The dictionary where keys are parameter names and values are the + corresponding parameter values as floats. + """ + param_names = results_object.varnames + param_vals = results_object.varvals + params_dict = dict(zip(param_names, param_vals)) + return params_dict + + # End of file From 83fd535aab39e29efaf156d7a531335104977c28 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:26:18 -0500 Subject: [PATCH 07/13] news --- news/init-w-results.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 news/init-w-results.rst diff --git a/news/init-w-results.rst b/news/init-w-results.rst new file mode 100644 index 00000000..ae63a94a --- /dev/null +++ b/news/init-w-results.rst @@ -0,0 +1,23 @@ +**Added:** + +* Added ``initialize_recipe_with_results`` to ``FitRecipe``. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* From 0c25030f992c33c11d23443e2eb9d2b5885ce046 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:28:49 -0500 Subject: [PATCH 08/13] fix accident in test_fitresults --- tests/test_fitresults.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 4a2fde67..90bb1552 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -39,6 +39,9 @@ Chi2 0.00000000 Reduced Chi2 0.00000000 Rw 0.00000007 + +Variables (Uncertainties invalid) +------------------------------------------------------------------------------ """ expected_refined_variables = ["amplitude", "wave_number", "phase_shift"] From 0625461e63416df2497ca3e028c16248c1aed251 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:49:22 -0500 Subject: [PATCH 09/13] use get_results_dictionary method to get params_dict --- src/diffpy/srfit/fitbase/fitrecipe.py | 14 ++++++++++++-- src/diffpy/srfit/fitbase/fitresults.py | 9 +++++++++ src/diffpy/srfit/util/inpututils.py | 21 --------------------- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index ca3d34a8..28822043 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -1230,8 +1230,18 @@ def initialize_recipe_with_results(self, results, verbose=True): If the input results is not a FitResults object or a path to a results file. """ - if hasattr(results, "print_results"): - params_dict = utils.get_dict_from_results_object(results) + if hasattr(results, "get_results_dictionary"): + params_dict = results.get_results_dictionary() + metrics_in_dict = [ + "Residual", + "Contributions", + "Restraints", + "Chi2", + "Reduced Chi2", + "Rw", + ] + for metric in metrics_in_dict: + params_dict.pop(metric, None) elif isinstance(results, (str, Path)): params_dict = utils.get_dict_from_results_file(results) else: diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index c154d018..a83d6a9c 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -66,6 +66,14 @@ new_base="diffpy.srfit.fitbase.FitResults", ) +initializeRecipe_dep_msg = build_deprecation_message( + "diffpy.srfit.fitbase", + "initializeRecipe", + "FitRecipe.in", + removal_version, + new_base="diffpy.srfit.fitbase.FitResults", +) + class FitResults(object): """Class for processing, presenting and storing results of a fit. @@ -820,6 +828,7 @@ def resultsDictionary(results): return mpairs +@deprecated(initializeRecipe_dep_msg) def initializeRecipe(recipe, results): """Initialize the variables of a recipe from a results file. diff --git a/src/diffpy/srfit/util/inpututils.py b/src/diffpy/srfit/util/inpututils.py index 9eb2e067..f2e0a9df 100644 --- a/src/diffpy/srfit/util/inpututils.py +++ b/src/diffpy/srfit/util/inpututils.py @@ -92,25 +92,4 @@ def get_dict_from_results_file( return parsed_results_dict -def get_dict_from_results_object(results_object) -> dict[str, float]: - """Get a dictionary of parameter names and values from a FitResults - object. - - Parameters - ---------- - results_object : FitResults - The FitResults object containing the parameter names and values. - - Returns - ------- - params_dict : dict - The dictionary where keys are parameter names and values are the - corresponding parameter values as floats. - """ - param_names = results_object.varnames - param_vals = results_object.varvals - params_dict = dict(zip(param_names, param_vals)) - return params_dict - - # End of file From 17f2b10c0363fc6335fdb14e1d987144c7203672 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 15:52:43 -0500 Subject: [PATCH 10/13] initializeRecipe deprecation --- src/diffpy/srfit/fitbase/fitresults.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index a83d6a9c..4f91b6d5 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -69,9 +69,9 @@ initializeRecipe_dep_msg = build_deprecation_message( "diffpy.srfit.fitbase", "initializeRecipe", - "FitRecipe.in", + "initialize_recipe_with_results", removal_version, - new_base="diffpy.srfit.fitbase.FitResults", + new_base="diffpy.srfit.fitbase.FitRecipe", ) @@ -830,7 +830,14 @@ def resultsDictionary(results): @deprecated(initializeRecipe_dep_msg) def initializeRecipe(recipe, results): - """Initialize the variables of a recipe from a results file. + """**This function has been deprecated and will be** **removed in + version 4.0.0.** + + **Please use** + **diffpy.srfit.fitbase.FitRecipe.initialize_recipe_with_results** + **instead.** + + Initialize the variables of a recipe from a results file. This reads the results from file and initializes any variables (fixed or free) in the recipe to the results values. Note that the recipe has to be From 9e205d73b19be203db941a17a3a604db34931871 Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 16:20:18 -0500 Subject: [PATCH 11/13] add better docstrings to fitrecipe and fitresults --- src/diffpy/srfit/fitbase/fitrecipe.py | 378 +++++++++++++++++-------- src/diffpy/srfit/fitbase/fitresults.py | 163 ++++++----- 2 files changed, 356 insertions(+), 185 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index 28822043..a88e4487 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -131,63 +131,63 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): Attributes ---------- - name + name : str A name for this FitRecipe. - fithooks + fithooks : list List of FitHook instances that can pass information out - of the system during a refinement. By default, the is + of the system during a refinement. By default, this is populated by a PrintFitHook instance. - _constraints + _constraints : dict A dictionary of Constraints, indexed by the constrained Parameter. Constraints can be added using the 'constrain' method. - _oconstraints + _oconstraints : list An ordered list of the constraints from this and all sub-components. - _calculators + _calculators : dict A managed dictionary of Calculators. - _contributions + _contributions : OrderedDict A managed OrderedDict of FitContributions. - _parameters + _parameters : OrderedDict A managed OrderedDict of parameters (in this case the parameters are varied). - _parsets + _parsets : dict A managed dictionary of ParameterSets. - _eqfactory + _eqfactory : diffpy.srfit.equation.builder.EquationFactory A diffpy.srfit.equation.builder.EquationFactory instance that is used to create constraints and - restraints from string - _restraintlist + restraints from strings. + _restraintlist : list A list of restraints from this and all sub-components. - _restraints + _restraints : set A set of Restraints. Restraints can be added using the 'restrain' or 'confine' methods. - _ready + _ready : bool A flag indicating if all attributes are ready for the calculation. - _tagmanager + _tagmanager : TagManager A TagManager instance for managing tags on Parameters. - _weights + _weights : list List of weighing factors for each FitContribution. The weights are multiplied by the residual of the FitContribution when determining the overall residual. - _fixedtag + _fixedtag : str "__fixed", used for tagging variables as fixed. Don't use this tag unless you want issues. Properties ---------- - names + names : list Variable names (read only). See get_names. - values + values : numpy.ndarray Variable values (read only). See get_values. - fixednames + fixednames : list Names of the fixed refinable variables (read only). - fixedvalues + fixedvalues : numpy.ndarray Values of the fixed refinable variables (read only). - bounds + bounds : list of tuple Bounds on parameters (read only). See get_bounds_pairs. - bounds2 + bounds2 : tuple of numpy.ndarray Bounds on parameters (read only). See get_bounds_array. """ @@ -269,12 +269,12 @@ def push_fit_hook(self, fithook, index=None): diffpy.srfit.fitbase.fithook.FitHook class for the required interface. Added FitHooks will be called sequentially during refinement. - Attributes + Parameters ---------- - fithook - FitHook instance to add to the sequence - index - Index for inserting fithook into the list of fit hooks. If + fithook : diffpy.srfit.fitbase.fithook.FitHook + FitHook instance to add to the sequence. + index : int or None, optional + Index for inserting fithook into the list of fit hooks. If this is None (default), the fithook is added to the end. """ if index is None: @@ -297,18 +297,20 @@ def pushFitHook(self, fithook, index=None): def pop_fit_hook(self, fithook=None, index=-1): """Remove a FitHook by index or reference. - Attributes + Parameters ---------- - fithook + fithook : diffpy.srfit.fitbase.fithook.FitHook or None, optional FitHook instance to remove from the sequence. If this is None (default), default to index. - index + index : int, optional Index of FitHook instance to remove (default -1). - - Raises ValueError if fithook is not None, but is not present in the - sequence. - Raises IndexError if the sequence is empty or index is out of range. + Raises + ------ + ValueError + If fithook is not None, but is not present in the sequence. + IndexError + If the sequence is empty or index is out of range. """ if fithook is not None: self.fithooks.remove(fithook) @@ -355,15 +357,18 @@ def clearFitHooks(self): def add_contribution(self, con, weight=1.0): """Add a FitContribution to the FitRecipe. - Attributes + Parameters ---------- - con + con : FitContribution The FitContribution to be stored. + weight : float, optional + The weight of the FitContribution. Default is 1.0. - - Raises ValueError if the FitContribution has no name - Raises ValueError if the FitContribution has the same name as some - other managed object. + Raises + ------ + ValueError + If the FitContribution has no name or if the FitContribution has + the same name as some other managed object. """ self._add_object(con, self._contributions, True) self._weights.append(weight) @@ -381,7 +386,19 @@ def addContribution(self, con, weight=1.0): return def set_weight(self, con, weight): - """Set the weight of a FitContribution.""" + """Set the weight of a FitContribution. + + Parameters + ---------- + con : FitContribution + The FitContribution object whose weight is to be set. + weight : float + The weight value to assign to the specified FitContribution. + + Returns + ------- + None + """ idx = list(self._contributions.values()).index(con) self._weights[idx] = weight return @@ -398,15 +415,16 @@ def setWeight(self, con, weight): def add_parameter_set(self, parset): """Add a ParameterSet to the hierarchy. - Attributes + Parameters ---------- - parset + parset : ParameterSet The ParameterSet to be stored. - - Raises ValueError if the ParameterSet has no name. - Raises ValueError if the ParameterSet has the same name as some other - managed object. + Raises + ------ + ValueError + If the ParameterSet has no name or if the ParameterSet has the same + name as some other managed object. """ self._add_object(parset, self._parsets, True) return @@ -424,7 +442,19 @@ def addParameterSet(self, parset): def remove_parameter_set(self, parset): """Remove a ParameterSet from the hierarchy. - Raises ValueError if parset is not managed by this object. + This method removes the specified ParameterSet object from the internal + hierarchy of managed ParameterSets. If the provided ParameterSet is not + currently managed by this object, a ValueError will be raised. + + Parameters: + ----------- + parset : ParameterSet + The ParameterSet instance to be removed from the hierarchy. + + Raises: + ------- + ValueError + If the provided ParameterSet is not managed by this object. """ self._remove_object(parset, self._parsets) return @@ -444,7 +474,7 @@ def residual(self, p=[]): Parameters ---------- - p + p : list or numpy.ndarray The list of current variable values, provided in the same order as the '_parameters' list. If p is an empty iterable (default), then it is assumed that the parameters have already been @@ -495,7 +525,7 @@ def scalar_residual(self, p=[]): Parameters ---------- - p + p : list or numpy.ndarray The list of current variable values, provided in the same order as the '_parameters' list. If p is an empty iterable (default), then it is assumed that the parameters have already been @@ -533,7 +563,10 @@ def _prepare(self): This updates the local restraints with those of the contributions. - Raises AttributeError if there are variables without a value. + Raises + ------ + AttributeError + If there are variables without a value. """ # Only prepare if the configuration has changed within the recipe @@ -684,37 +717,40 @@ def add_variable( ): """Add a variable to be refined. - Attributes + Parameters ---------- - par + par : diffpy.srfit.fitbase.Parameter A Parameter that will be varied during a fit. - value + value : float or None, optional An initial value for the variable. If this is None (default), then the current value of par will be used. - name + name : str or None, optional A name for this variable. If name is None (default), then the name of the parameter will be used. - fixed + fixed : bool, optional Fix the variable so that it does not vary (default False). - tag + tag : str or None, optional A tag for the variable. This can be used to retrieve, fix or free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". - tags + tags : list of str, optional A list of tags (default []). Both tag and tags can be applied. - Returns ------- - vars + ParameterProxy ParameterProxy (variable) for the passed Parameter. - - Raises ValueError if the name of the variable is already taken by - another managed object. - Raises ValueError if par is constant. - Raises ValueError if par is constrained. + Raises + ------ + ValueError + If the name of the variable is already taken by + another managed object. + ValueError + If par is constant. + ValueError + If par is constrained. """ name = name or par.name if par.const: @@ -752,13 +788,15 @@ def delete_variable(self, var): Note that constraints and restraints involving the variable are not modified. - Attributes + Parameters ---------- - var + var : ParameterProxy A variable of the FitRecipe. - - Raises ValueError if var is not part of the FitRecipe. + Raises + ------ + ValueError + If var is not part of the FitRecipe. """ self._remove_parameter(var) @@ -792,29 +830,31 @@ def create_new_variable( optimization routine, and therefore should only be created to be used in constraint or restraint equations. - Attributes + Parameters ---------- - name + name : str The name of the variable. The variable will be able to be used by this name in restraint and constraint equations. - value + value : float or None, optional An initial value for the variable. If this is None (default), then the variable will be given the value of the first non-None-valued Parameter constrained to it. If this fails, an error will be thrown when 'residual' is called. - fixed + fixed : bool, optional Fix the variable so that it does not vary (default False). The variable will still be managed by the FitRecipe. - tag + tag : str or None, optional A tag for the variable. This can be used to fix and free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". - tags + tags : list of str, optional A list of tags (default []). Both tag and tags can be applied. - - Returns the new variable (Parameter instance). + Returns + ------- + Parameter + The new variable (Parameter instance). """ # This will fix the Parameter var = self._new_parameter(name, value) @@ -910,16 +950,51 @@ def __get_vars_from_args(self, *args, **kw): return varargs def fix(self, *args, **kw): - """Fix a parameter by reference, name or tag. + """Fix one or more parameters by reference, name, or tag. - A fixed variable is not refined. Variables are free by default. + This method marks specified parameters as fixed, meaning they will not + be refined during the fitting process. By default, all parameters are + free (not fixed). Parameters can be specified using their references, + names, or tags. Additionally, keyword arguments can be used to assign + specific values to the fixed parameters. - This method accepts string or variable arguments. An argument of - "all" selects all variables. Keyword arguments must be parameter - names, followed by a value to assign to the fixed variable. + Parameters + ---------- + *args: + Positional arguments specifying the parameters to fix. These + can be parameter objects, their names as strings, or tags. + The special string "all" can be used to select all + parameters. + **kw: + Keyword arguments where the keys are parameter names and the + values are the values to assign to the corresponding + fixed parameters. + + Raises + ------ + ValueError: + If an unknown parameter, name, or tag is passed, or if a + tag is passed as a keyword argument. + + Example + ------- + + :: + + # Fix a parameter by reference + recipe.fix(param1) - Raises ValueError if an unknown Parameter, name or tag is - passed, or if a tag is passed in a keyword. + # Fix a parameter by name + recipe.fix("param2") + + # Fix all parameters + recipe.fix("all") + + # Fix parameters by tag + recipe.fix(tag="group1") + + # Fix a parameter and assign it a value + recipe.fix(param3=10.0) """ # Check the inputs and get the variables from them varargs = self.__get_vars_from_args(*args, **kw) @@ -935,17 +1010,44 @@ def fix(self, *args, **kw): return def free(self, *args, **kw): - """Free a parameter by reference, name or tag. + """Free one or more parameters by reference, name, or tag. - A free variable is refined. Variables are free by default. - Constrained variables are not free. + This method marks specified parameters as free, allowing them to be + refined during the fitting process. By default, variables + are free unless they are constrained. Constrained variables + cannot be freed. - This method accepts string or variable arguments. An argument of - "all" selects all variables. Keyword arguments must be parameter - names, followed by a value to assign to the fixed variable. + Parameters + ---------- + *args : str or Parameter + Positional arguments specifying the parameters to free. + These can be: + - Parameter objects + - Names of parameters (as strings) + - Tags associated with parameters (as strings) + - The string "all" to select all parameters. + **kw : dict + Keyword arguments specifying parameter names as keys and + their values to assign after freeing. This is useful + for setting the value of a parameter while marking it as free. - Raises ValueError if an unknown Parameter, name or tag is - passed, or if a tag is passed in a keyword. + Raises + ------ + ValueError + If an unknown parameter, name, or tag is passed, or if a + tag is passed as a keyword argument. + + Notes + ----- + - Parameters that are already free will remain free. + - Tags associated with fixed parameters will be removed when they + are freed. + - If keyword arguments are provided, the corresponding parameter values + will be updated after freeing. + + Returns + ------- + None """ # Check the inputs and get the variables from them varargs = self.__get_vars_from_args(*args, **kw) @@ -962,7 +1064,24 @@ def free(self, *args, **kw): return def is_free(self, var): - """Check if a variable is fixed.""" + """Determine if a variable is free (not fixed) in the fit + recipe. + + This method checks whether the specified variable does not have the + fixed tag associated with it, indicating that it is free to vary + during the fitting process. + + Parameters + ---------- + var : object + The variable to check. This is typically an instance of a parameter + or variable object used in the fit recipe. + + Returns + ------- + bool + True if the variable is free (not fixed), False otherwise. + """ return not self._tagmanager.hasTags(var, self._fixedtag) @deprecated(isFree_dep_msg) @@ -980,13 +1099,15 @@ def unconstrain(self, *pars): This removes any constraints on a Parameter. If the Parameter is also a variable of the recipe, it will be freed as well. - Attributes + Parameters ---------- - *pars - The names of Parameters or Parameters to unconstrain. - + *pars : str or Parameter + The names of Parameters or Parameter objects to unconstrain. - Raises ValueError if the Parameter is not constrained. + Raises + ------ + ValueError + If the Parameter is not constrained. """ update = False for par in pars: @@ -1020,26 +1141,29 @@ def constrain(self, par, con, ns={}): and its current value is None. A constrained variable will be set as fixed. - Attributes + Parameters ---------- - par + par : Parameter The Parameter to constrain. - con + con : str or Parameter A string representation of the constraint equation or a - Parameter to constrain to. A constraint equation must + Parameter to constrain to. A constraint equation must consist of numpy operators and "known" Parameters. Parameters are known if they are in the ns argument, or if they are managed by this object. - ns + ns : dict, optional A dictionary of Parameters, indexed by name, that are used in the eqstr, but not part of this object (default {}). - - Raises ValueError if ns uses a name that is already used for a - variable. - Raises ValueError if eqstr depends on a Parameter that is not part of - the FitRecipe and that is not defined in ns. - Raises ValueError if par is marked as constant. + Raises + ------ + ValueError + If ns uses a name that is already used for a variable. + ValueError + If eqstr depends on a Parameter that is not part of the FitRecipe + and that is not defined in ns. + ValueError + If par is marked as constant. """ if isinstance(par, str): name = par @@ -1070,10 +1194,24 @@ def constrain(self, par, con, ns={}): return def get_values(self): - """Get the current values of the variables in a list.""" - return array( + """Retrieve the current values of all free variables in the fit + recipe. + + This method collects the values of all parameters that are marked as + free (i.e., adjustable during the fitting process) and returns them + as a NumPy array. + + Returns + ------- + + values_array : numpy.ndarray + An array containing the current values of all free + variables in the fit recipe. + """ + values_array = array( [v.value for v in self._parameters.values() if self.is_free(v)] ) + return values_array @deprecated(getValues_dep_msg) def getValues(self): @@ -1084,8 +1222,20 @@ def getValues(self): return self.get_values() def get_names(self): - """Get the names of the variables in a list.""" - return [v.name for v in self._parameters.values() if self.is_free(v)] + """Retrieve the names of all free variables in the fit recipe. + + This method iterates through the parameters in the fit recipe and + returns a list of names for those variables that are marked as free. + + Returns + ------- + parameter_names :list of str + A list containing the names of free variables. + """ + parameter_names = [ + v.name for v in self._parameters.values() if self.is_free(v) + ] + return parameter_names @deprecated(getNames_dep_msg) def getNames(self): diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index 4f91b6d5..bf286a3b 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -80,58 +80,80 @@ class FitResults(object): Attributes ---------- - recipe - The recipe containing the results. - cov - The covariance matrix from the recipe. - conresults - An ordered dictionary of ContributionResults for each - FitContribution, indexed by the FitContribution name. - derivstep - The fractional step size for calculating numeric - derivatives. Default 1e-8. - varnames - Names of the variables in the recipe. - varvals - Values of the variables in the recipe. - varunc - Uncertainties in the variable values. - showfixed - Show fixed variables (default True). - fixednames - Names of the fixed variables of the recipe. - fixedvals - Values of the fixed variables of the recipe. - showcon - Show constraint values in the output (default False). - connames - Names of the constrained parameters. - convals - Values of the constrained parameters. - conunc - Uncertainties in the constraint values. - residual - The scalar residual of the recipe. - penalty - The penalty to residual from the restraints. - chi2 - The chi2 of the recipe. - cumchi2 - The cumulative chi2 of the recipe. - rchi2 - The reduced chi2 of the recipe. - rw - The Rw of the recipe. - cumrw - The cumulative Rw of the recipe. - messages - A list of messages about the results. - precision - The precision of numeric output (default 8). - _dcon - The derivatives of the constraint equations with respect to - the variables. This is used internally. + recipe : FitRecipe + The recipe from which the results were generated. + + cov : numpy.ndarray or None + Covariance matrix of the refined variables. None if unavailable. + + conresults : collections.OrderedDict[str, ContributionResults] + Ordered mapping of FitContribution name → ContributionResults. + + derivstep : float + Fractional step size used for numerical derivatives (default 1e-8). + + varnames : list[str] + Names of refined variables in the recipe. + + varvals : numpy.ndarray + Optimized values of the refined variables. + + varunc : numpy.ndarray or None + Estimated standard uncertainties of the variables. None if invalid. + + showfixed : bool + Whether fixed variables are included in formatted output + (default True). + + fixednames : list[str] + Names of variables held fixed during refinement. + + fixedvals : numpy.ndarray + Values of the fixed variables. + + showcon : bool + Whether constrained parameters are included in formatted output + (default False). + + connames : list[str] + Names of constrained parameters. + convals : numpy.ndarray + Values of constrained parameters. + + conunc : numpy.ndarray or None + Uncertainties of constrained parameters. None if unavailable. + + residual : float + Scalar residual value of the recipe. + + penalty : float + Penalty contribution to the residual from restraints. + + chi2 : float + Chi-squared value of the fit. + + cumchi2 : numpy.ndarray + Cumulative chi-squared as a function of data index. + + rchi2 : float + Reduced chi-squared of the fit. + + rw : float + Weighted R-factor of the fit. + + cumrw : numpy.ndarray + Cumulative weighted R-factor as a function of data index. + + messages : list[str] + Informational or warning messages associated with the results. + + precision : int + Number of digits used when formatting numeric output (default 8). + + _dcon : numpy.ndarray + Jacobian of constraint equations with respect to variables. + Used internally for uncertainty propagation. Each of these attributes, except the recipe, are created or updated when the update method is called. @@ -142,14 +164,13 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): Attributes ---------- - recipe - The recipe containing the results - update - Flag indicating whether to do an immediate update (default - True). - showcon + recipe : FitRecipe + The recipe containing the results. + update : bool + Flag indicating whether to do an immediate update (default True). + showfixed : bool Show fixed variables in the output (default True). - showcon + showcon : bool Show constraint values in the output (default False). """ self.recipe = recipe @@ -674,37 +695,37 @@ class ContributionResults(object): Attributes ---------- - y + y : numpy.ndarray or None The FitContribution's profile over the calculation range (default None). - dy + dy : numpy.ndarray or None The uncertainty in the FitContribution's profile over the calculation range (default None). - x + x : numpy.ndarray or None A numpy array of the calculated independent variable for the FitContribution (default None). - ycalc + ycalc : numpy.ndarray or None A numpy array of the calculated signal for the FitContribution (default None). - residual + residual : float The scalar residual of the FitContribution. - chi2 + chi2 : float The chi2 of the FitContribution. - cumchi2 + cumchi2 : numpy.ndarray The cumulative chi2 of the FitContribution. - rw + rw : float The Rw of the FitContribution. - cumrw + cumrw : numpy.ndarray The cumulative Rw of the FitContribution. - weight + weight : float The weight of the FitContribution in the recipe. - conlocs + conlocs : list The location of the constrained parameters in the FitContribution (see the RecipeContainer._locate_managed_object method). - convals + convals : list Values of the constrained parameters. - conunc + conunc : list Uncertainties in the constraint values. """ From 39178a67d24eee1de4907eed1e5f2ee360ad7c9f Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Thu, 26 Feb 2026 17:59:52 -0500 Subject: [PATCH 12/13] add 'The' to docstrings --- src/diffpy/srfit/fitbase/fitrecipe.py | 94 +++++++++++++------------- src/diffpy/srfit/fitbase/fitresults.py | 75 ++++++++++---------- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/diffpy/srfit/fitbase/fitrecipe.py b/src/diffpy/srfit/fitbase/fitrecipe.py index a88e4487..0aff6ecd 100644 --- a/src/diffpy/srfit/fitbase/fitrecipe.py +++ b/src/diffpy/srfit/fitbase/fitrecipe.py @@ -134,41 +134,41 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): name : str A name for this FitRecipe. fithooks : list - List of FitHook instances that can pass information out + The list of FitHook instances that can pass information out of the system during a refinement. By default, this is populated by a PrintFitHook instance. _constraints : dict - A dictionary of Constraints, indexed by the constrained + The dictionary of Constraints, indexed by the constrained Parameter. Constraints can be added using the 'constrain' method. _oconstraints : list - An ordered list of the constraints from this and all + The ordered list of the constraints from this and all sub-components. _calculators : dict - A managed dictionary of Calculators. + The managed dictionary of Calculators. _contributions : OrderedDict - A managed OrderedDict of FitContributions. + The managed OrderedDict of FitContributions. _parameters : OrderedDict - A managed OrderedDict of parameters (in this case the + The managed OrderedDict of parameters (in this case the parameters are varied). _parsets : dict - A managed dictionary of ParameterSets. + The managed dictionary of ParameterSets. _eqfactory : diffpy.srfit.equation.builder.EquationFactory - A diffpy.srfit.equation.builder.EquationFactory + The diffpy.srfit.equation.builder.EquationFactory instance that is used to create constraints and restraints from strings. _restraintlist : list - A list of restraints from this and all sub-components. + The list of restraints from this and all sub-components. _restraints : set - A set of Restraints. Restraints can be added using the + The set of Restraints. Restraints can be added using the 'restrain' or 'confine' methods. _ready : bool - A flag indicating if all attributes are ready for the + The flag indicating if all attributes are ready for the calculation. _tagmanager : TagManager - A TagManager instance for managing tags on Parameters. + The TagManager instance for managing tags on Parameters. _weights : list - List of weighing factors for each FitContribution. The + The list of weighing factors for each FitContribution. The weights are multiplied by the residual of the FitContribution when determining the overall residual. _fixedtag : str @@ -178,17 +178,17 @@ class FitRecipe(_fitrecipe_interface, RecipeOrganizer): Properties ---------- names : list - Variable names (read only). See get_names. + The variable names (read only). See get_names. values : numpy.ndarray - Variable values (read only). See get_values. + The variable values (read only). See get_values. fixednames : list - Names of the fixed refinable variables (read only). + The names of the fixed refinable variables (read only). fixedvalues : numpy.ndarray - Values of the fixed refinable variables (read only). + The values of the fixed refinable variables (read only). bounds : list of tuple - Bounds on parameters (read only). See get_bounds_pairs. + The bounds on parameters (read only). See get_bounds_pairs. bounds2 : tuple of numpy.ndarray - Bounds on parameters (read only). See get_bounds_array. + The bounds on parameters (read only). See get_bounds_array. """ fixednames = property( @@ -272,9 +272,9 @@ def push_fit_hook(self, fithook, index=None): Parameters ---------- fithook : diffpy.srfit.fitbase.fithook.FitHook - FitHook instance to add to the sequence. + The FitHook instance to add to the sequence. index : int or None, optional - Index for inserting fithook into the list of fit hooks. If + The index for inserting fithook into the list of fit hooks. If this is None (default), the fithook is added to the end. """ if index is None: @@ -300,10 +300,10 @@ def pop_fit_hook(self, fithook=None, index=-1): Parameters ---------- fithook : diffpy.srfit.fitbase.fithook.FitHook or None, optional - FitHook instance to remove from the sequence. If this is + The FitHook instance to remove from the sequence. If this is None (default), default to index. index : int, optional - Index of FitHook instance to remove (default -1). + The index of FitHook instance to remove (default -1). Raises ------ @@ -720,21 +720,21 @@ def add_variable( Parameters ---------- par : diffpy.srfit.fitbase.Parameter - A Parameter that will be varied during a fit. + The Parameter that will be varied during a fit. value : float or None, optional - An initial value for the variable. If this is None + The initial value for the variable. If this is None (default), then the current value of par will be used. name : str or None, optional - A name for this variable. If name is None (default), then + The name for this variable. If name is None (default), then the name of the parameter will be used. fixed : bool, optional Fix the variable so that it does not vary (default False). tag : str or None, optional - A tag for the variable. This can be used to retrieve, fix + The tag for the variable. This can be used to retrieve, fix or free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". tags : list of str, optional - A list of tags (default []). Both tag and tags can be + The list of tags (default []). Both tag and tags can be applied. Returns @@ -836,7 +836,7 @@ def create_new_variable( The name of the variable. The variable will be able to be used by this name in restraint and constraint equations. value : float or None, optional - An initial value for the variable. If this is None + The initial value for the variable. If this is None (default), then the variable will be given the value of the first non-None-valued Parameter constrained to it. If this fails, an error will be thrown when 'residual' is called. @@ -844,11 +844,11 @@ def create_new_variable( Fix the variable so that it does not vary (default False). The variable will still be managed by the FitRecipe. tag : str or None, optional - A tag for the variable. This can be used to fix and free + The tag for the variable. This can be used to fix and free variables by tag (default None). Note that a variable is automatically tagged with its name and "all". tags : list of str, optional - A list of tags (default []). Both tag and tags can be + The list of tags (default []). Both tag and tags can be applied. Returns @@ -960,14 +960,14 @@ def fix(self, *args, **kw): Parameters ---------- - *args: - Positional arguments specifying the parameters to fix. These - can be parameter objects, their names as strings, or tags. - The special string "all" can be used to select all + *args : str or Parameter + The positional arguments specifying the parameters to fix. + These can be parameter objects, their names as strings, or + tags. The special string "all" can be used to select all parameters. - **kw: - Keyword arguments where the keys are parameter names and the - values are the values to assign to the corresponding + **kw : dict + The keyword arguments where the keys are parameter names and + the values are the values to assign to the corresponding fixed parameters. Raises @@ -1020,14 +1020,14 @@ def free(self, *args, **kw): Parameters ---------- *args : str or Parameter - Positional arguments specifying the parameters to free. + The positional arguments specifying the parameters to free. These can be: - Parameter objects - Names of parameters (as strings) - Tags associated with parameters (as strings) - The string "all" to select all parameters. **kw : dict - Keyword arguments specifying parameter names as keys and + The keyword arguments specifying parameter names as keys and their values to assign after freeing. This is useful for setting the value of a parameter while marking it as free. @@ -1146,13 +1146,13 @@ def constrain(self, par, con, ns={}): par : Parameter The Parameter to constrain. con : str or Parameter - A string representation of the constraint equation or a + The string representation of the constraint equation or a Parameter to constrain to. A constraint equation must consist of numpy operators and "known" Parameters. Parameters are known if they are in the ns argument, or if they are managed by this object. ns : dict, optional - A dictionary of Parameters, indexed by name, that are used + The dictionary of Parameters, indexed by name, that are used in the eqstr, but not part of this object (default {}). Raises @@ -1205,7 +1205,7 @@ def get_values(self): ------- values_array : numpy.ndarray - An array containing the current values of all free + The array containing the current values of all free variables in the fit recipe. """ values_array = array( @@ -1230,7 +1230,7 @@ def get_names(self): Returns ------- parameter_names :list of str - A list containing the names of free variables. + The list containing the names of free variables. """ parameter_names = [ v.name for v in self._parameters.values() if self.is_free(v) @@ -1251,7 +1251,7 @@ def get_bounds_pairs(self): Returns ------- bounds_pair_list : list of tuple of float - A list of ``(lower, upper)`` bounds on the variables, in the same + The list of ``(lower, upper)`` bounds on the variables, in the same order as ``get_names`` and ``get_values``. """ return [v.bounds for v in self._parameters.values() if self.is_free(v)] @@ -1272,10 +1272,10 @@ def get_bounds_array(self): Returns ------- lower_bounds : numpy.ndarray - A numpy array of lower bounds on the variables, in the same order + The numpy array of lower bounds on the variables, in the same order as ``get_names`` and ``get_values``. upper_bounds : numpy.ndarray - A numpy array of upper bounds on the variables, in the same order + The numpy array of upper bounds on the variables, in the same order as ``get_names`` and ``get_values``. """ bounds = self.get_bounds_pairs() diff --git a/src/diffpy/srfit/fitbase/fitresults.py b/src/diffpy/srfit/fitbase/fitresults.py index bf286a3b..d8310109 100644 --- a/src/diffpy/srfit/fitbase/fitresults.py +++ b/src/diffpy/srfit/fitbase/fitresults.py @@ -84,75 +84,75 @@ class FitResults(object): The recipe from which the results were generated. cov : numpy.ndarray or None - Covariance matrix of the refined variables. None if unavailable. + The covariance matrix of the refined variables. None if unavailable. conresults : collections.OrderedDict[str, ContributionResults] - Ordered mapping of FitContribution name → ContributionResults. + The ordered mapping of FitContribution name → ContributionResults. derivstep : float - Fractional step size used for numerical derivatives (default 1e-8). + The fractional step size used for numerical derivatives (default 1e-8). varnames : list[str] - Names of refined variables in the recipe. + The names of refined variables in the recipe. varvals : numpy.ndarray - Optimized values of the refined variables. + The optimized values of the refined variables. varunc : numpy.ndarray or None - Estimated standard uncertainties of the variables. None if invalid. + The estimated standard uncertainties of the variables. None if invalid. showfixed : bool - Whether fixed variables are included in formatted output + Show the fixed variables in the formatted output (default True). fixednames : list[str] - Names of variables held fixed during refinement. + The names of variables held fixed during refinement. fixedvals : numpy.ndarray - Values of the fixed variables. + The values of the fixed variables. showcon : bool - Whether constrained parameters are included in formatted output + show the constrained parameters in the formatted output (default False). connames : list[str] - Names of constrained parameters. + The names of constrained parameters. convals : numpy.ndarray - Values of constrained parameters. + The values of constrained parameters. conunc : numpy.ndarray or None - Uncertainties of constrained parameters. None if unavailable. + The uncertainties of constrained parameters. None if unavailable. residual : float - Scalar residual value of the recipe. + The scalar residual value of the recipe. penalty : float - Penalty contribution to the residual from restraints. + The penalty contribution to the residual from restraints. chi2 : float - Chi-squared value of the fit. + The chi-squared value of the fit. cumchi2 : numpy.ndarray - Cumulative chi-squared as a function of data index. + The cumulative chi-squared as a function of data index. rchi2 : float - Reduced chi-squared of the fit. + The reduced chi-squared of the fit. rw : float - Weighted R-factor of the fit. + The weighted R-factor of the fit. cumrw : numpy.ndarray - Cumulative weighted R-factor as a function of data index. + The cumulative weighted R-factor as a function of data index. messages : list[str] - Informational or warning messages associated with the results. + The informational or warning messages associated with the results. precision : int - Number of digits used when formatting numeric output (default 8). + The number of digits used when formatting numeric output (default 8). _dcon : numpy.ndarray - Jacobian of constraint equations with respect to variables. + The jacobian of constraint equations with respect to variables. Used internally for uncertainty propagation. Each of these attributes, except the recipe, are created or updated when @@ -167,7 +167,8 @@ def __init__(self, recipe, update=True, showfixed=True, showcon=False): recipe : FitRecipe The recipe containing the results. update : bool - Flag indicating whether to do an immediate update (default True). + The flag indicating whether to do an immediate update + (default True). showfixed : bool Show fixed variables in the output (default True). showcon : bool @@ -597,11 +598,11 @@ def print_results(self, header="", footer="", update=False): Parameters ---------- header - A header to add to the output (default "") + The header to add to the output (default "") footer - A footer to add to the output (default "") + The footer to add to the output (default "") update - Flag indicating whether to call update() (default False). + The flag indicating whether to call update() (default False). """ print(self.get_results_string(header, footer, update).rstrip()) return @@ -626,13 +627,13 @@ def save_results(self, filename, header="", footer="", update=False): Parameters ---------------------------------- filename - Name of the save file. + The name of the save file. header - A header to add to the output (default "") + The header to add to the output (default "") footer - A footer to add to the output (default "") + The footer to add to the output (default "") update - Flag indicating whether to call update() (default False). + The flag indicating whether to call update() (default False). """ # Save the time and user from getpass import getuser @@ -666,8 +667,8 @@ def get_results_dictionary(self): Returns ------- results_dict : dict - A dictionary containing the variable names and values, and overall - metrics, from the FitResults. + The dictionary containing the variable names and values, + and overall metrics, from the FitResults. """ parameter_names = self.varnames parameter_values = self.varvals @@ -702,10 +703,10 @@ class ContributionResults(object): The uncertainty in the FitContribution's profile over the calculation range (default None). x : numpy.ndarray or None - A numpy array of the calculated independent variable for the + The numpy array of the calculated independent variable for the FitContribution (default None). ycalc : numpy.ndarray or None - A numpy array of the calculated signal for the FitContribution + The numpy array of the calculated signal for the FitContribution (default None). residual : float The scalar residual of the FitContribution. @@ -724,9 +725,9 @@ class ContributionResults(object): FitContribution (see the RecipeContainer._locate_managed_object method). convals : list - Values of the constrained parameters. + The values of the constrained parameters. conunc : list - Uncertainties in the constraint values. + The uncertainties in the constraint values. """ def __init__(self, con, weight, fitres): From 73704f41ad84c64e5cb73dc4968095077ecb0f8e Mon Sep 17 00:00:00 2001 From: Caden Myers Date: Fri, 27 Feb 2026 15:47:52 -0500 Subject: [PATCH 13/13] do linspace with odd number of points --- tests/conftest.py | 4 ++-- tests/test_fitresults.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 6b5b39c7..9b7a99fc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -153,7 +153,7 @@ def build_recipe_one_contribution(): def _build_recipe(): profile = Profile() - x = linspace(0, pi, 10) + x = linspace(0, pi, 11) y = sin(x) profile.set_observed_profile(x, y) contribution = FitContribution("c1") @@ -174,7 +174,7 @@ def build_recipe_two_contributions(): """Helper to build a recipe with two physically related contributions.""" profile1 = Profile() - x = linspace(0, pi, 50) + x = linspace(0, pi, 51) y1 = sin(x) # amplitude=1, freq=1 profile1.set_observed_profile(x, y1) diff --git a/tests/test_fitresults.py b/tests/test_fitresults.py index 90bb1552..c8797233 100644 --- a/tests/test_fitresults.py +++ b/tests/test_fitresults.py @@ -38,7 +38,7 @@ Restraints 0.00000000 Chi2 0.00000000 Reduced Chi2 0.00000000 -Rw 0.00000007 +Rw 0.00000010 Variables (Uncertainties invalid) ------------------------------------------------------------------------------