Ejemplo n.º 1
0
class Structure(object):
    """
    Structure class

    :param symbols: atoms symbols to initialize structure
    :type symbols: list
    :param numbers: atomic numbers to initialize structure
    :type numbers: list
    """
    def __init__(self, symbols=None, numbers=None, unitcell=1, ncells=None,
                 positions=None, rotations=False, translations=False, magnetic_moments=False):

        if positions is not None:
            numberOfAtoms = len(positions)
        else:
            numberOfAtoms = 0

        if ncells is not None:
            ncells = np.asarray(ncells)

        if ncells is not None and positions is not None and ncells.prod() != numberOfAtoms:
            raise ValueError("Product of ncells values doesn't equal length of positions")

        if isinstance(unitcell, UnitCell):
            self.unitcell = unitcell
        else:
            self.unitcell = UnitCell(unitcell)

        miindex = get_miindex(numberOfAtoms, ncells)

        self.atoms = DataFrame(index=miindex,
                               columns=['Z', 'symbol',
                                        'x', 'y', 'z'])

        if numbers is not None or symbols is not None:
            self.atoms.Z, self.atoms.symbol = get_atomic_number_symbol(Z=numbers, symbol=symbols)

        positions = np.asarray(positions)
        self.atoms[['x', 'y', 'z']] = positions

        if rotations:
            self.rotations = DataFrame(index=miindex.droplevel(3),
                                       columns=['w', 'x', 'y', 'z'])
        else:
            self.rotations = None

        if translations:
            self.translations = DataFrame(index=miindex.droplevel(3),
                                          columns=['x', 'y', 'z'])
        else:
            self.translations = None

        if magnetic_moments:
            self.magmons = DataFrame(index=miindex,
                                     columns=['spinx', 'spiny', 'spinz'])
        else:
            self.magmons = None

    @property
    def number_of_atoms(self):
        return len(self.atoms)

    @property
    def element(self):
        return self.atoms.symbol.values

    @property
    def xyz(self):
        return self.atoms[['x', 'y', 'z']].values

    @property
    def x(self):
        return self.atoms.x.values

    @property
    def y(self):
        return self.atoms.y.values

    @property
    def z(self):
        return self.atoms.z.values

    @property
    def xyz_cartn(self):
        return self.unitcell.cartesian(self.atoms[['x', 'y', 'z']].values +
                                       np.asarray([self.atoms.index.get_level_values(0).values,
                                                   self.atoms.index.get_level_values(1).values,
                                                   self.atoms.index.get_level_values(2).values]).T)

    def get_atom_symbols(self):
        return self.atoms.symbol.unique()

    def get_atom_Zs(self):
        return self.atoms.Z.unique()

    def get_atom_count(self):
        return self.atoms.symbol.value_counts()

    def get_atomic_numbers(self):
        return self.atoms.Z.values

    def get_chemical_symbols(self):
        return self.atoms.symbol.values

    def get_scaled_positions(self):
        return (self.atoms[['x', 'y', 'z']].values +
                np.asarray([self.atoms.index.get_level_values(0).values,
                            self.atoms.index.get_level_values(1).values,
                            self.atoms.index.get_level_values(2).values]).T)

    def get_positions(self):
        return self.xyz_cartn

    def get_magnetic_moments(self):
        return self.magmons.values

    def add_atom(self, i=0, j=0, k=0, site=0, Z=None, symbol=None, position=None):
        Z, symbol = get_atomic_number_symbol([Z], [symbol])
        if position is None:
            raise ValueError("position not provided")

        self.atoms.loc[i, j, k, site] = [Z[0], symbol[0],
                                         position[0], position[1], position[2]]

        if self.rotations is not None:
            self.rotations[i, j, k] = [1, 0, 0, 0]

        if self.translations is not None:
            self.translations[i, j, k] = [0, 0, 0]

    def rattle(self, scale=0.001, seed=None):
        """Randomly move all atoms by a normal distbution with a standard
        deviation given by scale.

        :param scale: standard deviation
        :type scale: float
        :param scale: seed for random number generator
        :type scale: int
        """
        rs = np.random.RandomState(seed)
        self.atoms[['x', 'y', 'z']] += rs.normal(scale=scale, size=self.xyz.shape)

    def repeat(self, rep):
        """Repeat the cells a number of time along each dimension

        *rep* argument should be either three value like *(1,2,3)* or
        a single value *r* equivalent to *(r,r,r)*."""

        if isinstance(rep, int):
            rep = np.array((rep, rep, rep, 1))
        else:
            rep = np.append(rep, 1)

        ncells = np.array(self.atoms.index.max()) + 1

        x = np.tile(np.reshape(self.x, ncells), rep).flatten()
        y = np.tile(np.reshape(self.y, ncells), rep).flatten()
        z = np.tile(np.reshape(self.z, ncells), rep).flatten()
        Z = np.tile(np.reshape(self.get_atomic_numbers(), ncells), rep).flatten()

        miindex = get_miindex(0, ncells * rep)

        self.atoms = DataFrame(index=miindex,
                               columns=['Z', 'symbol',
                                        'x', 'y', 'z'])

        self.atoms.Z, self.atoms.symbol = get_atomic_number_symbol(Z=Z)

        self.atoms.x = x
        self.atoms.y = y
        self.atoms.z = z

    def reindex(self, ncells):
        self.atoms.set_index(get_miindex(ncells=ncells), inplace=True)
Ejemplo n.º 2
0
class Structure(object):
    """
    Structure class

    :param symbols: atoms symbols to initialize structure
    :type symbols: list
    :param numbers: atomic numbers to initialize structure
    :type numbers: list
    """
    def __init__(self,
                 symbols=None,
                 numbers=None,
                 unitcell=1,
                 ncells=None,
                 positions=None,
                 rotations=False,
                 translations=False,
                 magnetic_moments=False):

        if positions is not None:
            numberOfAtoms = len(positions)
        else:
            numberOfAtoms = 0

        if ncells is not None:
            ncells = np.asarray(ncells)

        if ncells is not None and positions is not None and ncells.prod(
        ) != numberOfAtoms:
            raise ValueError(
                "Product of ncells values doesn't equal length of positions")

        if isinstance(unitcell, UnitCell):
            self.unitcell = unitcell
        else:
            self.unitcell = UnitCell(unitcell)

        miindex = get_miindex(numberOfAtoms, ncells)

        self.atoms = DataFrame(index=miindex,
                               columns=[
                                   'Z', 'symbol', 'x', 'y', 'z', 'cartn_x',
                                   'cartn_y', 'cartn_z'
                               ])

        if numbers is not None or symbols is not None:
            self.atoms.Z, self.atoms.symbol = get_atomic_number_symbol(
                Z=numbers, symbol=symbols)

        positions = np.asarray(positions)
        self.atoms[['x', 'y', 'z']] = positions

        if rotations:
            self.rotations = DataFrame(index=miindex.droplevel(3),
                                       columns=['w', 'x', 'y', 'z'])
        else:
            self.rotations = None

        if translations:
            self.translations = DataFrame(index=miindex.droplevel(3),
                                          columns=['x', 'y', 'z'])
        else:
            self.translations = None

        if magnetic_moments:
            self.magmons = DataFrame(index=miindex,
                                     columns=['spinx', 'spiny', 'spinz'])
        else:
            self.magmons = None

        self._recalculate_cartn()

    @property
    def number_of_atoms(self):
        return len(self.atoms)

    @property
    def element(self):
        return self.atoms.symbol.values

    @property
    def xyz(self):
        return self.atoms[['x', 'y', 'z']].values

    @property
    def x(self):
        return self.atoms.x.values

    @property
    def y(self):
        return self.atoms.y.values

    @property
    def z(self):
        return self.atoms.z.values

    @property
    def xyz_cartn(self):
        return self.atoms[['cartn_x', 'cartn_y', 'cartn_z']].values

    def get_atom_symbols(self):
        return self.atoms.symbol.unique()

    def get_atom_Zs(self):
        return self.atoms.Z.unique()

    def get_atom_count(self):
        return self.atoms.symbol.value_counts()

    def get_atomic_numbers(self):
        return self.atoms.Z.values

    def get_chemical_symbols(self):
        return self.atoms.symbol.values

    def get_scaled_positions(self):
        return (self.atoms[['x', 'y', 'z']].values + np.asarray([
            self.atoms.index.get_level_values(0).values,
            self.atoms.index.get_level_values(1).values,
            self.atoms.index.get_level_values(2).values
        ]).T)

    def get_positions(self):
        return self.xyz_cartn

    def get_magnetic_moments(self):
        return self.magmons.values

    def add_atom(self,
                 i=0,
                 j=0,
                 k=0,
                 site=0,
                 Z=None,
                 symbol=None,
                 position=None):
        Z, symbol = get_atomic_number_symbol([Z], [symbol])
        if position is None:
            raise ValueError("position not provided")

        cartn = self.unitcell.cartesian(position)[0]

        self.atoms.loc[i, j, k, site] = [
            Z[0], symbol[0], position[0], position[1], position[2], cartn[0],
            cartn[1], cartn[2]
        ]

        if self.rotations is not None:
            self.rotations[i, j, k] = [1, 0, 0, 0]

        if self.translations is not None:
            self.translations[i, j, k] = [0, 0, 0]

    def repeat(self, rep):
        """Repeat the cells a number of time along each dimension

        *rep* argument should be either three value like *(1,2,3)* or
        a single value *r* equivalent to *(r,r,r)*."""

        if isinstance(rep, int):
            rep = np.array((rep, rep, rep, 1))
        else:
            rep = np.append(rep, 1)

        ncells = np.array(self.atoms.index.max()) + 1

        x = np.tile(np.reshape(self.x, ncells), rep).flatten()
        y = np.tile(np.reshape(self.y, ncells), rep).flatten()
        z = np.tile(np.reshape(self.z, ncells), rep).flatten()
        Z = np.tile(np.reshape(self.get_atomic_numbers(), ncells),
                    rep).flatten()

        miindex = get_miindex(0, ncells * rep)

        self.atoms = DataFrame(index=miindex,
                               columns=[
                                   'Z', 'symbol', 'x', 'y', 'z', 'cartn_x',
                                   'cartn_y', 'cartn_z'
                               ])

        self.atoms.Z, self.atoms.symbol = get_atomic_number_symbol(Z=Z)

        self.atoms.x = x
        self.atoms.y = y
        self.atoms.z = z

        self._recalculate_cartn()

    def reindex(self, ncells):
        self.atoms.set_index(get_miindex(ncells=ncells), inplace=True)
        self._recalculate_cartn()

    def _recalculate_cartn(self):
        self.atoms[['cartn_x', 'cartn_y',
                    'cartn_z']] = self.unitcell.cartesian(
                        self.atoms[['x', 'y', 'z']].values + np.asarray([
                            self.atoms.index.get_level_values(0).values,
                            self.atoms.index.get_level_values(1).values,
                            self.atoms.index.get_level_values(2).values
                        ]).T)
Ejemplo n.º 3
0
def test_UnitCell_init():
    from numpy import pi
    unitcell = UnitCell()
    assert unitcell.cell == (1, 1, 1, 90, 90, 90)
    assert unitcell.reciprocalCell == (1, 1, 1, 90, 90, 90)
    assert unitcell.d(1, 0, 0) == 1
    assert unitcell.dstar(1, 0, 0) == 1
    assert unitcell.recAngle(1, 0, 0, 1, 0, 0) == 0
    assert unitcell.recAngle(1, 0, 0, 0, 1, 0, degrees=True) == 90
    assert_almost_equal(unitcell.recAngle(0, 1, 0, 0, 1, 1), pi/4)
    assert_almost_equal(unitcell.recAngle(0, 1, 0, 0, 1, 1, degrees=True), 45)
    assert unitcell.volume == 1
    assert unitcell.reciprocalVolume == 1
    assert_array_equal(unitcell.G, [[1, 0, 0],
                                    [0, 1, 0],
                                    [0, 0, 1]])
    assert_array_equal(unitcell.B, [[1, 0, 0],
                                    [0, 1, 0],
                                    [0, 0, 1]])
    assert_array_equal(unitcell.Binv, [[1, 0, 0],
                                       [0, 1, 0],
                                       [0, 0, 1]])

    unitcell = UnitCell(5)
    assert unitcell.cell == (5, 5, 5, 90, 90, 90)
    assert_array_almost_equal(unitcell.reciprocalCell, (0.2, 0.2, 0.2, 90, 90, 90))
    assert_almost_equal(unitcell.volume, 125)
    assert_almost_equal(unitcell.reciprocalVolume, 0.008)
    assert_array_almost_equal(unitcell.G, [[25, 0, 0],
                                           [0, 25, 0],
                                           [0, 0, 25]])
    assert_array_almost_equal(unitcell.B, [[0.2, 0, 0],
                                           [0, 0.2, 0],
                                           [0, 0, 0.2]])
    assert_array_almost_equal(unitcell.Binv, [[5, 0, 0],
                                              [0, 5, 0],
                                              [0, 0, 5]])

    unitcell = UnitCell(1, 2, 3)
    assert unitcell.cell == (1, 2, 3, 90, 90, 90)
    assert_array_almost_equal(unitcell.reciprocalCell, (1, 0.5, 0.333333, 90, 90, 90))
    assert unitcell.volume == 6
    assert_almost_equal(unitcell.reciprocalVolume, 0.1666667)
    assert_array_almost_equal(unitcell.G, [[1, 0, 0],
                                           [0, 4, 0],
                                           [0, 0, 9]])

    unitcell = UnitCell(4, 5, 6, 90, 90, 120)
    assert unitcell.d(1, 0, 0) == 3.4641016151377548
    assert unitcell.d(0, 1, 0) == 4.3301270189221936
    assert unitcell.d(0, 0, 1) == 6
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 1, 0, 0), 0)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 1, 0, 0, degrees=True), 0, decimal=5)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 1, 0), pi/3)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 1, 0, degrees=True), 60)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 0, 1), pi/2)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 0, 1, degrees=True), 90)
    assert_array_almost_equal(unitcell.cell,
                              (4, 5, 6, 90, 90, 120))
    assert_array_almost_equal(unitcell.reciprocalCell,
                              (0.288675, 0.2309401, 0.1666667, 90, 90, 60))
    assert_almost_equal(unitcell.volume, 103.9230485)
    assert_almost_equal(unitcell.reciprocalVolume, 0.0096225)
    assert_array_almost_equal(unitcell.G, [[16, -10, 0],
                                           [-10, 25, 0],
                                           [0,    0, 36]])
    assert_array_almost_equal(unitcell.B, [[0.288675, 0.11547, 0],
                                           [0,        0.2,     0],
                                           [0,        0,       0.166667]])

    assert_array_almost_equal(unitcell.Binv, [[3.464101, -2, 0],
                                              [0,         5, 0],
                                              [0,         0, 6]])

    assert_array_almost_equal(unitcell.cartesian([1, 0, 0]), [[3.464102, -2, 0]])
    assert_array_almost_equal(unitcell.cartesian([[1,   0,   0],
                                                  [0.1, 0.3, 0.5]]), [[3.464102, -2, 0],
                                                                      [0.34641, 1.3, 3]])
    assert_array_almost_equal(unitcell.fractional([3.464102, -2, 0]), [[1, 0, 0]])
    assert_array_almost_equal(unitcell.fractional([[0, 5, 0],
                                                   [0, 0, 3]]), [[0, 1, 0],
                                                                 [0, 0, 0.5]])

    # test __eq__
    assert unitcell != UnitCell()
    assert unitcell != UnitCell(5)
    assert unitcell == UnitCell(4, 5, 6, 90, 90, 120)
    assert unitcell != UnitCell(6, 5, 4, 120, 90, 90)

    unitcell = UnitCell([5, 6, 7, 89, 92, 121])
    assert unitcell.cell == (5, 6, 7, 89, 92, 121)
    assert_array_almost_equal(unitcell.reciprocalCell,
                              (0.233433, 0.194439, 0.142944, 89.965076, 88.267509, 59.014511))
    assert_almost_equal(unitcell.volume, 179.8954455)
    assert_almost_equal(unitcell.reciprocalVolume, 0.0055587844)
    assert_array_almost_equal(unitcell.G, [[25, -15.45114225, -1.22148238],
                                           [-15.45114225, 36, 0.73300107],
                                           [-1.22148238, 0.73300107, 49]])
    # Test __str__
    assert str(unitcell) == '(5.0, 6.0, 7.0, 89.0, 92.0, 121.0)'
Ejemplo n.º 4
0
def test_UnitCell_init():
    from numpy import pi
    unitcell = UnitCell()
    assert unitcell.cell == (1, 1, 1, 90, 90, 90)
    assert unitcell.reciprocalCell == (1, 1, 1, 90, 90, 90)
    assert unitcell.d(1, 0, 0) == 1
    assert unitcell.dstar(1, 0, 0) == 1
    assert unitcell.recAngle(1, 0, 0, 1, 0, 0) == 0
    assert unitcell.recAngle(1, 0, 0, 0, 1, 0, degrees=True) == 90
    assert_almost_equal(unitcell.recAngle(0, 1, 0, 0, 1, 1), pi / 4)
    assert_almost_equal(unitcell.recAngle(0, 1, 0, 0, 1, 1, degrees=True), 45)
    assert unitcell.volume == 1
    assert unitcell.reciprocalVolume == 1
    assert_array_equal(unitcell.G, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    assert_array_equal(unitcell.B, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    assert_array_equal(unitcell.Binv, [[1, 0, 0], [0, 1, 0], [0, 0, 1]])

    unitcell = UnitCell(5)
    assert unitcell.cell == (5, 5, 5, 90, 90, 90)
    assert_array_almost_equal(unitcell.reciprocalCell,
                              (0.2, 0.2, 0.2, 90, 90, 90))
    assert_almost_equal(unitcell.volume, 125)
    assert_almost_equal(unitcell.reciprocalVolume, 0.008)
    assert_array_almost_equal(unitcell.G, [[25, 0, 0], [0, 25, 0], [0, 0, 25]])
    assert_array_almost_equal(unitcell.B,
                              [[0.2, 0, 0], [0, 0.2, 0], [0, 0, 0.2]])
    assert_array_almost_equal(unitcell.Binv, [[5, 0, 0], [0, 5, 0], [0, 0, 5]])

    unitcell = UnitCell(1, 2, 3)
    assert unitcell.cell == (1, 2, 3, 90, 90, 90)
    assert_array_almost_equal(unitcell.reciprocalCell,
                              (1, 0.5, 0.333333, 90, 90, 90))
    assert unitcell.volume == 6
    assert_almost_equal(unitcell.reciprocalVolume, 0.1666667)
    assert_array_almost_equal(unitcell.G, [[1, 0, 0], [0, 4, 0], [0, 0, 9]])

    unitcell = UnitCell(4, 5, 6, 90, 90, 120)
    assert unitcell.d(1, 0, 0) == 3.4641016151377548
    assert unitcell.d(0, 1, 0) == 4.3301270189221936
    assert unitcell.d(0, 0, 1) == 6
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 1, 0, 0), 0)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 1, 0, 0, degrees=True),
                        0,
                        decimal=5)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 1, 0), pi / 3)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 1, 0, degrees=True), 60)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 0, 1), pi / 2)
    assert_almost_equal(unitcell.recAngle(1, 0, 0, 0, 0, 1, degrees=True), 90)
    assert_array_almost_equal(unitcell.cell, (4, 5, 6, 90, 90, 120))
    assert_array_almost_equal(unitcell.reciprocalCell,
                              (0.288675, 0.2309401, 0.1666667, 90, 90, 60))
    assert_almost_equal(unitcell.volume, 103.9230485)
    assert_almost_equal(unitcell.reciprocalVolume, 0.0096225)
    assert_array_almost_equal(unitcell.G,
                              [[16, -10, 0], [-10, 25, 0], [0, 0, 36]])
    assert_array_almost_equal(
        unitcell.B, [[0.288675, 0.11547, 0], [0, 0.2, 0], [0, 0, 0.166667]])

    assert_array_almost_equal(unitcell.Binv,
                              [[3.464101, -2, 0], [0, 5, 0], [0, 0, 6]])

    assert_array_almost_equal(unitcell.cartesian([1, 0, 0]),
                              [[3.464102, -2, 0]])
    assert_array_almost_equal(unitcell.cartesian([[1, 0, 0], [0.1, 0.3, 0.5]]),
                              [[3.464102, -2, 0], [0.34641, 1.3, 3]])
    assert_array_almost_equal(unitcell.fractional([3.464102, -2, 0]),
                              [[1, 0, 0]])
    assert_array_almost_equal(unitcell.fractional([[0, 5, 0], [0, 0, 3]]),
                              [[0, 1, 0], [0, 0, 0.5]])

    # test __eq__
    assert unitcell != UnitCell()
    assert unitcell != UnitCell(5)
    assert unitcell == UnitCell(4, 5, 6, 90, 90, 120)
    assert unitcell != UnitCell(6, 5, 4, 120, 90, 90)

    unitcell = UnitCell([5, 6, 7, 89, 92, 121])
    assert unitcell.cell == (5, 6, 7, 89, 92, 121)
    assert_array_almost_equal(
        unitcell.reciprocalCell,
        (0.233433, 0.194439, 0.142944, 89.965076, 88.267509, 59.014511))
    assert_almost_equal(unitcell.volume, 179.8954455)
    assert_almost_equal(unitcell.reciprocalVolume, 0.0055587844)
    assert_array_almost_equal(
        unitcell.G,
        [[25, -15.45114225, -1.22148238], [-15.45114225, 36, 0.73300107],
         [-1.22148238, 0.73300107, 49]])
    # Test __str__
    assert str(unitcell) == '(5.0, 6.0, 7.0, 89.0, 92.0, 121.0)'