diff --git a/news/enough-regression-points.rst b/news/enough-regression-points.rst new file mode 100644 index 0000000..8ff9e7c --- /dev/null +++ b/news/enough-regression-points.rst @@ -0,0 +1,23 @@ +**Added:** + +* Raise ``ValueError`` if the number of shared grid points between morphed and target functions is less than the number of parameters. + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/diffpy/morph/refine.py b/src/diffpy/morph/refine.py index 688e06e..8f1390d 100644 --- a/src/diffpy/morph/refine.py +++ b/src/diffpy/morph/refine.py @@ -83,7 +83,15 @@ def _residual(self, pvals): self.x_morph, self.y_morph, self.x_target, self.y_target ) rvec = _y_target - _y_morph - + if len(rvec) < len(pvals): + raise ValueError( + f"\nNumber of parameters (currently {len(pvals)}) cannot " + "exceed the number of shared grid points " + f"(currently {len(rvec)}). " + "Please reduce the number of morphing parameters or " + "provide new morphing and target functions with more " + "shared grid points." + ) # If first time computing residual if self.res_length is None: self.res_length = len(rvec) @@ -145,6 +153,9 @@ def refine(self, *args, **kw): ------ ValueError Exception raised if a minimum cannot be found. + ValueError + If the number of shared grid points between morphed function and + target function is smaller than the number of parameters. """ self.pars = args or self.chain.config.keys() diff --git a/tests/test_refine.py b/tests/test_refine.py index 4cf1bc7..76263bf 100644 --- a/tests/test_refine.py +++ b/tests/test_refine.py @@ -181,6 +181,62 @@ def stretch(x, y, stretch): assert res < err + def test_refine_grid_bad(self, user_filesystem): + grid = numpy.arange(2) + func = numpy.sin(grid) + grid1, func1, grid2, func2 = grid, func, grid, func + config = { + "stretch": 0.005, + "scale": 1.0, + "smear": 0, + } + chain = MorphChain(config) + refiner = Refiner(chain, grid1, func1, grid2, func2) + refpars = ["stretch", "scale", "smear"] + expected_error_message = ( + "\nNumber of parameters (currently 3) cannot " + "exceed the number of shared grid points " + "(currently 2). " + "Please reduce the number of morphing parameters or " + "provide new morphing and target functions with more " + "shared grid points." + ) + with pytest.raises( + ValueError, + ) as error: + refiner.refine(*refpars) + actual_error_message = str(error.value) + assert actual_error_message == expected_error_message + + # call from command line + import subprocess + + data_dir_path = user_filesystem / "cwd_dir" + morph_file = data_dir_path / "morph_data" + morph_data_text = [ + str(grid1[i]) + " " + str(func1[i]) for i in range(len(grid1)) + ] + morph_data_text = "\n".join(morph_data_text) + morph_file.write_text(morph_data_text) + target_file = data_dir_path / "target_data" + target_data_text = [ + str(grid2[i]) + " " + str(func2[i]) for i in range(len(grid2)) + ] + target_data_text = "\n".join(target_data_text) + target_file.write_text(target_data_text) + run_cmd = ["diffpy.morph"] + for key, value in config.items(): + run_cmd.append(f"--{key}") + run_cmd.append(f"{value}") + run_cmd.extend([str(morph_file), str(target_file)]) + run_cmd.append("-n") + result = subprocess.run(run_cmd, capture_output=True, text=True) + expected_error_message = ( + "diffpy.morph: error: " + expected_error_message + ) + actual_error_message = result.stderr.strip() + assert actual_error_message == expected_error_message + # End of class TestRefine