Exemplo n.º 1
0
 def setUpClass(cls):
     box_l = 20.0
     # start with a small box
     cls.system.box_l = np.array([box_l, box_l, box_l])
     cls.system.cell_system.set_n_square(use_verlet_lists=False)
     fene = FeneBond(k=30, d_r_max=2)
     cls.system.bonded_inter.add(fene)
     positions = polymer.positions(n_polymers=cls.num_poly,
                                   bond_length=0.9,
                                   beads_per_chain=cls.num_mono,
                                   seed=42)
     for p in positions:
         for ndx, m in enumerate(p):
             part_id = len(cls.system.part)
             cls.system.part.add(id=part_id, pos=m)
             if ndx > 0:
                 cls.system.part[part_id].add_bond((fene, part_id - 1))
     # bring two polymers to opposite corners:
     # far in cell centre, but mirror images are close
     head_id = 0
     tail_id = head_id + cls.num_mono
     cm = np.mean(cls.system.part[head_id:tail_id].pos, axis=0)
     cls.system.part[head_id:tail_id].pos = cls.system.part[
         head_id:tail_id].pos - cm + cls.system.box_l
     head_id = cls.num_mono + 1
     tail_id = head_id + cls.num_mono
     cm = np.mean(cls.system.part[head_id:tail_id].pos, axis=0)
     cls.system.part[head_id:tail_id].pos -= cm
Exemplo n.º 2
0
 def setUpClass(self):
     box_l = 20.0
     # start with a small bo
     self.system.box_l = np.array([box_l, box_l, box_l])
     self.system.cell_system.set_n_square(use_verlet_lists=False)
     fene = FeneBond(k=30, d_r_max=2)
     self.fene = fene
     self.system.bonded_inter.add(fene)
Exemplo n.º 3
0
    def test_fene(self):
        # system parameters
        box_l = 10.0
        system.box_l = [box_l, box_l, box_l]
        skin = 0.4
        time_step = 0.01
        system.time_step = time_step

        # thermostat and cell system
        system.cell_system.skin = skin
        system.periodicity = [1, 1, 1]

        # particles and bond
        system.part.add(
            id=0, pos=[9.9, 9.75, 9.9], type=0, mol_id=0, fix=[1, 1, 1])
        system.part.add(
            id=1, pos=[9.9, 10.25, 9.9], type=0, mol_id=0, fix=[1, 1, 1])

        k = 1e4
        d_r_max = 1.5
        r_0 = 0.1

        fene = FeneBond(k=k, d_r_max=d_r_max, r_0=r_0)
        system.bonded_inter.add(fene)
        system.part[0].add_bond((fene, 1))
        system.integrator.run(steps=0)

        sim_stress_bonded = system.analysis.stress_tensor()['bonded']
        sim_stress_fene = system.analysis.stress_tensor()[
            'bonded', len(system.bonded_inter) - 1]

        total_bonded_stresses = np.zeros([3, 3])
        for i in range(len(system.bonded_inter)):
            total_bonded_stresses = np.add(
                total_bonded_stresses, system.analysis.stress_tensor()['bonded', i])

        anal_stress_fene = self.get_anal_stress_fene(
            system.part[0].pos, system.part[1].pos, k, d_r_max, r_0)
        self.assertTrue(np.max(np.abs(sim_stress_bonded - anal_stress_fene))
                        < tol, 'bonded stress does not match analytical result')
        self.assertTrue(np.max(np.abs(sim_stress_fene - anal_stress_fene))
                        < tol, 'bonded stress for fene  does not match analytical result')
        self.assertTrue(np.max(np.abs(sim_stress_bonded - total_bonded_stresses))
                        < tol, 'bonded stresses do not sum up to the total value')

        sim_pressure_fene = system.analysis.pressure()[
            'bonded', len(system.bonded_inter) - 1]
        anal_pressure_fene = np.einsum("ii", anal_stress_fene) / 3.0
        self.assertTrue(np.max(np.abs(sim_pressure_fene - anal_pressure_fene))
                        < tol, 'bonded pressure for fene does not match analytical result')

        # Compare stress tensor observable to stress tensor from analysis
        np.testing.assert_allclose(
            StressTensor().calculate(),
            system.analysis.stress_tensor()["total"].reshape(9),
            atol=1E-10)

        system.part.clear()
Exemplo n.º 4
0
    def test(self):
        system = espressomd.System(box_l=[15.0, 15.0, 15.0])
        system.cell_system.skin = 1

        # Initial state. Skin does not influence cutoffs as long as there are
        # no interactions
        self.assertEqual(system.cell_system.max_cut_nonbonded, -1)
        self.assertEqual(system.cell_system.max_cut_bonded, -1)
        self.assertEqual(system.cell_system.interaction_range, -1)

        # Bonded interaction
        fene = FeneBond(r_0=1, d_r_max=2, k=1)
        system.bonded_inter.add(fene)
        self.assertEqual(system.cell_system.max_cut_bonded, 3)
        n_nodes = np.product(system.cell_system.node_grid)
        if n_nodes == 1:
            # Bonds don't influence interaction range
            self.assertEqual(system.cell_system.interaction_range, -1)
        else:
            self.assertEqual(
                system.cell_system.interaction_range,
                system.cell_system.max_cut_bonded + system.cell_system.skin)

        system.bonded_inter.remove(fene._bond_id)
        self.assertEqual(system.cell_system.max_cut_bonded, -1)
        self.assertEqual(system.cell_system.interaction_range, -1)

        if espressomd.has_features("LENNARD_JONES"):
            lj_off_params = system.non_bonded_inter[
                0, 0].lennard_jones.get_params()
            system.non_bonded_inter[0,
                                    0].lennard_jones.set_params(sigma=1,
                                                                epsilon=1,
                                                                cutoff=2.5,
                                                                shift="auto")
            self.assertEqual(system.cell_system.max_cut_nonbonded, 2.5)
            self.assertEqual(
                system.cell_system.interaction_range,
                system.cell_system.max_cut_nonbonded + system.cell_system.skin)

            system.non_bonded_inter[0, 0].lennard_jones.set_params(
                **lj_off_params)
            self.assertEqual(system.cell_system.max_cut_nonbonded, -1)
            self.assertEqual(system.cell_system.interaction_range, -1)
Exemplo n.º 5
0
 def setUpClass(self):
     box_l = 20.0
     # start with a small bo
     self.system.box_l = np.array([box_l, box_l, box_l])
     self.system.cell_system.set_n_square(use_verlet_lists=False)
     fene = FeneBond(k=30, d_r_max=2)
     self.system.bonded_inter.add(fene)
     polymer.create_polymer(N_P=self.num_poly,
                            bond_length=0.9,
                            MPC=self.num_mono,
                            bond=fene)
     # bring two polymers to opposite corners:
     # far in centre cell, but mirror images are close
     head_id = 0
     tail_id = head_id + self.num_mono
     cm = np.mean(self.system.part[head_id:tail_id].pos, axis=0)
     self.system.part[head_id:tail_id].pos = self.system.part[
         head_id:tail_id].pos - cm + self.system.box_l
     head_id = self.num_mono + 1
     tail_id = head_id + self.num_mono
     cm = np.mean(self.system.part[head_id:tail_id].pos, axis=0)
     self.system.part[head_id:tail_id].pos -= cm
Exemplo n.º 6
0
    def test_bonds(self):
        """Tests bond addition and removal."""

        p1 = self.system.part[self.pid]
        p2 = self.system.part.add(pos=p1.pos)
        inactive_bond = FeneBond(k=1, d_r_max=2)
        p2.add_bond([self.f1, p1])
        with self.assertRaisesRegex(RuntimeError, "already exists on particle"):
            p2.add_bond([self.f1, p1.id])
        with self.assertRaisesRegex(RuntimeError, "already exists on particle"):
            p2.add_bond((self.f1, p1))
        with self.assertRaisesRegex(Exception, "1st element of Bond has to be of type BondedInteraction or int"):
            p2.add_bond(('self.f1', p1))
        with self.assertRaisesRegex(ValueError, "Bond partners have to be of type integer or ParticleHandle"):
            p2.add_bond((self.f1, '1'))
        with self.assertRaisesRegex(ValueError, r"Bond FeneBond\(.+?\) needs 1 partner"):
            p2.add_bond((self.f1, p1, p2))
        with self.assertRaisesRegex(Exception, "The bonded interaction has not yet been added to the list of active bonds in ESPResSo"):
            p2.add_bond((inactive_bond, p1))
        p2.delete_bond([self.f1, p1])
        with self.assertRaisesRegex(RuntimeError, "doesn't exist on particle"):
            p2.delete_bond([self.f1, p1])
        with self.assertRaisesRegex(ValueError, "Bond partners have to be of type integer or ParticleHandle"):
            p2.delete_bond((self.f1, 'p1'))
Exemplo n.º 7
0
class PairCriteria(ut.TestCase):

    """Tests interface and implementation of pair criteria"""

    es = espressomd.System(box_l=[1., 1., 1.])

    f1 = FeneBond(k=1, d_r_max=0.05)
    es.bonded_inter.add(f1)
    f2 = FeneBond(k=1, d_r_max=0.05)
    es.bonded_inter.add(f2)
    es.part.add(id=0, pos=(0, 0, 0))
    es.part.add(id=1, pos=(0.91, 0, 0))
    p1 = es.part[0]
    p2 = es.part[1]
    epsilon = 1E-8

    def test_distance_crit_periodic(self):
        dc = pair_criteria.DistanceCriterion(cut_off=0.1)
        # Interface
        self.assertEqual(list(dc.get_params().keys()), ["cut_off", ])
        self.assertTrue(abs(dc.get_params()["cut_off"] - 0.1) < self.epsilon)

        # Decisions
        # Periodic system. Particles in range via minimum image convention
        self.es.periodicity = (1, 1, 1)
        self.assertTrue(dc.decide(self.p1, self.p2))
        self.assertTrue(dc.decide(self.p1.id, self.p2.id))

    @utx.skipIfMissingFeatures("PARTIAL_PERIODIC")
    def test_distance_crit_non_periodic(self):
        dc = pair_criteria.DistanceCriterion(cut_off=0.1)

        # Non-periodic system. Particles out of range
        self.es.periodicity = (0, 0, 0)
        self.assertTrue(not dc.decide(self.p1, self.p2))
        self.assertTrue(not dc.decide(self.p1.id, self.p2.id))

    @utx.skipIfMissingFeatures("LENNARD_JONES")
    def test_energy_crit(self):
        # Setup purely repulsive lj
        self.es.non_bonded_inter[0, 0].lennard_jones.set_params(
            sigma=0.11, epsilon=1, cutoff=2**(1. / 6.) * 0.11, shift="auto")
        ec = pair_criteria.EnergyCriterion(cut_off=0.001)
        # Interface
        self.assertEqual(list(ec.get_params().keys()), ["cut_off", ])
        self.assertTrue(abs(ec.get_params()["cut_off"] - 0.001) < self.epsilon)

        # Decisions
        # Periodic system. Particles in range via minimum image convention
        self.es.periodicity = (1, 1, 1)
        self.assertTrue(ec.decide(self.p1, self.p2))
        self.assertTrue(ec.decide(self.p1.id, self.p2.id))

    @utx.skipIfMissingFeatures(["LENNARD_JONES", "PARTIAL_PERIODIC"])
    def test_energy_crit_non_periodic(self):
        # Setup purely repulsive lj
        self.es.non_bonded_inter[0, 0].lennard_jones.set_params(
            sigma=0.11, epsilon=1, cutoff=2**(1. / 6.) * 0.11, shift="auto")
        ec = pair_criteria.EnergyCriterion(cut_off=0.001)
        # Interface
        self.assertEqual(list(ec.get_params().keys()), ["cut_off", ])
        self.assertTrue(abs(ec.get_params()["cut_off"] - 0.001) < self.epsilon)

        # Non-periodic system. Particles out of range
        self.es.periodicity = (0, 0, 0)
        self.assertTrue(not ec.decide(self.p1, self.p2))
        self.assertTrue(not ec.decide(self.p1.id, self.p2.id))

    def test_bond_crit(self):
        bc = pair_criteria.BondCriterion(bond_type=0)
        # Interface
        self.assertEqual(list(bc.get_params().keys()), ["bond_type", ])
        self.assertEqual(bc.get_params()["bond_type"], 0)

        # Decisions
        # No bond yet. Should return false
        self.assertTrue(not bc.decide(self.p1, self.p2))
        self.assertTrue(not bc.decide(self.p1.id, self.p2.id))

        # Add bond. Then the criterion should match
        self.es.part[0].bonds = ((0, 1),)
        self.assertTrue(bc.decide(self.p1, self.p2))
        self.assertTrue(bc.decide(self.p1.id, self.p2.id))

        # Place bond on the 2nd particle. The criterion should still match
        self.es.part[0].bonds = ()
        self.es.part[1].bonds = ((0, 0),)
        self.assertTrue(bc.decide(self.p1, self.p2))
        self.assertTrue(bc.decide(self.p1.id, self.p2.id))
Exemplo n.º 8
0
class ParticleProperties(ut.TestCase):

    # Particle id to work on
    pid = 17

    # Error tolerance when comparing arrays/tuples...
    tol = 1E-9

    # Handle for espresso system
    system = espressomd.System(box_l=[100.0, 100.0, 100.0])
    system.cell_system.skin = 0
    system.time_step = 0.01

    f1 = FeneBond(k=1, d_r_max=2)
    system.bonded_inter.add(f1)
    f2 = FeneBond(k=1, d_r_max=2)
    system.bonded_inter.add(f2)

    def setUp(self):
        if not self.system.part.exists(self.pid):
            self.system.part.add(id=self.pid, pos=(0, 0, 0))

    def tearDown(self):
        self.system.part.clear()

    def generateTestForVectorProperty(_propName, _value):
        """Generates test cases for vectorial particle properties such as
        position, velocity...
        1st arg: name of the property (e.g., "pos"),
        2nd array: value to be used for testing. Has to be numpy.array of floats
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.system.part[self.pid], propName, value)
            np.testing.assert_allclose(
                np.array(getattr(self.system.part[self.pid], propName)),
                value,
                err_msg=propName + ": value set and value gotten back differ.",
                atol=self.tol)

        return func

    def generateTestForScalarProperty(_propName, _value):
        """Generates test cases for scalar particle properties such as
        type, mass, charge...
        1st arg: name of the property (e.g., "type"),
        2nd array: value to be used for testing. int or float
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.system.part[self.pid], propName, value)
            self.assertEqual(
                getattr(self.system.part[self.pid], propName), value,
                propName + ": value set and value gotten back differ.")

        return func

    test_pos = generateTestForVectorProperty("pos", np.array([0.1, 0.2, 0.3]))
    test_v = generateTestForVectorProperty("v", np.array([0.2, 0.3, 0.4]))
    test_f = generateTestForVectorProperty("f", np.array([0.2, 0.3, 0.7]))
    test_type = generateTestForScalarProperty("type", int(3))
    test_mol_id = generateTestForScalarProperty("mol_id", int(3))

    test_bonds_property = generateTestForScalarProperty(
        "bonds", ((f1, 1), (f2, 2)))

    if espressomd.has_features(["MASS"]):
        test_mass = generateTestForScalarProperty("mass", 1.3)

    if espressomd.has_features(["ROTATION"]):

        for x in 0, 1:
            for y in 0, 1:
                for z in 0, 1:
                    test_rotation = generateTestForVectorProperty(
                        "rotation", np.array([x, y, z], dtype=int))

        test_omega_lab = generateTestForVectorProperty("omega_lab",
                                                       np.array([4., 2., 1.]))
        test_omega_body = generateTestForVectorProperty(
            "omega_body", np.array([4., 72., 1.]))
        test_torque_lab = generateTestForVectorProperty(
            "torque_lab", np.array([4., 72., 3.7]))
        # The tested value has to be normalized!
        test_quat = generateTestForVectorProperty(
            "quat", np.array([0.5, 0.5, 0.5, 0.5]))

        if espressomd.has_features(["LANGEVIN_PER_PARTICLE"]):
            if espressomd.has_features(["PARTICLE_ANISOTROPY"]):
                test_gamma = generateTestForVectorProperty(
                    "gamma", np.array([2., 9., 0.23]))

                def test_gamma_single(self):
                    self.system.part[self.pid].gamma = 17.4
                    np.testing.assert_array_equal(
                        np.copy(self.system.part[self.pid].gamma),
                        np.array([17.4, 17.4, 17.4]),
                        "gamma: value set and value gotten back differ.")
            else:
                test_gamma = generateTestForScalarProperty("gamma", 17.3)

            if espressomd.has_features(["PARTICLE_ANISOTROPY"]):
                test_gamma_rot = generateTestForVectorProperty(
                    "gamma_rot", np.array([5., 10., 0.33]))

                def test_gamma_rot_single(self):
                    self.system.part[self.pid].gamma_rot = 15.4
                    np.testing.assert_array_equal(
                        np.copy(self.system.part[self.pid].gamma_rot),
                        np.array([15.4, 15.4, 15.4]),
                        "gamma_rot: value set and value gotten back differ.")
            else:
                test_gamma_rot = generateTestForScalarProperty(
                    "gamma_rot", 14.23)
    # test_director=generateTestForVectorProperty("director",
    # np.array([0.5,0.4,0.3]))

    if espressomd.has_features(["ELECTROSTATICS"]):
        test_charge = generateTestForScalarProperty("q", -19.7)

    if espressomd.has_features(["EXTERNAL_FORCES"]):
        test_ext_force = generateTestForVectorProperty("ext_force",
                                                       [0.1, 0.2, 0.3])
        test_fix = generateTestForVectorProperty("fix", [True, False, True])

    if espressomd.has_features(["EXTERNAL_FORCES", "ROTATION"]):
        test_ext_torque = generateTestForVectorProperty(
            "ext_torque", [.4, .5, .6])

    if espressomd.has_features(["DIPOLES"]):
        test_dip = generateTestForVectorProperty("dip",
                                                 np.array([0.5, -0.5, 3]))
        test_dipm = generateTestForScalarProperty("dipm", -9.7)

    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))
            self.system.part.add(id=1, pos=(0, 0, 0))
            self.system.part[1].vs_relative = (0, 5.0, (0.5, -0.5, -0.5, -0.5))
            self.system.part[1].vs_quat = [1, 2, 3, 4]
            np.testing.assert_array_equal(self.system.part[1].vs_quat,
                                          [1, 2, 3, 4])
            res = self.system.part[1].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)

    @utx.skipIfMissingFeatures("DIPOLES")
    def test_contradicting_properties_dip_dipm(self):
        with self.assertRaises(ValueError):
            self.system.part.add(pos=[0, 0, 0], dip=[1, 1, 1], dipm=1.0)

    @utx.skipIfMissingFeatures(["DIPOLES", "ROTATION"])
    def test_contradicting_properties_dip_quat(self):
        with self.assertRaises(ValueError):
            self.system.part.add(pos=[0, 0, 0],
                                 dip=[1, 1, 1],
                                 quat=[1.0, 1.0, 1.0, 1.0])

    @utx.skipIfMissingFeatures("ELECTROSTATICS")
    def test_particle_selection(self):
        s = self.system
        s.part.clear()
        positions = ((0.2, 0.3, 0.4), (0.4, 0.2, 0.3), (0.7, 0.7, 0.7))
        charges = [0, 1E-6, -1, 1]

        # Place particles
        i = 0
        for pos in positions:
            for q in charges:
                s.part.add(pos=pos, q=q, id=i)
                i += 1

        # Scalar property
        res = s.part.select(q=0)
        self.assertEqual(len(res.id), len(positions))
        for p in res:
            self.assertAlmostEqual(p.q, 0, places=13)

        # Vectorial property
        res = s.part.select(pos=(0.2, 0.3, 0.4))
        self.assertEqual(len(res.id), len(charges))
        for p in res:
            np.testing.assert_allclose((0.2, 0.3, 0.4),
                                       np.copy(p.pos),
                                       atol=1E-12)

        # Two criteria
        res = s.part.select(pos=(0.2, 0.3, 0.4), q=0)
        self.assertEqual(tuple(res.id), (0, ))

        # Empty result
        res = s.part.select(q=17)
        self.assertEqual(tuple(res.id), ())
        # User-specified criterion
        res = s.part.select(lambda p: p.pos[0] < 0.5)
        self.assertEqual(tuple(sorted(res.id)), (0, 1, 2, 3, 4, 5, 6, 7))

    def test_image_box(self):
        s = self.system
        s.part.clear()

        pos = 1.5 * s.box_l

        s.part.add(pos=pos)

        np.testing.assert_equal(np.copy(s.part[0].image_box), [1, 1, 1])

    def test_accessing_invalid_id_raises(self):
        self.system.part.clear()
        handle_to_non_existing_particle = self.system.part[42]
        with self.assertRaises(RuntimeError):
            handle_to_non_existing_particle.id

    def test_parallel_property_setters(self):
        s = self.system
        s.part.clear()
        s.part.add(pos=s.box_l * np.random.random((100, 3)))

        # Copy individual properties of particle 0
        print(
            "If this test hangs, there is an mpi deadlock in a particle property setter."
        )
        for p in espressomd.particle_data.particle_attributes:
            # Uncomment to identify guilty property
            # print( p)

            if not hasattr(s.part[0], p):
                raise Exception(
                    "Inconsistency between ParticleHandle and particle_data.particle_attributes"
                )
            try:
                setattr(s.part[:], p, getattr(s.part[0], p))
            except AttributeError:
                print("Skipping read-only", p)
            # Cause a different mpi callback to uncover deadlock immediately
            x = getattr(s.part[:], p)

    def test_zz_remove_all(self):
        for id in self.system.part[:].id:
            self.system.part[id].remove()
        self.system.part.add(pos=np.random.random(
            (100, 3)) * self.system.box_l,
                             id=np.arange(100, dtype=int))
        ids = self.system.part[:].id
        np.random.shuffle(ids)
        for id in ids:
            self.system.part[id].remove()
        with self.assertRaises(Exception):
            self.system.part[17].remove()

    def test_coord_fold_corner_cases(self):
        system = self.system
        system.time_step = .5
        system.cell_system.set_domain_decomposition(use_verlet_lists=False)
        system.cell_system.skin = 0
        system.min_global_cut = 3
        system.part.clear()
        p1 = system.part.add(pos=3 * [np.nextafter(0., -1.)],
                             v=system.box_l / 3)
        print(p1.pos)
        p2 = system.part.add(pos=np.nextafter(system.box_l, 2 * system.box_l),
                             v=system.box_l / 3)
        print(p2.pos)
        p3 = system.part.add(pos=np.nextafter(system.box_l, (0, 0, 0)),
                             v=system.box_l / 3)
        print(p3.pos)
        p4 = system.part.add(pos=3 * [np.nextafter(0., 1.)],
                             v=system.box_l / 3)
        print(p4.pos)
        system.integrator.run(3)
        for p in system.part:
            for i in range(3):
                self.assertGreaterEqual(p.pos_folded[i], 0)
                self.assertLess(p.pos_folded[i], system.box_l[i])

        # Force resort
        system.part.add(pos=(0, 0, 0))
        system.integrator.run(9)
        for p in system.part:
            for i in range(3):
                self.assertGreaterEqual(p.pos_folded[i], 0)
                self.assertLess(p.pos_folded[i], system.box_l[i])
Exemplo n.º 9
0
class ClusterAnalysis(ut.TestCase):
    """Tests the cluster analysis"""

    es = espressomd.System(box_l=(1, 1, 1))

    f = FeneBond(k=1, d_r_max=0.05)
    es.bonded_inter.add(f)

    # Firt cluster
    es.part.add(id=0, pos=(0, 0, 0))
    es.part.add(id=1, pos=(0.91, 0, 0), bonds=((0, 0), ))
    es.part.add(id=2, pos=(0, 0.2, 0))
    es.part.add(id=3, pos=(0, 0.1, 0))

    # 2nd cluster
    es.part.add(id=4, pos=(0.5, 0.5, 0.5))
    es.part.add(id=5, pos=(0.55, 0.5, 0.5))

    cs = ClusterStructure()
    np.random.seed(1)

    # Setup check
    handle_errors("")

    def test_00_fails_without_criterion_set(self):
        with (self.assertRaises(Exception)):
            self.cs.run_for_all_pairs()

    def test_set_criterion(self):
        # Test setters/getters for criteria
        dc = DistanceCriterion(cut_off=0.11)
        self.cs.set_params(pair_criterion=dc)
        # Do we get back the right criterion
        dc_ret = self.cs.get_params()["pair_criterion"]
        # Note: This work around the fact that the script interface does not
        # yet assign the correct derived class when returning an object
        self.assertEqual(dc_ret.name(), "PairCriteria::DistanceCriterion")
        self.assertAlmostEqual(dc_ret.get_params()["cut_off"], 0.11, places=7)

        # Is the cluster structure empty before being used

    def test_analysis_for_all_pairs(self):
        # Run cluster analysis
        self.cs.set_params(pair_criterion=DistanceCriterion(cut_off=0.12))
        self.cs.run_for_all_pairs()

        # Number of clusters
        self.assertEqual(len(self.cs.clusters), 2)
        cids = self.cs.cluster_ids()

        # Sizes of individual clusters
        l2 = self.cs.clusters[cids[1]].size()
        l1 = len(self.cs.clusters[cids[0]].particle_ids())

        # Clusters should contain 2 and 4 particles
        self.assertEqual(min(l1, l2), 2)
        self.assertEqual(max(l1, l2), 4)

        # Verify particle ids
        smaller_cluster = None
        bigger_cluster = None
        if l1 < l2:
            smaller_cluster = self.cs.clusters[cids[0]]
            bigger_cluster = self.cs.clusters[cids[1]]
        else:
            smaller_cluster = self.cs.clusters[cids[1]]
            bigger_cluster = self.cs.clusters[cids[0]]

        self.assertEqual(bigger_cluster.particle_ids(), [0, 1, 2, 3])
        self.assertEqual(smaller_cluster.particle_ids(), [4, 5])

        # Test obtaining a ParticleSlice for a cluster
        pids = bigger_cluster.particle_ids()
        particles = bigger_cluster.particles()
        # Do the number of entries match
        self.assertEqual(len(pids), len(particles.id_selection))

        # Compare ids of particles in the slice
        self.assertEqual(all(particles.id_selection), all(pids))

        # Test iteration over clusters
        visited_sizes = []
        for c in self.cs.clusters:
            visited_sizes.append(c[1].size())
        visited_sizes = sorted(visited_sizes)
        self.assertEqual(visited_sizes, [2, 4])

    def test_zz_single_cluster_analysis(self):
        self.es.part.clear()
        # Place particles on a line (crossing periodic boundaries)
        for x in np.arange(-0.2, 0.21, 0.01):
            self.es.part.add(pos=(x, 1.1 * x, 1.2 * x))
        self.cs.pair_criterion = DistanceCriterion(cut_off=0.13)
        self.cs.run_for_all_pairs()
        self.assertEqual(len(self.cs.clusters), 1)

        for c in self.cs.clusters:
            # Discard cluster id
            c = c[1]

            # Center of mass should be at origin
            self.assertTrue(
                np.sqrt(np.sum(np.array(c.center_of_mass())**2)) <= 1E-8)

            # Longest distance
            self.assertTrue(
                abs(c.longest_distance() -
                    self.es.distance(self.es.part[0], self.es.part[
                        len(self.es.part) - 1])) <= 1E-8)

            # Radius of gyration
            rg = 0.
            com_particle = self.es.part[len(self.es.part) / 2]
            for p in c.particles():
                rg += self.es.distance(p, com_particle)**2
            rg /= len(self.es.part)
            rg = np.sqrt(rg)
            self.assertTrue(abs(c.radius_of_gyration() - rg) <= 1E-6)

            # Fractal dimension calc require gsl
            if not espressomd.has_features("GSL"):
                print("Skipping fractal dimension tests for lack of GSL")
                return
            # The fractal dimension of a line should be 1

            dr = 0.
            self.assertAlmostEqual(c.fractal_dimension(dr=dr)[0],
                                   1,
                                   delta=0.05)

            # Fractal dimension of a disk should be close to 2
            self.es.part.clear()
            center = np.array((0.1, .02, 0.15))
            for i in range(3000):
                r_inv, phi = np.random.random(2) * np.array((0.2, 2 * np.pi))
                r = 1 / r_inv
                self.es.part.add(pos=center +
                                 r * np.array((np.sin(phi), np.cos(phi), 0)))
            self.cs.clear()
            self.cs.run_for_all_pairs()
            cid = self.cs.cluster_ids()[0]
            df = self.cs.clusters[cid].fractal_dimension(dr=0.001)
            self.assertAlmostEqual(df[0], 2, delta=0.08)

    def test_analysis_for_bonded_particles(self):
        # Run cluster analysis
        self.cs.set_params(pair_criterion=BondCriterion(bond_type=0))
        self.cs.run_for_bonded_particles()

        # There should be one cluster containing particles 0 and 1
        self.assertEqual(len(self.cs.clusters), 1)
        self.assertEqual(
            self.cs.clusters[self.cs.cluster_ids()[0]].particle_ids(), [0, 1])

        # Check particle to cluster id mapping, once by ParticleHandle, once by id
        self.assertEqual(self.cs.cid_for_particle(self.es.part[0]),
                         self.cs.cluster_ids()[0])
        self.assertEqual(self.cs.cid_for_particle(1), self.cs.cluster_ids()[0])
Exemplo n.º 10
0
 def setUp(self):
     self.es.part[self.pid].pos = 0, 0, 0
     self.es.bondedInter[0] = FeneBond(k=1, d_r_max=5)
     self.es.bondedInter[1] = FeneBond(k=1, d_r_max=5)
Exemplo n.º 11
0
class ParticleProperties(ut.TestCase):

    # Particle id to work on
    pid = 17

    # Error tolerance when comparing arrays/tuples...
    tol = 1E-9

    # Handle for espresso system
    es = espressomd.System()

    f1 = FeneBond(k=1, d_r_max=5)
    es.bonded_inter.add(f1)
    f2 = FeneBond(k=1, d_r_max=5)
    es.bonded_inter.add(f2)

    def arraysNearlyEqual(self, a, b):
        """Test, if the magnitude of the difference between two arrays is smaller than the tolerance"""

        # Check length
        if len(a) != len(b):
            return False

        # We have to use a loop, since we can't be sure, we're getting numpy
        # arrays
        sum = 0.
        for i in range(len(a)):
            sum += abs(a[i] - b[i])

        if sum > self.tol:
            return False

        return True

    def setUp(self):
        if not self.es.part.exists(self.pid):
            self.es.part.add(id=self.pid, pos=(0, 0, 0))

    def generateTestForVectorProperty(_propName, _value):
        """Generates test cases for vectorial particle properties such as
        position, velocity...
        1st arg: name of the property (e.g., "pos"), 
        2nd array: value to be used for testing. Has to be numpy.array of floats
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.es.part[self.pid], propName, value)
            self.assertTrue(
                self.arraysNearlyEqual(
                    getattr(self.es.part[self.pid], propName), value),
                propName + ": value set and value gotten back differ.")

        return func

    def generateTestForScalarProperty(_propName, _value):
        """Generates test cases for scalar particle properties such as
        type, mass, charge...
        1st arg: name of the property (e.g., "type"), 
        2nd array: value to be used for testing. int or float
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.es.part[self.pid], propName, value)
            self.assertTrue(
                getattr(self.es.part[self.pid], propName) == value,
                propName + ": value set and value gotten back differ.")

        return func

    test_pos = generateTestForVectorProperty("pos", np.array([0.1, 0.2, 0.3]))
    test_v = generateTestForVectorProperty("v", np.array([0.2, 0.3, 0.4]))
    test_f = generateTestForVectorProperty("f", np.array([0.2, 0.3, 0.7]))
    test_type = generateTestForScalarProperty("type", int(3))

    test_bonds_property = generateTestForScalarProperty(
        "bonds", ((f1, 1), (f2, 2)))

    if "MASS" in espressomd.features():
        test_mass = generateTestForScalarProperty("mass", 1.3)

    if "ROTATION" in espressomd.features():
        test_omega_lab = generateTestForVectorProperty("omega_lab",
                                                       np.array([4., 2., 1.]))
        test_omega_body = generateTestForVectorProperty(
            "omega_body", np.array([4., 72., 1.]))
        test_torque_lab = generateTestForVectorProperty(
            "torque_lab", np.array([4., 72., 3.7]))
        # The tested value has to be normalized!
        test_quat = generateTestForVectorProperty(
            "quat", np.array([0.5, 0.5, 0.5, 0.5]))
        if "ROTATIONAL_INERTIA" in espressomd.features():
            test_gamma_rot = generateTestForVectorProperty(
                "gamma_rot", np.array([5., 10., 0.33]))
        else:
            test_gamma_rot = generateTestForScalarProperty("gamma_rot", 14.23)


#    test_director=generateTestForVectorProperty("director",np.array([0.5,0.4,0.3]))

    if "ELECTROSTATICS" in espressomd.features():
        test_charge = generateTestForScalarProperty("q", -19.7)

    if "DIPOLES" in espressomd.features():
        test_dip = generateTestForVectorProperty("dip",
                                                 np.array([0.5, -0.5, 3]))
        test_dipm = generateTestForScalarProperty("dipm", -9.7)

    if "VIRTUAL_SITES" in espressomd.features():
        test_virtual = generateTestForScalarProperty("virtual", 1)
    if "VIRTUAL_SITES_RELATIVE" in espressomd.features():

        def test_zz_vs_relative(self):
            self.es.part.add(id=0, pos=(0, 0, 0))
            self.es.part.add(id=1, pos=(0, 0, 0))
            self.es.part[1].vs_relative = (0, 5.0, (0.5, -0.5, -0.5, -0.5))
            res = self.es.part[1].vs_relative
            self.assertTrue(
                res[0] == 0 and res[1] == 5.0 and self.arraysNearlyEqual(
                    res[2], np.array((0.5, -0.5, -0.5, -0.5))),
                "vs_relative: " + res.__str__())
Exemplo n.º 12
0
    def test_fene(self):
        # system parameters
        system.box_l = 3 * [10.0]
        skin = 0.4
        time_step = 0.01
        system.time_step = time_step

        # thermostat and cell system
        system.cell_system.skin = skin
        system.periodicity = [1, 1, 1]

        # particles and bond
        p0 = system.part.add(pos=[9.9, 9.75, 9.9],
                             type=0,
                             mol_id=0,
                             fix=[1, 1, 1])
        p1 = system.part.add(pos=[9.9, 10.25, 9.9],
                             type=0,
                             mol_id=0,
                             fix=[1, 1, 1])

        k = 1e4
        d_r_max = 1.5
        r_0 = 0.1

        fene = FeneBond(k=k, d_r_max=d_r_max, r_0=r_0)
        system.bonded_inter.add(fene)
        p0.add_bond((fene, p1))
        system.integrator.run(steps=0)

        sim_pressure_tensor = system.analysis.pressure_tensor()
        sim_pressure_tensor_bonded = sim_pressure_tensor['bonded']
        sim_pressure_tensor_fene = sim_pressure_tensor[
            'bonded', len(system.bonded_inter) - 1]

        total_bonded_pressure_tensor = np.zeros([3, 3])
        for i in range(len(system.bonded_inter)):
            total_bonded_pressure_tensor += sim_pressure_tensor['bonded', i]

        anal_pressure_tensor_fene = self.get_anal_pressure_tensor_fene(
            p0.pos, p1.pos, k, d_r_max, r_0)
        np.testing.assert_allclose(
            sim_pressure_tensor_bonded,
            anal_pressure_tensor_fene,
            atol=tol,
            err_msg='bonded pressure tensor does not match analytical result')
        np.testing.assert_allclose(
            sim_pressure_tensor_fene,
            anal_pressure_tensor_fene,
            atol=tol,
            err_msg=
            'bonded pressure tensor for fene does not match analytical result')
        np.testing.assert_allclose(
            sim_pressure_tensor_bonded,
            total_bonded_pressure_tensor,
            atol=tol,
            err_msg='bonded pressure tensor do not sum up to the total value')

        sim_pressure = system.analysis.pressure()
        sim_pressure_fene = sim_pressure['bonded',
                                         len(system.bonded_inter) - 1]
        anal_pressure_fene = np.einsum("ii", anal_pressure_tensor_fene) / 3.0
        np.testing.assert_allclose(
            sim_pressure_fene,
            anal_pressure_fene,
            atol=tol,
            err_msg='bonded pressure for fene does not match analytical result'
        )

        # Compare pressure observables to pressure from analysis
        np.testing.assert_allclose(PressureTensor().calculate(),
                                   sim_pressure_tensor["total"],
                                   rtol=0,
                                   atol=1E-10)
        self.assertAlmostEqual(Pressure().calculate(),
                               sim_pressure["total"],
                               delta=tol)
Exemplo n.º 13
0
class ParticleProperties(ut.TestCase):

    # Particle id to work on
    pid = 17

    # Error tolerance when comparing arrays/tuples...
    tol = 1E-9

    # Handle for espresso system
    system = espressomd.System(box_l=[100.0, 100.0, 100.0])
    system.cell_system.skin = 0
    system.time_step = 0.01

    f1 = FeneBond(k=1, d_r_max=2)
    system.bonded_inter.add(f1)
    f2 = FeneBond(k=1, d_r_max=2)
    system.bonded_inter.add(f2)

    def setUp(self):
        if not self.system.part.exists(self.pid):
            self.system.part.add(id=self.pid, pos=(0, 0, 0))

    def tearDown(self):
        self.system.part.clear()

    def generateTestForVectorProperty(_propName, _value):
        """Generates test cases for vectorial particle properties such as
        position, velocity...
        1st arg: name of the property (e.g., "pos"),
        2nd array: value to be used for testing. Has to be numpy.array of floats
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.system.part[self.pid], propName, value)
            np.testing.assert_allclose(
                np.array(getattr(self.system.part[self.pid], propName)), value,
                err_msg=propName + ": value set and value gotten back differ.",
                atol=self.tol)

        return func

    def generateTestForScalarProperty(_propName, _value):
        """Generates test cases for scalar particle properties such as
        type, mass, charge...
        1st arg: name of the property (e.g., "type"),
        2nd array: value to be used for testing. int or float
        """
        # This is executed, when generateTestForVectorProperty() is called
        propName = _propName
        value = _value

        def func(self):
            # This code is run at the execution of the generated function.
            # It will use the state of the variables in the outer function,
            # which was there, when the outer function was called
            setattr(self.system.part[self.pid], propName, value)
            self.assertEqual(getattr(self.system.part[self.pid], propName),
                             value, propName + ": value set and value gotten back differ.")

        return func

    test_pos = generateTestForVectorProperty("pos", np.array([0.1, 0.2, 0.3]))
    test_v = generateTestForVectorProperty("v", np.array([0.2, 0.3, 0.4]))
    test_f = generateTestForVectorProperty("f", np.array([0.2, 0.3, 0.7]))
    test_type = generateTestForScalarProperty("type", int(3))
    test_mol_id = generateTestForScalarProperty("mol_id", int(3))

    test_bonds_property = generateTestForScalarProperty(
        "bonds", ((f1, 1), (f2, 2)))

    if espressomd.has_features(["MASS"]):
        test_mass = generateTestForScalarProperty("mass", 1.3)

    if espressomd.has_features(["ROTATION"]):

        for x in 0, 1:
            for y in 0, 1:
                for z in 0, 1:
                    test_rotation = generateTestForVectorProperty(
                        "rotation", np.array([x, y, z], dtype=int))

        test_omega_lab = generateTestForVectorProperty(
            "omega_lab", np.array([4., 2., 1.]))
        test_omega_body = generateTestForVectorProperty(
            "omega_body", np.array([4., 72., 1.]))
        test_torque_lab = generateTestForVectorProperty(
            "torque_lab", np.array([4., 72., 3.7]))
        # The tested value has to be normalized!
        test_quat = generateTestForVectorProperty(
            "quat", np.array([0.5, 0.5, 0.5, 0.5]))

        def test_director(self):
            """
            Test `director`. When set, it should get normalized.

            """
            sample_vector = np.array([0.5, -0.4, 1.3])
            sample_vector_normalized = sample_vector / \
                np.linalg.norm(sample_vector)

            setattr(self.system.part[self.pid], "director", sample_vector)
            np.testing.assert_allclose(
                np.array(getattr(self.system.part[self.pid], "director")),
                sample_vector_normalized
            )

        if espressomd.has_features(["THERMOSTAT_PER_PARTICLE"]):
            if espressomd.has_features(["PARTICLE_ANISOTROPY"]):
                test_gamma = generateTestForVectorProperty(
                    "gamma", np.array([2., 9., 0.23]))

                def test_gamma_single(self):
                    self.system.part[self.pid].gamma = 17.4
                    np.testing.assert_array_equal(
                        np.copy(self.system.part[self.pid].gamma),
                        np.array([17.4, 17.4, 17.4]),
                        "gamma: value set and value gotten back differ.")
            else:
                test_gamma = generateTestForScalarProperty("gamma", 17.3)

            if espressomd.has_features(["PARTICLE_ANISOTROPY"]):
                test_gamma_rot = generateTestForVectorProperty(
                    "gamma_rot", np.array([5., 10., 0.33]))

                def test_gamma_rot_single(self):
                    self.system.part[self.pid].gamma_rot = 15.4
                    np.testing.assert_array_equal(
                        np.copy(self.system.part[self.pid].gamma_rot),
                        np.array([15.4, 15.4, 15.4]),
                        "gamma_rot: value set and value gotten back differ.")
            else:
                test_gamma_rot = generateTestForScalarProperty(
                    "gamma_rot", 14.23)

    if espressomd.has_features(["ELECTROSTATICS"]):
        test_charge = generateTestForScalarProperty("q", -19.7)

    if espressomd.has_features(["EXTERNAL_FORCES"]):
        test_ext_force = generateTestForVectorProperty(
            "ext_force", [0.1, 0.2, 0.3])
        test_fix = generateTestForVectorProperty("fix", [True, False, True])

    if espressomd.has_features(["EXTERNAL_FORCES", "ROTATION"]):
        test_ext_torque = generateTestForVectorProperty(
            "ext_torque", [.4, .5, .6])

    if espressomd.has_features(["DIPOLES"]):
        test_dip = generateTestForVectorProperty(
            "dip", np.array([0.5, -0.5, 3]))
        test_dipm = generateTestForScalarProperty("dipm", -9.7)

    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))
            self.system.part.add(id=1, pos=(0, 0, 0))
            self.system.part[1].vs_relative = (0, 5.0, (0.5, -0.5, -0.5, -0.5))
            self.system.part[1].vs_quat = [1, 2, 3, 4]
            np.testing.assert_array_equal(
                self.system.part[1].vs_quat, [1, 2, 3, 4])
            res = self.system.part[1].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"):
                self.system.part[1].vs_relative = (0, 5.0)
            with self.assertRaisesRegex(ValueError, "particle id has to be given as an int"):
                self.system.part[1].vs_relative = ('0', 5.0, (1, 0, 0, 0))
            with self.assertRaisesRegex(ValueError, "distance has to be given as a float"):
                self.system.part[1].vs_relative = (0, '5', (1, 0, 0, 0))
            with self.assertRaisesRegex(ValueError, "quaternion has to be given as a tuple of 4 floats"):
                self.system.part[1].vs_relative = (0, 5.0, (1, 0, 0))

    @utx.skipIfMissingFeatures("DIPOLES")
    def test_contradicting_properties_dip_dipm(self):
        with self.assertRaises(ValueError):
            self.system.part.add(pos=[0, 0, 0], dip=[1, 1, 1], dipm=1.0)

    @utx.skipIfMissingFeatures(["DIPOLES", "ROTATION"])
    def test_contradicting_properties_dip_quat(self):
        with self.assertRaises(ValueError):
            self.system.part.add(pos=[0, 0, 0], dip=[1, 1, 1],
                                 quat=[1.0, 1.0, 1.0, 1.0])

    @utx.skipIfMissingFeatures("ELECTROSTATICS")
    def test_particle_selection(self):
        s = self.system
        s.part.clear()
        positions = ((0.2, 0.3, 0.4), (0.4, 0.2, 0.3), (0.7, 0.7, 0.7))
        charges = [0, 1E-6, -1, 1]

        # Place particles
        i = 0
        for pos in positions:
            for q in charges:
                s.part.add(pos=pos, q=q, id=i)
                i += 2

        # Scalar property
        res = s.part.select(q=0)
        self.assertEqual(len(res.id), len(positions))
        for p in res:
            self.assertAlmostEqual(p.q, 0, places=13)

        # Vectorial property
        res = s.part.select(pos=(0.2, 0.3, 0.4))
        self.assertEqual(len(res.id), len(charges))
        for p in res:
            np.testing.assert_allclose(
                (0.2, 0.3, 0.4), np.copy(p.pos), atol=1E-12)

        # Two criteria
        res = s.part.select(pos=(0.2, 0.3, 0.4), q=0)
        self.assertEqual(tuple(res.id), (0,))

        # Empty result
        res = s.part.select(q=17)
        self.assertEqual(tuple(res.id), ())
        # User-specified criterion
        res = s.part.select(lambda p: p.pos[0] < 0.5)
        np.testing.assert_equal(sorted(res.id), np.arange(0, 16, 2, dtype=int))

    def test_image_box(self):
        s = self.system
        s.part.clear()

        pos = 1.5 * s.box_l

        s.part.add(pos=pos)

        np.testing.assert_equal(np.copy(s.part[0].image_box), [1, 1, 1])

    def test_accessing_invalid_id_raises(self):
        self.system.part.clear()
        handle_to_non_existing_particle = self.system.part[42]
        with self.assertRaises(RuntimeError):
            handle_to_non_existing_particle.id

    def test_parallel_property_setters(self):
        s = self.system
        s.part.clear()
        s.part.add(pos=s.box_l * np.random.random((100, 3)))

        # Copy individual properties of particle 0
        print(
            "If this test hangs, there is an mpi deadlock in a particle property setter.")
        for p in espressomd.particle_data.particle_attributes:
            # Uncomment to identify guilty property
            # print( p)

            if not hasattr(s.part[0], p):
                raise Exception(
                    "Inconsistency between ParticleHandle and particle_data.particle_attributes")
            try:
                setattr(s.part[:], p, getattr(s.part[0], p))
            except AttributeError:
                print("Skipping read-only", p)
            # Cause a different mpi callback to uncover deadlock immediately
            _ = getattr(s.part[:], p)

    def test_remove_particle(self):
        """Tests that if a particle is removed,
        it no longer exists and bonds to the removed particle are
        also removed."""

        p1 = self.system.part[self.pid]
        p2 = self.system.part.add(pos=p1.pos, bonds=[(self.f1, p1.id)])

        p1.remove()
        self.assertFalse(self.system.part.exists(self.pid))
        self.assertEqual(len(p2.bonds), 0)

    def test_bonds(self):
        """Tests bond addition and removal."""

        p1 = self.system.part[self.pid]
        p2 = self.system.part.add(pos=p1.pos)
        inactive_bond = FeneBond(k=1, d_r_max=2)
        p2.add_bond([self.f1, p1])
        with self.assertRaisesRegex(RuntimeError, "already exists on particle"):
            p2.add_bond([self.f1, p1.id])
        with self.assertRaisesRegex(RuntimeError, "already exists on particle"):
            p2.add_bond((self.f1, p1))
        with self.assertRaisesRegex(Exception, "1st element of Bond has to be of type BondedInteraction or int"):
            p2.add_bond(('self.f1', p1))
        with self.assertRaisesRegex(ValueError, "Bond partners have to be of type integer or ParticleHandle"):
            p2.add_bond((self.f1, '1'))
        with self.assertRaisesRegex(ValueError, r"Bond FeneBond\(.+?\) needs 1 partner"):
            p2.add_bond((self.f1, p1, p2))
        with self.assertRaisesRegex(Exception, "The bonded interaction has not yet been added to the list of active bonds in ESPResSo"):
            p2.add_bond((inactive_bond, p1))
        p2.delete_bond([self.f1, p1])
        with self.assertRaisesRegex(RuntimeError, "doesn't exist on particle"):
            p2.delete_bond([self.f1, p1])
        with self.assertRaisesRegex(ValueError, "Bond partners have to be of type integer or ParticleHandle"):
            p2.delete_bond((self.f1, 'p1'))

    def test_zz_remove_all(self):
        for id in self.system.part[:].id:
            self.system.part[id].remove()
        self.system.part.add(
            pos=np.random.random((100, 3)) * self.system.box_l,
            id=np.arange(100, dtype=int))
        ids = self.system.part[:].id
        np.random.shuffle(ids)
        for id in ids:
            self.system.part[id].remove()
        with self.assertRaises(Exception):
            self.system.part[17].remove()

    def test_coord_fold_corner_cases(self):
        system = self.system
        system.time_step = .5
        system.cell_system.set_domain_decomposition(use_verlet_lists=False)
        system.cell_system.skin = 0
        system.min_global_cut = 3
        system.part.clear()
        p1 = system.part.add(
            pos=3 * [np.nextafter(0., -1.)], v=system.box_l / 3)
        print(p1.pos)
        p2 = system.part.add(
            pos=np.nextafter(system.box_l, 2 * system.box_l), v=system.box_l / 3)
        print(p2.pos)
        p3 = system.part.add(
            pos=np.nextafter(system.box_l, (0, 0, 0)), v=system.box_l / 3)
        print(p3.pos)
        p4 = system.part.add(
            pos=3 * [np.nextafter(0., 1.)], v=system.box_l / 3)
        print(p4.pos)
        system.integrator.run(3)
        for p in system.part:
            for i in range(3):
                self.assertGreaterEqual(p.pos_folded[i], 0)
                self.assertLess(p.pos_folded[i], system.box_l[i])

        # Force resort
        system.part.add(pos=(0, 0, 0))
        system.integrator.run(9)
        for p in system.part:
            for i in range(3):
                self.assertGreaterEqual(p.pos_folded[i], 0)
                self.assertLess(p.pos_folded[i], system.box_l[i])

    def test_particle_slice(self):
        """Tests operations on slices of particles"""

        system = self.system

        # Empty slice
        system.part.clear()
        self.assertEqual(len(system.part[:]), 0)
        self.assertEqual(len(system.part[:].pos), 0)
        self.assertEqual(len(system.part[:].id), 0)
        with self.assertRaises(AttributeError):
            system.part[:].pos = ((1, 2, 3,),)

        # Slice containing particles
        ids = [1, 4, 6, 3, 8, 9]
        pos = np.random.random((len(ids), 3))
        system.part.add(id=ids, pos=pos)

        # All particles
        self.assertEqual(len(system.part[:]), len(ids))
        np.testing.assert_equal(system.part[:].id, sorted(ids))
        np.testing.assert_equal(system.part[:].pos, pos[np.argsort(ids)])

        # Access via slicing
        np.testing.assert_equal(system.part[4:9].id,
                                [i for i in sorted(ids) if i >= 4 and i < 9])
        np.testing.assert_equal(system.part[9:4:-1].id,
                                [i for i in sorted(ids, key=lambda i:-i) if i > 4 and i <= 9])
        # Check that negative start and end on slices are not accepted
        with self.assertRaises(IndexError):
            system.part[-1:]
        with self.assertRaises(IndexError):
            system.part[:-1]

        # Setting particle properties on a slice
        system.part[:5].pos = 0, 0, 0
        np.testing.assert_equal(system.part[:].pos,
                                [pos[i] if ids[i] >= 5 else [0, 0, 0] for i in np.argsort(ids)])

        # Slice access via explicit list of ids
        np.testing.assert_equal(system.part[ids[1:4]].id, ids[1:4])
        # Check that ids passed in an explicit list must exist
        with self.assertRaises(IndexError):
            system.part[99, 3]
        # Check that wrong types are not accepted
        with self.assertRaises(TypeError):
            system.part[[ids[0], 1.2]]

    def test_to_dict(self):
        self.system.part.clear()
        p = self.system.part.add(
            pos=np.random.uniform(size=(10, 3)) * self.system.box_l)
        pp = str(p)
        pdict = p.to_dict()
        p.remove()
        self.system.part.add(pdict)
        self.assertEqual(str(self.system.part.select()), pp)