예제 #1
0
def traingular_2d_hamiltonian(J1=-0e-21,
                              k1=np.array([-000 * mu_B]),
                              k1dir=np.array([[0.0, 0, 1.0]])):
    """
    Isolated spin in an applied field. field:10T, time step: 1fs.
    Total time: 100 ps, No Langevin term.
    """
    # make model
    atoms = Atoms(
        symbols="H",
        positions=[[0, 0, 0]],
        cell=[[1, 0, 0], [-1.0 / 2, np.sqrt(3) / 2, 0], [0, 0, 1]])
    spin = np.array([[0, 1, 0]])

    ham = SpinHamiltonian(
        cell=atoms.cell,
        pos=atoms.get_scaled_positions(),
        spinat=spin,
        zion=atoms.get_atomic_numbers())
    ham.gilbert_damping = [1.0]
    J = {
        (0, 0, (1, 0, 0)): J1,
        (0, 0, (0, 1, 0)): J1,
        (0, 0, (1, 1, 0)): J1,
        (0, 0, (-1, 0, 0)): J1,
        (0, 0, (0, -1, 0)): J1,
        (0, 0, (-1, -1, 0)): J1,
    }
    ham.set_exchange_ijR(exchange_Jdict=J)
    ham.set_uniaxial_mca(k1, k1dir)
    return ham
예제 #2
0
def square_2d_hamiltonian(Jx=-5e-21,
                          Jy=-5e-21,
                          k1=np.array([-000 * mu_B]),
                          k1dir=np.array([[0.0, 0, 1.0]])):
    atoms = Atoms(
        symbols="H",
        positions=[[0, 0, 0]],
        cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    spin = np.array([[0, 1, 0]])

    ham = SpinHamiltonian(
        cell=atoms.cell,
        pos=atoms.get_scaled_positions(),
        spinat=spin,
        zion=atoms.get_atomic_numbers())
    ham.gilbert_damping = [1.0]
    J = {
        (0, 0, (1, 0, 0)): Jx,
        (0, 0, (-1, 0, 0)): Jx,
        (0, 0, (0, 1, 0)): Jy,
        (0, 0, (0, -1, 0)): Jy,
    }
    ham.set_exchange_ijR(exchange_Jdict=J)
    ham.set_uniaxial_mca(k1, k1dir)
    return ham
예제 #3
0
def in_cell(atoms: Atoms, index=None, position=None):
    '''
    Checks if `x` and `y` scaled coordinates are between 0 and 1
    :param atoms: MUST have scaled_positions property
    :param index: atom index
    :param position:
    :return: bool
    '''
    if index is not None:
        scaled = atoms.get_scaled_positions()[index][:2]
    elif position is not None:
        # scales position to cell
        scaled = np.linalg.solve(atoms.cell.T, position.T).T[:2]
    else:
        raise ValueError('at least one of `position` or `index` '
                         'must be provided')
    return all(0 <= coord < 1 for coord in scaled)
예제 #4
0
def canting_1d_hamiltonian(
        J1=3e-21,
        #J2=0e-21,
        DMI1=[0, 0, 0e-21],
        DMI2=[0, 0, -0e-21],
        k1=np.array([-0 * mu_B]),
        k1dir=np.array([[0.0, 0.0, 1.0]]),
        plot_type='2d'):
    # make model
    atoms = Atoms(symbols="H", positions=[[0, 0, 0]], cell=[1, 1, 1])
    spin = np.array([[0, 1, 0]])

    ham = SpinHamiltonian(
        cell=atoms.cell,
        pos=atoms.get_scaled_positions(),
        spinat=spin,
        zion=atoms.get_atomic_numbers())
    ham.gilbert_damping = [0.8]
    #ham.gyro_ratio=[1.0]

    J = {
        (0, 0, (1, 0, 0)): J1,
        (0, 0, (-1, 0, 0)): J1,
        #(0, 0, (2, 0, 0)): J2,
        #(0, 0, (-2, 0, 0)): J2,
    }
    ham.set_exchange_ijR(exchange_Jdict=J)

    k1 = k1
    k1dir = k1dir
    ham.set_uniaxial_mca(k1, k1dir)
    sc_ham = ham.make_supercell(np.diag([2, 1, 1]))

    DMI1val = np.array(DMI1)
    DMI2val = np.array(DMI2)
    DMI = {
        (0, 1, (0, 0, 0)): DMI1val,
        (1, 0, (0, 0, 0)): -DMI1val,
        (0, 1, (-1, 0, 0)): -DMI2val,
        (1, 0, (1, 0, 0)): DMI2val,
    }
    sc_ham.set_dmi_ijR(dmi_ddict=DMI)

    return sc_ham
예제 #5
0
def cubic_3d_2site_hamiltonian(Jx=-0e-21,
                               Jy=-0e-21,
                               Jz=0e-21,
                               DMI=[0, 0, 0e-21],
                               k1=np.array([-0 * mu_B]),
                               k1dir=np.array([[0.0, 0, 1.0]])):
    atoms = Atoms(
        symbols="H",
        positions=[[0, 0, 0]],
        cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    spin = np.array([[0, 1, 0]])

    ham = SpinHamiltonian(
        cell=atoms.cell,
        pos=atoms.get_scaled_positions(),
        spinat=spin,
        zion=atoms.get_atomic_numbers())
    ham.gilbert_damping = [0.8]
    J = {
        (0, 0, (1, 0, 0)): Jx,
        (0, 0, (-1, 0, 0)): Jx,
        (0, 0, (0, 1, 0)): Jy,
        (0, 0, (0, -1, 0)): Jy,
        (0, 0, (0, 0, 1)): Jz,
        (0, 0, (0, 0, -1)): Jz,
    }
    ham.set_exchange_ijR(exchange_Jdict=J)
    ham.set_uniaxial_mca(k1, k1dir)
    sc_ham = ham.make_supercell(np.diag([2, 1, 1]))
    DMIval = np.array(DMI)
    DMI = {
        (0, 1, (0, 0, 0)): DMIval,
        #(1, 0, (0, 0, 0)): -DMIval,
        (0, 1, (-1, 0, 0)): DMIval,
        #(1, 0, (1, 0, 0)): -DMIval,
        #(0, 0, (0, 1, 0)): DMIval,
        #(0, 0, (0, -1, 0)): -DMIval,
        #(0, 0, (-1, 0, 0)): -DMIval,
        #(0, 0, (1, 0, 0)): DMIval,
    }
    sc_ham.set_dmi_ijR(dmi_ddict=DMI)
    return sc_ham
예제 #6
0
파일: ribbon.py 프로젝트: yfyh2013/ase
def graphene_nanoribbon(n,
                        m,
                        type='zigzag',
                        saturated=False,
                        C_H=1.09,
                        C_C=1.42,
                        vacuum=None,
                        magnetic=False,
                        initial_mag=1.12,
                        sheet=False,
                        main_element='C',
                        saturate_element='H'):
    """Create a graphene nanoribbon.

    Creates a graphene nanoribbon in the x-z plane, with the nanoribbon
    running along the z axis.

    Parameters:

    n: int
        The width of the nanoribbon.
    m: int
        The length of the nanoribbon.
    type: str
        The orientation of the ribbon.  Must be either 'zigzag'
        or 'armchair'.
    saturated: bool
        If true, hydrogen atoms are placed along the edge.
    C_H: float
        Carbon-hydrogen bond length.  Default: 1.09 Angstrom.
    C_C: float
        Carbon-carbon bond length.  Default: 1.42 Angstrom.
    vacuum: None (default) or float
        Amount of vacuum added to non-periodic directions, if present.
    magnetic: bool
        Make the edges magnetic.
    initial_mag: float
        Magnitude of magnetic moment if magnetic.
    sheet: bool
        If true, make an infinite sheet instead of a ribbon (default: False)
    """

    b = sqrt(3) * C_C / 4
    arm_unit = Atoms(main_element + '4',
                     pbc=(1, 0, 1),
                     cell=[4 * b, 0, 3 * C_C])
    arm_unit.positions = [[0, 0, 0], [b * 2, 0, C_C / 2.],
                          [b * 2, 0, 3 * C_C / 2.], [0, 0, 2 * C_C]]
    zz_unit = Atoms(main_element + '2',
                    pbc=(1, 0, 1),
                    cell=[3 * C_C / 2.0, 0, b * 4])
    zz_unit.positions = [[0, 0, 0], [C_C / 2.0, 0, b * 2]]
    atoms = Atoms()

    if type == 'zigzag':
        edge_index0 = np.arange(m) * 2 + 1
        edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2
        if magnetic:
            mms = np.zeros(m * n * 2)
            for i in edge_index0:
                mms[i] = initial_mag
            for i in edge_index1:
                mms[i] = -initial_mag

        for i in range(n):
            layer = zz_unit.repeat((1, 1, m))
            layer.positions[:, 0] -= 3 * C_C / 2 * i
            if i % 2 == 1:
                layer.positions[:, 2] += 2 * b
                layer[-1].position[2] -= b * 4 * m
            atoms += layer
        if magnetic:
            atoms.set_initial_magnetic_moments(mms)
        if saturated:
            H_atoms0 = Atoms(saturate_element + str(m))
            H_atoms0.positions = atoms[edge_index0].positions
            H_atoms0.positions[:, 0] += C_H
            H_atoms1 = Atoms(saturate_element + str(m))
            H_atoms1.positions = atoms[edge_index1].positions
            H_atoms1.positions[:, 0] -= C_H
            atoms += H_atoms0 + H_atoms1
        atoms.cell = [n * 3 * C_C / 2, 0, m * 4 * b]

    elif type == 'armchair':
        for i in range(n):
            layer = arm_unit.repeat((1, 1, m))
            layer.positions[:, 0] -= 4 * b * i
            atoms += layer
        if saturated:
            arm_right_saturation = Atoms(saturate_element + '2',
                                         pbc=(1, 0, 1),
                                         cell=[4 * b, 0, 3 * C_C])
            arm_right_saturation.positions = [[
                -sqrt(3) / 2 * C_H, 0, C_H * 0.5
            ], [-sqrt(3) / 2 * C_H, 0, 2 * C_C - C_H * 0.5]]
            arm_left_saturation = Atoms(saturate_element + '2',
                                        pbc=(1, 0, 1),
                                        cell=[4 * b, 0, 3 * C_C])
            arm_left_saturation.positions = [[
                b * 2 + sqrt(3) / 2 * C_H, 0, C_C / 2 - C_H * 0.5
            ], [b * 2 + sqrt(3) / 2 * C_H, 0, 3 * C_C / 2.0 + C_H * 0.5]]
            arm_right_saturation.positions[:, 0] -= 4 * b * (n - 1)
            atoms += arm_right_saturation.repeat((1, 1, m))
            atoms += arm_left_saturation.repeat((1, 1, m))

        atoms.cell = [b * 4 * n, 0, 3 * C_C * m]

    atoms.set_pbc([sheet, False, True])
    atoms.set_scaled_positions(atoms.get_scaled_positions() % 1.0)
    if not sheet:
        atoms.cell[0] = 0.0
    if vacuum:
        atoms.center(vacuum, axis=1)
        if not sheet:
            atoms.center(vacuum, axis=0)
    return atoms
예제 #7
0
파일: geometry.py 프로젝트: jboes/ase
#                    [ 24.49041667,  -4.07833333,  -16.32208333],
#                    [ 18.37145833,  14.29020833,  -24.48166667],
#                    [ 24.49916667,  12.25541667,  -20.39458333],
#                    [ 18.36854167,  16.32791667,  -30.60645833],
#                    [ 19.0575    ,   0.01166667,    5.45333333],
#                    [ 23.13388889,   6.80888889,    1.36722222],
#                    [ 35.3825    ,   5.45333333,  -16.31333333]])
#

# Test the wrap function.
scaled_positions = np.array([[2.0, 3.2, 4.3]])
cell = np.array([[5.43, 5.43, 0.0], [5.43, -5.43, 0.0], [0.00, 0.00, 40.0]])
atoms = Atoms(scaled_positions=scaled_positions, symbols=["Si"], cell=cell, pbc=[True, True, False])
atoms.wrap()
correct_pos = np.array([0.0, 0.2, 4.3])
assert np.allclose(correct_pos, atoms.get_scaled_positions(wrap=False))

positions = np.array(
    [
        [4.0725, -4.0725, -1.3575],
        [1.3575, -1.3575, -1.3575],
        [2.715, -2.715, 0.0],
        [4.0725, 1.3575, -1.3575],
        [0.0, 0.0, 0.0],
        [2.715, 2.715, 0.0],
        [6.7875, -1.3575, -1.3575],
        [5.43, 0.0, 0.0],
    ]
)
cell = np.array([[5.43, 5.43, 0.0], [5.43, -5.43, 0.0], [0.00, 0.00, 40.0]])
atoms = Atoms(positions=positions, symbols=["Si"] * 8, cell=cell, pbc=[True, True, False])
예제 #8
0
class SislWrapper():
    def __init__(self, sisl_hamiltonian, shift_fermi=None, spin=None):
        self.ham = sisl_hamiltonian
        self.shift_fermi = shift_fermi
        self.spin = spin
        self.orbs = []
        self.orb_dict = defaultdict(lambda: [])
        g = self.ham._geometry
        _atoms = self.ham._geometry._atoms
        atomic_numbers = []
        atom_positions = g.xyz
        self.cell = np.array(g.sc.cell)
        for ia, a in enumerate(_atoms):
            atomic_numbers.append(a.Z)
        self.atoms = Atoms(numbers=atomic_numbers,
                           cell=self.cell,
                           positions=atom_positions)
        xred = self.atoms.get_scaled_positions()
        sdict = list(symbol_number(self.atoms).keys())
        if self.ham.spin.is_colinear:
            if spin is None:
                raise ValueError("For colinear spin, spin must be given")
        else:
            if spin is not None:
                raise ValueError(
                    "For non-colinear spin and unpolarized spin, spin should be None"
                )

        self.positions = []
        if self.ham.spin.is_colinear:
            for ia, a in enumerate(_atoms):
                symnum = sdict[ia]
                orb_names = []
                for x in a.orbitals:
                    name = f"{symnum}|{x.name()}|{spin}"
                    orb_names.append(name)
                    self.positions.append(xred[ia])
                self.orbs += orb_names
                self.orb_dict[ia] += orb_names
            self.norb = len(self.orbs)
            self.nbasis = self.norb
        elif self.ham.spin.is_spinorbit:
            for spin in ['up', 'down']:
                for ia, a in enumerate(_atoms):
                    symnum = sdict[ia]
                    orb_names = []
                    for x in a.orbitals:
                        name = f"{symnum}|{x.name()}|{spin}"
                        orb_names.append(name)
                        self.positions.append(xred[ia])
                    self.orbs += orb_names
                    self.orb_dict[ia] += orb_names
            self.norb = len(self.orbs) / 2
            self.nbasis = len(self.orbs)
        else:
            for ia, a in enumerate(_atoms):
                symnum = sdict[ia]
                orb_names = []
                for x in a.orbitals:
                    name = f"{symnum}|{x.name()}|None"
                    orb_names.append(name)
                    self.positions.append(xred[ia])
                self.orbs += orb_names
                self.orb_dict[ia] += orb_names
            self.norb = len(self.orbs)
            self.nbasis = len(self.orbs)
        self.positions = np.array(self.positions, dtype=float)

    def print_orbs(self):
        print(self.orb_dict)

    def solve(self, k):
        if self.spin is None:
            evals, evecs = self.ham.eigh(k=k, eigvals_only=False)
        else:
            evals, evecs = self.ham.eigh(k=k,
                                         spin=self.spin,
                                         eigvals_only=False)
        if self.shift_fermi:
            evals += self.shift_fermi
        return evals, evecs

    def Hk(self, k, format='dense'):
        if self.spin is not None:
            return self.ham.Hk(k, format=format, spin=self.spin)
        else:
            return self.ham.Hk(k, format=format)

    def solve_all(self, kpts, orth=False):
        evals = []
        evecs = []
        for ik, k in enumerate(kpts):
            if orth and self.ham.orthogonal:
                S = self.ham.Sk(k, format='dense')
                Smh = Lowdin(S)
                H = self.Hk(k, format='dense')
                Horth = Smh.T.conj() @ H @ Smh
                evalue, evec = eigh(Horth)
            else:
                evalue, evec = self.solve(k)
            evals.append(evalue)
            evecs.append(evec)
        return np.array(evals, dtype=float), np.array(evecs,
                                                      dtype=complex,
                                                      order='C')

    def get_fermi_level(self):
        if self.shift_fermi:
            return self.shift_fermi
        else:
            return 0.0
예제 #9
0
class phonon_unfolder:
    """ phonon unfolding class"""

    def __init__(self,
                 atoms,
                 supercell_matrix,
                 eigenvectors,
                 qpoints,
                 tol_r=0.03,
                 ndim=3,
                 labels=None,
                 compare=None,
                 phase=True,
                 ghost_atoms=None):
        """
        Params:
        ===================
        atoms: The structure of supercell.
        supercell matrix: The matrix that convert the primitive cell to supercell.
        eigenvectors: The phonon eigenvectors. format np.array() index=[ikpts, ifreq, 3*iatoms+j]. j=0..2
        qpoints: list of q-points, note the q points are in the BZ of the supercell.
        tol_r: tolerance. If abs(a-b) <r, they are seen as the same atom.
        ndim: number of dimensions. For 3D phonons, use ndim=3. For electrons(no spin), ndim=1. For spinors, use ndim=2 (TODO: spinor not tested. is it correct?).
        labels: labels of the basis. for 3D phonons, ndim can be set to 1 alternately, with labels set to ['x','y','z']*natoms. The labels are used to decide if two basis are identical by translation. (Not used for phonon)
        compare: how to decide the basis are identical (Not used for phonon)
        ghost_atoms: scaled positions of ghost atoms in case of vacancies.
        """
        self._atoms = atoms
        self._scmat = supercell_matrix
        self._evecs = eigenvectors
        self._qpts = qpoints
        self._tol_r = tol_r
        self._ndim = ndim
        self._labels = labels
        self._trans_rs = None
        self._trans_indices = None

        if ghost_atoms is not None:
            print("adding ghosts")
            symbols = atoms.get_chemical_symbols()
            positions = list(atoms.get_scaled_positions())
            cell = atoms.get_cell()
            for gatom in ghost_atoms:
                # sorry Rn, you are the chosen one to be the ghost. unlikely to appear in a phonon calculation.
                symbols.append('C')
                positions.append(gatom)
            self._atoms = Atoms(symbols, scaled_positions=positions, cell=cell)
            # set the eigenvectors to zeros for the ghosts.
            nkpt, nbranch, neigdim = self._evecs.shape
            evecs = np.zeros((nkpt, nbranch+ 3 * len(ghost_atoms), neigdim + 3 * len(ghost_atoms)), dtype=self._evecs.dtype)
            evecs[:,:neigdim, :neigdim]=self._evecs
            self._evecs=evecs
        self._make_translate_maps()
        self._phase = phase

    def _translate(self, evec, r):
        """
        T(r) psi: r is integer numbers of primitive cell lattice matrix.
        Params:
        =================
        evec: an eigen vector of supercell
        r: The translate vector

        Returns:
        ================
         tevec: translated vector.
        """
        pass

    def _make_translate_maps(self):
        """
        find the mapping between supercell and translated cell.
        Returns:
        ===============
        A N * (ndim*natoms) array.
        index[i] is the mapping from supercell to translated supercell so that
        T(r_i) psi = psi[indices[i]].

        TODO: vacancies/add_atoms not supported. How to do it? For vacancies, a ghost atom can be added. For add_atom, maybe we can just ignore them? Will it change the energy spectrum?
        """
        a1 = Atoms(symbols='H', positions=[(0, 0, 0)], cell=[1, 1, 1])
        sc = make_supercell(a1, self._scmat)
        rs = sc.get_scaled_positions()
        positions = np.array(self._atoms.get_scaled_positions())
        indices = np.zeros(
            [len(rs), len(positions) * self._ndim], dtype='int32')
        for i, ri in enumerate(rs):
            inds = []
            Tpositions = positions + np.array(ri)
            close_to_int = lambda x: np.all(np.abs(x - np.round(x)) < self._tol_r)
            for i_atom, pos in enumerate(positions):
                jatoms=None
                d=100000
                for j_atom, Tpos in enumerate(Tpositions):
                    dpos = Tpos - pos
                    dj=np.linalg.norm(dpos - np.round(dpos))
                    if dj<d:
                        d=dj
                        jatom=j_atom
                    #if close_to_int(dpos):
                #indices[i, j_atom * self._ndim:j_atom * self._ndim +
                #                self._ndim] = np.arange(
                #                    i_atom * self._ndim,
                #                    i_atom * self._ndim + self._ndim)
                indices[i, jatom * self._ndim:jatom * self._ndim +
                                self._ndim] = np.arange(
                                    i_atom * self._ndim,
                                    i_atom * self._ndim + self._ndim)


        self._trans_rs = rs
        self._trans_indices = indices
        print(indices)
        for ind in indices:
            print(len(ind), len(set(ind)))

    def get_weight(self, evec, qpt, G=np.array([0, 0, 0])):
        """
        get the weight of a mode which has the wave vector of qpt and eigenvector of evec.
        W= sum_1^N < evec| T(r_i)exp(-I (K+G) * r_i| evec>, here G=0. T(r_i)exp(-I K r_i)| evec> = evec[indices[i]]
        """
        weight = 0j
        N = len(self._trans_rs)
        for r_i, ind in zip(self._trans_rs, self._trans_indices):
            if self._phase:
                #weight += np.vdot(evec, evec[ind]*np.exp(-1j * np.dot(qpt+G,r_i)) ) /N
                #r_i =np.dot(self._scmat,r_i)
                weight += np.vdot(evec, evec[ind]) * np.exp(
                    -1j * 2 * np.pi * np.dot(qpt + G, r_i)) / N
            else:
                weight += (np.vdot(evec, evec[ind]) ) / N * np.exp(
                    -1j * 2 * np.pi * np.dot(G, r_i))

        return weight.real

    def get_weights(self):
        """
        Get the weight for all the modes.
        """
        nqpts, nfreqs = self._evecs.shape[0], self._evecs.shape[1]
        weights = np.zeros([nqpts, nfreqs])
        for iqpt in range(nqpts):
            for ifreq in range(nfreqs):
                weights[iqpt, ifreq] = self.get_weight(
                    self._evecs[iqpt, :, ifreq], self._qpts[iqpt])

        self._weights = weights
        return self._weights