Ejemplo n.º 1
0
    def convert_units(self, new_units):
        r"""
        Converts the atomic positions in another units.

        Parameters
        ----------
        new_units: str
            The new units in which the positions should be converted.
            Can either be "angstrom" or "atomic".
        """
        if new_units not in ["angstrom", "atomic"]:
            raise ValueError("New units are not recognized.")
        if self.units == new_units:
            pass
        elif self.units == "atomic" and new_units == "angstrom":
            for atom in self:
                atom.position = atom.position * B_TO_ANG
            self.cell = Cell.new(self.cell * B_TO_ANG)
        elif self.units == "angstrom" and new_units == "atomic":
            for atom in self:
                atom.position = atom.position * ANG_TO_B
            self.cell = Cell.new(self.cell * ANG_TO_B)
        elif self.units == "reduced" and new_units == "atomic":
            for atom in self:
                atom.position = np.sum(atom.position * self.cell, axis=0)
        elif self.units == "reduced" and new_units == "angstrom":
            for atom in self:
                atom.position = np.sum(atom.position * self.cell * B_TO_ANG,
                                       axis=0)
            self.cell = Cell.new(self.cell * B_TO_ANG)
        else:
            raise NotImplementedError
        self.units = new_units
Ejemplo n.º 2
0
 def cell(self, cell):
     if len(cell) == 2:
         cell, angles = cell
     else:
         angles = None
     if isinstance(cell, Cell):
         self._cell = cell
     elif cell is None:
         self._cell = Cell.new()
     elif isinstance(cell, list) or isinstance(cell, np.ndarray):
         if isinstance(cell, list):
             cell = np.array([
                 abs(float(size)) if size not in [".inf", "inf"] else 0.0
                 for size in cell
             ])
         if cell.size == 3 and angles is not None:
             if len(angles) == 3:
                 cell = np.concatenate([cell, angles])
             else:
                 raise ValueError("Need three angles to define a cell.")
         if cell.size in [3, 6, 9]:
             self._cell = Cell.new(cell)
         else:
             raise ValueError(
                 "Cell definition is not valid. See ase.cell.Cell documentation."
             )
     else:
         raise ValueError(
             "Cell definition is not valid. See ase.cell.Cell documentation."
         )
Ejemplo n.º 3
0
def test_line_lattice():
    from ase.cell import Cell
    kx = Cell.new([5, 0, 0]).bandpath(path='GX', npoints=2).kpts
    kz = Cell.new([0, 0, 5]).bandpath(path='GX', npoints=2).kpts
    print(kx)
    print(kz)
    kx[1, 0] -= 0.5
    kz[1, 2] -= 0.5
    assert abs(kx).max() == 0.0
    assert abs(kz).max() == 0.0
def test_bandstructure_transform_mcl(testdir):
    # Test that bandpath() correctly transforms the band path from
    # reference (canonical) cell to actual cell provided by user.

    def _atoms(cell):
        atoms = Atoms(cell=cell, pbc=True)
        atoms.calc = FreeElectrons()
        return atoms

    # MCL with beta > 90, which is a common convention -- but ours is
    # alpha < 90.  We want the bandpath returned by that cell to yield the
    # exact same band structure as our own (alpha < 90) version of the
    # same cell.
    cell = Cell.new([3., 5., 4., 90., 110., 90.])
    lat = cell.get_bravais_lattice()

    density = 10.0
    cell0 = lat.tocell()
    path0 = lat.bandpath(density=density)

    print(cell.cellpar().round(3))
    print(cell0.cellpar().round(3))

    with workdir('files', mkdir=True):
        bs = calculate_band_structure(_atoms(cell),
                                      cell.bandpath(density=density))
        bs.write('bs.json')
        # bs.plot(emin=0, emax=20, filename='fig.bs.svg')

        bs0 = calculate_band_structure(_atoms(cell0), path0)
        bs0.write('bs0.json')
        # bs0.plot(emin=0, emax=20, filename='fig.bs0.svg')

    maxerr = np.abs(bs.energies - bs0.energies).max()
    assert maxerr < 1e-12, maxerr
Ejemplo n.º 5
0
    def _variant_name(self, a, b, c, alpha, beta, gamma):
        cell = Cell.new([a, b, c, alpha, beta, gamma])
        icellpar = Cell(cell.reciprocal()).cellpar()
        kangles = kalpha, kbeta, kgamma = icellpar[3:]

        def raise_unconventional():
            raise UnconventionalLattice(
                tri_angles_explanation.format(*kangles))

        eps = self._eps
        if abs(kgamma - 90) < eps:
            if kalpha > 90 and kbeta > 90:
                var = '2a'
            elif kalpha < 90 and kbeta < 90:
                var = '2b'
            else:
                # Is this possible?  Maybe due to epsilon
                raise_unconventional()
        elif all(kangles > 90):
            if kgamma > min(kangles):
                raise_unconventional()
            var = '1a'
        elif all(kangles < 90):  # and kgamma > max(kalpha, kbeta):
            if kgamma < max(kangles):
                raise_unconventional()
            var = '1b'
        else:
            raise_unconventional()

        return 'TRI' + var
Ejemplo n.º 6
0
    def __init__(self, atoms, cellpar, na=1, nb=1, nc=1):
        """
        Create a crystal object.

        A crystal consists of a unit cell and atoms with fractional coordinates. The atoms cartesian coordinates are calculated based on the unit cell (defined by the cell parameters `a`, `b`, `c`, `alpha`, `beta`, and `gamma`) on the fly.

        Parameters
        ----------
        atoms: list
            A list of CIFAtom objects
        cellpar: array-like
            A 6-length array
        na, nb, nc: int
            Bookkeeping numbers for keeping track of how many times the crystal has been "multiplied" - no real use except for when writing MULTEM files
        """
        self.atoms = atoms
        self.cellpar = np.array(cellpar, dtype=float)

        dummy_cell = Cell(np.eye(3))
        self.cell = dummy_cell.new(cell=self.cellpar)
        self.na = na
        self.nb = nb
        self.nc = nc

        site_labels = set([atom.site_label for atom in self.atoms])
        site_keys = site_labels
        self.site_dict = {}
        for label, key in zip(site_labels, site_keys):
            self.site_dict[label] = key
Ejemplo n.º 7
0
def test_monoclinic():
    """Test band structure from different variations of hexagonal cells."""
    mc1 = Cell([[1, 0, 0], [0, 1, 0], [0, 0.2, 1]])
    par = mc1.cellpar()
    mc2 = Cell.new(par)
    mc3 = Cell([[1, 0, 0], [0, 1, 0], [-0.2, 0, 1]])
    mc4 = Cell([[1, 0, 0], [-0.2, 1, 0], [0, 0, 1]])
    path = 'GYHCEM1AXH1'

    firsttime = True
    for cell in [mc1, mc2, mc3, mc4]:
        a = Atoms(cell=cell, pbc=True)
        a.cell *= 3
        a.calc = FreeElectrons(nvalence=1, kpts={'path': path})

        lat = a.cell.get_bravais_lattice()
        assert lat.name == 'MCL'
        a.get_potential_energy()
        bs = a.calc.band_structure()
        coords, labelcoords, labels = bs.get_labels()
        assert ''.join(labels) == path
        e_skn = bs.energies

        if firsttime:
            coords1 = coords
            labelcoords1 = labelcoords
            e_skn1 = e_skn
            firsttime = False
        else:
            for d in [coords - coords1,
                      labelcoords - labelcoords1,
                      e_skn - e_skn1]:
                print(abs(d).max())
                assert abs(d).max() < 1e-13, d
Ejemplo n.º 8
0
def test_bravais_eps():
    import numpy as np
    from ase.cell import Cell

    # This tests a BCT cell which would be mischaracterized as MCLC
    # depending on comparson's precision (fix: c432fd52ecfdca).
    # The cell should actually be MCLC for small tolerances,
    # and BCT with larger ones.  But it would always come out MCLC.
    #
    # The solution is that the Niggli reduction must run with a more
    # coarse precision than the lattice recognition algorithm.
    #
    # Danger: Since the two mechanisms (Niggli, lattice recognition)
    # define their precisions differently, it is not certain whether this
    # problem is entirely gone.
    cellpar = np.array([3.42864, 3.42864, 3.42864, 125.788, 125.788, 80.236])
    cell = Cell.new(cellpar)
    mclc = cell.get_bravais_lattice(eps=1e-4)
    bct = cell.get_bravais_lattice(eps=1e-3)

    print(mclc)
    print(bct)
    assert mclc.name == 'MCLC'
    assert bct.name == 'BCT'

    # Original cell is not perfect (rounding).
    perfect_bct_cell = bct.tocell()
    # perfect_bct_cellpar = bct.cellpar()
    assert perfect_bct_cell.get_bravais_lattice().name == 'BCT'
Ejemplo n.º 9
0
def test_bravais_orcc_mcl():
    import numpy as np
    from ase.cell import Cell
    from ase.calculators.emt import EMT
    from ase import Atoms

    def get_e(cell):
        atoms = Atoms('Au', cell=cell, pbc=1)
        atoms.calc = EMT()
        return atoms.get_potential_energy()

    cell = Cell.new([[1, 0, 0], [0, 2, 0], [0.5, 0, 3]])

    lat = cell.get_bravais_lattice()
    assert lat.name == 'ORCC'

    cell2 = lat.tocell()
    e1 = get_e(cell)
    e2 = get_e(cell2)
    print(e1, e2)
    assert abs(e2 - e1) < 1e-12

    cp1 = cell.niggli_reduce()[0].cellpar()
    cp2 = lat.tocell().niggli_reduce()[0].cellpar()
    print('cellpar1', cp1)
    print('cellpar2', cp2)
    assert np.abs(cp2 - cp1).max() < 1e-12

    mcl_cell = Cell.new([[1, 0, 0], [0, 2, 0], [0.5 - 1e-3, 0, 3]])
    mcl_lat = mcl_cell.get_bravais_lattice()
    assert mcl_lat.name == 'MCL'
    e1 = get_e(mcl_cell)
    e2 = get_e(mcl_lat.tocell())
    assert abs(e2 - e1) < 1e-11, abs(e2 - e1)  # (Error is actually 1e-12)
    cp1 = mcl_cell.niggli_reduce()[0].cellpar()
    cp2 = mcl_lat.tocell().niggli_reduce()[0].cellpar()
    print(cp1)
    print(cp2)
    assert np.abs(cp2 - cp1).max() < 1e-12
Ejemplo n.º 10
0
def test_new():
    assert np.array_equal(Cell.new(), np.zeros((3, 3)))
    assert np.array_equal(Cell.new([1, 2, 3]), np.diag([1, 2, 3]))
    assert Cell.new(testcellpar).cellpar() == pytest.approx(testcellpar)
    arr = np.arange(9).reshape(3, 3)
    assert np.array_equal(Cell.new(arr), arr)
    with pytest.raises(ValueError):
        Cell.new([1, 2, 3, 4])
Ejemplo n.º 11
0
def test_mclc_eps():
    a = 6.41
    c = 5.87
    alpha = 76.7
    beta = 103.3
    gamma = 152.2

    # This lattice maps to something within tolerance of an MCLC lattice,
    # but the candidate was discarded due to being unconventional (b > c).
    # This test verifies that the problem was fixed.
    #
    # There could be similar problems for other kinds of lattice.  It
    # could perhaps cause the algorithm to find MCL/MCLC/TRI lattices
    # with higher-than-necessary orthogonality defect if some
    # candidates are discarded for this reason.

    cell = Cell.new([a, a, c, alpha, beta, gamma])
    lat = cell.get_bravais_lattice(eps=1e-2)
    print(lat)
    assert lat.name == 'MCLC'
Ejemplo n.º 12
0
    def __init__(self, cell, kpts=None, special_points=None, path=None):
        if kpts is None:
            kpts = np.empty((0, 3))

        if special_points is None:
            special_points = {}
        else:
            special_points = dict(special_points)

        if path is None:
            path = ''

        self.cell = cell = Cell.new(cell)
        assert cell.shape == (3, 3)
        assert kpts.ndim == 2 and kpts.shape[1] == 3
        self.icell = self.cell.reciprocal()
        self.kpts = kpts
        self.special_points = special_points
        assert isinstance(path, str)
        self.path = path
Ejemplo n.º 13
0
import pytest
import itertools
from ase.cell import Cell


def all_pbcs():
    values = [False, True]
    yield from itertools.product(values, values, values)


@pytest.mark.parametrize('cell', [Cell.new([3, 4, 5]), Cell.new([2, 0, 3])])
def test_uncomplete(cell):
    for pbc in all_pbcs():
        ucell = cell.uncomplete(pbc)
        assert ucell.rank == sum(pbc & cell.any(1))

    assert all(cell.uncomplete(True).any(1) == cell.any(1)), (cell.uncomplete(True), cell)
    assert all(cell.uncomplete(1).any(1) == cell.any(1))
    assert cell.uncomplete(False).rank == 0
    assert cell.uncomplete(0).rank == 0
Ejemplo n.º 14
0
from ase.cell import Cell
kx = Cell.new([5, 0, 0]).bandpath(path='GX', npoints=2).kpts
kz = Cell.new([0, 0, 5]).bandpath(path='GX', npoints=2).kpts
print(kx)
print(kz)
kx[1, 0] -= 0.5
kz[1, 2] -= 0.5
assert abs(kx).max() == 0.0
assert abs(kz).max() == 0.0
Ejemplo n.º 15
0
    def __init__(self,
                 cell,
                 atom=None,
                 fractional_position=np.array([0, 0, 0]),
                 dwf=np.nan,
                 occupancy=1,
                 charge=0,
                 site_label='',
                 symbol=''):
        '''
        Create a CifAtom object

        A CIFAtom is an ASE Atom object with additional fields read from a cif file, such as Debye-Waller factors and site labels.

        Parameters
        ----------
        cell: ase.cell.Cell
            The cell in which the atom belongs.
        kwargs: Keyword arguments passed on to ase.Atom
            Can also be used to specify additional fields not supported by ASE, such as Debye-Waller factors.

        Examples
        --------
        To make an atom with a debye-waller factor different form NaN (default), pass on the debye-waller factor using the keyword "debye_waller_factor":
        ```
        my_cif_atom = CIFAtom(symbol='Al', position = [0, 0, 0], debye-waller-factor=1.006)
        ```

        '''

        if isinstance(atom, CIFAtom):
            cell = atom.cell
            fractional_position = atom.fractional_position
            dwf = atom.dwf
            site_label = atom.site_label
            occupancy = atom.occupancy

        if isinstance(cell, Cell):
            self.cell = cell
        else:
            cell = np.array(cell, dtype=float)
            if cell.shape == (3, 3):
                self.cell = Cell(cell)
            elif cell.shape == (6, ):
                dummy_cell = Cell(np.eye(3))
                self.cell = dummy_cell.new(cell)
            else:
                raise ValueError(
                    'Cell must be size (3,3) or (6,), got cell {cell!r} of shape {cell.shape}'
                    .format(cell=cell))
        self.fractional_position = np.array(fractional_position, dtype=float)
        self.dwf = float(dwf)
        try:
            self.site_label = int(site_label)
        except ValueError:
            if isinstance(site_label, str):
                warn('String site labels may not be supported by MULTEM')
                self.site_label = site_label
            else:
                raise TypeError(
                    'Type of {site_label} (type {t}) is not supported for site_labels'
                    .format(site_label=site_label, t=type(site_label)))
        self.occupancy = float(occupancy)

        position = self.cell.cartesian_positions(self.fractional_position)
        super().__init__(symbol=symbol, charge=charge, position=position)
Ejemplo n.º 16
0
def test_bravais_check():
    import numpy as np
    from ase.cell import Cell
    from ase.lattice import bravais_lattices, UnsupportedLattice
    from ase.build import bulk, fcc111
    from ase.test.testsuite import must_raise

    bravais = {}
    for name in bravais_lattices:
        bravais[name.lower()] = bravais_lattices[name]

    def check_single(name, cell, pbc=None):
        c = Cell(cell)

        try:
            print('TEST', c, pbc)
            if pbc[:2].all() or sum(pbc) == 1:
                lattice = c.get_bravais_lattice(pbc=pbc)
            else:
                with must_raise(UnsupportedLattice):
                    lattice = c.get_bravais_lattice(pbc=pbc)
                return
        except RuntimeError:
            print('error checking {}'.format(name))
            raise
        name1 = lattice.name.lower()
        latname = name.split('@')[0]
        ok = latname == name1
        print(name, '-->', name1, 'OK' if ok else 'ERR', c.cellpar())
        assert ok, 'Expected {} but found {}'.format(latname, name1)

    def check(name, cell, pbc=None):
        if pbc is None:
            pbc = cell.any(1)
        pbc = np.asarray(pbc)
        cell = Cell(cell)

        # Check all three positive permutations:
        check_single(name + '@012', cell[[0, 1, 2]], pbc=pbc[[0, 1, 2]])
        # 2D lattice determination only supports pbc=(1,1,0) and hence we
        # check the permutations only for 3D lattices:
        if cell.rank == 3 and pbc.sum() != 1:
            check_single(name + '@201', cell[[2, 0, 1]], pbc=pbc[[2, 0, 1]])
            check_single(name + '@120', cell[[1, 2, 0]], pbc=pbc[[1, 2, 0]])

    check('cub', bravais['cub'](3.3).tocell())
    check('fcc', bravais['fcc'](3.4).tocell())
    check('fcc', bulk('Au').cell)
    check('bcc', bravais['bcc'](3.5).tocell())
    check('bcc', bulk('Fe').cell)
    check('tet', bravais['tet'](4., 5.).tocell())
    check('tet', np.diag([4., 5., 5.]))
    check('tet', np.diag([5., 4., 5.]))
    check('tet', np.diag([5., 5., 4.]))
    check('bct', bravais['bct'](3., 4.).tocell())
    check('orc', bravais['orc'](3., 4., 5.).tocell())
    check('orcf', bravais['orcf'](4., 5., 7.).tocell())
    check('orci', bravais['orci'](2., 5., 6.).tocell())
    check('orcc', bravais['orcc'](3., 4., 5.).tocell())
    check('hex', fcc111('Au', size=(1, 1, 3), periodic=True).cell)
    check('hex', bravais['hex'](5., 6.).tocell())
    check('rhl', bravais['rhl'](4., 54.).tocell())
    check('mcl', bravais['mcl'](2., 3., 4., 62.).tocell())
    check('mclc', bravais['mclc'](3., 4., 5., 75.).tocell())
    check('tri', bravais['tri'](7., 6., 5., 65., 70., 80.).tocell())

    # For 2D materials we have to check both the tocell() method
    # but also for realistic cell nonzero nonperiodic axis.
    check('sqr', bravais['sqr'](3.).tocell())
    check('sqr',
          Cell(np.diag([3., 3., 10.])),
          pbc=np.array([True, True, False]))

    check('crect', bravais['crect'](3., 40).tocell())

    alpha = 40 / 360 * 2 * np.pi
    a = 3
    x = np.cos(alpha)
    y = np.sin(alpha)

    crectcell = np.array([[a, 0, 0], [a * x, a * y, 0], [0, 0, 10]])
    check('crect', Cell(crectcell), pbc=[1, 1, 0])

    check('rect', bravais['rect'](3., 4.).tocell())
    check('rect', Cell.new([3, 4, 10]), pbc=[1, 1, 0])

    check('hex2d', bravais['hex2d'](3.).tocell())
    x = 0.5 * np.sqrt(3)
    hexcell = np.array([[a, 0, 0], [-0.5 * a, x * a, 0], [0., 0., 0.]])
    check('hex2d', Cell(hexcell))

    check('obl', bravais['obl'](3., 4., 40).tocell())

    b = 4
    x = np.cos(alpha)
    y = np.sin(alpha)
    oblcell = np.array([[a, 0, 0], [b * x, b * y, 0], [0, 0, 10]])
    check('obl', Cell(oblcell), pbc=np.array([True, True, False]))

    # 1-d:
    check('line', Cell(np.diag([a, 0, 0.0])))
    check('line', Cell(np.diag([a, 1, 1.0])), pbc=np.array([1, 0, 0]))
    check('line', Cell(np.diag([0.0, 0, a])))
    check('line', Cell(np.diag([1.0, 1, a])), pbc=np.array([0, 0, 1]))
Ejemplo n.º 17
0
import numpy as np
from ase.cell import Cell

# This tests a BCT cell which would be mischaracterized as MCLC
# depending on comparson's precision (fix: c432fd52ecfdca).
# The cell should actually be MCLC for small tolerances,
# and BCT with larger ones.  But it would always come out MCLC.
#
# The solution is that the Niggli reduction must run with a more
# coarse precision than the lattice recognition algorithm.
#
# Danger: Since the two mechanisms (Niggli, lattice recognition)
# define their precisions differently, it is not certain whether this
# problem is entirely gone.
cellpar = np.array([3.42864, 3.42864, 3.42864, 125.788, 125.788, 80.236])
cell = Cell.new(cellpar)
mclc = cell.get_bravais_lattice(eps=1e-4)
bct = cell.get_bravais_lattice(eps=1e-3)

print(mclc)
print(bct)
assert mclc.name == 'MCLC'
assert bct.name == 'BCT'

# Original cell is not perfect (rounding).
perfect_bct_cell = bct.tocell()
perfect_bct_cellpar = bct.cellpar()
assert perfect_bct_cell.get_bravais_lattice().name == 'BCT'
Ejemplo n.º 18
0
import itertools
from ase.cell import Cell


def all_pbcs():
    values = [False, True]
    yield from itertools.product(values, values, values)


def test(cell):
    for pbc in all_pbcs():
        ucell = cell.uncomplete(pbc)
        assert ucell.rank == sum(pbc & cell.any(1))

    assert all(
        cell.uncomplete(True).any(1) == cell.any(1)), (cell.uncomplete(True),
                                                       cell)
    assert all(cell.uncomplete(1).any(1) == cell.any(1))
    assert cell.uncomplete(False).rank == 0
    assert cell.uncomplete(0).rank == 0


test(Cell.new([3, 4, 5]))
test(Cell.new([2, 0, 3]))
Ejemplo n.º 19
0
 def get_cell(self) -> Cell:
     cellpar = self.get_cellpar()
     if cellpar is None:
         return Cell.new([0, 0, 0])
     return Cell.new(cellpar)
Ejemplo n.º 20
0
def orthogonalize_cell(atoms: Atoms,
                       max_repetitions: int = 5,
                       return_transform: bool = False,
                       transform: Union[bool, str] = True,
                       tolerance=0.01):
    """
    Make the cell of an ASE atoms object orthogonal. This is accomplished by repeating the cell until lattice vectors
    are close to the three principal Cartesian directions. If the structure is not exactly orthogonal after the
    structure is repeated by a given maximum the remaining difference will be made up by applying strain.

    Parameters
    ----------
    atoms : ASE atoms object
        The non-orthogonal atoms object.
    max_repetitions : int
        The maximum number of repetions allowed. Increase this to allow more repetitions and hence less strain.
    return_transform : bool
        If true, return the transformations that were applied to make the atoms orthogonal.
    transform : bool
        If false no transformation is applied to make the cell orthogonal, hence a non-orthogonal cell may be returned.


    Returns
    -------
    atoms : ASE atoms object
        The orthogonal atoms.
    transform : tuple of arrays
        The applied transform in the form the euler angles
    """
    eps = 1e-12

    zero_vectors = np.linalg.norm(atoms.cell, axis=0) < eps

    if zero_vectors.sum() > 1:
        raise RuntimeError(
            "two or more lattice vectors of the provided Atoms has no length")
    elif zero_vectors.sum() == 1:
        atoms.center(axis=np.where(zero_vectors)[0], vacuum=tolerance + eps)

    k = np.arange(-max_repetitions, max_repetitions + 1)
    l = np.arange(-max_repetitions, max_repetitions + 1)
    m = np.arange(-max_repetitions, max_repetitions + 1)

    a, b, c = atoms.cell

    vectors = np.abs(((k[:, None] * a[None])[:, None, None] +
                      (l[:, None] * b[None])[None, :, None] +
                      (m[:, None] * c[None])[None, None, :]))

    norm = np.linalg.norm(vectors, axis=-1)
    nonzero = norm > eps
    norm[nonzero == 0] = eps

    new_vectors = []
    for i in range(3):
        angles = vectors[..., i] / norm

        optimal = np.abs(angles.max() - angles < eps)

        optimal = np.where(optimal * nonzero)
        n = np.linalg.norm(vectors[optimal], axis=1)

        j = np.argmin(n)
        new_vector = np.array(
            [k[optimal[0][j]], l[optimal[1][j]], m[optimal[2][j]]])

        new_vector = np.sign(np.dot(new_vector, atoms.cell)[i]) * new_vector
        new_vectors.append(new_vector)

    atoms = cut(atoms, *new_vectors, tolerance=tolerance)

    cell = Cell.new(np.linalg.norm(atoms.cell, axis=0))
    A = np.linalg.solve(atoms.cell.complete(), cell.complete())

    if transform is True:
        atoms.positions[:] = np.dot(atoms.positions, A)
        atoms.cell[:] = cell

    elif transform == 'raise':
        if not is_cell_orthogonal(atoms):
            raise RuntimeError()

    atoms = shrink_cell(atoms, 2)

    if return_transform and transform:
        rotation, zoom, shear = decompose_affine_transform(A)
        return atoms, (np.array(rotation_matrix_to_euler(rotation)), zoom,
                       shear)
    else:
        return atoms
Ejemplo n.º 21
0
def cell():
    return Cell.new(testcellpar)
Ejemplo n.º 22
0
    def from_dict(cls, posinp):
        r"""
        Initialize the input positions from a dictionary.

        Parameters
        ----------
        posinp : dict
            Posinp as a dictionary coming from an InputParams or
            Logfile instance.

        Returns
        -------
        Posinp
            Posinp initialized from an dictionary.


        >>> pos_dict = {
        ...     "units": "reduced",
        ...     "cell": [8.07007483423, 'inf', 4.65925987792],
        ...     "positions": [
        ...         {'C': [0.08333333333, 0.5, 0.25]},
        ...         {'C': [0.41666666666, 0.5, 0.25]},
        ...         {'C': [0.58333333333, 0.5, 0.75]},
        ...         {'C': [0.91666666666, 0.5, 0.75]},
        ...     ]
        ... }
        >>> pos = Posinp.from_dict(pos_dict)
        >>> pos.boundary_conditions
        'surface'

        If there is no "cell" key, then the boundary conditions are set
        to "free". Here, given that the units are reduced, this raises
        a ValueError:

        >>> del pos_dict["cell"]
        >>> pos = Posinp.from_dict(pos_dict)
        Traceback (most recent call last):
        ...
        ValueError: Cannot use reduced units with free boundary conditions
        """
        # Read data from the dictionary
        atoms = []  # atomic positions
        for atom in posinp["positions"]:
            atoms.append(Atom.from_dict(atom))
        units = posinp.get("units", "atomic")  # Units of the coordinates
        cell = posinp.get("cell")  # Simulation cell size
        angles = posinp.get("angles")
        # Infer the boundary conditions from the value of cell
        if cell is None:
            boundary_conditions = "free"
        else:
            if not isinstance(cell, Cell):
                cell = [
                    abs(float(size)) if size not in [".inf", "inf"] else 0.0
                    for size in cell
                ]
                cell = Cell.new(cell)
            lengths_counter = Counter(list(cell.lengths()))
            if lengths_counter[0] == 1:
                boundary_conditions = "surface"
            elif lengths_counter[0] == 3:
                boundary_conditions = "free"
            else:
                boundary_conditions = "periodic"
        return cls(atoms, units, boundary_conditions, cell=cell, angles=angles)
Ejemplo n.º 23
0
from ase.dft.band_structure import calculate_band_structure
from ase.calculators.test import FreeElectrons
from ase.cell import Cell


def _atoms(cell):
    atoms = Atoms(cell=cell, pbc=True)
    atoms.calc = FreeElectrons()
    return atoms


# MCL with beta > 90, which is a common convention -- but ours is
# alpha < 90.  We want the bandpath returned by that cell to yield the
# exact same band structure as our own (alpha < 90) version of the
# same cell.
cell = Cell.new([3., 5., 4., 90., 110., 90.])
lat = cell.get_bravais_lattice()

density = 10.0
cell0 = lat.tocell()
path0 = lat.bandpath(density=density)

print(cell.cellpar().round(3))
print(cell0.cellpar().round(3))

with workdir('files', mkdir=True):
    bs = calculate_band_structure(_atoms(cell), cell.bandpath(density=density))
    bs.write('bs.json')
    # bs.plot(emin=0, emax=20, filename='fig.bs.svg')

    bs0 = calculate_band_structure(_atoms(cell0), path0)
Ejemplo n.º 24
0
 def test_free_boundary_conditions_has_no_cell(self):
     assert (self.free_pos.cell == Cell.new()).all()
Ejemplo n.º 25
0
class TestPosinp:

    # Posinp with surface boundary conditions
    surface_filename = os.path.join(tests_fol, "surface.xyz")
    pos = Posinp.from_file(surface_filename)
    # Posinp with free boundary conditions
    free_filename = os.path.join(tests_fol, "free.xyz")
    free_pos = Posinp.from_file(free_filename)
    periodic_filename = os.path.join(tests_fol, "periodic.xyz")
    periodic_pos = Posinp.from_file(periodic_filename)
    # Posinp read from a string
    string = """\
4   atomic
free
C    0.6661284109   0.000000000   1.153768252
C    3.330642055    0.000000000   1.153768252
C    4.662898877    1.000000000   3.461304757
C    7.327412521    0.000000000   3.461304757"""
    str_pos = Posinp.from_string(string)

    value = [len(pos), pos.units, pos.boundary_conditions, pos.cell, pos[0], pos.angles]
    expected = [
        4,
        "reduced",
        "surface",
        Cell.new(np.array([8.07007483423, 0.0, 4.65925987792])),
        Atom("C", [0.08333333333, 0.5, 0.25]),
        np.array([90.0, 90.0, 90.0]),
    ]

    def test_from_file(self):
        for v, e in zip(self.value, self.expected):
            if isinstance(v, np.ndarray) or isinstance(v, Cell):
                assert np.allclose(v, e)
            else:
                assert v == e

    def test_from_string(self):
        assert self.str_pos == self.free_pos

    def test_repr(self):
        atoms = [Atom("C", [0, 0, 0]), Atom("N", [0, 0, 1])]
        new_pos = Posinp(atoms, units="angstroem", boundary_conditions="free")
        msg = (
            "Posinp([Atom('C', [0.0, 0.0, 0.0]), Atom('N', [0.0, 0.0, "
            "1.0])], 'angstroem', 'free', cell=Cell([0.0, 0.0, 0.0]), angles=[90. 90. 90.])"
        )
        assert repr(new_pos) == msg

    def test_write(self):
        fname = os.path.join(tests_fol, "test.xyz")
        self.pos.write(fname)
        assert self.pos == Posinp.from_file(fname)
        os.remove(fname)

    def test_free_boundary_conditions_has_no_cell(self):
        assert (self.free_pos.cell == Cell.new()).all()

    def test_translate_atom(self):
        new_pos = self.pos.translate_atom(0, [0.5, 0, 0])
        assert new_pos != self.pos
        assert new_pos[0] == Atom("C", [0.58333333333, 0.5, 0.25])

    @pytest.mark.parametrize(
        "fname", ["free_reduced.xyz", "missing_atom.xyz", "additional_atom.xyz"]
    )
    def test_init_raises_ValueError(self, fname):
        with pytest.raises(ValueError):
            Posinp.from_file(os.path.join(tests_fol, fname))

    @pytest.mark.parametrize(
        "to_evaluate",
        [
            "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic')",
            "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic', cell=[1, 1])",
            "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic', cell=[1,'inf',1])",
        ],
    )
    def test_init_raises_ValueError2(self, to_evaluate):
        with pytest.raises(ValueError):
            eval(to_evaluate)

    def test_positions(self):
        expected = [7.327412521, 0.0, 3.461304757]
        pos1 = Posinp(
            [Atom("C", expected)], units="angstroem", boundary_conditions="free"
        )
        pos2 = pos1.translate_atom(0, [-7.327412521, 0.0, -3.461304757])
        assert np.allclose(pos1.positions, expected)
        assert np.allclose(pos2.positions, [0, 0, 0])

    def test___eq__(self):
        atom1 = Atom("N", [0.0, 0.0, 0.0])
        atom2 = Atom("N", [0.0, 0.0, 1.1])
        pos1 = Posinp([atom1, atom2], "angstroem", "free")
        pos2 = Posinp([atom2, atom1], "angstroem", "free")
        assert pos1 == pos2  # The order of the atoms in the list do not count
        assert pos1 != 1  # No error if other object is not a posinp

    def test_with_surface_boundary_conditions(self):
        # Two Posinp instances with surface BC are the same even if they
        # have a different cell size along y-axis
        pos_with_inf = Posinp(
            [
                Atom(
                    "N",
                    [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779],
                ),
                Atom(
                    "N",
                    [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154],
                ),
            ],
            "angstroem",
            "surface",
            cell=[40, ".inf", 40],
        )
        with pytest.raises(ValueError):
            pos_wo_inf = Posinp(
                [
                    Atom(
                        "N",
                        [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779],
                    ),
                    Atom(
                        "N",
                        [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154],
                    ),
                ],
                "angstroem",
                "surface",
                cell=[40, 40, 40],
            )
        # They are obviously different if the cell size along the other
        # directions are not the same
        pos2_with_inf = Posinp(
            [
                Atom(
                    "N",
                    [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779],
                ),
                Atom(
                    "N",
                    [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154],
                ),
            ],
            "angstroem",
            "surface",
            cell=[20, "inf", 40],
        )
        assert pos_with_inf != pos2_with_inf
        # They still have the same BC
        assert pos2_with_inf.boundary_conditions == pos_with_inf.boundary_conditions

    def test_to_centroid(self):
        atoms = [Atom("N", [0, 0, 0]), Atom("N", [0, 0, 1.1])]
        pos = Posinp(atoms, units="angstroem", boundary_conditions="free")
        expected_atoms = [Atom("N", [0, 0, -0.55]), Atom("N", [0, 0, 0.55])]
        expected_pos = Posinp(
            expected_atoms, units="angstroem", boundary_conditions="free"
        )
        assert pos.to_centroid() == expected_pos

    def test_to_barycenter(self):
        atoms = [Atom("N", [0, 0, 0]), Atom("N", [0, 0, 1.1])]
        pos = Posinp(atoms, units="angstroem", boundary_conditions="free")
        expected_atoms = [Atom("N", [0, 0, -0.55]), Atom("N", [0, 0, 0.55])]
        expected_pos = Posinp(
            expected_atoms, units="angstroem", boundary_conditions="free"
        )
        assert pos.to_barycenter() == expected_pos

    def test_distance(self):
        assert np.isclose(self.free_pos.distance(0, 2), 4.722170992308181)

    def test_convert(self):
        pos1 = self.periodic_pos.positions
        assert self.periodic_pos.units == "angstroem"
        self.periodic_pos.convert_units("atomic")
        assert np.isclose(
            self.periodic_pos.positions,
            np.array(
                [
                    [0.15747717, 0.94486299, 0.4724315],
                    [0.78738583, 0.94486299, 0.4724315],
                    [1.10234016, 0.94486299, 1.41729449],
                    [1.73224882, 0.94486299, 1.41729449],
                ]
            ),
        ).all()
        assert self.periodic_pos.units == "atomic"
        self.periodic_pos.convert_units("angstroem")
        assert np.isclose(self.periodic_pos.positions, pos1).all()
        assert self.periodic_pos.units == "angstroem"
        self.periodic_pos.convert_units("angstroem")
        assert np.isclose(self.periodic_pos.positions, pos1).all()
        red = Posinp.from_file(tests_fol + "reduced.xyz")
        red.convert_units("angstroem")
        print(red.positions)
        assert np.isclose(
            red.positions,
            np.array(
                [
                    [0.4233418, 1.32294312, 0.95251905],
                    [3.81007619, 0.26458862, 0.47625952],
                ]
            ),
        ).all()

    def test_angles(self):
        h2o = Posinp.from_file(tests_fol + "H2Orelaxed.xyz")
        a = h2o.angle(1, 0, 2) * 180 / np.pi
        assert np.isclose(a, 104.1219, atol=10 ** -4)
        a1, a2 = h2o.angle(0, 1, 2), h2o.angle(2, 1, 0)
        assert a1 == a2
Ejemplo n.º 26
0
import numpy as np
from ase.cell import Cell
from ase.calculators.emt import EMT
from ase import Atoms


def get_e(cell):
    atoms = Atoms('Au', cell=cell, pbc=1)
    atoms.calc = EMT()
    return atoms.get_potential_energy()


cell = Cell.new([[1, 0, 0], [0, 2, 0], [0.5, 0, 3]])

lat = cell.get_bravais_lattice()
assert lat.name == 'ORCC'

cell2 = lat.tocell()
e1 = get_e(cell)
e2 = get_e(cell2)
print(e1, e2)
assert abs(e2 - e1) < 1e-12

cp1 = cell.niggli_reduce()[0].cellpar()
cp2 = lat.tocell().niggli_reduce()[0].cellpar()
print('cellpar1', cp1)
print('cellpar2', cp2)
assert np.abs(cp2 - cp1).max() < 1e-12

mcl_cell = Cell.new([[1, 0, 0], [0, 2, 0], [0.5 - 1e-3, 0, 3]])
mcl_lat = mcl_cell.get_bravais_lattice()
Ejemplo n.º 27
0
# but also for realistic cell nonzero nonperiodic axis.
check('sqr', bravais['sqr'](3.).tocell())
check('sqr', Cell(np.diag([3., 3., 10.])), pbc=np.array([True, True, False]))

check('crect', bravais['crect'](3., 40).tocell())

alpha = 40 / 360 * 2 * np.pi
a = 3
x = np.cos(alpha)
y = np.sin(alpha)

crectcell = np.array([[a, 0, 0], [a * x, a * y, 0], [0, 0, 10]])
check('crect', Cell(crectcell), pbc=[1, 1, 0])

check('rect', bravais['rect'](3., 4.).tocell())
check('rect', Cell.new([3, 4, 10]), pbc=[1, 1, 0])

check('hex2d', bravais['hex2d'](3.).tocell())
x = 0.5 * np.sqrt(3)
hexcell = np.array([[a, 0, 0], [-0.5 * a, x * a, 0], [0., 0., 0.]])
check('hex2d', Cell(hexcell))

check('obl', bravais['obl'](3., 4., 40).tocell())

b = 4
x = np.cos(alpha)
y = np.sin(alpha)
oblcell = np.array([[a, 0, 0], [b * x, b * y, 0], [0, 0, 10]])
check('obl', Cell(oblcell), pbc=np.array([True, True, False]))

# 1-d: