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")
예제 #3
0
    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)
예제 #4
0
    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")
예제 #6
0
파일: lj.py 프로젝트: espressomd/espresso
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()
예제 #7
0
    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()
예제 #8
0
 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)
예제 #10
0
    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)
예제 #11
0
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')
예제 #12
0
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)
예제 #13
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)
예제 #14
0
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)
예제 #15
0
# 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()