def test_mdlc(self): s = self.system rho = 0.3 # This is only for box size calculation. The actual particle number is # lower, because particles are removed from the mdlc gap region n_particle = 100 particle_radius = 0.5 box_l = np.cbrt(4 * n_particle * np.pi / (3 * rho)) * particle_radius s.box_l = 3 * [box_l] ref_E_path = tests_common.data_path("mdlc_reference_data_energy.dat") ref_E = float(np.genfromtxt(ref_E_path)) * DIPOLAR_PREFACTOR gap_size = 2.0 # Particles data = np.genfromtxt( tests_common.data_path("mdlc_reference_data_forces_torques.dat")) partcls = s.part.add(pos=data[:, 1:4], dip=data[:, 4:7]) partcls.rotation = 3 * [True] dp3m = espressomd.magnetostatics.DipolarP3M( prefactor=DIPOLAR_PREFACTOR, mesh=32, accuracy=1E-4) mdlc = espressomd.magnetostatics.DLC(maxPWerror=1E-5, gap_size=gap_size, actor=dp3m) s.actors.add(mdlc) s.integrator.run(0) err_f = self.vector_error(partcls.f, data[:, 7:10] * DIPOLAR_PREFACTOR) err_t = self.vector_error(partcls.torque_lab, data[:, 10:13] * DIPOLAR_PREFACTOR) err_e = s.analysis.energy()["dipolar"] - ref_E tol_f = 2E-3 tol_t = 2E-3 tol_e = 1E-3 self.assertLessEqual(abs(err_e), tol_e, "Energy difference too large") self.assertLessEqual(abs(err_t), tol_t, "Torque difference too large") self.assertLessEqual(abs(err_f), tol_f, "Force difference too large") # Check if error is thrown when particles enter the MDLC gap # positive direction p0 = s.part.by_id(0) p0.pos = [s.box_l[0] / 2, s.box_l[1] / 2, s.box_l[2] - gap_size / 2] with self.assertRaises(Exception): self.system.analysis.energy() with self.assertRaises(Exception): self.integrator.run(2) # negative direction p0.pos = [s.box_l[0] / 2, s.box_l[1] / 2, -gap_size / 2] with self.assertRaises(Exception): self.system.analysis.energy() with self.assertRaises(Exception): self.integrator.run(2)
def test_scafacos_dipoles(self): s = self.system rho = 0.09 # This is only for box size calculation. The actual particle number is # lower, because particles are removed from the mdlc gap region n_particle = 1000 particle_radius = 1 box_l = np.cbrt(4 * n_particle * np.pi / (3 * rho)) * particle_radius s.box_l = 3 * [box_l] # Particles data = np.genfromtxt( tests_common.data_path("p3m_magnetostatics_system.data")) partcls = s.part.add(pos=data[:, 1:4], dip=data[:, 4:7]) partcls.rotation = 3 * [True] scafacos = espressomd.magnetostatics.Scafacos( prefactor=DIPOLAR_PREFACTOR, method_name="p2nfft", method_params={ "p2nfft_verbose_tuning": 0, "pnfft_N": "32,32,32", "pnfft_n": "32,32,32", "pnfft_window_name": "bspline", "pnfft_m": "4", "p2nfft_ignore_tolerance": "1", "pnfft_diff_ik": "0", "p2nfft_r_cut": "11", "p2nfft_alpha": "0.31" }) s.actors.add(scafacos) s.integrator.run(0) expected = np.genfromtxt( tests_common.data_path("p3m_magnetostatics_expected.data"))[:, 1:] err_f = self.vector_error(partcls.f, expected[:, 0:3] * DIPOLAR_PREFACTOR) err_t = self.vector_error(partcls.torque_lab, expected[:, 3:6] * DIPOLAR_PREFACTOR) ref_E = 5.570 * DIPOLAR_PREFACTOR err_e = s.analysis.energy()["dipolar"] - ref_E tol_f = 2E-3 tol_t = 2E-3 tol_e = 1E-3 self.assertLessEqual(abs(err_e), tol_e, "Energy difference too large") self.assertLessEqual(abs(err_t), tol_t, "Torque difference too large") self.assertLessEqual(abs(err_f), tol_f, "Force difference too large")
def test_compressibility(self): system = self.system system.box_l = [5.86326165] * 3 data = np.genfromtxt(tests_common.data_path("npt_lj_system.data")) p_ext = 2.0 system.part.add(pos=data[:, :3], v=data[:, 3:]) system.non_bonded_inter[0, 0].lennard_jones.set_params(epsilon=1, sigma=1, cutoff=1.12246, shift=0.25) system.thermostat.set_npt(kT=1.0, gamma0=2, gammav=0.004, seed=42) system.integrator.set_isotropic_npt(ext_pressure=p_ext, piston=0.0001) system.integrator.run(800) avp = 0 n = 30000 skip_p = 8 ls = np.zeros(n) for t in range(n): system.integrator.run(2) if t % skip_p == 0: avp += system.analysis.pressure()['total'] ls[t] = system.box_l[0] avp /= (n / skip_p) Vs = np.array(ls)**3 compressibility = np.var(Vs) / np.average(Vs) self.assertAlmostEqual(avp, p_ext, delta=0.02) self.assertAlmostEqual(compressibility, 0.32, delta=0.02)
def test_02__direction(self): """Test for NpT constrained in one direction.""" data = np.genfromtxt(tests_common.data_path("npt_lj_system.data")) ref_box_l = 1.01 * np.max(data[:, 0:3]) system = self.system system.box_l = 3 * [ref_box_l] system.part.add(pos=data[:, 0:3], type=len(data) * [2]) system.non_bonded_inter[2, 2].wca.set_params(epsilon=1., sigma=1.) system.time_step = 0.01 for n in range(3): direction = np.roll([True, False, False], n) system.box_l = 3 * [ref_box_l] system.part.all().pos = data[:, 0:3] system.part.all().v = data[:, 3:6] system.thermostat.set_npt(kT=1.0, gamma0=2, gammav=0.004, seed=42) system.integrator.set_isotropic_npt(ext_pressure=2.0, piston=0.0001, direction=direction) system.integrator.run(20) box_l_rel = np.copy(system.box_l) / ref_box_l box_l_rel_ref = np.roll([np.max(box_l_rel), 1., 1.], n) np.testing.assert_allclose(box_l_rel, box_l_rel_ref, atol=1e-10) self.assertGreater(np.max(box_l_rel), 2)
def test_p3m(self): s = self.system rho = 0.09 # This is only for box size calculation. The actual particle number is # lower, because particles are removed from the mdlc gap region n_particle = 1000 particle_radius = 1 box_l = np.cbrt(4 * n_particle * np.pi / (3 * rho)) * particle_radius s.box_l = 3 * [box_l] # Particles data = np.genfromtxt( tests_common.data_path("p3m_magnetostatics_system.data")) partcls = s.part.add(pos=data[:, 1:4], dip=data[:, 4:7]) partcls.rotation = 3 * [True] dp3m = espressomd.magnetostatics.DipolarP3M( prefactor=DIPOLAR_PREFACTOR, mesh=32, accuracy=1E-6, epsilon="metallic") s.actors.add(dp3m) s.integrator.run(0) expected = np.genfromtxt( tests_common.data_path("p3m_magnetostatics_expected.data"))[:, 1:] err_f = self.vector_error(partcls.f, expected[:, 0:3] * DIPOLAR_PREFACTOR) err_t = self.vector_error(partcls.torque_lab, expected[:, 3:6] * DIPOLAR_PREFACTOR) ref_E = 5.570 * DIPOLAR_PREFACTOR err_e = s.analysis.energy()["dipolar"] - ref_E tol_f = 2E-3 tol_t = 2E-3 tol_e = 1E-3 self.assertLessEqual(abs(err_e), tol_e, "Energy difference too large") self.assertLessEqual(abs(err_t), tol_t, "Torque difference too large") self.assertLessEqual(abs(err_f), tol_f, "Force difference too large")
class LennardJonesTest(ut.TestCase): system = espressomd.System(box_l=[1.0, 1.0, 1.0]) data = np.loadtxt(tests_common.data_path('lj_system.dat')) pos = data[:, 1:4] forces = data[:, 4:7] def setUp(self): self.system.part.clear() self.system.box_l = [10.7437] * 3 lj_eps = 1.0 lj_sig = 1.0 lj_cut = 1.12246 self.system.non_bonded_inter[0, 0].lennard_jones.set_params( epsilon=lj_eps, sigma=lj_sig, cutoff=lj_cut, shift="auto") self.system.cell_system.skin = 0.4 self.system.time_step = .1 self.system.part.add(pos=self.pos) def check(self): all_partcls = self.system.part.all() f_diff = np.linalg.norm(all_partcls.f - self.forces, axis=1) max_deviation = np.max(np.abs(all_partcls.f - self.forces)) self.assertLess(np.mean(f_diff), 1e-7) self.assertLess(max_deviation, 1e-5) def test_dd(self): self.system.cell_system.set_regular_decomposition( use_verlet_lists=False) self.system.integrator.run(recalc_forces=True, steps=0) self.check() def test_dd_vl(self): self.system.cell_system.set_regular_decomposition( use_verlet_lists=True) # Build VL and calc ia self.system.integrator.run(recalc_forces=True, steps=0) self.check() # Calc is from VLs self.system.integrator.run(recalc_forces=True, steps=0) self.check()
def test_scafacos(self): system = self.system rho = 0.3 # This is only for box size calculation. The actual particle number is # lower, because particles are removed from the mdlc gap region n_particle = 100 particle_radius = 0.5 box_l = np.cbrt(4 * n_particle * np.pi / (3 * rho)) * particle_radius system.box_l = 3 * [box_l] for dim in (2, 1): with self.subTest(f"{dim} dimensions"): # Read reference data if dim == 2: file_prefix = "mdlc" system.periodicity = [1, 1, 0] else: system.periodicity = [1, 0, 0] file_prefix = "scafacos_dipoles_1d" ref_e_path = tests_common.data_path( f"{file_prefix}_reference_data_energy.dat") ref_e = float(np.genfromtxt(ref_e_path)) # Particles data = np.genfromtxt(tests_common.data_path( f"{file_prefix}_reference_data_forces_torques.dat")) system.part.add(pos=data[:, 1:4], dip=data[:, 4:7]) system.part.all().rotation = 3 * [True] if dim == 2: scafacos = espressomd.magnetostatics.Scafacos( prefactor=1., method_name="p2nfft", method_params={ "p2nfft_verbose_tuning": 0, "pnfft_N": "80,80,160", "pnfft_window_name": "bspline", "pnfft_m": "4", "p2nfft_ignore_tolerance": "1", "pnfft_diff_ik": "0", "p2nfft_r_cut": "6", "p2nfft_alpha": "0.8", "p2nfft_epsB": "0.05"}) # change box geometry in x,y direction to ensure that # scafacos survives it system.box_l = np.array([1., 1., 1.3]) * box_l else: # 1d periodic in x scafacos = espressomd.magnetostatics.Scafacos( prefactor=1., method_name="p2nfft", method_params={ "p2nfft_verbose_tuning": 1, "pnfft_N": "32,128,128", "pnfft_direct": 0, "p2nfft_r_cut": 2.855, "p2nfft_alpha": "1.5", "p2nfft_intpol_order": "-1", "p2nfft_reg_kernel_name": "ewald", "p2nfft_p": "16", "p2nfft_ignore_tolerance": "1", "pnfft_window_name": "bspline", "pnfft_m": "8", "pnfft_diff_ik": "1", "p2nfft_epsB": "0.125"}) system.box_l = np.array([1., 1., 1.]) * box_l system.actors.add(scafacos) system.integrator.run(0) fcs_f = np.copy(system.part.all().f) fcs_t = np.copy(system.part.all().torque_lab) fcs_e = system.analysis.energy()["dipolar"] ref_f = data[:, 7:10] ref_t = data[:, 10:13] tol_f = 1E-4 tol_t = 1E-3 tol_e = 1E-3 np.testing.assert_allclose(fcs_e, ref_e, atol=tol_e, err_msg="Energy doesn't match") np.testing.assert_allclose(fcs_t, ref_t, atol=tol_t, err_msg="Torques don't match") np.testing.assert_allclose(fcs_f, ref_f, atol=tol_f, err_msg="Forces don't match") system.part.clear() system.actors.clear()
def setUp(self): data = np.load(tests_common.data_path("coulomb_tuning_system.npz")) self.ref_forces = data['forces'] self.system.part.add(pos=data['pos'], q=data['charges'])
class CoulombMixedPeriodicity(ut.TestCase): """Test mixed periodicity electrostatics""" system = espressomd.System(box_l=[10., 10., 10.]) data = np.genfromtxt( tests_common.data_path("coulomb_mixed_periodicity_system.data")) # Reference energy from MMM2D ref_energy = 216.640984711 def setUp(self): self.system.box_l = [10., 10., 10.] self.system.time_step = 0.01 self.system.cell_system.skin = 0. # Add particles to system and store reference forces in hash # Input format: id pos q f self.system.part.add(pos=self.data[:, 1:4], q=self.data[:, 4]) self.ref_forces = self.data[:, 5:8] def tearDown(self): self.system.part.clear() self.system.actors.clear() def compare(self, method_name, force_tol, energy_tol): self.system.integrator.run(0) forces_step1 = np.copy(self.system.part.all().f) energy_step1 = self.system.analysis.energy()["total"] err_msg = f"difference too large for method {method_name}" np.testing.assert_allclose(forces_step1, self.ref_forces, atol=force_tol, err_msg=f"Force {err_msg}") np.testing.assert_allclose(energy_step1, self.ref_energy, atol=energy_tol, err_msg=f"Energy {err_msg}") # triggering a solver re-initialization via a box resize # should not affect the forces nor the energies original_box_l = np.copy(self.system.box_l) self.system.box_l = original_box_l * 1.1 self.system.box_l = original_box_l self.system.integrator.run(0) forces_step2 = np.copy(self.system.part.all().f) energy_step2 = self.system.analysis.energy()["total"] err_msg = f"method {method_name} deviates after cells reinitialization" np.testing.assert_allclose(forces_step1, forces_step2, atol=1e-12, err_msg=f"Force {err_msg}") np.testing.assert_allclose(energy_step2, energy_step1, rtol=1e-12, err_msg=f"Energy {err_msg}") def setup_elc_system(self): # Make sure, the data satisfies the gap for p in self.system.part: assert p.pos[2] >= 0. and p.pos[2] <= 9., f'particle {p.id} in gap' self.system.cell_system.set_regular_decomposition() self.system.cell_system.node_grid = sorted( self.system.cell_system.node_grid, key=lambda x: -x) self.system.periodicity = [1, 1, 1] @utx.skipIfMissingFeatures(["P3M"]) def test_elc_cpu(self): self.system.box_l = [10., 10., 12.] self.setup_elc_system() p3m = espressomd.electrostatics.P3M(prefactor=1., accuracy=1e-6, mesh=[42, 42, 50], r_cut=3.5) elc = espressomd.electrostatics.ELC(actor=p3m, maxPWerror=1E-6, gap_size=3) self.system.actors.add(elc) self.compare("elc", force_tol=1e-5, energy_tol=1e-4) @utx.skipIfMissingGPU() @utx.skipIfMissingFeatures(["P3M"]) def test_elc_gpu(self): self.system.box_l = [10., 10., 12.] self.setup_elc_system() p3m = espressomd.electrostatics.P3M(prefactor=1., accuracy=1e-6, mesh=[42, 42, 50], r_cut=3.5) elc = espressomd.electrostatics.ELC(actor=p3m, maxPWerror=1E-6, gap_size=3.) self.system.actors.add(elc) self.compare("elc", force_tol=1e-5, energy_tol=1e-4) @utx.skipIfMissingFeatures(["SCAFACOS"]) @utx.skipIfMissingScafacosMethod("p2nfft") def test_scafacos_p2nfft(self): self.system.box_l = [10., 10., 10.] self.system.periodicity = [1, 1, 0] self.system.cell_system.set_regular_decomposition() scafacos = espressomd.electrostatics.Scafacos(prefactor=1, method_name="p2nfft", method_params={ "tolerance_field": 5E-5, "pnfft_n": "96,96,128", "pnfft_N": "96,96,128", "r_cut": 2.4, "pnfft_m": 3 }) self.system.actors.add(scafacos) self.assertTrue(scafacos.call_method("get_near_field_delegation")) self.compare("scafacos_p2nfft", force_tol=1e-4, energy_tol=1.8e-3) # calculating near field in ScaFaCoS should yield the same result scafacos.call_method("set_near_field_delegation", delegate=False) self.assertFalse(scafacos.call_method("get_near_field_delegation")) self.compare("scafacos_p2nfft", force_tol=1e-4, energy_tol=1.8e-3)
def test(self): import object_in_fluid as oif system = espressomd.System(box_l=(10, 10, 10)) self.assertEqual(system.max_oif_objects, 0) system.time_step = 0.4 system.cell_system.skin = 0.5 # creating the template for OIF object cell_type = oif.OifCellType( nodes_file=str(tests_common.data_path("sphere393nodes.dat")), triangles_file=str( tests_common.data_path("sphere393triangles.dat")), system=system, ks=1.0, kb=1.0, kal=1.0, kag=0.1, kv=0.1, check_orientation=False, resize=(3.0, 3.0, 3.0)) # creating the OIF object cell0 = oif.OifCell(cell_type=cell_type, particle_type=0, origin=[5.0, 5.0, 5.0]) self.assertEqual(system.max_oif_objects, 1) partcls = system.part.all() # fluid diameter_init = cell0.diameter() print(f"initial diameter = {diameter_init}") # OIF object is being stretched by factor 1.5 partcls.pos = (partcls.pos - 5) * 1.5 + 5 diameter_stretched = cell0.diameter() print(f"stretched diameter = {diameter_stretched}") # Apply non-isotropic deformation partcls.pos = partcls.pos * np.array((0.96, 1.05, 1.02)) # Test that restoring forces net to zero and don't produce a torque system.integrator.run(1) total_force = np.sum(partcls.f, axis=0) np.testing.assert_allclose(total_force, [0., 0., 0.], atol=1E-12) total_torque = np.zeros(3) for p in system.part: total_torque += np.cross(p.pos, p.f) np.testing.assert_allclose(total_torque, [0., 0., 0.], atol=2E-12) # main integration loop system.thermostat.set_langevin(kT=0, gamma=0.7, seed=42) # OIF object is let to relax into relaxed shape of the sphere for _ in range(2): system.integrator.run(steps=240) diameter_final = cell0.diameter() print(f"final diameter = {diameter_final}") self.assertAlmostEqual(diameter_final / diameter_init - 1, 0, delta=0.005)
class StokesianDynamicsTest(ut.TestCase): system = s # Digitized reference data of Figure 5b from # Durlofsky et al., J. Fluid Mech. 180, 21 (1987) # https://doi.org/10.1017/S002211208700171X data = np.loadtxt(tests_common.data_path('dancing.txt')) def setUp(self): self.system.box_l = [10] * 3 self.system.periodicity = [0, 0, 0] self.system.cell_system.skin = 0.4 def tearDown(self): self.system.constraints.clear() self.system.part.clear() def falling_spheres(self, time_step, l_factor, t_factor, sd_method='fts'): self.system.time_step = time_step self.system.part.add(pos=[-5 * l_factor, 0, 0], rotation=[1, 1, 1]) self.system.part.add(pos=[0 * l_factor, 0, 0], rotation=[1, 1, 1]) self.system.part.add(pos=[7 * l_factor, 0, 0], rotation=[1, 1, 1]) self.system.integrator.set_stokesian_dynamics( viscosity=1.0 / (t_factor * l_factor), radii={0: 1.0 * l_factor}, approximation_method=sd_method) gravity = espressomd.constraints.Gravity( g=[0, -1.0 * l_factor / (t_factor**2), 0]) self.system.constraints.add(gravity) self.system.time_step = 1.0 * t_factor obs = espressomd.observables.ParticlePositions(ids=(0, 1, 2)) acc = espressomd.accumulators.TimeSeries(obs=obs, delta_N=1) self.system.auto_update_accumulators.add(acc) acc.update() if sd_method == 'fts': y_min = -555 intsteps = 8000 else: y_min = -200 intsteps = 3000 intsteps = int(intsteps * t_factor / self.system.time_step) self.system.integrator.run(intsteps) simul = acc.time_series()[:, :, 0:2] paper = self.data.reshape([-1, 3, 2]) for pid in range(3): dist = [] # the simulated trajectory is oversampled by a ratio of # (90/t_factor):1 compared to the published trajectory for desired in paper[:, pid] * l_factor: if desired[1] < y_min * l_factor: break # find the closest point in the simulated trajectory idx = np.abs(simul[:, pid, 1] - desired[1]).argmin() actual = simul[idx, pid] dist.append(np.linalg.norm(actual - desired)) self.assertLess(idx, intsteps, msg='Insufficient sampling') np.testing.assert_allclose(dist, 0, rtol=0, atol=0.5 * l_factor) def test_default(self): self.falling_spheres(1.0, 1.0, 1.0) def test_rescaled(self): self.falling_spheres(1.0, 4.5, 2.5) def test_different_time_step(self): self.falling_spheres(0.7, 1.0, 1.0) def test_default_ft(self): self.falling_spheres(1.0, 1.0, 1.0, 'ft')
class CoulombCloudWall(ut.TestCase): """This compares p3m, p3m_gpu electrostatic forces and energy against stored data.""" system = espressomd.System(box_l=[10., 10., 20.]) system.time_step = 0.01 system.cell_system.skin = 0.4 data = np.genfromtxt( tests_common.data_path("coulomb_cloud_wall_duplicated_system.data")) tolerance = 1E-3 p3m_params = { 'prefactor': 1., 'r_cut': 1.001, 'accuracy': 1e-3, 'mesh': [64, 64, 128], 'mesh_off': [0.5, 0.5, 0.5], 'cao': 7, 'alpha': 2.70746 } # Reference energy from p3m in the tcl test case reference_energy = 2. * 148.94229549 def setUp(self): # Add particles to system and store reference forces in hash # Input format: id pos q f self.system.part.add(pos=self.data[:, 1:4], q=self.data[:, 4]) self.forces = self.data[:, 5:8] def tearDown(self): self.system.part.clear() self.system.actors.clear() def compare(self, method_name, energy=True): # Compare forces and energy now in the system to stored ones # Force force_diff = np.linalg.norm(self.system.part.all().f - self.forces, axis=1) self.assertLess(np.mean(force_diff), self.tolerance, msg="Absolute force difference too large for method " + method_name) # Energy if energy: self.assertAlmostEqual( self.system.analysis.energy()["total"], self.reference_energy, delta=self.tolerance, msg="Absolute energy difference too large for " + method_name) # Tests for individual methods @utx.skipIfMissingFeatures("P3M") def test_p3m(self): self.system.actors.add( espressomd.electrostatics.P3M(**self.p3m_params, tune=False)) self.system.integrator.run(0) self.compare("p3m", energy=True) @utx.skipIfMissingGPU() def test_p3m_gpu(self): self.system.actors.add( espressomd.electrostatics.P3MGPU(**self.p3m_params, tune=False)) self.system.integrator.run(0) self.compare("p3m_gpu", energy=False) def test_zz_deactivation(self): # The energy is 0 if no method is active self.assertEqual(self.system.analysis.energy()["total"], 0.0)
class CoulombCloudWall(ut.TestCase): """ Compare P3M CPU, P3M GPU and ScaFaCoS P2NFFT electrostatic forces and energy against stored data. """ system = espressomd.System(box_l=[10., 10., 10.]) data = np.genfromtxt( tests_common.data_path("coulomb_cloud_wall_system.data")) tolerance = 1E-3 p3m_params = { 'r_cut': 1.001, 'accuracy': 1e-3, 'mesh': [64, 64, 64], 'cao': 7, 'alpha': 2.70746 } # Reference energy from P3M reference_energy = 148.94229549 def setUp(self): self.system.time_step = 0.01 self.system.cell_system.skin = 0.4 # Add particles to system and store reference forces in hash # Input format: id pos q f self.system.part.add(pos=self.data[:, 1:4], q=self.data[:, 4]) self.reference_forces = self.data[:, 5:8] def tearDown(self): self.system.part.clear() self.system.actors.clear() def compare(self, method_name, prefactor, force_tol, energy_tol): # Compare forces and energy now in the system to reference data err_msg = f"difference too large for method {method_name}" # Force np.testing.assert_allclose(np.copy(self.system.part.all().f) / prefactor, self.reference_forces, atol=force_tol, err_msg=f"Force {err_msg}") # Energy self.assertAlmostEqual(self.system.analysis.energy()["total"] / prefactor, self.reference_energy, delta=energy_tol, msg=f"Energy {err_msg}") @utx.skipIfMissingFeatures(["P3M"]) def test_p3m_cpu(self): self.system.actors.add( espressomd.electrostatics.P3M(**self.p3m_params, prefactor=3., tune=False)) self.system.integrator.run(0) self.compare("p3m", prefactor=3., force_tol=2e-3, energy_tol=1e-3) @utx.skipIfMissingGPU() @utx.skipIfMissingFeatures(["P3M"]) def test_p3m_gpu(self): self.system.actors.add( espressomd.electrostatics.P3MGPU(**self.p3m_params, prefactor=2.2, tune=False)) self.system.integrator.run(0) self.compare("p3m_gpu", prefactor=2.2, force_tol=2e-3, energy_tol=1e-3) @utx.skipIfMissingFeatures(["SCAFACOS"]) @utx.skipIfMissingScafacosMethod("p2nfft") def test_scafacos_p2nfft(self): self.system.actors.add( espressomd.electrostatics.Scafacos(prefactor=2.8, method_name="p2nfft", method_params={ "p2nfft_r_cut": 1.001, "tolerance_field": 1E-4 })) self.system.integrator.run(0) self.compare("scafacos_p2nfft", prefactor=2.8, force_tol=1e-3, energy_tol=1e-3) def test_zz_deactivation(self): # Is the energy and force 0, if no methods active self.assertEqual(self.system.analysis.energy()["total"], 0.0) self.system.integrator.run(0, recalc_forces=True) for p in self.system.part: self.assertAlmostEqual(np.linalg.norm(p.f), 0, places=11)
class ElectrostaticInteractionsTests: # Handle to espresso system system = espressomd.System(box_l=[10.0] * 3) system.periodicity = [0, 0, 1] system.time_step = 0.01 system.cell_system.skin = 0.4 system.cell_system.set_n_square() system.thermostat.set_langevin(kT=0, gamma=1, seed=8) data = np.loadtxt(tests_common.data_path("mmm1d_data.txt")) p_pos = data[:, 1:4] p_q = data[:, 4] forces_target = data[:, 5:8] energy_target = -7.156365298205383 def setUp(self): self.system.box_l = [10.0] * 3 self.system.periodicity = [0, 0, 1] self.system.cell_system.set_n_square() def tearDown(self): self.system.part.clear() self.system.actors.clear() def test_forces_and_energy(self): self.system.part.add(pos=self.p_pos, q=self.p_q) mmm1d = self.MMM1D(prefactor=1.0, maxPWerror=1e-20) self.system.actors.add(mmm1d) self.system.integrator.run(steps=0) measured_f = np.copy(self.system.part.all().f) np.testing.assert_allclose(measured_f, self.forces_target, atol=self.allowed_error) measured_el_energy = self.system.analysis.energy()["coulomb"] self.assertAlmostEqual( measured_el_energy, self.energy_target, delta=self.allowed_error, msg="Measured energy deviates too much from stored result") def check_with_analytical_result(self, prefactor, accuracy): p = self.system.part.by_id(0) f_measured = p.f energy_measured = self.system.analysis.energy()["total"] target_energy_config = -1.00242505606 * prefactor target_force_z_config = 0.99510759 * prefactor self.assertAlmostEqual( f_measured[0], 0, delta=self.allowed_error, msg="Measured force in x deviates too much from analytical result") self.assertAlmostEqual( f_measured[1], 0, delta=self.allowed_error, msg="Measured force in y deviates too much from analytical result") self.assertAlmostEqual( f_measured[2], target_force_z_config, delta=accuracy, msg="Measured force in z deviates too much from analytical result") self.assertAlmostEqual( energy_measured, target_energy_config, delta=self.allowed_error, msg="Measured energy deviates too much from analytical result") def test_with_analytical_result(self): self.system.part.add(pos=[0, 0, 0], q=1) self.system.part.add(pos=[0, 0, 1], q=-1) mmm1d = self.MMM1D(prefactor=1.0, maxPWerror=1e-20) self.system.actors.add(mmm1d) self.assertTrue(mmm1d.is_tuned) self.system.integrator.run(steps=0, recalc_forces=True) self.check_with_analytical_result(prefactor=1.0, accuracy=0.0004) def test_bjerrum_length_change(self): self.system.part.add(pos=[0, 0, 0], q=1) self.system.part.add(pos=[0, 0, 1], q=-1) mmm1d = self.MMM1D(prefactor=2.0, maxPWerror=1e-20) self.system.actors.add(mmm1d) self.assertTrue(mmm1d.is_tuned) self.system.integrator.run(steps=0, recalc_forces=True) self.check_with_analytical_result(prefactor=2.0, accuracy=0.0017) # actor should remain in a valid state after a cell system reset forces1 = np.copy(self.system.part.all().f) self.system.box_l = self.system.box_l self.system.periodicity = self.system.periodicity self.system.cell_system.node_grid = self.system.cell_system.node_grid self.system.integrator.run(steps=0, recalc_forces=True) forces2 = np.copy(self.system.part.all().f) np.testing.assert_allclose(forces1, forces2, atol=1e-12, rtol=0.) def test_infinite_wire(self): """ For an infinite wire, the energy per ion is :math:`MC\\frac{q}{a}` with :math:`M = - \\ln{2}` the 1D Madelung constant, :math:`C` the electrostatics prefactor, :math:`q` the ion charge and :math:`a` the lattice constant. Likewise, the pressure for one ion can be derived as :math:`MC\\frac{q}{aV}` with :math:`V` the simulation box volume. For more details, see Orion Ciftja, "Equivalence of an infinite one-dimensional ionic crystal to a simple electrostatic model", Results in Physics, Volume 13, 2019, 102325, doi:10.1016/j.rinp.2019.102325 """ n_pairs = 128 n_part = 2 * n_pairs self.system.box_l = 3 * [n_part] for i in range(n_pairs): self.system.part.add(pos=[0., 0., 2. * i + 0.], q=+1.) self.system.part.add(pos=[0., 0., 2. * i + 1.], q=-1.) self.system.actors.add( self.MMM1D(prefactor=1., maxPWerror=1e-20, far_switch_radius=n_pairs / 2.)) energy = self.system.analysis.energy()["coulomb"] p_scalar = self.system.analysis.pressure()["coulomb"] p_tensor = self.system.analysis.pressure_tensor()["coulomb"] ref_energy = -np.log(2.) np.testing.assert_allclose(energy / n_part, ref_energy, atol=0., rtol=5e-7) np.testing.assert_allclose(p_scalar, 0., atol=1e-12) np.testing.assert_allclose(p_tensor, 0., atol=1e-12)
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # import espressomd import espressomd.magnetostatics import pathlib import numpy as np import unittest as ut import unittest_decorators as utx import tests_common OPEN_BOUNDARIES_REF_ENERGY = tests_common.data_path( "dipolar_open_boundaries_energy.npy") OPEN_BOUNDARIES_REF_ARRAYS = tests_common.data_path( "dipolar_open_boundaries_arrays.npy") @utx.skipIfMissingFeatures(["DIPOLES"]) class dds(ut.TestCase): system = espressomd.System(box_l=[3, 3, 3]) system.time_step = 0.01 system.cell_system.skin = 0.1 system.periodicity = [False, False, False] def tearDown(self): self.system.part.clear()