Exemple #1
0
parser = argparse.ArgumentParser(epilog=__doc__)
parser.add_argument('cs_bulk',
                    type=float,
                    help="bulk salt concentration [1/sigma^3], e.g. 1e-3")
args = parser.parse_args()

# System parameters
#############################################################
cs_bulk = args.cs_bulk
N0 = 70
box_l = (N0 / cs_bulk)**(1.0 / 3.0)

# Integration parameters
#############################################################
system = espressomd.System(box_l=[box_l, box_l, box_l])
np.random.seed(seed=42)
system.time_step = 0.01
system.cell_system.skin = 0.4
temperature = 1.0

#############################################################
#  Setup System                                             #
#############################################################

# Particle setup
#############################################################
# type 0 = HA
# type 1 = A-
# type 2 = H+
Exemple #2
0
args = parser.parse_args()

output_path = "output/sim" + str(args.sim)
if not os.path.isdir(output_path):
    os.makedirs(output_path)
    print('Saving data to ' + output_path)
else:
    warnings.warn("Folder {} already exists, files will be overwritten".format(
        output_path))

boxX = 22.0
boxY = 14.0
boxZ = 15.0
time_step = 0.1

system = espressomd.System(box_l=(boxX, boxY, boxZ))
system.time_step = time_step
system.cell_system.skin = 0.2

# creating the template for RBCs
cell_type = oif.OifCellType(nodes_file="input/rbc374nodes.dat",
                            triangles_file="input/rbc374triangles.dat",
                            system=system,
                            ks=0.04,
                            kb=0.016,
                            kal=0.02,
                            kag=0.9,
                            kv=1.0,
                            check_orientation=False,
                            resize=(2.0, 2.0, 2.0))
class InteractionsBondedTest(ut.TestCase):
    system = espressomd.System(box_l=[17.0, 9.0, 8.0])
    np.random.seed(seed=system.seed)

    box_l = 10.

    start_pos = np.random.rand(3) * box_l
    axis = np.random.rand(3)
    axis /= np.linalg.norm(axis)
    steps = 10

    def setUp(self):
        self.system.box_l = [self.box_l] * 3
        self.system.cell_system.skin = 0.4
        self.system.time_step = .2

        self.system.part.add(id=0, pos=self.start_pos, type=0)
        self.system.part.add(id=1, pos=self.start_pos, type=0)

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

    # Test Harmonic Bond

    def test_harmonic(self):
        hb_k = 5
        hb_r_0 = 1.5
        hb_r_cut = 3.355

        hb = espressomd.interactions.HarmonicBond(k=hb_k,
                                                  r_0=hb_r_0,
                                                  r_cut=hb_r_cut)
        self.run_test(
            hb, lambda r: tests_common.harmonic_force(
                scalar_r=r, k=hb_k, r_0=hb_r_0, r_cut=hb_r_cut),
            lambda r: tests_common.harmonic_potential(
                scalar_r=r, k=hb_k, r_0=hb_r_0, r_cut=hb_r_cut), 0.01,
            hb_r_cut, True)

    # Test Fene Bond
    def test_fene(self):
        fene_k = 23.15
        fene_d_r_max = 3.355
        fene_r_0 = 1.1

        fene = espressomd.interactions.FeneBond(k=fene_k,
                                                d_r_max=fene_d_r_max,
                                                r_0=fene_r_0)
        self.run_test(
            fene, lambda r: tests_common.fene_force(
                scalar_r=r, k=fene_k, d_r_max=fene_d_r_max, r_0=fene_r_0),
            lambda r: tests_common.fene_potential(
                scalar_r=r, k=fene_k, d_r_max=fene_d_r_max, r_0=fene_r_0),
            0.01, fene_r_0 + fene_d_r_max, True)

    @ut.skipIf(
        not espressomd.has_features(["ELECTROSTATICS"]),
        "ELECTROSTATICS feature is not available, skipping coulomb test.")
    def test_coulomb(self):
        coulomb_k = 1
        q1 = 1
        q2 = -1
        self.system.part[0].q = q1
        self.system.part[1].q = q2
        self.run_test(
            espressomd.interactions.BondedCoulomb(prefactor=coulomb_k),
            lambda r: tests_common.coulomb_force(r, coulomb_k, q1, q2),
            lambda r: tests_common.coulomb_potential(r, coulomb_k, q1, q2),
            0.01, self.system.box_l[0] / 3)

    @ut.skipIf(not espressomd.has_features(
        ["ELECTROSTATICS"]
    ), "ELECTROSTATICS feature is not available, skipping coulomb short range test."
               )
    def test_coulomb_sr(self):
        # with negated actual charges and only short range int: cancels out all
        # interactions
        q1 = 1.2
        q2 = -q1
        self.system.part[0].q = q1
        self.system.part[1].q = q2
        r_cut = 2

        sr_solver = espressomd.electrostatics.DH(prefactor=2,
                                                 kappa=0.8,
                                                 r_cut=r_cut)
        self.system.actors.add(sr_solver)
        coulomb_sr = espressomd.interactions.BondedCoulombSRBond(q1q2=-q1 * q2)

        # no break test, bond can't break. it extends as far as the short range
        # part of the electrostatics actor
        self.run_test(coulomb_sr,
                      lambda r: [0., 0., 0.],
                      lambda r: 0,
                      0.01,
                      r_cut,
                      test_breakage=False)

    def test_quartic(self):
        """Tests the Quartic bonded interaction by comparing the potential and force against the analytic values"""

        quartic_k0 = 2.
        quartic_k1 = 5.
        quartic_r = 0.5
        quartic_r_cut = self.system.box_l[0] / 3.

        quartic = espressomd.interactions.QuarticBond(k0=quartic_k0,
                                                      k1=quartic_k1,
                                                      r=quartic_r,
                                                      r_cut=quartic_r_cut)

        self.run_test(
            quartic, lambda r: tests_common.quartic_force(k0=quartic_k0,
                                                          k1=quartic_k1,
                                                          r=quartic_r,
                                                          r_cut=quartic_r_cut,
                                                          scalar_r=r),
            lambda r: tests_common.quartic_potential(k0=quartic_k0,
                                                     k1=quartic_k1,
                                                     r=quartic_r,
                                                     r_cut=quartic_r_cut,
                                                     scalar_r=r), 0.01,
            quartic_r_cut, True)

    def run_test(self,
                 bond_instance,
                 force_func,
                 energy_func,
                 min_dist,
                 cutoff,
                 test_breakage=False):
        self.system.bonded_inter.add(bond_instance)
        self.system.part[0].bonds = ((bond_instance, 1), )

        # n+1 steps from min_dist to cut, then we remove the cut, because that
        # may break the bond due to rounding errors
        for dist in np.linspace(min_dist, cutoff, self.steps + 1)[:-1]:
            self.system.part[
                1].pos = self.system.part[0].pos + self.axis * dist
            self.system.integrator.run(recalc_forces=True, steps=0)

            # Calculate energies
            E_sim = self.system.analysis.energy()["total"]
            E_ref = energy_func(dist)

            # Calculate forces
            f0_sim = np.copy(self.system.part[0].f)
            f1_sim = np.copy(self.system.part[1].f)
            f1_ref = self.axis * force_func(dist)

            # Check that energies match, ...
            self.assertAlmostEqual(E_sim, E_ref)
            # force equals minus the counter-force  ...
            np.testing.assert_allclose(f0_sim, -f1_sim, 1E-12)
            # and has correct value.
            np.testing.assert_almost_equal(f1_sim, f1_ref)

            # Pressure
            # Isotropic pressure =1/3 Trace Stress tensor
            # =1/(3V) sum_i f_i r_i
            # where F is the force between the particles and r their distance
            p_expected = 1. / 3. * \
                np.dot(f1_sim, self.axis * dist) / self.system.volume()
            p_sim = self.system.analysis.pressure()["total"]
            self.assertAlmostEqual(p_sim, p_expected, delta=1E-12)

            # Pressure tensor
            # P_ij = 1/V F_i r_j
            p_tensor_expected = np.outer(
                f1_sim, self.axis * dist) / self.system.volume()
            p_tensor_sim = self.system.analysis.stress_tensor()["total"]
            np.testing.assert_allclose(p_tensor_sim,
                                       p_tensor_expected,
                                       atol=1E-12)
        if test_breakage:
            self.system.part[
                1].pos = self.system.part[0].pos + self.axis * cutoff * (1.01)
            with self.assertRaisesRegexp(
                    Exception, "Encountered errors during integrate"):
                self.system.integrator.run(recalc_forces=True, steps=0)
Exemple #4
0
class Exclusions(ut.TestCase):
    s = espressomd.System(box_l=[1.0, 1.0, 1.0])
    s.seed = s.cell_system.get_state()['n_nodes'] * [1234]

    def setUp(self):
        self.s.part.clear()
        self.s.box_l = 3 * [10]
        self.s.cell_system.skin = 0.4
        self.s.time_step = 0.01

    def test_add_remove(self):
        self.s.part.add(id=0, pos=[0, 0, 0])
        self.s.part.add(id=1, pos=[0, 0, 0])
        self.s.part.add(id=2, pos=[0, 0, 0])

        self.s.part[0].add_exclusion(1)
        self.s.part[0].add_exclusion(2)
        self.assertTrue((self.s.part[0].exclusions == [1, 2]).all())
        self.s.part[0].delete_exclusion(1)
        self.assertEqual(self.s.part[0].exclusions, [2])
        self.s.part[0].delete_exclusion(2)
        self.assertEqual(list(self.s.part[0].exclusions), [])

    def test_transfer(self):
        self.s.part.add(id=0, pos=[0, 0, 0], v=[1., 1., 1])
        self.s.part.add(id=1, pos=[0, 0, 0])
        self.s.part.add(id=2, pos=[0, 0, 0])
        self.s.part.add(id=3, pos=[0, 0, 0])

        self.s.part[0].exclusions = [1, 2, 3]

        for i in range(15):
            self.s.integrator.run(100)
            self.assertTrue((self.s.part[0].exclusions == [1, 2, 3]).all())

    @ut.skipIf(not espressomd.has_features(['LENNARD_JONES']), "Skipping test")
    def test_particle_property(self):
        self.s.non_bonded_inter[0, 0].lennard_jones.set_params(epsilon=1.,
                                                               sigma=2.,
                                                               cutoff=1.5,
                                                               shift=0.0)

        self.s.part.add(id=0, pos=[0, 0, 0], type=0)
        self.s.part.add(id=1, pos=[1, 0, 0], type=0)

        pair_energy = self.s.analysis.energy()['total']
        self.assertGreater(pair_energy, 0.)

        pair_pressure = self.s.analysis.pressure()['total']
        self.assertGreater(pair_pressure, 0.)

        self.s.integrator.run(0)
        pair_force = self.s.part[0].f[0]
        self.assertGreater(abs(pair_force), 0.)
        self.assertAlmostEqual(self.s.part[1].f[0], -pair_force, places=7)

        self.s.part.add(id=2, pos=[2, 0, 0], type=0)
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.analysis.energy()['total'],
                               2 * pair_energy)
        self.assertAlmostEqual(self.s.analysis.pressure()['total'],
                               2 * pair_pressure)
        self.assertAlmostEqual(self.s.part[2].f[0], -pair_force, places=7)

        self.s.part[1].exclusions = [0, 2]
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.analysis.energy()['total'], 0)
        self.assertAlmostEqual(self.s.analysis.pressure()['total'], 0)
        self.assertAlmostEqual(self.s.part[0].f[0], 0, places=7)
        self.assertAlmostEqual(self.s.part[1].f[0], 0, places=7)
        self.assertAlmostEqual(self.s.part[2].f[0], 0, places=7)

        self.s.part[1].exclusions = [0]
        self.assertAlmostEqual(self.s.analysis.energy()['total'], pair_energy)
        self.assertAlmostEqual(self.s.analysis.pressure()['total'],
                               pair_pressure)
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.part[0].f[0], 0, places=7)
        self.assertAlmostEqual(self.s.part[1].f[0], pair_force, places=7)
        self.assertAlmostEqual(self.s.part[2].f[0], -pair_force, places=7)

        self.s.part[1].exclusions = []
        self.assertAlmostEqual(self.s.analysis.energy()['total'],
                               2 * pair_energy)
        self.assertAlmostEqual(self.s.analysis.pressure()['total'],
                               2 * pair_pressure)
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.part[0].f[0], pair_force, places=7)
        self.assertAlmostEqual(self.s.part[1].f[0], 0, places=7)
        self.assertAlmostEqual(self.s.part[2].f[0], -pair_force, places=7)

        self.s.part[1].exclusions = [0]
        self.assertAlmostEqual(self.s.analysis.energy()['total'], pair_energy)
        self.assertAlmostEqual(self.s.analysis.pressure()['total'],
                               pair_pressure)
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.part[0].f[0], 0, places=7)
        self.assertAlmostEqual(self.s.part[1].f[0], pair_force, places=7)
        self.assertAlmostEqual(self.s.part[2].f[0], -pair_force, places=7)

    @ut.skipIf(not espressomd.has_features(['P3M']), "Skipping test")
    def test_electrostatics_not_excluded(self):
        from espressomd.electrostatics import P3M
        self.s.part.add(id=0, pos=[0, 0, 0], type=0, q=+1.)
        self.s.part.add(id=1, pos=[1, 0, 0], type=0, q=-1.)

        # Small alpha means large short-range contribution
        self.s.actors.add(
            P3M(prefactor=1,
                r_cut=3.0,
                accuracy=1e-3,
                mesh=32,
                cao=7,
                alpha=0.1,
                tune=False))

        # Only short-range part of the coulomb energy
        pair_energy = self.s.analysis.energy()[('coulomb', 0)]
        self.assertGreater(abs(pair_energy), 0.)

        self.s.integrator.run(0)
        pair_force = self.s.part[0].f[0]
        self.assertGreater(abs(pair_force), 0.)
        self.assertAlmostEqual(self.s.part[1].f[0], -pair_force, places=7)

        pair_pressure = self.s.analysis.pressure()[('coulomb', 0)]
        self.assertGreater(abs(pair_pressure), 0.)

        self.s.part[0].exclusions = [1]
        # Force and energy should not be changed by the exclusion
        self.s.integrator.run(0)
        self.assertAlmostEqual(self.s.part[0].f[0], pair_force, places=7)
        self.assertAlmostEqual(self.s.part[1].f[0], -pair_force, places=7)
        self.assertAlmostEqual(self.s.analysis.energy()[('coulomb', 0)],
                               pair_energy,
                               places=7)
        self.assertAlmostEqual(self.s.analysis.pressure()[('coulomb', 0)],
                               pair_pressure,
                               places=7)
Exemple #5
0
class TabulatedTest(ut.TestCase):
    s = espressomd.System(box_l=[1.0, 1.0, 1.0])
    s.seed = s.cell_system.get_state()['n_nodes'] * [1234]
    s.box_l = 3 * [10]
    s.time_step = 0.01
    s.cell_system.skin = 0.4

    def setUp(self):
        self.force = np.zeros((100,))
        self.energy = np.zeros((100,))
        self.min_ = 1.
        self.max_ = 2.

        self.dx = (self.max_ - self.min_) / 99.
        for i in range(0, 100):
            self.force[i] = 5 + i * 2.3 * self.dx
            self.energy[i] = 5 - i * 2.3 * self.dx

        self.s.part.clear()
        self.s.part.add(id=0, type=0, pos=[5., 5., 5.0])
        self.s.part.add(id=1, type=0, pos=[5., 5., 5.5])

    def check(self):
        # Below cutoff
        np.testing.assert_allclose(np.copy(self.s.part[:].f), 0.0)

        for z in np.linspace(0, self.max_ - self.min_, 200, endpoint=False):
            self.s.part[1].pos = [5., 5., 6. + z]
            self.s.integrator.run(0)
            np.testing.assert_allclose(
                np.copy(self.s.part[0].f), [0., 0., -(5. + z * 2.3)])
            np.testing.assert_allclose(
                np.copy(self.s.part[0].f), -np.copy(self.s.part[1].f))
            self.assertAlmostEqual(
                self.s.analysis.energy()['total'], 5. - z * 2.3)

    @utx.skipIfMissingFeatures("TABULATED")
    def test_non_bonded(self):
        self.s.non_bonded_inter[0, 0].tabulated.set_params(
            min=self.min_, max=self.max_, energy=self.energy, force=self.force)

        np.testing.assert_allclose(
            self.force, self.s.non_bonded_inter[0, 0].tabulated.get_params()['force'])
        np.testing.assert_allclose(
            self.energy, self.s.non_bonded_inter[0, 0].tabulated.get_params()['energy'])
        self.assertAlmostEqual(
            self.min_, self.s.non_bonded_inter[0, 0].tabulated.get_params()['min'])
        self.assertAlmostEqual(
            self.max_, self.s.non_bonded_inter[0, 0].tabulated.get_params()['max'])

        self.check()

        self.s.non_bonded_inter[0, 0].tabulated.set_params(
            min=-1, max=-1, energy=[], force=[])

    def test_bonded(self):
        from espressomd.interactions import TabulatedDistance

        tb = TabulatedDistance(min=self.min_, max=self.max_,
                               energy=self.energy, force=self.force)
        self.s.bonded_inter.add(tb)

        np.testing.assert_allclose(self.force, tb.params['force'])
        np.testing.assert_allclose(self.energy, tb.params['energy'])
        self.assertAlmostEqual(self.min_, tb.params['min'])
        self.assertAlmostEqual(self.max_, tb.params['max'])

        self.s.part[0].add_bond((tb, 1))

        self.check()

        self.s.part[0].delete_bond((tb, 1))
Exemple #6
0
    return stress


def stress_nonbonded_intra(particle_pairs):
    stress = np.zeros([3, 3])
    for p1, p2 in particle_pairs:
        if p1.type == 0 and p2.type == 0 and p1.mol_id == p2.mol_id:
            r = p1.pos - p2.pos
            d = np.sqrt(np.sum(r**2))
            r_hat = r / d
            f = (24.0 * 1.0 * (2.0 * 1.0**12 / d**13 - 1.0**6 / d**7)) * r_hat
            stress += np.einsum('i,j', f, r) / np.prod(system.box_l)
    return stress


system = espressomd.System(box_l=[1.0, 1.0, 1.0])


@utx.skipIfMissingFeatures(['LENNARD_JONES'])
class Stress(ut.TestCase):
    def test(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.thermostat.set_langevin(kT=0.0, gamma=1.0, seed=41)
        system.cell_system.skin = skin
        system.periodicity = [1, 1, 1]
Exemple #7
0
class DDSGPUTest(ut.TestCase):
    # Handle for espresso system
    system = espressomd.System(box_l=[1.0, 1.0, 1.0])

    @ut.skipIf(system.cell_system.get_state()["n_nodes"] > 1,
               "Skipping test: only runs for n_nodes == 1")
    def test(self):
        pf_dds_gpu = 2.34
        pf_dawaanr = 3.524
        ratio_dawaanr_dds_gpu = pf_dawaanr / pf_dds_gpu
        self.system.box_l = 3 * [15]
        self.system.periodicity = [0, 0, 0]
        self.system.time_step = 1E-4
        self.system.cell_system.skin = 0.1

        for n in [128, 541]:
            dipole_modulus = 1.3
            part_dip = dipole_modulus * tests_common.random_dipoles(n)
            part_pos = np.random.random((n, 3)) * self.system.box_l[0]
            self.system.part.add(pos=part_pos, dip=part_dip)

            self.system.non_bonded_inter[0, 0].lennard_jones.set_params(
                epsilon=10.0, sigma=0.5, cutoff=0.55, shift="auto")

            self.system.thermostat.turn_off()
            self.system.integrator.set_steepest_descent(f_max=0.0,
                                                        gamma=0.1,
                                                        max_displacement=0.1)
            self.system.integrator.run(500)
            g = espressomd.galilei.GalileiTransform()
            g.kill_particle_motion(rotation=True)
            self.system.integrator.set_vv()

            self.system.non_bonded_inter[0, 0].lennard_jones.set_params(
                epsilon=0.0, sigma=0.0, cutoff=0.0, shift=0.0)

            self.system.cell_system.skin = 0.0
            self.system.time_step = 0.01
            self.system.thermostat.turn_off()
            # gamma should be zero in order to avoid the noise term in force
            # and torque
            self.system.thermostat.set_langevin(kT=1.297, gamma=0.0, seed=42)

            dds_cpu = espressomd.magnetostatics.DipolarDirectSumCpu(
                prefactor=pf_dawaanr)
            self.system.actors.add(dds_cpu)
            self.system.integrator.run(steps=0, recalc_forces=True)

            dawaanr_f = np.copy(self.system.part.all().f)
            dawaanr_t = np.copy(self.system.part.all().torque_lab)
            dawaanr_e = self.system.analysis.energy()["total"]

            del dds_cpu
            for i in range(len(self.system.actors.active_actors)):
                self.system.actors.remove(self.system.actors.active_actors[i])

            self.system.integrator.run(steps=0, recalc_forces=True)
            dds_gpu = espressomd.magnetostatics.DipolarDirectSumGpu(
                prefactor=pf_dds_gpu)
            self.system.actors.add(dds_gpu)
            self.system.integrator.run(steps=0, recalc_forces=True)

            ddsgpu_f = np.copy(self.system.part.all().f)
            ddsgpu_t = np.copy(self.system.part.all().torque_lab)
            ddsgpu_e = self.system.analysis.energy()["total"]

            # compare
            for i in range(n):
                np.testing.assert_allclose(
                    np.array(dawaanr_t[i]),
                    ratio_dawaanr_dds_gpu * np.array(ddsgpu_t[i]),
                    err_msg=f'Torques do not match for particle {i}',
                    atol=3e-3)
                np.testing.assert_allclose(
                    np.array(dawaanr_f[i]),
                    ratio_dawaanr_dds_gpu * np.array(ddsgpu_f[i]),
                    err_msg=f'Forces do not match for particle {i}',
                    atol=3e-3)
            self.assertAlmostEqual(
                dawaanr_e,
                ddsgpu_e * ratio_dawaanr_dds_gpu,
                places=2,
                msg='Energies for dawaanr {0} and dds_gpu {1} do not match.'.
                format(dawaanr_e, ratio_dawaanr_dds_gpu * ddsgpu_e))

            self.system.integrator.run(steps=0, recalc_forces=True)

            del dds_gpu
            self.system.actors.clear()
            self.system.part.clear()
class InteractionsBondedTest(ut.TestCase):
    system = espressomd.System(box_l=[1.0, 1.0, 1.0])
    np.random.seed(seed=system.seed)

    box_l = 10.

    start_pos = [5., 5., 5.]
    axis = np.array([1., 0., 0.])
    axis /= np.linalg.norm(axis)
    rel_pos_1 = np.array([0., 1., 0.])
    rel_pos_2 = np.array([0., 0., 1.])

    def setUp(self):

        self.system.box_l = [self.box_l] * 3
        self.system.cell_system.skin = 0.4
        self.system.time_step = .1

        self.system.part.add(id=0, pos=self.start_pos, type=0)
        self.system.part.add(id=1, pos=self.start_pos, type=0)
        self.system.part.add(id=2, pos=self.start_pos, type=0)
        self.system.part.add(id=3, pos=self.start_pos, type=0)

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

    # Analytical Expression
    def dihedral_angle(self, p1, p2, p3, p4):
        """
        Calculate the dihedral angle phi based on particles' position p1, p2, p3, p4.
        """
        v12 = p2 - p1
        v23 = p3 - p2
        v34 = p4 - p3

        v12Xv23 = np.cross(v12, v23)
        l_v12Xv23 = np.linalg.norm(v12Xv23)
        v23Xv34 = np.cross(v23, v34)
        l_v23Xv34 = np.linalg.norm(v23Xv34)

        # if dihedral angle is not defined, phi := -1.
        if l_v12Xv23 <= 1e-8 or l_v23Xv34 <= 1e-8:
            return -1
        else:
            cosphi = np.abs(np.dot(v12Xv23, v23Xv34)) / (l_v12Xv23 * l_v23Xv34)
            return np.arccos(cosphi)

    # Test Dihedral Angle
    def test_dihedral(self):
        dh_k = 1
        dh_phase = np.pi / 6
        dh_n = 1

        dh = espressomd.interactions.Dihedral(bend=dh_k,
                                              mult=dh_n,
                                              phase=dh_phase)
        self.system.bonded_inter.add(dh)
        self.system.part[1].add_bond((dh, 0, 2, 3))
        self.system.part[2].pos = self.system.part[1].pos + [1, 0, 0]

        N = 111
        d_phi = np.pi / (N * 4)
        for i in range(N):
            self.system.part[0].pos = self.system.part[1].pos + \
                rotate_vector(self.rel_pos_1, self.axis, i * d_phi)
            self.system.part[3].pos = self.system.part[2].pos + \
                rotate_vector(self.rel_pos_2, self.axis, -i * d_phi)
            self.system.integrator.run(recalc_forces=True, steps=0)

            # Calculate energies
            E_sim = self.system.analysis.energy()["bonded"]
            phi = self.dihedral_angle(self.system.part[0].pos,
                                      self.system.part[1].pos,
                                      self.system.part[2].pos,
                                      self.system.part[3].pos)
            E_ref = dihedral_potential(dh_k, phi, dh_n, dh_phase)

            # Calculate forces
            f2_sim = self.system.part[1].f
            _, f2_ref, _ = dihedral_force(dh_k, dh_n, dh_phase,
                                          self.system.part[0].pos,
                                          self.system.part[1].pos,
                                          self.system.part[2].pos,
                                          self.system.part[3].pos)

            # Check that energies match, ...
            np.testing.assert_almost_equal(E_sim, E_ref)
            # and has correct value.
            f2_sim_copy = np.copy(f2_sim)
            np.testing.assert_almost_equal(f2_sim_copy, f2_ref)

    # Test Tabulated Dihedral Angle
    @utx.skipIfMissingFeatures(["TABULATED"])
    def test_tabulated_dihedral(self):
        N = 111
        d_phi = 2 * np.pi / N
        # tabulated values for the range [0, 2*pi]
        tab_phi = [i * d_phi for i in range(N + 1)]
        tab_energy = [np.cos(i * d_phi) for i in range(N + 1)]
        tab_force = [np.cos(i * d_phi) for i in range(N + 1)]

        dihedral_tabulated = espressomd.interactions.Tabulated(
            type='dihedral',
            energy=tab_energy,
            force=tab_force,
            min=0.,
            max=2 * np.pi)
        self.system.bonded_inter.add(dihedral_tabulated)
        self.system.part[1].add_bond((dihedral_tabulated, 0, 2, 3))
        self.system.part[2].pos = self.system.part[1].pos + [1, 0, 0]

        # check stored parameters
        interaction_id = len(self.system.bonded_inter) - 1
        tabulated = self.system.bonded_inter[interaction_id]
        np.testing.assert_allclose(tabulated.params['force'], tab_force)
        np.testing.assert_allclose(tabulated.params['energy'], tab_energy)
        np.testing.assert_almost_equal(tabulated.params['min'], 0.)
        np.testing.assert_almost_equal(tabulated.params['max'], 2 * np.pi)

        # measure at half the angular resolution to observe interpolation
        for i in range(2 * N - 1):
            # increase dihedral angle by d_phi (phi ~ 0 at i = 0)
            self.system.part[0].pos = self.system.part[1].pos + \
                rotate_vector(self.rel_pos_1, self.axis, -i * d_phi / 4)
            self.system.part[3].pos = self.system.part[2].pos + \
                rotate_vector(self.rel_pos_1, self.axis, i * d_phi / 4)
            self.system.integrator.run(recalc_forces=True, steps=0)

            # Calculate energies
            E_sim = self.system.analysis.energy()["bonded"]

            # Get tabulated values
            j = i // 2
            if i % 2 == 0:
                E_ref = tab_energy[j]
            else:
                E_ref = (tab_energy[j] + tab_energy[j + 1]) / 2.0

            # Check that energies match, ...
            np.testing.assert_almost_equal(E_sim, E_ref)
class AnalyzeDistributions(ut.TestCase):
    system = espressomd.System(box_l=[1.0, 1.0, 1.0])
    np.random.seed(1234)
    num_part = 10

    @classmethod
    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)
        for p in range(cls.num_part):
            cls.system.part.add(id=p,
                                pos=np.random.random() * cls.system.box_l)

    def calc_rdf(self, r, bins):
        # this generates indices for all i<j combinations
        ij = np.triu_indices(len(r), k=1)
        r_ij = r[ij[0]] - r[ij[1]]
        dist = np.sqrt(np.sum(r_ij**2, axis=1))
        hist = np.histogram(dist, bins=bins, density=False)[0]
        return hist

    def calc_min_distribution(self, bins):
        dist = []
        for i in range(self.num_part):
            dist.append(self.system.analysis.dist_to(id=i))
        hist = np.histogram(dist, bins=bins, density=False)[0]
        return hist / (float(np.sum(hist)))

    # test system.analysis.rdf()
    def test_rdf(self):
        # increase PBC for remove mirror images
        old_pos = self.system.part[:].pos.copy()
        self.system.box_l = self.system.box_l * 2.
        self.system.part[:].pos = old_pos
        r_min = 0.0
        r_max = 100.0
        r_bins = 10
        bin_width = (r_max - r_min) / r_bins
        bins = np.arange(r_min, r_max + bin_width, bin_width)
        bin_volume = 4. / 3. * np.pi * (bins[1:]**3 - bins[:-1]**3)
        box_volume = np.prod(self.system.box_l)
        # all the same type
        core_rdf = self.system.analysis.rdf(rdf_type='rdf',
                                            type_list_a=[0],
                                            type_list_b=[0],
                                            r_min=r_min,
                                            r_max=r_max,
                                            r_bins=r_bins)
        num_pair = 0.5 * (self.num_part) * (self.num_part - 1)
        r = self.system.part[:].pos
        # bins
        self.assertTrue(np.allclose(core_rdf[0], (bins[1:] + bins[:-1]) * 0.5))
        # rdf
        self.assertTrue(
            np.allclose(core_rdf[1] * bin_volume * num_pair / box_volume,
                        self.calc_rdf(r, bins)))
        # change one type
        self.system.part[0].type = 1
        r = self.system.part[1:].pos
        core_rdf = self.system.analysis.rdf(rdf_type='rdf',
                                            type_list_a=[0],
                                            type_list_b=[0],
                                            r_min=r_min,
                                            r_max=r_max,
                                            r_bins=r_bins)
        num_pair = 0.5 * (self.num_part - 1) * (self.num_part - 2)
        self.assertTrue(
            np.allclose(core_rdf[1] * bin_volume * num_pair / box_volume,
                        self.calc_rdf(r, bins)))

        # compare with type
        core_rdf = self.system.analysis.rdf(rdf_type='rdf',
                                            type_list_a=[1],
                                            type_list_b=[0],
                                            r_min=r_min,
                                            r_max=r_max,
                                            r_bins=r_bins)
        num_pair = (self.num_part - 1)
        dist = np.sqrt(
            np.sum((self.system.part[1:].pos - self.system.part[0].pos)**2,
                   axis=1))
        hist = np.histogram(dist, bins=bins, density=False)[0]
        self.assertTrue(
            np.allclose(core_rdf[1] * bin_volume * num_pair / box_volume,
                        hist))
        # restore PBC
        self.system.box_l = self.system.box_l / 2.
        self.system.part[:].pos = old_pos

    # test system.analysis.distribution(), all the same particle types
    def test_distribution_lin(self):
        # increase PBC for remove mirror images
        old_pos = self.system.part[:].pos.copy()
        self.system.box_l = self.system.box_l * 2.
        self.system.part[:].pos = old_pos
        r_min = 0.0
        r_max = 100.0
        r_bins = 100
        bins = np.linspace(r_min, r_max, num=r_bins + 1, endpoint=True)
        # no int flag
        core_rdf = self.system.analysis.distribution(type_list_a=[0],
                                                     type_list_b=[0],
                                                     r_min=r_min,
                                                     r_max=r_max,
                                                     r_bins=r_bins,
                                                     log_flag=0,
                                                     int_flag=0)
        # bins
        self.assertTrue(np.allclose(core_rdf[0], (bins[1:] + bins[:-1]) * 0.5))

        # rdf
        self.assertTrue(
            np.allclose(core_rdf[1], self.calc_min_distribution(bins)))
        # with int flag
        core_rdf = self.system.analysis.distribution(type_list_a=[0],
                                                     type_list_b=[0],
                                                     r_min=r_min,
                                                     r_max=r_max,
                                                     r_bins=r_bins,
                                                     log_flag=0,
                                                     int_flag=1)
        self.assertTrue(
            np.allclose(core_rdf[1],
                        np.cumsum(self.calc_min_distribution(bins))))
class Rotation(ut.TestCase):
    s = espressomd.System(box_l=[1.0, 1.0, 1.0])
    s.seed = s.cell_system.get_state()['n_nodes'] * [1234]
    s.cell_system.skin = 0
    s.time_step = 0.01

    def test_langevin(self):
        """Applies langevin thermostat and checks that correct axes get
           thermalized"""
        s = self.s
        s.thermostat.set_langevin(gamma=1, kT=1, seed=42)
        for x in 0, 1:
            for y in 0, 1:
                for z in 0, 1:
                    s.part.clear()
                    s.part.add(id=0,
                               pos=(0, 0, 0),
                               rotation=(x, y, z),
                               quat=(1, 0, 0, 0),
                               omega_body=(0, 0, 0),
                               torque_lab=(0, 0, 0))
                    s.integrator.run(500)
                    self.validate(x, 0)
                    self.validate(y, 1)
                    self.validate(z, 2)

    def validate(self, rotate, coord):
        if rotate:
            # self.assertNotEqual(self.s.part[0].torque_body[coord],0)
            self.assertNotEqual(self.s.part[0].omega_body[coord], 0)
        else:
            # self.assertEqual(self.s.part[0].torque_body[coord],0)
            self.assertEqual(self.s.part[0].omega_body[coord], 0)

    @utx.skipIfMissingFeatures("EXTERNAL_FORCES")
    def test_axes_changes(self):
        """Verifies that rotation axes in body and space frame stay the same
           and other axes don't"""
        s = self.s
        s.part.clear()
        s.part.add(id=0, pos=(0.9, 0.9, 0.9), ext_torque=(1, 1, 1))
        s.thermostat.turn_off()
        for dir in 0, 1, 2:
            # Reset orientation
            s.part[0].quat = [1, 0, 0, 0]

            # Enable rotation in a single direction
            rot = [0, 0, 0]
            rot[dir] = 1
            s.part[0].rotation = rot

            s.integrator.run(30)

            s.integrator.run(100)

            # Check other axes:
            for axis in [1, 0, 0], [0, 1, 0], [0, 0, 1]:
                if rot == axis:
                    # The axis for which rotation is on should coincide in body
                    # and space frame
                    self.assertAlmostEqual(np.dot(
                        rot, s.part[0].convert_vector_body_to_space(rot)),
                                           1,
                                           places=8)
                else:
                    # For non-rotation axis, body and space frame should differ
                    self.assertLess(
                        np.dot(axis,
                               s.part[0].convert_vector_body_to_space(axis)),
                        0.95)

    def test_frame_conversion_and_rotation(self):
        s = self.s
        s.part.clear()
        p = s.part.add(pos=np.random.random(3), rotation=(1, 1, 1))

        # Space and body frame co-incide?
        np.testing.assert_allclose(np.copy(p.director),
                                   p.convert_vector_body_to_space((0, 0, 1)),
                                   atol=1E-10)

        # Random vector should still co-incide
        v = (1., 5.5, 17)
        np.testing.assert_allclose(v,
                                   p.convert_vector_space_to_body(v),
                                   atol=1E-10)
        np.testing.assert_allclose(v,
                                   p.convert_vector_body_to_space(v),
                                   atol=1E-10)

        # Particle rotation

        p.rotate((1, 2, 0), np.pi / 4)
        # Check angle for director
        self.assertAlmostEqual(np.arccos(np.dot(p.director, (0, 0, 1))),
                               np.pi / 4,
                               delta=1E-10)
        # Check other vector
        v = (5, -7, 3)
        v_r = p.convert_vector_body_to_space(v)
        self.assertAlmostEqual(np.dot(v, v), np.dot(v_r, v_r), delta=1e-10)
        np.testing.assert_allclose(p.convert_vector_space_to_body(v_r),
                                   v,
                                   atol=1E-10)

        # Rotation axis should co-incide
        np.testing.assert_allclose((1, 2, 0),
                                   p.convert_vector_body_to_space((1, 2, 0)))

        # Check rotation axis with all elements set
        p.rotate(axis=(-5, 2, 17), angle=1.)
        v = (5, -7, 3)
        v_r = p.convert_vector_body_to_space(v)
        self.assertAlmostEqual(np.dot(v, v), np.dot(v_r, v_r), delta=1e-10)
        np.testing.assert_allclose(p.convert_vector_space_to_body(v_r),
                                   v,
                                   atol=1E-10)
class TestLBPressureACF:
    """Tests that the thermalized LB pressure auto correlation function
    is consistent with the chosen viscosity
    """

    system = espressomd.System(box_l=[AGRID * N_CELLS] * 3)

    system.time_step = TAU
    system.cell_system.skin = 0

    def tearDown(self):
        self.system.actors.clear()
        self.system.thermostat.turn_off()

    def test(self):
        # setup
        system = self.system
        lb = self.lb_class(agrid=AGRID,
                           dens=DENS,
                           visc=VISC,
                           tau=TAU,
                           kT=KT,
                           seed=SEED)
        system.actors.add(lb)
        system.thermostat.set_lb(LB_fluid=lb, seed=2)

        # Warmup
        system.integrator.run(500)

        # sampling
        steps = 50000
        p_global = np.zeros((steps, 3, 3))
        p_node = np.zeros((steps, 3, 3))

        node = lb[0, 0, 0]

        for i in range(steps):
            p_node[i] = node.pressure_tensor
            p_global[i] = lb.pressure_tensor

            system.integrator.run(2)

        # Test that <sigma_[i!=j]> ~=0 and sigma_[ij]=sigma_[ji]
        tol_global = 4 / np.sqrt(steps)
        tol_node = tol_global * np.sqrt(N_CELLS**3)

        # check single node
        for i in range(3):
            for j in range(i + 1, 3):
                avg_ij = np.average(p_node[:, i, j])
                avg_ji = np.average(p_node[:, i, j])
                self.assertEqual(avg_ij, avg_ji)

                self.assertLess(avg_ij, tol_node)

        # check system-wide pressure
        for i in range(3):
            for j in range(i + 1, 3):
                avg_ij = np.average(p_global[:, i, j])
                avg_ji = np.average(p_global[:, i, j])
                self.assertEqual(avg_ij, avg_ji)

                self.assertLess(avg_ij, tol_global)

        # Check that stress auto correlatin matches dynamic viscosity
        # eta = V/kT integral(stress acf)
        all_viscs = []
        for i in range(3):
            for j in range(i + 1, 3):

                # Calculate acf
                tmp = np.correlate(p_global[:, i, j],
                                   p_global[:, i, j],
                                   mode="full")
                acf = tmp[len(tmp) // 2:] / steps

                # integrate first part numerically, fit exponential to tail
                t_max_fit = 50 * TAU
                ts = np.arange(0, t_max_fit, 2 * TAU)
                numeric_integral = np.trapz(acf[:len(ts)], dx=2 * TAU)

                # fit tail
                def f(x, a, b):
                    return a * np.exp(-b * x)

                (a, b), _ = curve_fit(f, acf[:len(ts)], ts)
                tail = f(ts[-1], a, b) / b

                integral = numeric_integral + tail

                measured_visc = integral * system.volume() / KT

                self.assertAlmostEqual(measured_visc,
                                       VISC * DENS,
                                       delta=VISC * DENS * .15)
                all_viscs.append(measured_visc)

        # Check average over xy, xz and yz against tighter limit
        self.assertAlmostEqual(np.average(all_viscs),
                               VISC * DENS,
                               delta=VISC * DENS * .07)
class ObservableTests(ut.TestCase):
    n_tries = 50
    n_parts = 5
    box_l = 5.
    system = espressomd.System(box_l=3 * [box_l])
    system.periodicity = [1, 1, 1]
    system.time_step = 0.01
    system.cell_system.skin = 0.2 * box_l

    def setUp(self):
        for i in range(self.n_parts):
            self.system.part.add(pos=[1 + i, 1 + i, 1 + i], id=i)
        self.partcls = self.system.part.all()

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

    def test_ParticleDistances(self):
        """
        Check ParticleDistances, for a particle pair and for a chain.
        """
        pids = list(range(self.n_parts))
        obs_single = espressomd.observables.ParticleDistances(ids=[0, 1])
        obs_chain = espressomd.observables.ParticleDistances(ids=pids)
        # take periodic boundaries into account: bond length cannot exceed
        # half the box size along the smallest axis
        min_dim = np.min(self.system.box_l)
        max_bond_length = min_dim / 2.01

        for _ in range(self.n_tries):
            # build polymer
            pos = np.zeros((self.n_parts, 3), dtype=float)
            pos[0] = np.random.uniform(low=0, high=min_dim, size=3)
            for i in range(1, self.n_parts):
                pos[i] = pos[i - 1] + np.random.uniform(
                    low=0, high=max_bond_length, size=3)
            self.partcls.pos = pos
            # expected values
            distances = np.linalg.norm(pos[1:] - pos[:-1], axis=1)
            # observed values
            self.system.integrator.run(0)
            res_obs_single = obs_single.calculate()
            res_obs_chain = obs_chain.calculate()
            # checks
            self.assertEqual(np.prod(res_obs_single.shape), 1)
            self.assertEqual(np.prod(res_obs_chain.shape), self.n_parts - 1)
            self.assertAlmostEqual(res_obs_single[0], distances[0], places=9)
            np.testing.assert_array_almost_equal(
                res_obs_chain, distances, decimal=9,
                err_msg="Data did not agree for observable ParticleDistances")

        # check exceptions
        for i in range(2):
            with self.assertRaises(RuntimeError):
                espressomd.observables.ParticleDistances(ids=np.arange(i))

    def test_BondAngles(self):
        """
        Check BondAngles, for a particle triple and for a chain.
        """
        pids = list(range(self.n_parts))
        obs_single = espressomd.observables.BondAngles(ids=[0, 1, 2])
        obs_chain = espressomd.observables.BondAngles(ids=pids)
        # take periodic boundaries into account: bond length cannot exceed
        # half the box size along the smallest axis
        min_dim = np.min(self.system.box_l)
        max_bond_length = min_dim / 2.01

        for _ in range(self.n_tries):
            # build polymer
            pos = np.zeros((self.n_parts, 3), dtype=float)
            pos[0] = np.random.uniform(low=0, high=min_dim, size=3)
            for i in range(1, self.n_parts):
                pos[i] = pos[i - 1] + np.random.uniform(
                    low=0, high=max_bond_length, size=3)
            self.partcls.pos = pos
            # expected values
            v1 = pos[:-2] - pos[1:-1]
            v2 = pos[2:] - pos[1:-1]
            l1 = np.linalg.norm(v1, axis=1)
            l2 = np.linalg.norm(v2, axis=1)
            angles = np.arccos((v1 * v2).sum(1) / l1 / l2)
            # observed values
            self.system.integrator.run(0)
            res_obs_single = obs_single.calculate()
            res_obs_chain = obs_chain.calculate()
            # checks
            self.assertEqual(np.prod(res_obs_single.shape), 1)
            self.assertEqual(np.prod(res_obs_chain.shape), self.n_parts - 2)
            self.assertAlmostEqual(res_obs_single[0], angles[0], places=9)
            np.testing.assert_array_almost_equal(
                res_obs_chain, angles, decimal=9,
                err_msg="Data did not agree for observable BondAngles")

        # check exceptions
        for i in range(3):
            with self.assertRaises(RuntimeError):
                espressomd.observables.BondAngles(ids=np.arange(i))

    def test_BondDihedrals(self):
        """
        Check BondDihedrals, for a particle quadruple and for a chain.
        """
        def rotate_vector(v, k, phi):
            """Rotates vector v around unit vector k by angle phi.
            Uses Rodrigues' rotation formula."""
            vrot = v * np.cos(phi) + np.cross(k, v) * \
                np.sin(phi) + k * np.dot(k, v) * (1.0 - np.cos(phi))
            return vrot

        def rotate_particle(p2, p3, p4, phi):
            """Rotates particle p4 around the axis formed by the bond
            between p2 and p3."""
            k = p3 - p2
            k /= np.linalg.norm(k)
            return p3 + rotate_vector(p4 - p3, k, phi)

        def calculate_dihedral(a, b, c, d):
            v1 = b - a
            v2 = c - b
            v3 = d - c
            b1 = np.cross(v1, v2)
            b2 = np.cross(v2, v3)
            u2 = v2 / np.linalg.norm(v2)
            return np.arctan2(np.dot(np.cross(b1, b2), u2), np.dot(b1, b2))

        def place_particles(bl, offset):
            """Place 5 particles in the XY plane with bond length `bl` and
            bond angle = 120 degrees. The chain is then shifted by `offset`."""
            phi = 2 * np.pi / 3
            pos = np.zeros((self.n_parts, 3), dtype=float)
            pos[0] = [bl * np.cos(phi), bl * np.sin(phi), 0.]
            pos[1] = [0., 0., 0.]
            pos[2] = [bl, 0., 0.]
            pos[3] = pos[2] + [bl * np.cos(np.pi - phi), bl * np.sin(phi), 0.]
            pos[4] = pos[3] + [bl, 0., 0.]
            pos += offset
            self.partcls.pos = pos
            return pos

        pids = list(range(self.n_parts))
        obs_single = espressomd.observables.BondDihedrals(ids=pids[:4])
        obs_chain = espressomd.observables.BondDihedrals(ids=pids)

        # test multiple angles, take periodic boundaries into account
        p0, p4 = self.system.part.by_ids([0, 4])
        for bond_length in [0.1, self.box_l / 2.0]:
            for offset in [1.0, self.box_l / 2.0]:
                for phi in np.arange(0, np.pi, np.pi / 6):
                    # place particles and keep list of unfolded positions
                    pos = place_particles(bond_length, 3 * [offset])
                    # rotate the 1st particle
                    p0.pos = pos[0] = rotate_particle(*pos[1:4, :][::-1],
                                                      phi=phi)
                    # rotate the 5th particle
                    p4.pos = pos[4] = rotate_particle(*pos[2:5, :], phi=phi)
                    # expected values
                    dih1 = calculate_dihedral(*pos[0:4, :][::-1])
                    dih2 = calculate_dihedral(*pos[1:5, :])
                    # observed values
                    self.system.integrator.run(0)
                    res_obs_single = obs_single.calculate()
                    res_obs_chain = obs_chain.calculate()
                    # checks
                    self.assertEqual(np.prod(res_obs_single.shape), 1)
                    self.assertEqual(
                        np.prod(res_obs_chain.shape),
                        self.n_parts - 3)
                    self.assertAlmostEqual(res_obs_single[0], dih1, places=9)
                    np.testing.assert_array_almost_equal(
                        res_obs_chain, [dih1, dih2], decimal=9,
                        err_msg="Data did not agree for observable BondDihedrals")

        # check exceptions
        for i in range(4):
            with self.assertRaises(RuntimeError):
                espressomd.observables.BondDihedrals(ids=np.arange(i))

    def test_CosPersistenceAngles(self):
        # First test: compare with python implementation
        self.system.part.clear()
        partcls = self.system.part.add(pos=np.array(
            [np.linspace(0, self.system.box_l[0], 20)] * 3).T + np.random.random((20, 3)))
        obs = espressomd.observables.CosPersistenceAngles(
            ids=partcls.id)
        np.testing.assert_allclose(
            obs.calculate(), cos_persistence_angles(partcls.pos))
        self.system.part.clear()
        # Second test: place particles with fixed angles and check that the
        # result of PersistenceAngle.calculate()[i] is i*phi
        delta_phi = np.radians(4)
        for i in range(10):
            pos = [np.cos(i * delta_phi), np.sin(i * delta_phi), 0.0]
            self.system.part.add(pos=pos)
        new_partcls = self.system.part.all()
        obs = espressomd.observables.CosPersistenceAngles(
            ids=new_partcls.id)
        expected = np.arange(1, 9) * delta_phi
        np.testing.assert_allclose(obs.calculate(), np.cos(expected))

        # check exceptions
        for i in range(3):
            with self.assertRaises(RuntimeError):
                espressomd.observables.CosPersistenceAngles(ids=np.arange(i))
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
"""
Set up a linear polymer.
"""
import espressomd
espressomd.assert_features(["WCA"])
from espressomd import interactions
from espressomd import polymer
from espressomd.io.writer import vtf  # pylint: disable=import-error
import numpy as np

# System parameters
#############################################################

system = espressomd.System(box_l=[100, 100, 100])
system.set_random_state_PRNG()
#system.seed = system.cell_system.get_state()['n_nodes'] * [1234]
np.random.seed(seed=system.seed)

system.time_step = 0.01
system.cell_system.skin = 0.4
system.cell_system.set_n_square(use_verlet_lists=False)
outfile = open('polymer.vtf', 'w')

system.non_bonded_inter[0, 0].wca.set_params(epsilon=1, sigma=1)

fene = interactions.FeneBond(k=10, d_r_max=2)
system.bonded_inter.add(fene)

positions = polymer.positions(n_polymers=1,