Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve exception handling and fix various regressions #4479

Merged
merged 10 commits into from
Mar 22, 2022
2 changes: 1 addition & 1 deletion samples/grand_canonical.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import espressomd.reaction_ensemble
import espressomd.electrostatics

required_features = ["P3M", "EXTERNAL_FORCES", "WCA"]
required_features = ["P3M", "WCA"]
espressomd.assert_features(required_features)

parser = argparse.ArgumentParser(epilog=__doc__ + epilog)
Expand Down
20 changes: 13 additions & 7 deletions src/core/unit_tests/Particle_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,6 @@ BOOST_AUTO_TEST_CASE(rattle_constructors) {
}
#endif // BOND_CONSTRAINT

#ifdef EXTERNAL_FORCES
#ifdef ROTATION
BOOST_AUTO_TEST_CASE(particle_bitfields) {
auto p = Particle();

Expand All @@ -255,24 +253,32 @@ BOOST_AUTO_TEST_CASE(particle_bitfields) {
BOOST_CHECK(not p.can_rotate_around(1));

// check setting of one axis
#ifdef EXTERNAL_FORCES
p.set_fixed_along(1, true);
p.set_can_rotate_around(1, true);
BOOST_CHECK(p.is_fixed_along(1));
BOOST_CHECK(p.can_rotate_around(1));
BOOST_CHECK(p.has_fixed_coordinates());
#endif
#ifdef ROTATION
p.set_can_rotate_around(1, true);
BOOST_CHECK(p.can_rotate_around(1));
BOOST_CHECK(p.can_rotate());
#endif

// check that unsetting is properly registered
#ifdef EXTERNAL_FORCES
p.set_fixed_along(1, false);
p.set_can_rotate_around(1, false);
BOOST_CHECK(not p.has_fixed_coordinates());
#endif
#ifdef ROTATION
p.set_can_rotate_around(1, false);
BOOST_CHECK(not p.can_rotate());
#endif

// check setting of all flags at once
#ifdef ROTATION
p.set_can_rotate_all_axes();
BOOST_CHECK(p.can_rotate_around(0));
BOOST_CHECK(p.can_rotate_around(1));
BOOST_CHECK(p.can_rotate_around(2));
#endif
}
#endif // ROTATION
#endif // EXTERNAL_FORCES
14 changes: 7 additions & 7 deletions testsuite/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function(PYTHON_TEST)
set(TEST_FILE ${TEST_FILE_CONFIGURED})

if(NOT DEFINED TEST_MAX_NUM_PROC)
set(TEST_MAX_NUM_PROC 1)
set(TEST_MAX_NUM_PROC 4)
endif()

if(${TEST_MAX_NUM_PROC} GREATER ${TEST_NP})
Expand Down Expand Up @@ -61,20 +61,20 @@ function(CHECKPOINT_TEST)
endif()
if(TEST_SUFFIX)
set(TEST_ARGUMENTS "Test_suffix_${TEST_SUFFIX}__${TEST_MODES}")
set(TEST_SUFFIX "${TEST_MODES}_${TEST_SUFFIX}")
set(TEST_SUFFIX "_${TEST_MODES}_${TEST_SUFFIX}")
else()
set(TEST_ARGUMENTS "Test__${TEST_MODES}")
set(TEST_SUFFIX "${TEST_MODES}")
set(TEST_SUFFIX "_${TEST_MODES}")
endif()
python_test(
FILE save_checkpoint.py MAX_NUM_PROC ${TEST_NPROCS} LABELS ${TEST_LABELS}
SUFFIX ${TEST_SUFFIX} ARGUMENTS ${TEST_ARGUMENTS} DEPENDENCIES
unittest_generator.py)
FILE save_checkpoint.py MAX_NUM_PROC ${TEST_MAX_NUM_PROC} LABELS
${TEST_LABELS} SUFFIX ${TEST_SUFFIX} ARGUMENTS ${TEST_ARGUMENTS}
DEPENDENCIES unittest_generator.py)
python_test(
FILE
test_checkpoint.py
MAX_NUM_PROC
${TEST_NPROCS}
${TEST_MAX_NUM_PROC}
LABELS
${TEST_LABELS}
SUFFIX
Expand Down
12 changes: 4 additions & 8 deletions testsuite/python/field_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,10 @@ def test_homogeneous_flow_field(self):

def test_potential_field(self):
h = np.array([.2, .2, .2])
box = np.array([10., 10., 10.])
scaling = 2.6

field_data = espressomd.constraints.PotentialField.field_from_fn(
box, h, self.potential)
self.system.box_l, h, self.potential)

F = espressomd.constraints.PotentialField(
field=field_data,
Expand Down Expand Up @@ -186,10 +185,9 @@ def test_potential_field(self):
@utx.skipIfMissingFeatures("ELECTROSTATICS")
def test_electric_potential_field(self):
h = np.array([.2, .2, .2])
box = np.array([10., 10., 10.])

field_data = espressomd.constraints.ElectricPotential.field_from_fn(
box, h, self.potential)
self.system.box_l, h, self.potential)

F = espressomd.constraints.ElectricPotential(
field=field_data, grid_spacing=h)
Expand All @@ -213,11 +211,10 @@ def test_electric_potential_field(self):

def test_force_field(self):
h = np.array([.8, .8, .8])
box = np.array([10., 10., 10.])
scaling = 2.6

field_data = espressomd.constraints.ForceField.field_from_fn(
box, h, self.force)
self.system.box_l, h, self.force)

F = espressomd.constraints.ForceField(
field=field_data,
Expand Down Expand Up @@ -245,11 +242,10 @@ def test_force_field(self):

def test_flow_field(self):
h = np.array([.8, .8, .8])
box = np.array([10., 10., 10.])
gamma = 2.6

field_data = espressomd.constraints.FlowField.field_from_fn(
box, h, self.force)
self.system.box_l, h, self.force)

F = espressomd.constraints.FlowField(
field=field_data,
Expand Down
7 changes: 6 additions & 1 deletion testsuite/python/interactions_non-bonded_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@


class Non_bonded_interactionsTests(ut.TestCase):
system = espressomd.System(box_l=[20.0, 20.0, 20.0])
system = espressomd.System(box_l=[30.0, 30.0, 30.0])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this number even matter in the test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, with 20 on the x-axis the test fails on 3 MPI ranks because the LJ range of 8.4 is too large. This error message never surfaced before because runtime errors were never checked when setting a interaction. It's only when the integrator runs that it throws, which can be really confusing when the integrator is run indirectly, e.g. via P3M tuning...


def tearDown(self):
if espressomd.has_features(["LENNARD_JONES"]):
self.system.non_bonded_inter[0, 0].lennard_jones.set_params(
epsilon=0., sigma=0., cutoff=0., shift=0.)

def intersMatch(self, inType, outInter, inParams, outParams, msg_long):
"""Check, if the interaction type set and gotten back as well as the
Expand Down
2 changes: 1 addition & 1 deletion testsuite/python/lb_vtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def set_lbf(self):
self.system.lbboundaries.add(espressomd.lbboundaries.LBBoundary(
shape=espressomd.shapes.Wall(normal=[1, 0, 0], dist=1.5)))
self.system.lbboundaries.add(espressomd.lbboundaries.LBBoundary(
shape=espressomd.shapes.Wall(normal=[-1, 0, 0], dist=-10.5)))
shape=espressomd.shapes.Wall(normal=[-1, 0, 0], dist=-8.5)))
return lbf

def parse_vtk(self, filepath, name, shape):
Expand Down
46 changes: 23 additions & 23 deletions testsuite/python/particle.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,29 +182,29 @@ def test_gamma_rot_single(self):

if espressomd.has_features(["VIRTUAL_SITES"]):
test_virtual = generateTestForScalarProperty("virtual", 1)
if espressomd.has_features(["VIRTUAL_SITES_RELATIVE"]):
def test_yy_vs_relative(self):
self.system.part.add(id=0, pos=(0, 0, 0))
p1 = self.system.part.add(id=1, pos=(0, 0, 0))
p1.vs_relative = (0, 5.0, (0.5, -0.5, -0.5, -0.5))
p1.vs_quat = [1, 2, 3, 4]
np.testing.assert_array_equal(
p1.vs_quat, [1, 2, 3, 4])
res = p1.vs_relative
self.assertEqual(res[0], 0, "vs_relative: " + res.__str__())
self.assertEqual(res[1], 5.0, "vs_relative: " + res.__str__())
np.testing.assert_allclose(
res[2], np.array((0.5, -0.5, -0.5, -0.5)),
err_msg="vs_relative: " + res.__str__(), atol=self.tol)
# check exceptions
with self.assertRaisesRegex(ValueError, "needs input in the form"):
p1.vs_relative = (0, 5.0)
with self.assertRaisesRegex(ValueError, "particle id has to be given as an int"):
p1.vs_relative = ('0', 5.0, (1, 0, 0, 0))
with self.assertRaisesRegex(ValueError, "distance has to be given as a float"):
p1.vs_relative = (0, '5', (1, 0, 0, 0))
with self.assertRaisesRegex(ValueError, "quaternion has to be given as a tuple of 4 floats"):
p1.vs_relative = (0, 5.0, (1, 0, 0))

@utx.skipIfMissingFeatures(["VIRTUAL_SITES_RELATIVE"])
def test_vs_relative(self):
self.system.part.add(id=0, pos=(0, 0, 0))
p1 = self.system.part.add(id=1, pos=(0, 0, 0))
p1.vs_relative = (0, 5.0, (0.5, -0.5, -0.5, -0.5))
p1.vs_quat = [1, 2, 3, 4]
np.testing.assert_array_equal(p1.vs_quat, [1, 2, 3, 4])
res = p1.vs_relative
self.assertEqual(res[0], 0, f"vs_relative: {res}")
self.assertEqual(res[1], 5.0, f"vs_relative: {res}")
np.testing.assert_allclose(
res[2], np.array((0.5, -0.5, -0.5, -0.5)),
err_msg=f"vs_relative: {res}", atol=self.tol)
# check exceptions
with self.assertRaisesRegex(ValueError, "needs input in the form"):
p1.vs_relative = (0, 5.0)
with self.assertRaisesRegex(ValueError, "particle id has to be given as an int"):
p1.vs_relative = ('0', 5.0, (1, 0, 0, 0))
with self.assertRaisesRegex(ValueError, "distance has to be given as a float"):
p1.vs_relative = (0, '5', (1, 0, 0, 0))
with self.assertRaisesRegex(ValueError, "quaternion has to be given as a tuple of 4 floats"):
p1.vs_relative = (0, 5.0, (1, 0, 0))

@utx.skipIfMissingFeatures("DIPOLES")
def test_contradicting_properties_dip_dipm(self):
Expand Down
2 changes: 1 addition & 1 deletion testsuite/python/random_pairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def check_n_squared(self, n2_pairs):

def test(self):
periods = [0, 1]
self.system.periodicity = True, True, True
self.system.periodicity = [True, True, True]
check_non_bonded_loop_trace(self.system)

for periodicity in itertools.product(periods, periods, periods):
Expand Down
51 changes: 15 additions & 36 deletions testsuite/python/reaction_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,20 @@ def check_reaction_parameters(reactions, parameters):
method.exclusion_range,
exclusion_range,
delta=1e-10)
if exclusion_radius_per_type: # Avoid this test for widom method
if not isinstance(method, espressomd.reaction_ensemble.WidomInsertion):
self.assertEqual(
list(
method.exclusion_radius_per_type.keys()),
[1])
list(method.exclusion_radius_per_type.keys()), [1])
self.assertAlmostEqual(
method.exclusion_radius_per_type[1],
exclusion_radius_per_type[1],
delta=1e-10)
method.exclusion_radius_per_type = {2: 0.2}
self.assertEqual(
list(
method.exclusion_radius_per_type.keys()),
[2])
list(method.exclusion_radius_per_type.keys()), [2])
self.assertAlmostEqual(
method.exclusion_radius_per_type[2],
0.2,
delta=1e-10)
method.exclusion_radius_per_type[2], 0.2, delta=1e-10)
self.assertAlmostEqual(
method.get_volume(),
self.system.volume(),
delta=1e-10)
method.get_volume(), self.system.volume(), delta=1e-10)
method.set_volume(volume=1.)
self.assertAlmostEqual(method.get_volume(), 1., delta=1e-10)
self.assertEqual(method.get_non_interacting_type(), 100)
Expand Down Expand Up @@ -165,36 +157,23 @@ def check_reaction_parameters(reactions, parameters):
self.assertEqual(len(method.reactions), 0)

def test_interface(self):
params = {'exclusion_range': 0.8,
'exclusion_radius_per_type': {1: 0.1}}

# reaction ensemble
method = espressomd.reaction_ensemble.ReactionEnsemble(
kT=1.5, exclusion_range=0.8, seed=12, exclusion_radius_per_type={1: 0.1})
self.check_interface(
method,
kT=1.5,
exclusion_range=0.8,
gamma=1.2,
exclusion_radius_per_type={
1: 0.1})
kT=1.4, seed=12, **params)
self.check_interface(method, kT=1.4, gamma=1.2, **params)

# constant pH ensemble
method = espressomd.reaction_ensemble.ConstantpHEnsemble(
kT=1.5, exclusion_range=0.8, seed=12, constant_pH=10, exclusion_radius_per_type={1: 0.1})
self.check_interface(
method,
kT=1.5,
exclusion_range=0.8,
gamma=1.2,
exclusion_radius_per_type={
1: 0.1})
kT=1.5, seed=14, constant_pH=10, **params)
self.check_interface(method, kT=1.5, gamma=1.2, **params)

# Widom insertion
method = espressomd.reaction_ensemble.WidomInsertion(kT=1.6, seed=12)
self.check_interface(
method,
kT=1.6,
exclusion_range=0.,
gamma=1.,
exclusion_radius_per_type={})
method = espressomd.reaction_ensemble.WidomInsertion(kT=1.6, seed=16)
self.check_interface(method, kT=1.6, gamma=1., exclusion_range=0.,
exclusion_radius_per_type={})

def test_exceptions(self):
single_reaction_params = {
Expand Down
27 changes: 12 additions & 15 deletions testsuite/python/virtual_sites_relative.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@
import tests_common


@utx.skipIfMissingFeatures("VIRTUAL_SITES_RELATIVE")
@utx.skipIfMissingFeatures(["VIRTUAL_SITES_RELATIVE", "LENNARD_JONES"])
class VirtualSites(ut.TestCase):
system = espressomd.System(box_l=[1.0, 1.0, 1.0])

np.random.seed(42)

def setUp(self):
self.system.box_l = [10.0, 10.0, 10.0]

def tearDown(self):
self.system.part.clear()
self.system.thermostat.turn_off()
self.system.integrator.set_vv()
self.system.non_bonded_inter[0, 0].lennard_jones.set_params(
epsilon=0., sigma=0., cutoff=0., shift=0.)

def multiply_quaternions(self, a, b):
return np.array(
Expand Down Expand Up @@ -85,8 +92,10 @@ def test_aa_method_switching(self):
espressomd.virtual_sites.VirtualSitesRelative)

def test_vs_quat(self):
self.system.time_step = 0.01
self.system.min_global_cut = 0.23
# First check that quaternion of virtual particle is unchanged if
# have_quaterion is false.
# have_quaternion is false.
self.system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative(
have_quaternion=False)
self.assertFalse(self.system.virtual_sites.have_quaternion)
Expand Down Expand Up @@ -129,20 +138,12 @@ def test_vs_quat(self):
# Check exceptions.
with self.assertRaisesRegex(ValueError, "Argument of vs_auto_relate_to has to be of type ParticleHandle or int"):
p2.vs_auto_relate_to('0')
try:
p2.vs_auto_relate_to(p1)
except BaseException:
self.fail('Failed to set a vs from a particle handle')

def test_pos_vel_forces(self):
system = self.system
system.cell_system.skin = 0.3
system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative()
system.box_l = [10, 10, 10]
system.time_step = 0.004
system.thermostat.turn_off()
system.non_bonded_inter[0, 0].lennard_jones.set_params(
epsilon=0, sigma=0, cutoff=0, shift=0)

# Check setting of min_global_cut
system.min_global_cut = 0.23
Expand Down Expand Up @@ -215,7 +216,7 @@ def run_test_lj(self):
system = self.system
system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative()
# Parameters
n = 90
n = 40
phi = 0.6
sigma = 1.
eps = .025
Expand Down Expand Up @@ -296,10 +297,6 @@ def run_test_lj(self):
self.assertNotAlmostEqual(enegry_pre_change, enegry_post_change)
self.assertNotAlmostEqual(pressure_pre_change, pressure_post_change)

# Turn off lj interaction
system.non_bonded_inter[0, 0].lennard_jones.set_params(
epsilon=0, sigma=0, cutoff=0, shift=0)

def test_lj(self):
"""Run LJ fluid test for different cell systems."""
system = self.system
Expand Down