Ejemplo n.º 1
0
def symmetrize_results(
    energies,
    velocities,
    curvature,
    other_properties,
    ir_to_full_idx,
    rotation_matrices,
    reciprocal_lattice,
):
    similarity_matrices = np.array(
        [similarity_transformation(reciprocal_lattice, r) for r in rotation_matrices]
    )
    inv_similarity_matrices = np.array([np.linalg.inv(s) for s in similarity_matrices])

    for spin in energies:
        energies[spin] = energies[spin][:, ir_to_full_idx]
        velocities[spin] = rotate_velocities(
            velocities[spin][..., ir_to_full_idx], similarity_matrices
        )

        if curvature:
            curvature[spin] = rotate_curvature(
                curvature[spin][:, ir_to_full_idx, ...],
                similarity_matrices,
                inv_similarity_matrices,
            )

        if other_properties:
            for label, prop in other_properties[spin].items():
                other_properties[spin][label] = prop[:, ir_to_full_idx]

    return energies, velocities, curvature, other_properties
Ejemplo n.º 2
0
def get_symmetrized_strain_mapping(
    bulk_structure,
    strain_mapping,
    symprec=defaults["symprec"],
    symprec_deformation=defaults["symprec"] / 100,
):
    # get symmetry operations of the bulk structure
    frac_ops = get_symmops(bulk_structure, symprec=symprec)

    for strain, calc in strain_mapping.items():
        # expand band structure to cover full brillouin zone, otherwise rotation won't
        # include all necessary points
        # default symprec is lower otherwise the strain will not be noticed
        calc["bandstructure"] = expand_bandstructure(
            calc["bandstructure"], symprec=symprec_deformation)

    for strain, calc in strain_mapping.items():
        k_old = get_kpoints_from_bandstructure(calc["bandstructure"],
                                               sort=True)
        k_old = kpoints_to_first_bz(k_old)

        for frac_op in frac_ops:
            # apply cartesian transformation matrix from the right side
            # hence the transpose
            r_cart = similarity_transformation(bulk_structure.lattice.matrix.T,
                                               frac_op.rotation_matrix.T)
            tstrain = strain.rotate(r_cart)

            independent = tstrain.get_deformation_matrix().is_independent(
                _mapping_tol)
            if independent and tstrain not in strain_mapping:
                rband = rotate_bandstructure(calc["bandstructure"], frac_op)

                k_new = get_kpoints_from_bandstructure(rband, sort=True)
                k_new = kpoints_to_first_bz(k_new)

                # check whether k-points match; if no match found this indicates
                # that the real and reciprocal lattice have different symmetries
                kpoints_match = np.max(np.linalg.norm(k_old - k_new,
                                                      axis=1)) < 0.001

                if kpoints_match:
                    tcalc = {
                        "reference": calc["reference"],
                        "bandstructure": rband
                    }
                    strain_mapping[tstrain] = tcalc

    return strain_mapping
Ejemplo n.º 3
0
def desymmetrize_deformation_potentials(deformation_potentials,
                                        structure,
                                        rotations,
                                        op_mapping,
                                        kp_mapping,
                                        pbar=True):
    logger.info("Desymmetrizing deformation potentials")
    t0 = time.perf_counter()

    rlat = structure.lattice.reciprocal_lattice.matrix
    sims = np.array([similarity_transformation(rlat, r) for r in rotations])
    inv_sims = np.array([np.linalg.inv(s) for s in sims])

    sims = sims[op_mapping]
    inv_sims = inv_sims[op_mapping]

    all_deformation_potentials = {}
    for spin, spin_deformation_potentials in deformation_potentials.items():
        all_deformation_potentials[spin] = np.zeros(
            (len(spin_deformation_potentials), len(sims), 3, 3))

        state_idxs = list(
            np.ndindex((len(spin_deformation_potentials), len(sims))))
        if pbar:
            state_idxs = get_progress_bar(state_idxs, desc="progress")

        for b_idx, k_idx in state_idxs:
            map_idx = kp_mapping[k_idx]

            sim = sims[k_idx]
            inv_sim = inv_sims[k_idx]

            inner = np.dot(sim, spin_deformation_potentials[b_idx, map_idx])
            rot_deform = np.abs(np.dot(inner, inv_sim))

            # inner = np.dot(spin_deformation_potentials[b_idx, map_idx], inv_sim)
            # rot_deform = np.abs(np.dot(sim, inner))
            # inner = np.dot(spin_deformation_potentials[b_idx, map_idx], sim)
            # rot_deform = np.abs(np.dot(inv_sim, inner))

            all_deformation_potentials[spin][b_idx, k_idx] = rot_deform

    log_time_taken(t0)
    return all_deformation_potentials
Ejemplo n.º 4
0
def desymmetrize_coefficients(
    coeffs,
    gpoints,
    kpoints,
    structure,
    rotations,
    translations,
    is_tr,
    op_mapping,
    kp_mapping,
    pbar=True,
):
    logger.info("Desymmetrizing wavefunction coefficients")
    t0 = time.perf_counter()

    ncl = is_ncl(coeffs)
    rots = rotations[op_mapping]
    taus = translations[op_mapping]
    trs = is_tr[op_mapping]

    su2s = None
    if ncl:
        # get cartesian rotation matrix
        r_cart = [
            similarity_transformation(structure.lattice.matrix.T, r.T)
            for r in rotations
        ]

        # calculate SU(2)
        su2_no_dagger = np.array([rotation_matrix_to_su2(r) for r in r_cart])

        # calculate SU(2)^{dagger}
        su2 = np.conjugate(su2_no_dagger).transpose((0, 2, 1))
        su2s = su2[op_mapping]

    g_mesh = (np.abs(gpoints).max(axis=0) + 3) * 2
    g1, g2, g3 = (gpoints + g_mesh / 2).astype(int).T  # indices of g-points to keep

    all_rot_coeffs = {}
    for spin, spin_coeffs in coeffs.items():
        coeff_shape = (len(spin_coeffs), len(rots)) + tuple(g_mesh)
        if ncl:
            coeff_shape += (2,)
        rot_coeffs = np.zeros(coeff_shape, dtype=complex)

        state_idxs = list(range(len(rots)))
        if pbar:
            state_idxs = get_progress_bar(state_idxs, desc="progress")

        for k_idx in state_idxs:
            map_idx = kp_mapping[k_idx]

            rot = rots[k_idx]
            tau = taus[k_idx]
            tr = trs[k_idx]
            kpoint = kpoints[map_idx]

            rot_kpoint = np.dot(rot, kpoint)
            kdiff = np.around(rot_kpoint)
            rot_kpoint -= kdiff

            edges = np.around(rot_kpoint, 5) == -0.5
            rot_kpoint += edges
            kdiff -= edges

            rot_gpoints = np.dot(rot, gpoints.T).T
            rot_gpoints = np.around(rot_gpoints).astype(int)
            rot_gpoints += kdiff.astype(int)

            if tr:
                tau = -tau

            factor = np.exp(-1j * 2 * np.pi * np.dot(rot_gpoints + rot_kpoint, tau))
            rg1, rg2, rg3 = (rot_gpoints + g_mesh / 2).astype(int).T

            if ncl:
                # perform rotation in spin space
                su2 = su2s[k_idx]
                rc = np.zeros_like(spin_coeffs[:, map_idx])
                rc[:, :, 0] = (
                    su2[0, 0] * spin_coeffs[:, map_idx, :, 0]
                    + su2[0, 1] * spin_coeffs[:, map_idx, :, 1]
                )
                rc[:, :, 1] = (
                    su2[1, 0] * spin_coeffs[:, map_idx, :, 0]
                    + su2[1, 1] * spin_coeffs[:, map_idx, :, 1]
                )
                rot_coeffs[:, k_idx, rg1, rg2, rg3] = factor[None, :, None] * rc
            else:
                rot_coeffs[:, k_idx, rg1, rg2, rg3] = spin_coeffs[:, map_idx] * factor

            if tr and not ncl:
                rot_coeffs[:, k_idx] = np.conjugate(rot_coeffs[:, k_idx])

        all_rot_coeffs[spin] = rot_coeffs[:, :, g1, g2, g3]

    log_time_taken(t0)
    return all_rot_coeffs