Exemplo n.º 1
0
def get_fc2_translational_invariance(supercell,
                                     trans,
                                     coeff,
                                     ifc_map,
                                     precision=1e-6):
    natom = supercell.get_number_of_atoms()
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    num_irred = trans.shape[-1]
    ti_transforms = [np.zeros(num_irred)]
    for i, atom1 in enumerate(unit_atoms):
        ti_transform = np.zeros((9, num_irred))
        for atom2 in np.arange(natom):
            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():
                # ti_transform_row = ti_transform[k] / np.abs(ti_transform[k]).max()
                # ti_transforms.append(ti_transform_row)
                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 translational invariance:%d" % (
        len(ti_transforms) - 1)
    CC, transform, independent = gaussian(np.array(ti_transforms), precision)
    return independent, transform
Exemplo n.º 2
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
Exemplo n.º 3
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
Exemplo n.º 4
0
def get_fc2_translational_invariance(supercell, trans, coeff, ifc_map, precision=1e-6):
    natom = supercell.get_number_of_atoms()
    unit_atoms = np.unique(supercell.get_supercell_to_unitcell_map())
    num_irred = trans.shape[-1]
    ti_transforms =[np.zeros(num_irred)]
    for i, atom1 in enumerate(unit_atoms):
        ti_transform = np.zeros((9, num_irred))
        for atom2 in np.arange(natom):
            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():
                # ti_transform_row = ti_transform[k] / np.abs(ti_transform[k]).max()
                # ti_transforms.append(ti_transform_row)
                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 translational invariance:%d"% (len(ti_transforms) - 1)
    CC, transform, independent = gaussian(np.array(ti_transforms), precision)
    return independent, transform
Exemplo n.º 5
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
Exemplo n.º 6
0
def get_fc2_spg_invariance(pairs_orig,
                           positions,
                           rotations1,
                           translations1,
                           mappings1,
                           rotations2,
                           num_rotations2,
                           mappings2,
                           lattice,
                           symprec):
    indatoms1 = np.unique(mappings1)
    doublets_dict = []
    for index_pair,pair in enumerate(pairs_orig):
        doublet_dict = {}
        CC = [np.zeros(9)]
        for permute in list(permutations([0,1])):
            rot_all = []
            atom1, atom2= [pair[i] for i in permute]
            if not mappings1[atom1] == pair[0]:
                continue
            for numope in get_all_operations_at_star(rotations1,
                                                     translations1,
                                                     positions,
                                                     atom1,
                                                     mappings1,
                                                     symprec):
                #get all the symmetry operation that keeps atom1 unchanged
                rot1, tran = rotations1[numope], translations1[numope]
                atom1_1 = mappings1[atom1]
                index1 = np.where(indatoms1 == atom1_1)[0][0] # index of the first irreducible atom
                atom2_1 = get_atom_sent_by_operation(atom2, positions, rot1, tran, symprec=symprec)
                site_syms = rotations2[index1][:num_rotations2[index1]]
                if mappings2[index1, atom2_1] != pair[1]:
                    continue
                for rot2 in get_rotations_at_star(site_syms, positions, atom1_1, atom2_1, mappings2[index1], symprec):
                    rot = np.dot(rot2, rot1)
                    isfound = False
                    for r in rot_all:
                        if (np.abs(r-rot) < symprec).all():
                            isfound = True
                            break
                    if not isfound:
                        rot_all.append(rot)
                    else:
                        continue
                    rot_cart = np.double(similarity_transformation(lattice, rot))
                    seq = "".join(["ik"[i] for i in permute])
                    PP  = np.einsum("ij,kl -> %sjl"%seq, rot_cart, rot_cart).reshape(9, 9).T
                    BB = PP - np.eye(9)
                    for i in np.arange(9):
                        is_found = False
                        if not (np.abs(BB[i]) < symprec).all():
                            for j in np.arange(len(CC)):
                                if (np.abs(BB[i] - CC[j]) < symprec).all():
                                    is_found = True
                                    break
                            if not is_found:
                                CC.append(BB[i])
        CC, transform, independent = gaussian(np.array(CC))
        doublet_dict['independent'] = [ind + index_pair * 9 for ind in independent] # independent ele
        doublet_dict['transform'] = transform
        doublets_dict.append(doublet_dict)
    num_irred = [len(dic['independent']) for dic in doublets_dict]
    trans = np.zeros((len(doublets_dict), 9, sum(num_irred)), dtype="float")
    for i, doub  in enumerate(doublets_dict):
        start = sum(num_irred[:i])
        length = num_irred[i]
        trans[i,:, start:start + length] = doub['transform']
    return np.hstack((dic['independent'] for dic in doublets_dict)), trans
Exemplo n.º 7
0
def get_fc3_spg_invariance(triplets,
                           positions,
                           rotations1,
                           translations1,
                           mappings1,
                           rotations2,
                           num_rotations2,
                           mappings2,
                           rotations3,
                           num_rotations3,
                           mappings3,
                           lattice,
                           symprec,
                           is_disperse=False):
    "Find all spg symmetries that map the triplet to itself and thus the symmetry would act as constraints"
    triplets_dict = []
    iatoms1 = np.unique(mappings1)
    for itriplet, triplet in enumerate(triplets):
        triplet_dict = {}
        triplet_dict["triplet"] = triplet
        CC = [np.zeros(27)]

        for permute in list(permutations(
            [0, 1, 2])):  # Leave out the original triplet
            rot_all = []
            atom1, atom2, atom3 = [triplet[i] for i in permute]
            if not mappings1[atom1] == triplet[0]:
                continue
            for numope in get_all_operations_at_star(rotations1, translations1,
                                                     positions, atom1,
                                                     mappings1, symprec):
                #get all the symmetry operations that keep atom1 unchanged
                rot1, tran = rotations1[numope], translations1[numope]
                atom1_1 = mappings1[atom1]
                index1 = np.where(iatoms1 == atom1_1)[0][
                    0]  # index of the first irreducible atom
                atom2_1 = get_atom_sent_by_operation(atom2,
                                                     positions,
                                                     rot1,
                                                     tran,
                                                     symprec=symprec)
                atom3_1 = get_atom_sent_by_operation(atom3,
                                                     positions,
                                                     rot1,
                                                     tran,
                                                     symprec=symprec)
                site_syms = rotations2[index1, :num_rotations2[index1]]
                mapping2 = mappings2[
                    index1]  # now atom1 would be fixed under its site symmetries
                iatoms2 = np.unique(mapping2)
                if mapping2[atom2_1] != triplet[1]:
                    continue
                for rot2 in get_rotations_at_star(site_syms, positions,
                                                  atom1_1, atom2_1, mapping2,
                                                  symprec):
                    #get all the symmetry operations that keep both atom1 and atom2 unchanged
                    atom2_2 = mapping2[atom2_1]
                    atom3_2 = get_atom_sent_by_site_sym(
                        atom3_1, atom1_1, positions, rot2,
                        symprec=symprec)  #no matter atom1_1 or atom2_1
                    index2 = np.where(iatoms2 == atom2_2)[0][
                        0]  # index of the second irreducible atom
                    site_syms3 = rotations3[index1,
                                            index2, :num_rotations3[index1,
                                                                    index2]]
                    mapping3 = mappings3[index1, index2]
                    if not mapping3[atom3_2] == triplet[2]:
                        continue
                    for rot3 in get_rotations_at_star(site_syms3, positions,
                                                      atom2_2, atom3_2,
                                                      mapping3, symprec):
                        rot = np.dot(rot3, np.dot(rot2, rot1))
                        isfound = False
                        for r in rot_all:
                            if (np.abs(r - rot) < symprec).all():
                                isfound = True
                                break
                        if not isfound:
                            rot_all.append(rot)
                        else:
                            continue
                        # rot_cart = np.double(similarity_transformation(lattice, rot))
                        # seq = "".join(["ikm"[i] for i in permute])
                        # PP  = np.einsum("ij,kl,mn -> %sjln"%seq, rot_cart, rot_cart, rot_cart).reshape(27, 27).T

                        rot_cart = np.double(
                            similarity_transformation(lattice, rot)).T
                        seq = "".join([
                            'ikm'[permute.index(i)] for i in range(3)
                        ])  # find the original index before permutation
                        PP = np.einsum("ij,kl,mn -> %sjln" % seq, rot_cart,
                                       rot_cart, rot_cart).reshape(27, 27)
                        BB = PP - np.eye(27)
                        for i in np.arange(27):
                            is_found = False
                            if not (np.abs(BB[i]) < symprec).all():
                                row = BB[i] / np.abs(BB[i]).max()
                                for j in np.arange(len(CC)):
                                    if (np.abs(row - CC[j]) < symprec).all():
                                        is_found = True
                                        break
                                if not is_found:
                                    CC.append(row)
        DD = np.array(CC, dtype='double')
        CC, transform, independent = gaussian(DD)
        triplet_dict['independent'] = [
            ind + itriplet * 27 for ind in independent
        ]  # independent ele
        triplet_dict['transform'] = transform
        triplets_dict.append(triplet_dict)
    num_irred = [len(dic['independent']) for dic in triplets_dict]
    ind_elements = np.hstack((dic['independent'] for dic in triplets_dict))
    if is_disperse:
        from scipy.sparse import coo_matrix
        trans = []
        for i, trip in enumerate(triplets_dict):
            start = sum(num_irred[:i])
            length = num_irred[i]
            transform_tmp = np.zeros((27, sum(num_irred)), dtype="float")
            transform_tmp[:, start:start + length] = trip['transform']
            non_zero = np.where(np.abs(transform_tmp) > symprec)
            transform_tmp_sparse = coo_matrix(
                (transform_tmp[non_zero], non_zero), shape=transform_tmp.shape)
            trans.append(transform_tmp_sparse)
    else:
        trans = np.zeros((len(triplets_dict), 27, sum(num_irred)),
                         dtype="float")
        for i, trip in enumerate(triplets_dict):
            start = sum(num_irred[:i])

            length = num_irred[i]
            trans[i, :, start:start + length] = trip['transform']
    return ind_elements, trans
Exemplo n.º 8
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
Exemplo n.º 9
0
def get_fc2_spg_invariance(pairs_orig, positions, rotations1, translations1,
                           mappings1, rotations2, num_rotations2, mappings2,
                           lattice, symprec):
    indatoms1 = np.unique(mappings1)
    doublets_dict = []
    for index_pair, pair in enumerate(pairs_orig):
        doublet_dict = {}
        CC = [np.zeros(9)]
        for permute in list(permutations([0, 1])):
            rot_all = []
            atom1, atom2 = [pair[i] for i in permute]
            if not mappings1[atom1] == pair[0]:
                continue
            for numope in get_all_operations_at_star(rotations1, translations1,
                                                     positions, atom1,
                                                     mappings1, symprec):
                #get all the symmetry operation that keeps atom1 unchanged
                rot1, tran = rotations1[numope], translations1[numope]
                atom1_1 = mappings1[atom1]
                index1 = np.where(indatoms1 == atom1_1)[0][
                    0]  # index of the first irreducible atom
                atom2_1 = get_atom_sent_by_operation(atom2,
                                                     positions,
                                                     rot1,
                                                     tran,
                                                     symprec=symprec)
                site_syms = rotations2[index1][:num_rotations2[index1]]
                if mappings2[index1, atom2_1] != pair[1]:
                    continue
                for rot2 in get_rotations_at_star(site_syms, positions,
                                                  atom1_1, atom2_1,
                                                  mappings2[index1], symprec):
                    rot = np.dot(rot2, rot1)
                    isfound = False
                    for r in rot_all:
                        if (np.abs(r - rot) < symprec).all():
                            isfound = True
                            break
                    if not isfound:
                        rot_all.append(rot)
                    else:
                        continue
                    rot_cart = np.double(
                        similarity_transformation(lattice, rot))
                    seq = "".join(["ik"[i] for i in permute])
                    PP = np.einsum("ij,kl -> %sjl" % seq, rot_cart,
                                   rot_cart).reshape(9, 9).T
                    BB = PP - np.eye(9)
                    for i in np.arange(9):
                        is_found = False
                        if not (np.abs(BB[i]) < symprec).all():
                            for j in np.arange(len(CC)):
                                if (np.abs(BB[i] - CC[j]) < symprec).all():
                                    is_found = True
                                    break
                            if not is_found:
                                CC.append(BB[i])
        CC, transform, independent = gaussian(np.array(CC))
        doublet_dict['independent'] = [
            ind + index_pair * 9 for ind in independent
        ]  # independent ele
        doublet_dict['transform'] = transform
        doublets_dict.append(doublet_dict)
    num_irred = [len(dic['independent']) for dic in doublets_dict]
    trans = np.zeros((len(doublets_dict), 9, sum(num_irred)), dtype="float")
    for i, doub in enumerate(doublets_dict):
        start = sum(num_irred[:i])
        length = num_irred[i]
        trans[i, :, start:start + length] = doub['transform']
    return np.hstack((dic['independent'] for dic in doublets_dict)), trans
Exemplo n.º 10
0
def get_fc3_spg_invariance(triplets,
                           positions,
                           rotations1,
                           translations1,
                           mappings1,
                           rotations2,
                           num_rotations2,
                           mappings2,
                           rotations3,
                           num_rotations3,
                           mappings3,
                           lattice,
                           symprec,
                           is_disperse=False):
    "Find all spg symmetries that map the triplet to itself and thus the symmetry would act as constraints"
    triplets_dict = []
    iatoms1 = np.unique(mappings1)
    for itriplet, triplet in enumerate(triplets):
        triplet_dict = {}
        triplet_dict["triplet"] = triplet
        CC = [np.zeros(27)]

        for permute in list(permutations([0,1,2])): # Leave out the original triplet
            rot_all = []
            atom1, atom2, atom3 = [triplet[i] for i in permute]
            if not mappings1[atom1] == triplet[0]:
                continue
            for numope in get_all_operations_at_star(rotations1,
                                                     translations1,
                                                     positions,
                                                     atom1,
                                                     mappings1,
                                                     symprec):
                #get all the symmetry operations that keep atom1 unchanged
                rot1, tran = rotations1[numope], translations1[numope]
                atom1_1 = mappings1[atom1]
                index1 = np.where(iatoms1 == atom1_1)[0][0] # index of the first irreducible atom
                atom2_1 = get_atom_sent_by_operation(atom2, positions, rot1, tran, symprec=symprec)
                atom3_1 = get_atom_sent_by_operation(atom3, positions, rot1, tran, symprec=symprec)
                site_syms = rotations2[index1, :num_rotations2[index1]]
                mapping2 = mappings2[index1] # now atom1 would be fixed under its site symmetries
                iatoms2 = np.unique(mapping2)
                if mapping2[atom2_1] != triplet[1]:
                    continue
                for rot2 in get_rotations_at_star(site_syms, positions, atom1_1, atom2_1, mapping2, symprec):
                    #get all the symmetry operations that keep both atom1 and atom2 unchanged
                    atom2_2 = mapping2[atom2_1]
                    atom3_2 = get_atom_sent_by_site_sym(atom3_1, atom1_1, positions, rot2, symprec=symprec) #no matter atom1_1 or atom2_1
                    index2 = np.where(iatoms2 == atom2_2)[0][0]# index of the second irreducible atom
                    site_syms3 = rotations3[index1, index2, :num_rotations3[index1, index2]]
                    mapping3 = mappings3[index1, index2]
                    if not mapping3[atom3_2] == triplet[2]:
                        continue
                    for rot3 in get_rotations_at_star(site_syms3, positions, atom2_2, atom3_2, mapping3, symprec):
                        rot = np.dot(rot3, np.dot(rot2, rot1))
                        isfound = False
                        for r in rot_all:
                            if (np.abs(r-rot) < symprec).all():
                                isfound = True
                                break
                        if not isfound:
                            rot_all.append(rot)
                        else:
                            continue
                        # rot_cart = np.double(similarity_transformation(lattice, rot))
                        # seq = "".join(["ikm"[i] for i in permute])
                        # PP  = np.einsum("ij,kl,mn -> %sjln"%seq, rot_cart, rot_cart, rot_cart).reshape(27, 27).T

                        rot_cart = np.double(similarity_transformation(lattice, rot)).T
                        seq = "".join(['ikm'[permute.index(i)] for i in range(3)]) # find the original index before permutation
                        PP = np.einsum("ij,kl,mn -> %sjln"%seq, rot_cart, rot_cart, rot_cart).reshape(27, 27)
                        BB = PP - np.eye(27)
                        for i in np.arange(27):
                            is_found = False
                            if not (np.abs(BB[i]) < symprec).all():
                                row = BB[i] / np.abs(BB[i]).max()
                                for j in np.arange(len(CC)):
                                    if (np.abs(row - CC[j]) < symprec).all():
                                        is_found = True
                                        break
                                if not is_found:
                                    CC.append(row)
        DD = np.array(CC, dtype='double')
        CC, transform, independent = gaussian(DD)
        triplet_dict['independent'] = [ind + itriplet * 27 for ind in independent] # independent ele
        triplet_dict['transform'] = transform
        triplets_dict.append(triplet_dict)
    num_irred = [len(dic['independent']) for dic in triplets_dict]
    ind_elements = np.hstack((dic['independent'] for dic in triplets_dict))
    if is_disperse:
        from scipy.sparse import coo_matrix
        trans = []
        for i, trip in enumerate(triplets_dict):
            start = sum(num_irred[:i])
            length = num_irred[i]
            transform_tmp = np.zeros((27, sum(num_irred)), dtype="float")
            transform_tmp[:, start:start + length] = trip['transform']
            non_zero = np.where(np.abs(transform_tmp) > symprec)
            transform_tmp_sparse = coo_matrix((transform_tmp[non_zero], non_zero), shape=transform_tmp.shape)
            trans.append(transform_tmp_sparse)
    else:
        trans = np.zeros((len(triplets_dict), 27, sum(num_irred)), dtype="float")
        for i, trip in enumerate(triplets_dict):
            start = sum(num_irred[:i])

            length = num_irred[i]
            trans[i,:, start:start + length] = trip['transform']
    return ind_elements, trans