Пример #1
0
    def test_sparse(self):
        """Tests the sparse matrix creation.
        """
        # Dense
        desc = EwaldMatrix(n_atoms_max=5, permutation="none", flatten=True, sparse=False)
        vec = desc.create(H2O)
        self.assertTrue(type(vec) == np.ndarray)

        # Sparse
        desc = EwaldMatrix(n_atoms_max=5, permutation="none", flatten=True, sparse=True)
        vec = desc.create(H2O)
        self.assertTrue(type(vec) == scipy.sparse.coo_matrix)
Пример #2
0
    def test_flatten(self):
        """Tests the flattening.
        """
        # Unflattened
        desc = EwaldMatrix(n_atoms_max=5, permutation="none", flatten=False)
        matrix = desc.create(H2O)
        self.assertEqual(matrix.shape, (5, 5))

        # Flattened
        desc = EwaldMatrix(n_atoms_max=5, permutation="none", flatten=True)
        matrix = desc.create(H2O)
        self.assertEqual(matrix.shape, (25,))
Пример #3
0
    def test_electrostatics(self):
        """Tests that the results are consistent with the electrostatic
        interpretation. Each matrix [i, j] element should correspond to the
        Coulomb energy of a system consisting of the pair of atoms i, j.
        """
        system = H2O
        n_atoms = len(system)
        a = 0.5
        desc = EwaldMatrix(n_atoms_max=3, permutation="none", flatten=False)

        # The Ewald matrix contains the electrostatic interaction between atoms
        # i and j. Here we construct the total electrostatic energy for a
        # system consisting of atoms i and j.
        matrix = desc.create(system, a=a, rcut=rcut, gcut=gcut)
        energy_matrix = np.zeros(matrix.shape)
        for i in range(n_atoms):
            for j in range(n_atoms):
                if i == j:
                    energy_matrix[i, j] = matrix[i, j]
                else:
                    energy_matrix[i, j] = matrix[i, j] + matrix[i, i] + matrix[j, j]

        # Converts unit of q*q/r into eV
        conversion = 1e10 * scipy.constants.e / (4 * math.pi * scipy.constants.epsilon_0)
        energy_matrix *= conversion

        # The value in each matrix element should correspond to the Coulomb
        # energy of a system with with only those atoms. Here the energies from
        # the Ewald matrix are compared against the Ewald energy calculated
        # with pymatgen.
        positions = system.get_positions()
        atomic_num = system.get_atomic_numbers()
        for i in range(n_atoms):
            for j in range(n_atoms):
                if i == j:
                    pos = [positions[i]]
                    sym = [atomic_num[i]]
                else:
                    pos = [positions[i], positions[j]]
                    sym = [atomic_num[i], atomic_num[j]]

                i_sys = Atoms(
                    cell=system.get_cell(),
                    positions=pos,
                    symbols=sym,
                    pbc=True,
                )

                structure = Structure(
                    lattice=i_sys.get_cell(),
                    species=i_sys.get_atomic_numbers(),
                    coords=i_sys.get_scaled_positions(),
                )
                structure.add_oxidation_state_by_site(i_sys.get_atomic_numbers())
                ewald = EwaldSummation(structure, eta=a, real_space_cut=rcut, recip_space_cut=gcut)
                energy = ewald.total_energy

                # Check that the energy given by the pymatgen implementation is
                # the same as given by the descriptor
                self.assertTrue(np.allclose(energy_matrix[i, j], energy, atol=0.00001, rtol=0))
Пример #4
0
    def test_unit_cells(self):
        """Tests if arbitrary unit cells are accepted
        """
        desc = EwaldMatrix(n_atoms_max=3, permutation="none", flatten=False)
        molecule = H2O.copy()

        # A system without cell should produce an error
        molecule.set_cell([
            [0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0]
        ])
        with self.assertRaises(ValueError):
            nocell = desc.create(molecule,  a=0.5, rcut=rcut, gcut=gcut)

        # Large cell
        molecule.set_pbc(True)
        molecule.set_cell([
            [20.0, 0.0, 0.0],
            [0.0, 30.0, 0.0],
            [0.0, 0.0, 40.0]
        ])
        largecell = desc.create(molecule,  a=0.5, rcut=rcut, gcut=gcut)

        # Cubic cell
        molecule.set_cell([
            [2.0, 0.0, 0.0],
            [0.0, 2.0, 0.0],
            [0.0, 0.0, 2.0]
        ])
        cubic_cell = desc.create(molecule,  a=0.5, rcut=rcut, gcut=gcut)

        # Triclinic cell
        molecule.set_cell([
            [0.0, 2.0, 2.0],
            [2.0, 0.0, 2.0],
            [2.0, 2.0, 0.0]
        ])
        triclinic_smallcell = desc.create(molecule,  a=0.5, rcut=rcut, gcut=gcut)
Пример #5
0
    def test_create(self):
        """Tests different valid and invalid create values.
        """
        with self.assertRaises(ValueError):
            desc = EwaldMatrix(n_atoms_max=5)
            desc.create(H2O, rcut=10)
        with self.assertRaises(ValueError):
            desc = EwaldMatrix(n_atoms_max=5)
            desc.create(H2O, gcut=10)

        # Providing a only is valid
        desc = EwaldMatrix(n_atoms_max=5)
        desc.create(H2O, a=0.5)

        # Providing no parameters is valid
        desc = EwaldMatrix(n_atoms_max=5)
        desc.create(H2O)
Пример #6
0
    def test_a_independence(self):
        """Tests that the matrix elements are independent of the screening
        parameter 'a' used in the Ewald summation. Notice that the real space
        cutoff and reciprocal space cutoff have to be sufficiently large for
        this to be true, as 'a' controls the width of the Gaussian charge
        distribution.
        """
        rcut = 40
        gcut = 30
        prev_array = None
        for i, a in enumerate([0.1, 0.5, 1, 2, 3]):
            desc = EwaldMatrix(n_atoms_max=5, permutation="none", flatten=False)
            matrix = desc.create(H2O, a=a, rcut=rcut, gcut=gcut)

            if i > 0:
                self.assertTrue(np.allclose(prev_array, matrix, atol=0.001, rtol=0))
            prev_array = matrix
Пример #7
0
 def create(system):
     desc = EwaldMatrix(n_atoms_max=3, permutation="sorted_l2", flatten=True)
     return desc.create(system)