diff --git a/src/python/espressomd/cluster_analysis.py b/src/python/espressomd/cluster_analysis.py index dc7b03d9ec..7c4be448a1 100644 --- a/src/python/espressomd/cluster_analysis.py +++ b/src/python/espressomd/cluster_analysis.py @@ -42,7 +42,7 @@ class Cluster(ScriptInterfaceHelper): longest_distance() Longest distance between any combination of two particles in the cluster - fractal_dimension(dr=None) + fractal_dimension(dr) Estimates the cluster's fractal dimension by fitting the number of particles :math:`n` in spheres of growing radius around the center of mass to :math:`c*r_g^d`, where :math:`r_g` is the radius of gyration of the diff --git a/src/script_interface/cluster_analysis/Cluster.hpp b/src/script_interface/cluster_analysis/Cluster.hpp index 6e79a36537..0e7e32f4ab 100644 --- a/src/script_interface/cluster_analysis/Cluster.hpp +++ b/src/script_interface/cluster_analysis/Cluster.hpp @@ -57,7 +57,7 @@ class Cluster : public AutoParameters { } if (method == "fractal_dimension") { auto const [df, mean_sq_residual] = - m_cluster->fractal_dimension(get_value(parameters.at("dr"))); + m_cluster->fractal_dimension(get_value(parameters, "dr")); return std::vector({df, mean_sq_residual}); } if (method == "center_of_mass") { diff --git a/testsuite/python/cluster_analysis.py b/testsuite/python/cluster_analysis.py index 207fdb96a0..1de088ed9e 100644 --- a/testsuite/python/cluster_analysis.py +++ b/testsuite/python/cluster_analysis.py @@ -200,6 +200,31 @@ def test_single_cluster_analysis(self): df = self.cs.clusters[cid].fractal_dimension(dr=0.001) self.assertAlmostEqual(df[0], 2, delta=0.08) + def test_fractal_dimension_requires_dr(self): + # ``dr`` is a mandatory parameter (the histogram bin increment). The + # missing-parameter check happens during script-interface argument + # evaluation, before the GSL-guarded core function body, so this test + # does not require the GSL feature. + for x in np.arange(-0.2, 0.21, 0.01): + self.system.part.add(pos=(x, 1.1 * x, 1.2 * x)) + dc = espressomd.pair_criteria.DistanceCriterion(cut_off=0.13) + self.cs.pair_criterion = dc + self.cs.run_for_all_pairs() + self.assertEqual(len(self.cs.clusters), 1) + cluster = list(self.cs.clusters)[0][1] + + # Omitting ``dr`` entirely must raise the standard friendly + # "missing parameter" error (not an opaque ``unordered_map::at``). + with self.assertRaisesRegex( + RuntimeError, "Parameter 'dr' is missing"): + cluster.fractal_dimension() + # Passing ``dr=None`` (which the old docstring advertised as the + # default) must raise a clear conversion error, since ``dr`` has no + # meaningful default and ``None`` is not a valid float. + with self.assertRaisesRegex( + RuntimeError, "not convertible to 'double'"): + cluster.fractal_dimension(dr=None) + def test_analysis_for_bonded_particles(self): self.set_two_clusters() # Run cluster analysis