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+
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)
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)
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))
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]
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,