Skip to content

Commit d20f0ef

Browse files
RudolfWeeberclaude
authored andcommitted
analysis: reject calc_rh for chains shorter than 2 beads (espressomd#5371)
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent eae32b5 commit d20f0ef

3 files changed

Lines changed: 20 additions & 0 deletions

File tree

src/core/analysis/statistics_chain.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <boost/mpi/collectives/all_reduce.hpp>
3838

3939
#include <array>
40+
#include <cassert>
4041
#include <cmath>
4142
#include <functional>
4243
#include <stdexcept>
@@ -200,6 +201,7 @@ std::array<double, 4> calc_rg(System::System const &system, int chain_start,
200201

201202
std::array<double, 2> calc_rh(System::System const &system, int chain_start,
202203
int chain_length, int n_chains) {
204+
assert(chain_length >= 2);
203205
auto const &cell_structure = *system.cell_structure;
204206
GatherPos prefetch{*system.box_geo};
205207
double r_H = 0.0, r_H2 = 0.0;

src/script_interface/analysis/Analysis.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ Variant Analysis::do_call_method(std::string const &name,
221221
auto const chain_length = get_value<int>(parameters, "chain_length");
222222
auto const n_chains = get_value<int>(parameters, "number_of_chains");
223223
check_topology(*system.cell_structure, chain_start, chain_length, n_chains);
224+
context()->parallel_try_catch([&]() {
225+
if (chain_length < 2) {
226+
throw std::domain_error(
227+
"Hydrodynamic radius is undefined for chains shorter than 2 beads");
228+
}
229+
});
224230
auto const result = calc_rh(system, chain_start, chain_length, n_chains);
225231
return std::vector<double>(result.begin(), result.end());
226232
}

testsuite/python/analyze_chains.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,18 @@ def test_exceptions(self):
214214
method(chain_start=0, number_of_chains=0, chain_length=1)
215215
with self.assertRaisesRegex(ValueError, "needs at least 1 chain"):
216216
method(chain_start=0, number_of_chains=-1, chain_length=1)
217+
# the hydrodynamic radius is defined via a sum over distinct bead pairs;
218+
# for a single-bead chain there are no pairs and R_H is undefined
219+
# (0/0 = NaN), so it must be rejected
220+
with self.assertRaisesRegex(ValueError, "undefined for chains shorter than 2 beads"):
221+
analysis.calc_rh(chain_start=0, number_of_chains=num_poly,
222+
chain_length=1)
223+
# single-bead chains are well-defined for the end-to-end distance and
224+
# the radius of gyration (both are 0), so these must still succeed
225+
for method in (analysis.calc_re, analysis.calc_rg):
226+
result = method(chain_start=0, number_of_chains=num_poly,
227+
chain_length=1)
228+
self.assertTrue(np.all(np.isfinite(result)))
217229
self.assertIsNone(analysis.call_method("unknown"))
218230
if espressomd.has_features("VIRTUAL_SITES_RELATIVE"):
219231
with self.assertRaisesRegex(RuntimeError, "Center of mass is not well-defined"):

0 commit comments

Comments
 (0)