예제 #1
0
 def test_constructor(self):
     """Tests different valid and invalid constructor values.
     """
     with self.assertRaises(ValueError):
         EwaldSumMatrix(n_atoms_max=5, permutation="unknown")
     with self.assertRaises(ValueError):
         EwaldSumMatrix(n_atoms_max=-1)
예제 #2
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 = EwaldSumMatrix(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))
예제 #3
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 = EwaldSumMatrix(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
예제 #4
0
    def test_unit_cells(self):
        """Tests if arbitrary unit cells are accepted"""
        desc = EwaldSumMatrix(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_flatten(self):
        """Tests the flattening."""
        # Unflattened
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=False)
        matrix = desc.create(H2O)
        self.assertEqual(matrix.shape, (5, 5))

        # Flattened
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=True)
        matrix = desc.create(H2O)
        self.assertEqual(matrix.shape, (25, ))
예제 #6
0
 def test_exceptions(self):
     """Tests different invalid parameters that should raise an
     exception.
     """
     with self.assertRaises(ValueError):
         EwaldSumMatrix(n_atoms_max=5, permutation="unknown")
     with self.assertRaises(ValueError):
         EwaldSumMatrix(n_atoms_max=-1)
     with self.assertRaises(ValueError):
         em = EwaldSumMatrix(n_atoms_max=2)
         em.create([HHe, H2O])
예제 #7
0
    def test_sparse(self):
        """Tests the sparse matrix creation.
        """
        # Dense
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=True, sparse=False)
        vec = desc.create(H2O)
        self.assertTrue(type(vec) == np.ndarray)

        # Sparse
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=True, sparse=True)
        vec = desc.create(H2O)
        self.assertTrue(type(vec) == scipy.sparse.coo_matrix)
예제 #8
0
    def test_parallel_dense(self):
        """Tests creating dense output parallelly.
        """
        samples = [bulk("NaCl", "rocksalt", a=5.64), bulk('Cu', 'fcc', a=3.6)]
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=True, sparse=False)
        n_features = desc.get_number_of_features()

        # Test multiple systems, serial job
        output = desc.create(
            system=samples,
            n_jobs=1,
        )
        assumed = np.empty((2, n_features))
        assumed[0, :] = desc.create(samples[0])
        assumed[1, :] = desc.create(samples[1])
        self.assertTrue(np.allclose(output, assumed))

        # Test multiple systems, parallel job
        output = desc.create(
            system=samples,
            n_jobs=2,
        )
        assumed = np.empty((2, n_features))
        assumed[0, :] = desc.create(samples[0])
        assumed[1, :] = desc.create(samples[1])
        self.assertTrue(np.allclose(output, assumed))

        # Non-flattened output
        desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=False, sparse=False)
        output = desc.create(
            system=samples,
            n_jobs=2,
        )
        assumed = np.empty((2, 5, 5))
        assumed[0] = desc.create(samples[0])
        assumed[1] = desc.create(samples[1])
        self.assertTrue(np.allclose(np.array(output), assumed))
예제 #9
0
 def test_number_of_features(self):
     """Tests that the reported number of features is correct.
     """
     desc = EwaldSumMatrix(n_atoms_max=5, permutation="none", flatten=False)
     n_features = desc.get_number_of_features()
     self.assertEqual(n_features, 25)
예제 #10
0
    def test_create(self):
        """Tests different valid and invalid create values.
        """
        with self.assertRaises(ValueError):
            desc = EwaldSumMatrix(n_atoms_max=5)
            desc.create(H2O, rcut=10)
        with self.assertRaises(ValueError):
            desc = EwaldSumMatrix(n_atoms_max=5)
            desc.create(H2O, gcut=10)

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

        # Providing no parameters is valid
        desc = EwaldSumMatrix(n_atoms_max=5)
        desc.create(H2O)
예제 #11
0
 def create(system):
     desc = EwaldSumMatrix(n_atoms_max=3, permutation="sorted_l2", flatten=True)
     return desc.create(system)
예제 #12
0
import math
import scipy

from pymatgen.analysis.ewald import EwaldSummation
from pymatgen.core.structure import Structure

from dscribe.descriptors import EwaldSumMatrix

atomic_numbers = [1, 8]
rcut = 6.0
nmax = 8
lmax = 6

# Setting up the Ewald sum matrix descriptor
esm = EwaldSumMatrix(n_atoms_max=6, )

# Creation
from ase.build import bulk

# NaCl crystal created as an ASE.Atoms
nacl = bulk("NaCl", "rocksalt", a=5.64)

# Create output for the system
nacl_ewald = esm.create(nacl)

# Create output for multiple system
al = bulk("Al", "fcc", a=4.046)
fe = bulk("Fe", "bcc", a=2.856)
samples = [nacl, al, fe]
ewald_matrices = esm.create(samples)  # Serial
ewald_matrices = esm.create(samples, n_jobs=2)  # Parallel