Example #1
0
def show_rotational_invariance(force_constants,
                               supercell,
                               symprec=1e-5,
                               log_level=1):
    """
    *** Under development ***
    Just show how force constant is close to the condition of rotational invariance,
    """
    print "Check rotational invariance ..."

    fc = force_constants
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    volume_unitcell = supercell.get_volume() * len(unit_atoms) / supercell.get_number_of_atoms()
    abc = "xyz"
    eijk = np.zeros((3,3,3), dtype="intc")
    eijk[0,1,2] = eijk[1,2,0] = eijk[2,0,1] = 1
    eijk[0,2,1] = eijk[2,1,0] = eijk[1,0,2] = -1 # epsilon matrix, which is an antisymmetric 3 * 3 * 3 tensor

    stress = np.zeros((3, 3), dtype='double')
    for pi, p in enumerate(unit_atoms):
        for i in range(3):
            mat = np.zeros((3, 3), dtype='double')
            for s in range(supercell.get_number_of_atoms()):
                vecs = np.array(get_equivalent_smallest_vectors(
                        s, p, supercell, supercell.get_cell(), symprec))
                m = len(vecs)
                v = np.dot(vecs[:,:].sum(axis=0) / m, supercell.get_cell())
                for j in range(3):
                    for k in range(3):
                        mat[j, k] += (fc[p, s, i, j] * v[k] -
                                      fc[p, s, i, k] * v[j])
            stress += np.abs(mat)
            if log_level == 2:
                print "Atom %d %s" % (p+1, abc[i])
                for vec in mat:
                    print "%10.5f %10.5f %10.5f" % tuple(vec)
    if log_level == 1:
        print "System stress residue enduced by rigid-body rotations(eV/A)"
        for vec in stress:
            print "%10.5f %10.5f %10.5f" % tuple(vec)

    ElasticConstants = np.zeros((3,3,3,3), dtype='double')
    for s1 in unit_atoms:
        for s2 in range(supercell.get_number_of_atoms()):
            vec12s = np.array(get_equivalent_smallest_vectors(
                    s2, s1, supercell, supercell.get_cell(), symprec))
            vec12s = np.dot(vec12s, supercell.get_cell())
            for v12 in vec12s:
                ElasticConstants += -np.einsum('ij, k, l->ijkl', fc[s1, s2], v12, v12)  / len(vec12s) / 2.
    ElasticConstants = ElasticConstants.reshape(9,9)
    non_sym_tensor = ElasticConstants - ElasticConstants.T
    if log_level == 2:
        print 'Born-Huang rotational invariance condition (eV)'
        for i in range(9):
            print "%10.5f " * 9 %tuple(non_sym_tensor[i])
    elif log_level == 1:
        M_sum = np.abs(non_sym_tensor).sum()
        print 'Born-Huang rotational invariance condition (eV): %10.5f' %M_sum
    def run(self, atom_pairs):
        s2p = self._primitive.get_supercell_to_primitive_map()
        p2p = self._primitive.get_primitive_to_primitive_map()
        dists = np.zeros((len(self._temperatures), len(atom_pairs)),
                         dtype=float)
        for i, (atom1, atom2) in enumerate(atom_pairs):
            patom1 = p2p[s2p[atom1]]
            patom2 = p2p[s2p[atom2]]
            delta_r = get_equivalent_smallest_vectors(
                atom2, atom1, self._supercell, self._primitive.get_cell(),
                self._symprec)[0]

            self._project_eigenvectors(delta_r, self._primitive.get_cell())

            for freqs, vecs, q in zip(self._frequencies, self._p_eigenvectors,
                                      self._qpoints):
                c_cross = 1.0 / np.sqrt(
                    self._masses[patom1] * self._masses[patom2])
                c1 = 1.0 / self._masses[patom1]
                c2 = 1.0 / self._masses[patom2]

                for f, v in zip(freqs, vecs.T):
                    cross_term = self._get_cross(v, delta_r, q, patom1, patom2)
                    v2 = abs(v)**2
                    if f > self._cutoff_frequency:
                        for j, t in enumerate(self._temperatures):
                            dists[j, i] += self.get_Q2(f, t) * (
                                v2[patom1] * c1 + cross_term * c_cross +
                                v2[patom2] * c2)

        self._atom_pairs = atom_pairs
        self._distances = dists / len(self._frequencies)
Example #3
0
def rotational_invariance(force_constants,
                          supercell,
                          primitive,
                          symprec=1e-5):
    """
    *** Under development ***
    Just show how force constant is close to the condition of rotational invariance,
    """
    print("Check rotational invariance ...")

    fc = force_constants 
    p2s = primitive.get_primitive_to_supercell_map()

    abc = "xyz"
    
    for pi, p in enumerate(p2s):
        for i in range(3):
            mat = np.zeros((3, 3), dtype='double')
            for s in range(supercell.get_number_of_atoms()):
                vecs = np.array(get_equivalent_smallest_vectors(
                    s, p, supercell, primitive.get_cell(), symprec))
                m = len(vecs)
                v = np.dot(vecs[:,:].sum(axis=0) / m, primitive.get_cell())
                for j in range(3):
                    for k in range(3):
                        mat[j, k] += (fc[p, s, i, j] * v[k] -
                                      fc[p, s, i, k] * v[j])

            print("Atom %d %s" % (p + 1, abc[i]))
            for vec in mat:
                print("%10.5f %10.5f %10.5f" % tuple(vec))
Example #4
0
def get_trim_fc2(supercell,
                 trans,
                 coeff,
                 ifc_map,
                 symprec,
                 precision=1e-5,
                 pairs_included=None,
                 is_trim_boundary=False):
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred = trans.shape[-1]
    ti_transforms =[np.zeros(num_irred)]
    for i, atom1 in enumerate(unit_atoms):
        for atom2 in np.arange(natom):
            is_trim = False
            if pairs_included is not None and not pairs_included[ifc_map[atom1, atom2]]:
                is_trim = True
            if is_trim_boundary:
                dist = get_equivalent_smallest_vectors(atom2, atom1, supercell, supercell.get_cell(), symprec=symprec)
                if len(dist) > 1:
                    is_trim = True
            if is_trim:
                irred_doublet = ifc_map[atom1, atom2]
                ti_transform = np.dot(coeff[atom1, atom2], trans[irred_doublet])
                for k in range(9):
                    if not (np.abs(ti_transform[k])< precision).all():
                        argmax = np.argmax(np.abs(ti_transform[k]))
                        ti_transform[k] /= ti_transform[k, argmax]
                        is_exist = np.all(np.abs(ti_transform[k] - np.array(ti_transforms)) < precision, axis=1)
                        if (is_exist == False).all():
                            ti_transforms.append(ti_transform[k] / ti_transform[k, argmax])

    print "Number of constraints of fc2 from a cutoff of interaction distance:%d"%len(ti_transforms)
    CC, transform, independent = gaussian(np.array(ti_transforms), precision)
    return independent, transform
Example #5
0
    def set_thermal_distances( self, atom_pairs ):
        s2p = self.primitive.get_supercell_to_primitive_map()
        p2p = self.primitive.get_primitive_to_primitive_map()
        dists = np.zeros( ( len( self.temperatures), len( atom_pairs ) ), dtype=float )
        for i, ( atom1, atom2 ) in enumerate( atom_pairs ):
            patom1 = p2p[s2p[atom1]]
            patom2 = p2p[s2p[atom2]]
            delta_r = ( get_equivalent_smallest_vectors( atom2,
                                                         atom1,
                                                         self.supercell,
                                                         self.primitive.get_cell(),
                                                         self.symprec ) )[0]

            self.project_eigenvectors( delta_r, self.primitive.get_cell() )
            
            for eigs, vecs, q, w in zip( self.eigenvalues,
                                         self.p_eigenvectors,
                                         self.qpoints,
                                         self.weights ):
                c_cross = w / ( np.sqrt( self.masses[patom1] * self.masses[patom2] ) * AMU )
                c1 = w / ( self.masses[patom1] * AMU )
                c2 = w / ( self.masses[patom2] * AMU )

                for e, v in zip( eigs, vecs.T ):
                    cross_term = self.__get_cross( v, delta_r, q, patom1, patom2 )
                    v2 = abs(v)**2
                    if e > self.cutoff_eigenvalue:
                        omega = np.sqrt( e ) * self.factor # To THz
                        for j, t in enumerate( self.temperatures ):
                            dists[j,i] += self.get_Q2( omega, t ) * ( v2[patom1] * c1 + cross_term * c_cross + v2[patom2] * c2 )
            
        self.atom_pairs = atom_pairs
        self.distances = dists / self.weights.sum()
    def test(self):
        natoms = self._atoms.get_number_of_atoms()
        symprec = 1e-6

        dt_old = 0.0
        dt_new = 0.0
        for i in range(natoms):
            for j in range(natoms):
                t0 = time.time()
                tmp0 = get_equivalent_smallest_vectors(i, j, self._atoms,
                                                       self._primitive_matrix,
                                                       symprec)
                t1 = time.time()
                dt_old += t1 - t0

                t0 = time.time()
                tmp1 = get_equivalent_smallest_vectors_np(
                    i, j, self._atoms, self._primitive_matrix, symprec)
                t1 = time.time()
                dt_new += t1 - t0

                print(tmp0)
                print(tmp1)
                self.assertTrue(np.array_equal(tmp0, tmp1))
        print(dt_old)
        print(dt_new)
Example #7
0
    def run(self, atom_pairs):
        s2p = self._primitive.get_supercell_to_primitive_map()
        p2p = self._primitive.get_primitive_to_primitive_map()
        dists = np.zeros((len(self._temperatures), len(atom_pairs)), dtype=float)
        for i, (atom1, atom2) in enumerate(atom_pairs):
            patom1 = p2p[s2p[atom1]]
            patom2 = p2p[s2p[atom2]]
            delta_r = get_equivalent_smallest_vectors(atom2,
                                                      atom1,
                                                      self._supercell,
                                                      self._primitive.get_cell(),
                                                      self._symprec)[0]

            self._project_eigenvectors(delta_r, self._primitive.get_cell())
            
            for freqs, vecs, q in zip(self._frequencies,
                                      self._p_eigenvectors,
                                      self._qpoints):
                c_cross = 1.0 / np.sqrt(self._masses[patom1] *
                                        self._masses[patom2])
                c1 = 1.0 / self._masses[patom1]
                c2 = 1.0 / self._masses[patom2]

                for f, v in zip(freqs, vecs.T):
                    cross_term = self._get_cross(v, delta_r, q, patom1, patom2)
                    v2 = abs(v)**2
                    if f > self._cutoff_frequency:
                        for j, t in enumerate(self._temperatures):
                            dists[j, i] += self.get_Q2(f, t) * (
                                v2[patom1] * c1 + cross_term * c_cross + v2[patom2] * c2)
            
        self._atom_pairs = atom_pairs
        self._distances = dists / len(self._frequencies)
Example #8
0
def rotational_invariance(force_constants,
                          supercell,
                          primitive,
                          symprec=1e-5):
    """
    *** Under development ***
    Just show how force constant is close to the condition of rotational invariance,
    """
    print("Check rotational invariance ...")

    fc = force_constants
    p2s = primitive.get_primitive_to_supercell_map()

    abc = "xyz"

    for pi, p in enumerate(p2s):
        for i in range(3):
            mat = np.zeros((3, 3), dtype='double')
            for s in range(supercell.get_number_of_atoms()):
                vecs = np.array(get_equivalent_smallest_vectors(
                    s, p, supercell, primitive.get_cell(), symprec))
                m = len(vecs)
                v = np.dot(vecs[:,:].sum(axis=0) / m, primitive.get_cell())
                for j in range(3):
                    for k in range(3):
                        mat[j, k] += (fc[p, s, i, j] * v[k] -
                                      fc[p, s, i, k] * v[j])

            print("Atom %d %s" % (p + 1, abc[i]))
            for vec in mat:
                print("%10.5f %10.5f %10.5f" % tuple(vec))
Example #9
0
def rotational_invariance(force_constants,
                          supercell,
                          primitive,
                          symprec=1e-5):
    """
    *** Under development ***
    Just show how force constant is close to the condition of rotational invariance,
    """
    print "Check rotational invariance ..."

    fc = force_constants
    p2s = primitive.get_primitive_to_supercell_map()
    abc = "xyz"
    eijk = np.zeros((3,3,3), dtype="intc")
    eijk[0,1,2] = eijk[1,2,0] = eijk[2,0,1] = 1
    eijk[0,2,1] = eijk[2,1,0] = eijk[1,0,2] = -1 # epsilon matrix, which is an antisymmetric 3 * 3 * 3 tensor
    for pi, p in enumerate(p2s):
        for i in range(3):
            mat = np.zeros((3, 3), dtype='double')
            for s in range(supercell.get_number_of_atoms()):
                vecs = np.array(get_equivalent_smallest_vectors(
                        s, p, supercell, primitive.get_cell(), symprec))
                m = len(vecs)
                v = np.dot(vecs[:,:].sum(axis=0) / m, primitive.get_cell())
                for j in range(3):
                    for k in range(3):
                        mat[j, k] += (fc[p, s, i, j] * v[k] -
                                      fc[p, s, i, k] * v[j])

            print "Atom %d %s" % (p+1, abc[i])
            for vec in mat:
                print "%10.5f %10.5f %10.5f" % tuple(vec)

    Momentum = np.zeros((3,3,3,3), dtype='double')
    for s1 in p2s:
        for s2 in range(supercell.get_number_of_atoms()):
            vec12s = np.array(get_equivalent_smallest_vectors(
                    s2, s1, supercell, supercell.get_cell(), symprec))
            vec12s = np.dot(vec12s, supercell.get_cell())
            for v12 in vec12s:
                Momentum += -np.einsum('ij, k, l->ijkl', fc[s1, s2], v12, v12)  / len(vec12s) / 4.
    Momentum = Momentum.reshape(9,9)
    Momentum = Momentum - Momentum.T
    print 'Huang rotational invariance condition (eV)'
    for i in range(9):
        print "%10.5f " * 9 %tuple(Momentum[i])
Example #10
0
def get_trim_fc3(supercell,
                 trans,
                 triplets_reduced,
                 symprec,
                 precision=1e-5,
                 triplets_included=None,
                 is_trim_boundary=False):
    num_irred = trans[0].shape[-1]
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    zero_fc3s =[np.zeros(num_irred, dtype='double')]
    for i, (atom1, atom2, atom3) in enumerate(triplets_reduced):
        first = np.where(atom1 == unit_atoms)[0][0]
        is_trim = False
        if triplets_included is not None and not triplets_included[i]:
            is_trim = True
        if is_trim_boundary:
            dist12 = get_equivalent_smallest_vectors(atom2, atom1, supercell, supercell.get_cell(), symprec=symprec)
            dist23 = get_equivalent_smallest_vectors(atom3, atom2, supercell, supercell.get_cell(), symprec=symprec)
            dist13 = get_equivalent_smallest_vectors(atom3, atom1, supercell, supercell.get_cell(), symprec=symprec)
            if len(dist12) > 1 or len(dist23) > 1 or len(dist13) > 1:
                is_trim = True
        if is_trim:
            import scipy.sparse
            if scipy.sparse.issparse(trans[i]):
                zero_fc3 = trans[i].toarray()
            else:
                zero_fc3 = trans[i]
            for k in range(27):
                if not (np.abs(zero_fc3[k])< precision).all():
                    argmax = np.argmax(np.abs(zero_fc3[k]))
                    zero_fc3[k] /= zero_fc3[k, argmax]
                    is_exist = np.all(np.abs(zero_fc3[k] - np.array(zero_fc3s)) < precision, axis=1)
                    if (is_exist == False).all():
                        zero_fc3s.append(zero_fc3[k] / zero_fc3[k, argmax])
    print "Number of constraints of fc3 from a cutoff of interaction distance:%d"% (len(zero_fc3s) - 1)
    try:
        import _mdfc
        transform = np.zeros((num_irred, num_irred), dtype='double')
        independent = np.zeros(num_irred, dtype='intc')
        num_independent = _mdfc.gaussian(transform, np.array(zero_fc3s, dtype='double'), independent, precision)
        transform = transform[:, :num_independent]
        independent = independent[:num_independent]
    except ImportError:
        CC, transform, independent = gaussian_py(np.array(zero_fc3s, dtype='double'), prec=precision)
    return independent, transform
Example #11
0
 def get_triplet_inclusion(self, triplets=None):
     lattice = self._cell.get_cell()
     include_triplet = np.ones(len(triplets), dtype=bool)
     for i, (a1, a2, a3) in enumerate(triplets):
         d12 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a2, a1, self._cell, lattice, self._symprec)[0], lattice))
         d23 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a3, a2, self._cell, lattice, self._symprec)[0], lattice))
         d13 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a3, a1, self._cell, lattice, self._symprec)[0], lattice))
         if d12 > self._cut_radius[a1] + self._cut_radius[a2] and\
             d23 > self._cut_radius[a2] + self._cut_radius[a3] and\
             d13 > self._cut_radius[a1] + self._cut_radius[a3]:
             include_triplet[i] = False
     return include_triplet
Example #12
0
 def get_triplet_inclusion(self, triplets=None):
     lattice = self._cell.get_cell()
     include_triplet = np.ones(len(triplets), dtype=bool)
     for i, (a1, a2, a3) in enumerate(triplets):
         d12 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a2, a1, self._cell, lattice, self._symprec)[0], lattice))
         d23 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a3, a2, self._cell, lattice, self._symprec)[0], lattice))
         d13 = \
             np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                     a3, a1, self._cell, lattice, self._symprec)[0], lattice))
         if d12 > self._cut_radius[a1] + self._cut_radius[a2] and\
             d23 > self._cut_radius[a2] + self._cut_radius[a3] and\
             d13 > self._cut_radius[a1] + self._cut_radius[a3]:
             include_triplet[i] = False
     return include_triplet
Example #13
0
 def set_pair_distances(self):
     num_atom = self._cell.get_number_of_atoms()
     lattice = self._cell.get_cell()
     min_distances = np.zeros((num_atom, num_atom), dtype='double')
     for i in range(num_atom): # run in cell
         for j in range(i): # run in primitive
             min_distances[i, j] = np.linalg.norm(np.dot(
                     get_equivalent_smallest_vectors(
                         i, j, self._cell, lattice, self._symprec)[0], lattice))
     self._pair_distances = (min_distances + min_distances.T) / 2.
Example #14
0
def get_fc3_rotational_invariance(fc2,
                                  supercell,
                                  trans,
                                  coeff,
                                  ifc_map,
                                  symprec=1e-5,
                                  precision=1e-6):
    "Returning the constraint equations to be used in Lagrangian Multipliers"
    precision *= 1e2
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred = trans[0].shape[-1]
    lattice = supercell.get_cell()
    eijk = np.zeros((3, 3, 3), dtype="intc")
    eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
    eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[
        1, 0,
        2] = -1  # epsilon matrix, which is an antisymmetric 3 * 3 * 3 tensor
    torques = [np.zeros(num_irred + 1)]  # considering the constant column
    for i, atom1 in enumerate(unit_atoms):
        for atom2 in range(natom):
            torque = np.zeros((27, num_irred), dtype=np.float)
            t2_1 = np.einsum("cb, cav -> abv", fc2[atom1, atom2],
                             eijk).flatten()
            t2_2 = np.einsum("ac, cbv -> abv", fc2[atom1, atom2],
                             eijk).flatten()
            torque_fc2 = t2_1 + t2_2
            for atom3 in range(natom):
                fc_temp = mat_dot_product(coeff[i, atom2, atom3],
                                          trans[ifc_map[i, atom2, atom3]],
                                          is_sparse=True).reshape(3, 3, 3, -1)
                vectors = get_equivalent_smallest_vectors(
                    atom3, atom1, supercell, lattice, symprec)
                r_frac = np.array(vectors).sum(axis=0) / len(vectors)
                r = np.dot(r_frac, lattice)
                disp = np.einsum("j, ijk -> ik", r, eijk)
                t3 = np.einsum("abcN, cv -> abvN", fc_temp,
                               disp).reshape(27, num_irred)
                torque += t3
            torque = np.hstack(
                (torque,
                 -torque_fc2[:, np.newaxis]))  #negative sign means Bx = d
            for k in range(27):
                if not (np.abs(torque[k]) < precision).all():
                    argmax = np.argmax(np.abs(torque[k]))
                    torque[k] /= torque[k, argmax]
                    is_exist = np.all(
                        np.abs(torque[k] - np.array(torques)) < precision,
                        axis=1)
                    if (is_exist == False).all():
                        torques.append(torque[k] / torque[k, argmax])
    print "Number of constraints of IFC3 from rotational invariance:%d" % (
        len(torques) - 1)
    torques = np.array(torques)[1:]
    return torques[:, :-1], torques[:, -1]  # return B and d
Example #15
0
 def get_pair_inclusion(self, pairs=None):
     lattice = self._cell.get_cell()
     include_pair = np.ones(len(pairs), dtype=bool)
     if self._cut_radius_species is not None:
         for i, (a1, a2) in enumerate(pairs):
             distance = \
                 np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                         a2, a1, self._cell, lattice, self._symprec)[0], lattice))
             if distance > self._cut_radius[a1] + self._cut_radius[a2]:
                 include_pair[i] = False
     return include_pair
Example #16
0
 def set_pair_distances(self):
     num_atom = self._cell.get_number_of_atoms()
     lattice = self._cell.get_cell()
     self._pair_distances = np.zeros((num_atom, num_atom), dtype='double')
     for i in range(num_atom):
         for j in range(i):
             dist = np.linalg.norm(np.dot(
                     get_equivalent_smallest_vectors(
                         i, j, self._cell, lattice, self._symprec)[0], lattice))
             self._pair_distances[i, j] = dist
             self._pair_distances[j, i] = dist
Example #17
0
 def get_pair_inclusion(self, pairs=None):
     lattice = self._cell.get_cell()
     include_pair = np.ones(len(pairs), dtype=bool)
     if self._cut_radius_species is not None:
         for i, (a1, a2) in enumerate(pairs):
             distance = \
                 np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                         a2, a1, self._cell, lattice, self._symprec)[0], lattice))
             if distance > self._cut_radius[a1] + self._cut_radius[a2]:
                 include_pair[i] = False
     return include_pair
Example #18
0
 def set_pair_distances(self):
     num_atom = self._cell.get_number_of_atoms()
     lattice = self._cell.get_cell()
     min_distances = np.zeros((num_atom, num_atom), dtype='double')
     for i in range(num_atom):  # run in cell
         for j in range(i):  # run in primitive
             min_distances[i, j] = np.linalg.norm(
                 np.dot(
                     get_equivalent_smallest_vectors(
                         i, j, self._cell, lattice, self._symprec)[0],
                     lattice))
     self._pair_distances = (min_distances + min_distances.T) / 2.
Example #19
0
def cutoff_fc3_by_zero(fc3, supercell, cutoff_distance, symprec=1e-5):
    num_atom = supercell.get_number_of_atoms()
    lattice = supercell.get_cell()
    min_distances = np.zeros((num_atom, num_atom), dtype='double')
    for i in range(num_atom): # run in supercell
        for j in range(num_atom): # run in primitive
            min_distances[i, j] = np.linalg.norm(np.dot(
                    get_equivalent_smallest_vectors(
                        i, j, supercell, lattice, symprec)[0], lattice))

    for i, j, k in np.ndindex(num_atom, num_atom, num_atom):
        for pair in ((i, j), (j, k), (k, i)):
            if min_distances[pair] > cutoff_distance:
                fc3[i, j, k] = 0
                break
Example #20
0
def cutoff_fc3_by_zero(fc3, supercell, cutoff_distance, symprec=1e-5):
    num_atom = supercell.get_number_of_atoms()
    lattice = supercell.get_cell()
    min_distances = np.zeros((num_atom, num_atom), dtype='double')
    for i in range(num_atom): # run in supercell
        for j in range(num_atom): # run in primitive
            min_distances[i, j] = np.linalg.norm(np.dot(
                    get_equivalent_smallest_vectors(
                        i, j, supercell, lattice, symprec)[0], lattice))
            
    for i, j, k in np.ndindex(num_atom, num_atom, num_atom):
        for pair in ((i, j), (j, k), (k, i)):
            if min_distances[pair] > cutoff_distance:
                fc3[i, j, k] = 0
                break
Example #21
0
def get_trim_fc2(supercell,
                 trans,
                 coeff,
                 ifc_map,
                 symprec,
                 precision=1e-5,
                 pairs_included=None,
                 is_trim_boundary=False):
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred = trans.shape[-1]
    ti_transforms = [np.zeros(num_irred)]
    for i, atom1 in enumerate(unit_atoms):
        for atom2 in np.arange(natom):
            is_trim = False
            if pairs_included is not None and not pairs_included[ifc_map[
                    atom1, atom2]]:
                is_trim = True
            if is_trim_boundary:
                dist = get_equivalent_smallest_vectors(atom2,
                                                       atom1,
                                                       supercell,
                                                       supercell.get_cell(),
                                                       symprec=symprec)
                if len(dist) > 1:
                    is_trim = True
            if is_trim:
                irred_doublet = ifc_map[atom1, atom2]
                ti_transform = np.dot(coeff[atom1, atom2],
                                      trans[irred_doublet])
                for k in range(9):
                    if not (np.abs(ti_transform[k]) < precision).all():
                        argmax = np.argmax(np.abs(ti_transform[k]))
                        ti_transform[k] /= ti_transform[k, argmax]
                        is_exist = np.all(
                            np.abs(ti_transform[k] - np.array(ti_transforms)) <
                            precision,
                            axis=1)
                        if (is_exist == False).all():
                            ti_transforms.append(ti_transform[k] /
                                                 ti_transform[k, argmax])

    print "Number of constraints of fc2 from a cutoff of interaction distance:%d" % len(
        ti_transforms)
    CC, transform, independent = gaussian(np.array(ti_transforms), precision)
    return independent, transform
Example #22
0
 def _get_rotational_invariance_matrix(self, patom_num):
     rimat = np.zeros((9, 9 * self._num_atom + 3), dtype='double')
     rimat[:9, :3] = [[0, 0, 0], [-1, 0, 0], [1, 0, 0], [0, 1,
                                                         0], [0, 0, 0],
                      [0, -1, 0], [0, 0, -1], [0, 0, 1], [0, 0, 0]]
     for i in range(self._num_atom):
         vectors = get_equivalent_smallest_vectors(i, patom_num,
                                                   self._scell,
                                                   self._lattice.T,
                                                   self._symprec)
         r_frac = np.array(vectors).sum(axis=0) / len(vectors)
         r = np.dot(self._lattice, r_frac)
         rimat_each = np.kron(
             np.eye(3),
             [[0, r[2], -r[1]], [-r[2], 0, r[0]], [r[1], -r[0], 0]])
         rimat[:, (i * 9 + 3):((i + 1) * 9 + 3)] = rimat_each
     return rimat
Example #23
0
 def _get_rotational_invariance_matrix(self, patom_num):
     rimat = np.zeros((9, 9 * self._num_atom + 3), dtype="double")
     rimat[:9, :3] = [
         [0, 0, 0],
         [-1, 0, 0],
         [1, 0, 0],
         [0, 1, 0],
         [0, 0, 0],
         [0, -1, 0],
         [0, 0, -1],
         [0, 0, 1],
         [0, 0, 0],
     ]
     for i in range(self._num_atom):
         vectors = get_equivalent_smallest_vectors(i, patom_num, self._scell, self._lattice.T, self._symprec)
         r_frac = np.array(vectors).sum(axis=0) / len(vectors)
         r = np.dot(self._lattice, r_frac)
         rimat_each = np.kron(np.eye(3), [[0, r[2], -r[1]], [-r[2], 0, r[0]], [r[1], -r[0], 0]])
         rimat[:, (i * 9 + 3) : ((i + 1) * 9 + 3)] = rimat_each
     return rimat
Example #24
0
def get_fc3_rotational_invariance(fc2, supercell, trans, coeff, ifc_map, symprec=1e-5, precision=1e-6):
    "Returning the constraint equations to be used in Lagrangian Multipliers"
    precision *= 1e2
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred = trans[0].shape[-1]
    lattice = supercell.get_cell()
    eijk = np.zeros((3,3,3), dtype="intc")
    eijk[0,1,2] = eijk[1,2,0] = eijk[2,0,1] = 1
    eijk[0,2,1] = eijk[2,1,0] = eijk[1,0,2] = -1 # epsilon matrix, which is an antisymmetric 3 * 3 * 3 tensor
    torques =[np.zeros(num_irred + 1)] # considering the constant column
    for i, atom1 in enumerate(unit_atoms):
        for atom2 in range(natom):
            torque = np.zeros((27, num_irred), dtype=np.float)
            t2_1 = np.einsum("cb, cav -> abv", fc2[atom1, atom2], eijk).flatten()
            t2_2 = np.einsum("ac, cbv -> abv", fc2[atom1, atom2], eijk).flatten()
            torque_fc2 = t2_1 + t2_2
            for atom3 in range(natom):
                fc_temp = mat_dot_product(coeff[i, atom2, atom3], trans[ifc_map[i, atom2, atom3]], is_sparse=True).reshape(3, 3, 3, -1)
                vectors = get_equivalent_smallest_vectors(atom3,
                                                          atom1,
                                                          supercell,
                                                          lattice,
                                                          symprec)
                r_frac = np.array(vectors).sum(axis=0) / len(vectors)
                r = np.dot(r_frac, lattice)
                disp = np.einsum("j, ijk -> ik", r, eijk)
                t3 = np.einsum("abcN, cv -> abvN", fc_temp, disp).reshape(27, num_irred)
                torque += t3
            torque = np.hstack((torque, -torque_fc2[:, np.newaxis])) #negative sign means Bx = d
            for k in range(27):
                if not (np.abs(torque[k])< precision).all():
                    argmax = np.argmax(np.abs(torque[k]))
                    torque[k] /= torque[k, argmax]
                    is_exist = np.all(np.abs(torque[k] - np.array(torques)) < precision, axis=1)
                    if (is_exist == False).all():
                        torques.append(torque[k] / torque[k, argmax])
    print "Number of constraints of IFC3 from rotational invariance:%d"%(len(torques) - 1)
    torques = np.array(torques)[1:]
    return torques[:, :-1], torques[:, -1] # return B and d
Example #25
0
    def get_triplet_inclusion(self, triplets=None):
        if self._include_triplet is not None:
            return self._include_triplet
        else:
            lattice = self._cell.get_cell()
            if triplets is not None:
                include_triplet = np.ones(len(triplets), dtype=bool)
                for i, (a1, a2, a3) in enumerate(triplets):
                    d12 = \
                        np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                                a2, a1, self._cell, lattice, self._symprec)[0], lattice))
                    d23 = \
                        np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                                a3, a2, self._cell, lattice, self._symprec)[0], lattice))
                    d13 = \
                        np.linalg.norm(np.dot(get_equivalent_smallest_vectors(
                                a3, a1, self._cell, lattice, self._symprec)[0], lattice))
                    if d12 > self._cut_radius[a1] + self._cut_radius[a2] and\
                        d23 > self._cut_radius[a2] + self._cut_radius[a3] and\
                        d13 > self._cut_radius[a1] + self._cut_radius[a3]:
                        include_triplet[i] = False
            else:
                num_atom = self._cell.get_number_of_atoms()
                include_triplet= np.ones((num_atom, num_atom, num_atom), dtype=bool)
                if self._pair_distances is None:
                    self.set_pair_distances()
                for i in range(num_atom):
                    for j in range(i):
                        for k in range(j):
                            if (self._pair_distances[i,j] > self._cut_radius[i] + self._cut_radius[j] and
                                self._pair_distances[i,k] > self._cut_radius[i] + self._cut_radius[k] and
                                self._pair_distances[j,k] > self._cut_radius[j] + self._cut_radius[k]):
                                include_triplet[i, j, k] = False
                                include_triplet[i, k, j] = False
                                include_triplet[j, i, k] = False
                                include_triplet[j, k, i] = False
                                include_triplet[k, i, j] = False
                                include_triplet[k, j, i] = False
            self._include_triplet = include_triplet
            return include_triplet


#
# class Cutoff():
#     def __init__(self, species, cut_radius, cut_pair, cut_triplets):
#         self._cell = None
#         self._pair_distances = None
#         n = len(species)
#         if cut_radius is not None:
#             if len(cut_radius) == 1:
#                 self._cut_radius = [cut_radius[0] for i in range(n)]
#             elif len(cut_radius) == n:
#                 self._cut_radius = cut_radius
#             else:
#                 print_error_message("Cutoff radius number %d not equal the number of species %d!" %(len(cut_radius), n))
#         else:
#             self._cut_radius = None
#
#         # cutoff pair
#         cp = np.ones((n, n), dtype="float") * 10000
#         if cut_pair is not None:
#             if len(cut_pair) == (n +1) * n / 2:
#                 for i in range(n):
#                     for j in range(i,n):
#                         cp[i,j] = cp[j,i] = cut_pair.pop(0)
#                 self._cut_pair = cp
#             else:
#                 print_error_message("Cutoff pairs %d not equal to the number needed %d!" %(len(cut_pair), (n +1) * n / 2))
#         elif self._cut_radius is not None:
#             for i, j in np.ndindex((n,n)):
#                 cp[i,j] = self._cut_radius[i]+ self._cut_radius[j]
#             self._cut_pair = cp
#         else:
#             self._cut_pair = None
#
#         # cutoff triplet
#         ct = np.ones((n,n,n), dtype="float") * 10000
#         if cut_triplets is not None:
#             if len(cut_triplets) == n * (n + 1) * (n + 2) / 6:
#                 for i in range(n):
#                     for j in range(i,n):
#                         for k in range(j,n):
#                             ct[i,j,k] = ct[i,k,j] = ct[j,i,k] = ct[j,k,i] =\
#                                 ct[k,i,j] = ct[k,j,i] = cut_triplets.pop(0)
#                 self._cut_triplet = ct
#             else:
#                 print_error_message("Cutoff triplets %d not equal to the number needed %d!"\
#                                     %(len(cut_triplets), n * (n + 1) * (n + 2) / 6))
#         elif self._cut_pair is not None:
#             for i,j,k in np.ndindex((n,n,n)):
#                 ct[i,j,k] = min(self._cut_pair[i,j], self._cut_pair[i,k], self._cut_pair[j,k])
#             self._cut_triplet = ct
#         else:
#             self._cut_triplet = None
#
#     def set_cell(self, cell, symprec = 1e-5):
#         self._cell = cell
#         self._symprec = symprec
#         self._pair_distances = None
#
#     def get_cutoff_pair(self):
#         return self._cut_pair
#
#     def get_cutoff_radius(self):
#         return self._cut_radius
#
#     def get_cutoff_triplet(self):
#         return self._cut_triplet
#
#     def expand_pair(self):
#         unique_atoms, index_unique = np.unique(self._cell.get_atomic_numbers(), return_index=True)
#         unique_atoms = unique_atoms[np.argsort(index_unique)] # in order to keep the specie sequence unchanged
#         if self.get_cutoff_pair() is not None:
#             cutpair_expand = np.zeros((self._cell.get_number_of_atoms(), self._cell.get_number_of_atoms()), dtype="double")
#             for i in range(self._cell.get_number_of_atoms()):
#                 index_specie_i = np.where(unique_atoms == self._cell.get_atomic_numbers()[i])[0]
#                 for j in range(i, self._cell.get_number_of_atoms()):
#                     index_specie_j = np.where(unique_atoms == self._cell.get_atomic_numbers()[j])[0]
#                     cutpair_expand[i,j] = cutpair_expand[j,i] = self._cut_pair[index_specie_i, index_specie_j]
#         else:
#             cutpair_expand = None
#         return cutpair_expand
#
#     def expand_triplet(self):
#         natom = self._cell.get_number_of_atoms()
#         unique_atoms, index_unique = np.unique(self._cell.get_atomic_numbers(), return_index=True)
#         unique_atoms = unique_atoms[np.argsort(index_unique)] # in order to keep the specie sequence unchanged
#         if self.get_cutoff_triplet() is not None:
#             cut_triplet_expand = np.zeros((natom, natom, natom), dtype="double")
#             for i in range(natom):
#                 index_specie_i = np.where(unique_atoms == self._cell.get_atomic_numbers()[i])[0]
#                 for j in range(i, natom):
#                     index_specie_j = np.where(unique_atoms == self._cell.get_atomic_numbers()[j])[0]
#                     for k in range(j, natom):
#                         index_specie_k = np.where(unique_atoms == self._cell.get_atomic_numbers()[k])[0]
#                         cut_temp  = self._cut_triplet[index_specie_i, index_specie_j, index_specie_k]
#                         cut_triplet_expand[i,j,k] = cut_temp
#                         cut_triplet_expand[j,i,k] = cut_temp
#                         cut_triplet_expand[i,k,j] = cut_temp
#                         cut_triplet_expand[j,k,i] = cut_temp
#                         cut_triplet_expand[k,i,j] = cut_temp
#                         cut_triplet_expand[k,j,i] = cut_temp
#                         # cut_triplet_expand[i,j, k] =  self._cut_triplet[index_specie_i, index_specie_j, index_specie_k]
#         else:
#             cut_triplet_expand = None
#         return cut_triplet_expand
#
#     def set_pair_distances(self):
#         num_atom = self._cell.get_number_of_atoms()
#         lattice = self._cell.get_cell()
#
#         try:
#             from scipy.spatial.distance import cdist
#             positions = self._cell.get_scaled_positions()
#             positions_cart = self._cell.get_positions()
#             distances = []
#             for i in (-1, 0, 1):
#                 for j in (-1, 0, 1):
#                     for k in (-1, 0, 1):
#                         positions_trans = positions + np.array([i,j,k])
#                         positions_trans_cart = np.dot(positions_trans, lattice)
#                         distances.append(cdist(positions_cart, positions_trans_cart))
#             min_distances = np.min(np.array(distances), axis=0)
#         except ImportError:
#             min_distances = np.zeros((num_atom, num_atom), dtype='double')
#             for i in range(num_atom): # run in cell
#                 for j in range(num_atom): # run in primitive
#                     min_distances[i, j] = np.linalg.norm(np.dot(
#                             get_equivalent_smallest_vectors(
#                                 i, j, self._cell, lattice, self._symprec)[0], lattice))
#         self._pair_distances = min_distances
#
#     def get_pair_inclusion(self):
#         num_atom = self._cell.get_number_of_atoms()
#         cut_pair = self.expand_pair()
#         include_pair= np.ones((num_atom, num_atom), dtype=bool)
#         if self._pair_distances == None:
#             self.set_pair_distances()
#         for i, j in np.ndindex(num_atom, num_atom):
#             if cut_pair is not None:
#                 max_dist = max(self._pair_distances[i,j], self._pair_distances[j,i])
#                 if max_dist > cut_pair[i,j]:
#                     include_pair[i,j] = False
#         return include_pair
#
#     def get_triplet_inclusion(self):
#         num_atom = self._cell.get_number_of_atoms()
#         cut_triplet = self.expand_triplet()
#         include_triplet= np.ones((num_atom, num_atom, num_atom), dtype=bool)
#         if self._pair_distances == None:
#             self.set_pair_distances()
#         if cut_triplet is not None:
#             for i, j, k in np.ndindex(num_atom, num_atom, num_atom):
#                 max_dist = max(self._pair_distances[i,j], self._pair_distances[j,k],self._pair_distances[i,k])
#                 if max_dist > cut_triplet[i, j, k]:
#                     include_triplet[i,j, k] = False
#         return include_triplet
Example #26
0
def get_third_order_displacements(cell,
                                  symmetry,
                                  is_plusminus='auto',
                                  is_diagonal=False):
    # Atoms 1, 2, and 3 are defined as follows:
    #
    # Atom 1: The first displaced atom. Third order force constant
    #         between Atoms 1, 2, and 3 is calculated.
    # Atom 2: The second displaced atom. Second order force constant
    #         between Atoms 2 and 3 is calculated.
    # Atom 3: Force is mesuared on this atom.

    positions = cell.get_scaled_positions()
    lattice = cell.get_cell()

    # Least displacements for third order force constants in yaml file
    #
    # Data structure
    # [{'number': atom1,
    #   'displacement': [0.00000, 0.007071, 0.007071],
    #   'second_atoms': [ {'number': atom2,
    #                      'displacements': [[0.007071, 0.000000, 0.007071],
    #                                        [-0.007071, 0.000000, -0.007071]
    #                                        ,...]},
    #                     {'number': ... } ] },
    #  {'number': atom1, ... } ]

    # Least displacements of first atoms (Atom 1) are searched by
    # using respective site symmetries of the original crystal.
    disps_first = get_least_displacements(symmetry,
                                          is_plusminus=is_plusminus,
                                          is_diagonal=False)

    symprec = symmetry.get_symmetry_tolerance()

    dds = []
    for disp in disps_first:
        atom1 = disp[0]
        disp1 = disp[1:4]
        site_sym = symmetry.get_site_symmetry(atom1)

        dds_atom1 = {'number': atom1,
                     'direction': disp1,
                     'second_atoms': []}

        # Reduced site symmetry at the first atom with respect to 
        # the displacement of the first atoms.
        reduced_site_sym = get_reduced_site_symmetry(site_sym, disp1, symprec)
        # Searching orbits (second atoms) with respect to
        # the first atom and its reduced site symmetry.
        second_atoms = get_least_orbits(atom1,
                                        cell,
                                        reduced_site_sym,
                                        symprec)

        for atom2 in second_atoms:
            dds_atom2 = get_next_displacements(atom1,
                                               atom2,
                                               reduced_site_sym,
                                               positions,
                                               symprec,
                                               is_diagonal)
            min_distance = np.linalg.norm(
                np.dot(get_equivalent_smallest_vectors(
                        atom1,
                        atom2,
                        cell,
                        lattice,
                        symprec)[0], lattice))
            dds_atom2['distance'] = min_distance
            dds_atom1['second_atoms'].append(dds_atom2)
        dds.append(dds_atom1)
    
    return dds
Example #27
0
def get_fc2_rotational_invariance(supercell,
                                  trans,
                                  coeff,
                                  ifc_map,
                                  symprec,
                                  precision=1e-8,
                                  is_Huang=True): #Gazis-Wallis invariance
    positions = supercell.get_scaled_positions()
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred2 = trans.shape[-1]
    lattice = supercell.get_cell()
    eijk = np.zeros((3,3,3), dtype="intc")
    eijk[0,1,2] = eijk[1,2,0] = eijk[2,0,1] = 1
    eijk[0,2,1] = eijk[2,1,0] = eijk[1,0,2] = -1 # epsion matrix, which is an antisymmetric 3 * 3 * 3 tensor
    torques =[np.zeros(num_irred2)]
    for i, patom_num in enumerate(unit_atoms):
        force = np.zeros((27, num_irred2), dtype='double')
        for j in range(natom):
            fc_temp = np.dot(coeff[patom_num, j], trans[ifc_map[patom_num, j]]).reshape(3,3,-1)
            vectors = get_equivalent_smallest_vectors(j,
                                                      patom_num,
                                                      supercell,
                                                      lattice,
                                                      symprec)
            r_frac = np.array(vectors).sum(axis=0) / len(vectors)
            r = np.dot(r_frac, lattice)
            force_tmp = np.einsum('abN, c->abcN', fc_temp, r) - np.einsum('acN, b->abcN', fc_temp, r)
            force += force_tmp.reshape(27, -1)
        for k in range(27):
            if not (np.abs(force[k])< precision).all():
                argmax = np.argmax(np.abs(force[k]))
                force[k] /= force[k, argmax]
                is_exist = np.all(np.abs(force[k] - np.array(torques)) < precision, axis=1)
                if (is_exist == False).all():
                    torques.append(force[k] / force[k, argmax])
    print "Number of constraints of fc2 from rotational invariance:%d"%(len(torques)-1)
    CC, transform, independent = gaussian(np.array(torques), precision)
    if is_Huang:
        precision *= 1e2
        print "The Born-Huang invariance condition is also included in rotational symmetry"
        trans2 = mat_dot_product(trans, transform, is_sparse=True)
        num_irred2 = trans2.shape[-1]
        torques =[np.zeros(num_irred2)]
        unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
        torque_tmp = np.zeros((9, 9, num_irred2), dtype='double')
        for patom_num in unit_atoms:
            for j in range(natom):
                fc_temp = np.dot(coeff[patom_num, j], trans2[ifc_map[patom_num, j]])
                vectors12 = get_equivalent_smallest_vectors(j,
                                          patom_num,
                                          supercell,
                                          lattice,
                                          symprec)
                for r12 in vectors12:
                    v12 = np.dot(r12, lattice)
                    v12_outer = np.kron(v12, v12)
                    torque_tmp += np.einsum('iN, j->ijN', fc_temp, v12_outer) / len(vectors12)
        torque_tmp = torque_tmp - np.swapaxes(torque_tmp, 0, 1)
        torque_tmp = torque_tmp.reshape(-1, num_irred2)
        for i in range(81):
            if not (np.abs(torque_tmp[i])< precision).all():
                argmax = np.argmax(np.abs(torque_tmp[i]))
                torque_tmp[i] /= torque_tmp[i, argmax]
                is_exist = np.all(np.abs(torque_tmp[i] - np.array(torques)) < precision, axis=1)
                if (is_exist == False).all():
                    torques.append(torque_tmp[i] / torque_tmp[i, argmax])
        print "Number of constraints of fc2 from Born-Huang invariance condition:%d"%(len(torques)-1)
        CC, transform_gw, independent_gw = gaussian(np.array(torques), precision)

        independent = np.array([independent[i] for i in independent_gw])
        transform = np.dot(transform,transform_gw)
    return independent, transform
Example #28
0
def get_fc2_rotational_invariance(supercell,
                                  trans,
                                  coeff,
                                  ifc_map,
                                  symprec,
                                  precision=1e-8,
                                  is_Huang=True):  #Gazis-Wallis invariance
    positions = supercell.get_scaled_positions()
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    natom = supercell.get_number_of_atoms()
    num_irred2 = trans.shape[-1]
    lattice = supercell.get_cell()
    eijk = np.zeros((3, 3, 3), dtype="intc")
    eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
    eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[
        1, 0,
        2] = -1  # epsion matrix, which is an antisymmetric 3 * 3 * 3 tensor
    torques = [np.zeros(num_irred2)]
    for i, patom_num in enumerate(unit_atoms):
        force = np.zeros((27, num_irred2), dtype='double')
        for j in range(natom):
            fc_temp = np.dot(coeff[patom_num, j],
                             trans[ifc_map[patom_num, j]]).reshape(3, 3, -1)
            vectors = get_equivalent_smallest_vectors(j, patom_num, supercell,
                                                      lattice, symprec)
            r_frac = np.array(vectors).sum(axis=0) / len(vectors)
            r = np.dot(r_frac, lattice)
            force_tmp = np.einsum('abN, c->abcN', fc_temp, r) - np.einsum(
                'acN, b->abcN', fc_temp, r)
            force += force_tmp.reshape(27, -1)
        for k in range(27):
            if not (np.abs(force[k]) < precision).all():
                argmax = np.argmax(np.abs(force[k]))
                force[k] /= force[k, argmax]
                is_exist = np.all(
                    np.abs(force[k] - np.array(torques)) < precision, axis=1)
                if (is_exist == False).all():
                    torques.append(force[k] / force[k, argmax])
    print "Number of constraints of fc2 from rotational invariance:%d" % (
        len(torques) - 1)
    CC, transform, independent = gaussian(np.array(torques), precision)
    if is_Huang:
        precision *= 1e2
        print "The Born-Huang invariance condition is also included in rotational symmetry"
        trans2 = mat_dot_product(trans, transform, is_sparse=True)
        num_irred2 = trans2.shape[-1]
        torques = [np.zeros(num_irred2)]
        unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
        torque_tmp = np.zeros((9, 9, num_irred2), dtype='double')
        for patom_num in unit_atoms:
            for j in range(natom):
                fc_temp = np.dot(coeff[patom_num, j], trans2[ifc_map[patom_num,
                                                                     j]])
                vectors12 = get_equivalent_smallest_vectors(
                    j, patom_num, supercell, lattice, symprec)
                for r12 in vectors12:
                    v12 = np.dot(r12, lattice)
                    v12_outer = np.kron(v12, v12)
                    torque_tmp += np.einsum('iN, j->ijN', fc_temp,
                                            v12_outer) / len(vectors12)
        torque_tmp = torque_tmp - np.swapaxes(torque_tmp, 0, 1)
        torque_tmp = torque_tmp.reshape(-1, num_irred2)
        for i in range(81):
            if not (np.abs(torque_tmp[i]) < precision).all():
                argmax = np.argmax(np.abs(torque_tmp[i]))
                torque_tmp[i] /= torque_tmp[i, argmax]
                is_exist = np.all(
                    np.abs(torque_tmp[i] - np.array(torques)) < precision,
                    axis=1)
                if (is_exist == False).all():
                    torques.append(torque_tmp[i] / torque_tmp[i, argmax])
        print "Number of constraints of fc2 from Born-Huang invariance condition:%d" % (
            len(torques) - 1)
        CC, transform_gw, independent_gw = gaussian(np.array(torques),
                                                    precision)

        independent = np.array([independent[i] for i in independent_gw])
        transform = np.dot(transform, transform_gw)
    return independent, transform
Example #29
0
def show_rotational_invariance(force_constants,
                               supercell,
                               symprec=1e-5,
                               log_level=1):
    """
    *** Under development ***
    Just show how force constant is close to the condition of rotational invariance,
    """
    print "Check rotational invariance ..."

    fc = force_constants
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    volume_unitcell = supercell.get_volume() * len(
        unit_atoms) / supercell.get_number_of_atoms()
    abc = "xyz"
    eijk = np.zeros((3, 3, 3), dtype="intc")
    eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
    eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[
        1, 0,
        2] = -1  # epsilon matrix, which is an antisymmetric 3 * 3 * 3 tensor

    stress = np.zeros((3, 3), dtype='double')
    for pi, p in enumerate(unit_atoms):
        for i in range(3):
            mat = np.zeros((3, 3), dtype='double')
            for s in range(supercell.get_number_of_atoms()):
                vecs = np.array(
                    get_equivalent_smallest_vectors(s, p, supercell,
                                                    supercell.get_cell(),
                                                    symprec))
                m = len(vecs)
                v = np.dot(vecs[:, :].sum(axis=0) / m, supercell.get_cell())
                for j in range(3):
                    for k in range(3):
                        mat[j, k] += (fc[p, s, i, j] * v[k] -
                                      fc[p, s, i, k] * v[j])
            stress += np.abs(mat)
            if log_level == 2:
                print "Atom %d %s" % (p + 1, abc[i])
                for vec in mat:
                    print "%10.5f %10.5f %10.5f" % tuple(vec)
    if log_level == 1:
        print "System stress residue enduced by rigid-body rotations(eV/A)"
        for vec in stress:
            print "%10.5f %10.5f %10.5f" % tuple(vec)

    ElasticConstants = np.zeros((3, 3, 3, 3), dtype='double')
    for s1 in unit_atoms:
        for s2 in range(supercell.get_number_of_atoms()):
            vec12s = np.array(
                get_equivalent_smallest_vectors(s2, s1, supercell,
                                                supercell.get_cell(), symprec))
            vec12s = np.dot(vec12s, supercell.get_cell())
            for v12 in vec12s:
                ElasticConstants += -np.einsum('ij, k, l->ijkl', fc[s1, s2],
                                               v12, v12) / len(vec12s) / 2.
    ElasticConstants = ElasticConstants.reshape(9, 9)
    non_sym_tensor = ElasticConstants - ElasticConstants.T
    if log_level == 2:
        print 'Born-Huang rotational invariance condition (eV)'
        for i in range(9):
            print "%10.5f " * 9 % tuple(non_sym_tensor[i])
    elif log_level == 1:
        M_sum = np.abs(non_sym_tensor).sum()
        print 'Born-Huang rotational invariance condition (eV): %10.5f' % M_sum
Example #30
0
def get_trim_fc3(supercell,
                 trans,
                 triplets_reduced,
                 symprec,
                 precision=1e-5,
                 triplets_included=None,
                 is_trim_boundary=False):
    num_irred = trans[0].shape[-1]
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    zero_fc3s = [np.zeros(num_irred, dtype='double')]
    for i, (atom1, atom2, atom3) in enumerate(triplets_reduced):
        first = np.where(atom1 == unit_atoms)[0][0]
        is_trim = False
        if triplets_included is not None and not triplets_included[i]:
            is_trim = True
        if is_trim_boundary:
            dist12 = get_equivalent_smallest_vectors(atom2,
                                                     atom1,
                                                     supercell,
                                                     supercell.get_cell(),
                                                     symprec=symprec)
            dist23 = get_equivalent_smallest_vectors(atom3,
                                                     atom2,
                                                     supercell,
                                                     supercell.get_cell(),
                                                     symprec=symprec)
            dist13 = get_equivalent_smallest_vectors(atom3,
                                                     atom1,
                                                     supercell,
                                                     supercell.get_cell(),
                                                     symprec=symprec)
            if len(dist12) > 1 or len(dist23) > 1 or len(dist13) > 1:
                is_trim = True
        if is_trim:
            import scipy.sparse
            if scipy.sparse.issparse(trans[i]):
                zero_fc3 = trans[i].toarray()
            else:
                zero_fc3 = trans[i]
            for k in range(27):
                if not (np.abs(zero_fc3[k]) < precision).all():
                    argmax = np.argmax(np.abs(zero_fc3[k]))
                    zero_fc3[k] /= zero_fc3[k, argmax]
                    is_exist = np.all(
                        np.abs(zero_fc3[k] - np.array(zero_fc3s)) < precision,
                        axis=1)
                    if (is_exist == False).all():
                        zero_fc3s.append(zero_fc3[k] / zero_fc3[k, argmax])
    print "Number of constraints of fc3 from a cutoff of interaction distance:%d" % (
        len(zero_fc3s) - 1)
    try:
        import _mdfc
        transform = np.zeros((num_irred, num_irred), dtype='double')
        independent = np.zeros(num_irred, dtype='intc')
        num_independent = _mdfc.gaussian(transform,
                                         np.array(zero_fc3s, dtype='double'),
                                         independent, precision)
        transform = transform[:, :num_independent]
        independent = independent[:num_independent]
    except ImportError:
        CC, transform, independent = gaussian_py(np.array(zero_fc3s,
                                                          dtype='double'),
                                                 prec=precision)
    return independent, transform
Example #31
0
def get_third_order_displacements(cell,
                                  symmetry,
                                  is_plusminus='auto',
                                  is_diagonal=False):
    # Atoms 1, 2, and 3 are defined as follows:
    #
    # Atom 1: The first displaced atom. Third order force constant
    #         between Atoms 1, 2, and 3 is calculated.
    # Atom 2: The second displaced atom. Second order force constant
    #         between Atoms 2 and 3 is calculated.
    # Atom 3: Force is mesuared on this atom.

    positions = cell.get_scaled_positions()
    lattice = cell.get_cell()

    # Least displacements for third order force constants in yaml file
    #
    # Data structure
    # [{'number': atom1,
    #   'displacement': [0.00000, 0.007071, 0.007071],
    #   'second_atoms': [ {'number': atom2,
    #                      'displacements': [[0.007071, 0.000000, 0.007071],
    #                                        [-0.007071, 0.000000, -0.007071]
    #                                        ,...]},
    #                     {'number': ... } ] },
    #  {'number': atom1, ... } ]

    # Least displacements of first atoms (Atom 1) are searched by
    # using respective site symmetries of the original crystal.
    disps_first = get_least_displacements(symmetry,
                                          is_plusminus=is_plusminus,
                                          is_diagonal=False)

    symprec = symmetry.get_symmetry_tolerance()

    dds = []
    for disp in disps_first:
        atom1 = disp[0]
        disp1 = disp[1:4]
        site_sym = symmetry.get_site_symmetry(atom1)

        dds_atom1 = {'number': atom1,
                     'direction': disp1,
                     'second_atoms': []}

        # Reduced site symmetry at the first atom with respect to 
        # the displacement of the first atoms.
        reduced_site_sym = get_reduced_site_symmetry(site_sym, disp1, symprec)
        # Searching orbits (second atoms) with respect to
        # the first atom and its reduced site symmetry.
        second_atoms = get_least_orbits(atom1,
                                        cell,
                                        reduced_site_sym,
                                        symprec)

        for atom2 in second_atoms:
            dds_atom2 = get_next_displacements(atom1,
                                               atom2,
                                               reduced_site_sym,
                                               positions,
                                               symprec,
                                               is_diagonal)
            min_distance = np.linalg.norm(
                np.dot(get_equivalent_smallest_vectors(
                        atom1,
                        atom2,
                        cell,
                        lattice,
                        symprec)[0], lattice))
            dds_atom2['distance'] = min_distance
            dds_atom1['second_atoms'].append(dds_atom2)
        dds.append(dds_atom1)
    
    return dds