コード例 #1
0
def print_orbital_weights_dm_K(subdir, prefix):
    num_layers = 3
    assert (num_layers == 3)  # != 3 unimplemented

    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    layer_orbitals = get_layer_orbitals(wout_path, num_layers)
    Pzs = get_layer_projections(wout_path, num_layers)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    H_TB_K = Hk_recip(K_lat, Hr)
    Es, U = np.linalg.eigh(H_TB_K)
    top = top_valence_indices(E_F, 2 * num_layers, Es)

    layer_weights, layer_basis = get_layer_basis_from_dm_K(U, top, Pzs)

    dm_basis_weights = [
        get_state_weights(layer_orbitals, s) for s in layer_basis
    ]

    print("dm basis weights")
    print(dm_basis_weights)
コード例 #2
0
def _main():
    parser = ArgumentParser(description="Update disentanglement window in W90 input")
    parser.add_argument('--subdir', type=str, default=None,
            help="Subdirectory under work_base for all job dirs")
    parser.add_argument('prefix', type=str,
            help="Prefix of system to update")
    parser.add_argument('outer_min', type=float,
            help="Distance below E_F to start outer window")
    parser.add_argument('outer_max', type=float,
            help="Distance above E_F to stop outer window")
    parser.add_argument('inner_min', type=float,
            help="Distance below E_F to start inner window")
    parser.add_argument('inner_max', type=float,
            help="Distance above E_F to stop inner window")
    args = parser.parse_args()
    
    gconf = global_config()
    base_path = os.path.expandvars(gconf["work_base"])
    if args.subdir is not None:
        base_path = os.path.join(base_path, args.subdir)

    wandir = os.path.join(base_path, args.prefix, "wannier")
    scf_path = os.path.join(wandir, "scf.out")
    E_Fermi = fermi_from_scf(scf_path)

    outer = [args.outer_min, args.outer_max]
    inner = [args.inner_min, args.inner_max]

    win_path = os.path.join(wandir, "{}.win".format(args.prefix))
    Update_Disentanglement(win_path, E_Fermi, outer, inner)
コード例 #3
0
def print_orbital_weights_eigenstates_Gamma(subdir, prefix):
    num_layers = 3
    assert (num_layers == 3)  # != 3 unimplemented

    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    layer_orbitals = get_layer_orbitals(wout_path, num_layers)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    Gamma_lat = np.array([0.0, 0.0, 0.0])
    H_TB_Gamma = Hk_recip(Gamma_lat, Hr)
    Es, U = np.linalg.eigh(H_TB_Gamma)
    top = top_valence_indices(E_F, 2 * num_layers, Es)

    eigenstate_weights = [
        get_state_weights(layer_orbitals, U[:, [t]]) for t in top
    ]

    print("eigenstate weights")
    print(eigenstate_weights)
コード例 #4
0
def plot_orbital_weights_K(subdir, prefix):
    num_layers = 3
    assert (num_layers == 3)  # != 3 unimplemented

    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    layer_orbitals = get_layer_orbitals(wout_path, num_layers)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    H_TB_K = Hk_recip(K_lat, Hr)
    Es, U = np.linalg.eigh(H_TB_K)
    top = top_valence_indices(E_F, 2 * num_layers, Es)

    eigenstate_weights = [
        get_state_weights(layer_orbitals, U[:, [t]]) for t in top
    ]

    state_indices = [0, 0, 1, 1, 2, 2]
    labels = [
        r"$s_1$; $(+, \uparrow)$", r"$s_1$; $(-, \downarrow)$",
        r"$s_2$; $(+, \uparrow)$", r"$s_2$; $(-, \downarrow)$",
        r"$s_3$; $(+, \uparrow)$", r"$s_3$; $(-, \downarrow)$"
    ]
    weight_keys = [
        "(+, up)", "(-, down)", "(+, up)", "(-, down)", "(+, up)", "(-, down)"
    ]
    syms = ["D", "D", "o", "o", "s", "s"]
    colors = ["black", "red", "black", "red", "black", "red"]

    vals = []
    for state_index, label, key, sym, color in zip(state_indices, labels,
                                                   weight_keys, syms, colors):
        vals.append([])
        for layer_index in range(num_layers):
            vals[-1].append(eigenstate_weights[state_index][key][layer_index])

        plt.plot(range(num_layers),
                 vals[-1],
                 "k{}".format(sym),
                 markerfacecolor=(1, 1, 1, 0.0),
                 markeredgecolor=color,
                 label=label,
                 markersize=10)

    plt.xlim(0 - 0.1, num_layers - 1 + 0.1)
    plt.ylim(0, 1)

    plt.legend(loc=0)
    plt.savefig("{}_state_components.png".format(prefix),
                bbox_inches='tight',
                dpi=500)
コード例 #5
0
def get_extrema(work, prefix, k, k_prefix, num_layers, num_valence_bands,
                num_conduction_bands):
    wannier_dir = os.path.join(work, prefix, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    E_F = fermi_from_scf(scf_path)

    Hr = get_Hr(work, prefix)
    Hk = Hk_recip(k, Hr)

    Es, U = np.linalg.eigh(Hk)
    below_fermi, above_fermi = bracket_indices(Es, E_F)

    if num_layers != 2:
        raise ValueError(
            "get_layer_indices() unimplemented for num_layers != 2")

    layer_indices_up = get_layer_indices(work, prefix, 'up')
    layer_indices_down = get_layer_indices(work, prefix, 'down')
    layer_contribs_up = get_layer_contribs(layer_indices_up, U)
    layer_contribs_down = get_layer_contribs(layer_indices_down, U)

    extrema = {}

    def add_extrema_entries(i, band_index, vc_label):
        extrema["energy_{}_{}".format(vc_label, i)] = Es[band_index]

        for l in range(num_layers):
            layer_contrib = select_layer_contrib(layer_contribs_up,
                                                 layer_contribs_down, None, l,
                                                 band_index)

            extrema["contrib_layer_{}_{}_{}".format(l, vc_label,
                                                    i)] = layer_contrib

        for spin in ['up', 'down']:
            spin_contrib = sum([
                select_layer_contrib(layer_contribs_up, layer_contribs_down,
                                     spin, l, band_index)
                for l in range(num_layers)
            ])

            extrema["contrib_spin_{}_{}_{}".format(spin, vc_label,
                                                   i)] = spin_contrib

    for i, band_index in enumerate(
            range(below_fermi, below_fermi - num_valence_bands, -1)):
        add_extrema_entries(i, band_index, 'valence')

    for i, band_index in enumerate(
            range(above_fermi, above_fermi + num_conduction_bands)):
        add_extrema_entries(i, band_index, 'conduction')

    return extrema
コード例 #6
0
def get_system_details(work, prefix):
    wannier_dir = os.path.join(work, prefix, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    E_F = fermi_from_scf(scf_path)
    latVecs = _Angstrom_per_bohr * latVecs_from_scf(scf_path)
    D = latVecs.T
    R = 2.0 * np.pi * np.linalg.inv(D)

    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    K_Cart = np.dot(K_lat, R)

    Hr = get_Hr(work, prefix)
    Hk = Hk_Cart(K_Cart, Hr, latVecs)

    Es, U = np.linalg.eigh(Hk)

    return latVecs, K_Cart, Hr, Es, U, E_F
コード例 #7
0
def make_effective_Hamiltonian_Gamma(subdir,
                                     prefix,
                                     top_two_only,
                                     verbose=False):
    num_layers = 3

    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    latVecs = latVecs_from_scf(scf_path)
    alat_Bohr = 1.0
    R = 2 * np.pi * np.linalg.inv(latVecs.T)

    Gamma_cart = np.array([0.0, 0.0, 0.0])
    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    K_cart = np.dot(K_lat, R)

    if verbose:
        print(K_cart)
        print(latVecs)

    upto_factor = 0.3
    num_ks = 100

    ks = vec_linspace(Gamma_cart, upto_factor * K_cart, num_ks)
    xs = np.linspace(0.0, upto_factor, num_ks)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    if top_two_only:
        Pzs = [np.eye(get_total_orbitals(num_layers))]
    else:
        Pzs = get_layer_projections(wout_path, num_layers)

    H_TB_Gamma = Hk(Gamma_cart, Hr, latVecs)
    Es, U = np.linalg.eigh(H_TB_Gamma)

    if top_two_only:
        top = top_valence_indices(E_F, 2, Es)
    else:
        top = top_valence_indices(E_F, 2 * num_layers, Es)

    layer_weights, layer_basis = get_layer_basis_Gamma(U, top, Pzs, verbose)

    complement_basis_mat = nullspace(array_with_rows(layer_basis).conjugate())
    complement_basis = []
    for i in range(complement_basis_mat.shape[1]):
        v = complement_basis_mat[:, [i]]
        complement_basis.append(v / np.linalg.norm(v))

    assert (len(layer_basis) + len(complement_basis) == 22 * num_layers)

    for vl in [v.conjugate().T for v in layer_basis]:
        for vc in complement_basis:
            assert (abs(np.dot(vl, vc)[0, 0]) < 1e-12)

    # 0th order effective Hamiltonian: H(Gamma) in layer basis.
    H_layer_Gamma = layer_Hamiltonian_0th_order(H_TB_Gamma, layer_basis)

    #E_repr = sum([Es[t] for t in top]) / len(top)
    E_repr = Es[top[0]]
    H_correction = correction_Hamiltonian_0th_order(Gamma_cart, Hr, latVecs,
                                                    E_repr, complement_basis,
                                                    layer_basis)

    H0_tot = H_layer_Gamma + H_correction

    H_PQ = correction_Hamiltonian_PQ(K_cart, Hr, latVecs, complement_basis,
                                     layer_basis)

    # Momentum expectation values <z_{lp}| dH/dk_{c}|_Gamma |z_l>
    ps = layer_Hamiltonian_ps(Gamma_cart, Hr, latVecs, layer_basis)

    ps_correction = correction_Hamiltonian_ps(Gamma_cart, Hr, latVecs, E_repr,
                                              complement_basis, layer_basis)

    ps_tot = deepcopy(ps)
    for i, v in enumerate(ps_correction):
        ps_tot[i] += v

    # Inverse effective masses <z_{lp}| d^2H/dk_{cp}dk_{c}|_Gamma |z_l>
    mstar_invs = layer_Hamiltonian_mstar_inverses(Gamma_cart, Hr, latVecs,
                                                  layer_basis)

    mstar_invs_correction_base, mstar_invs_correction_other = correction_Hamiltonian_mstar_inverses(
        Gamma_cart, Hr, latVecs, E_repr, complement_basis, layer_basis)

    mstar_inv_tot = deepcopy(mstar_invs)
    for mstar_contrib in [
            mstar_invs_correction_base, mstar_invs_correction_other
    ]:
        for k, v in mstar_contrib.items():
            mstar_inv_tot[k] += v

    if verbose:
        print("H0")
        print(H_layer_Gamma)

        print("H_correction")
        print(H_correction)
        print("H_correction max")
        print(abs(H_correction).max())

        print("H_PQ max")
        print(abs(H_PQ).max())

        print("p")
        print(ps)

        print("ps max")
        print(max([abs(x).max() for x in ps]))

        print("ps correction")
        print(ps_correction)

        print("ps_correction max")
        print(max([abs(x).max() for x in ps_correction]))

        print("mstar_inv")
        print(mstar_invs)

        print("mstar_inv max")
        print(max([abs(v).max() for k, v in mstar_invs.items()]))

        print("mstar_inv_correction_base")
        print(mstar_invs_correction_base)

        print("mstar_inv_correction_base max")
        print(
            max([abs(v).max() for k, v in mstar_invs_correction_base.items()]))

        print("mstar_inv_correction_other")
        print(mstar_invs_correction_other)

        print("mstar_inv_correction_other max")
        print(
            max([abs(v).max()
                 for k, v in mstar_invs_correction_other.items()]))

        # Fit quality plots.
        H_layers = []
        for k in ks:
            q = k - Gamma_cart

            H_layers.append(
                H_kdotp(q, H_layer_Gamma, H_correction, ps, ps_correction,
                        mstar_invs, mstar_invs_correction_base,
                        mstar_invs_correction_other))

        Emks, Umks = [], []
        for band_index in range(len(layer_basis)):
            Emks.append([])
            Umks.append([])

        for k_index, Hk_layers in enumerate(H_layers):
            Es_layers, U_layers = np.linalg.eigh(Hk_layers)
            #print(k_index)
            #print("U", U)

            for band_index in range(len(layer_basis)):
                Emks[band_index].append(Es_layers)
                Umks[band_index].append(U_layers)

        for band_index in range(len(layer_basis)):
            plt.plot(xs, Emks[band_index])

        TB_Emks = []
        for m in range(len(top)):
            TB_Emks.append([])

        for k in ks:
            this_H_TB_k = Hk(k, Hr, latVecs)
            this_Es, this_U = np.linalg.eigh(this_H_TB_k)

            for m, i in enumerate(top):
                TB_Emks[m].append(this_Es[i])

        for TB_Em in TB_Emks:
            plt.plot(xs, TB_Em, 'k.')

        plt.show()

        # Effective masses.
        print("effective mass, top valence band, TB model: m^*_{xx; yy; xy}")
        print(
            effective_mass_band(lambda k: Hk(k, Hr, latVecs), Gamma_cart,
                                top[0], alat_Bohr))

        print(
            "effective mass, top valence band, k dot p model: m^*_{xx; yy; xy}"
        )
        print(
            effective_mass_band(
                lambda k:
                H_kdotp(k - Gamma_cart, H_layer_Gamma, H_correction, ps,
                        ps_correction, mstar_invs, mstar_invs_correction_base,
                        mstar_invs_correction_other), Gamma_cart,
                len(layer_basis) - 1, alat_Bohr))

        # Elements contributing to crossover scale.
        t_Gamma_a = H0_tot[0, 2]
        t_Gamma_b = H0_tot[0, 3]

        print("t_Gamma_a, t_Gamma_b")
        print(t_Gamma_a, t_Gamma_b)

        print("norm(t_Gamma_a)")
        print(abs(t_Gamma_a))

        print("[t_Gamma]_{2, 4}, [t_Gamma]_{2, 5}")
        print(H0_tot[2, 4], H0_tot[2, 5])

        t_Gamma_direct = H0_tot[0, 4]
        print("t_Gamma_direct, norm(t_Gamma_direct)")
        print(t_Gamma_direct, abs(t_Gamma_direct))

        print("E_SL_Gamma")
        print([H0_tot[i, i] for i in range(6)])

        print("H0_tot")
        print(H0_tot)

        Gamma_valence_max = Es[top[0]]

        print("H0")
        print_H0_LaTeX(H_layer_Gamma, Gamma_valence_max)

        print("H0_tot")
        print_H0_LaTeX(H0_tot, Gamma_valence_max)

        dump_model_np("{}_model_Gamma".format(prefix), H0_tot, ps_tot,
                      mstar_inv_tot)

    return H0_tot, ps_tot, mstar_inv_tot
コード例 #8
0
def _main():
    parser = argparse.ArgumentParser(
        "Plot band structure",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument("--DFT_only",
                        action='store_true',
                        help="Use DFT bands only (no Wannier)")
    parser.add_argument("--fermi_shift",
                        action='store_true',
                        help="Shift plotted energies so that E_F = 0")
    parser.add_argument("--band_extrema",
                        action='store_true',
                        help="Add lines at VBM/CBM")
    parser.add_argument("--minE",
                        type=float,
                        default=None,
                        help="Minimum energy to plot")
    parser.add_argument("--maxE",
                        type=float,
                        default=None,
                        help="Maximum energy to plot")
    parser.add_argument("--plot_evecs",
                        action='store_true',
                        help="Plot eigenvector decomposition")
    parser.add_argument(
        "--num_layers",
        type=int,
        default=3,
        help="Number of layers (required if group_layer_* options given)")
    parser.add_argument(
        "--group_layer_evecs_soc",
        action='store_true',
        help="Group eigenvectors weights by layer, assuming SOC")
    parser.add_argument(
        "--group_layer_evecs_no_soc",
        action='store_true',
        help="Group eigenvectors weights by layer, assuming no SOC")
    parser.add_argument("--show",
                        action='store_true',
                        help="Show band plot instead of outputting file")
    args = parser.parse_args()

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")

    E_F = fermi_from_scf(scf_path)
    if args.minE is not None and args.maxE is not None:
        if args.fermi_shift:
            minE_plot = E_F + args.minE
            maxE_plot = E_F + args.maxE
        else:
            minE_plot = args.minE
            maxE_plot = args.maxE
    else:
        minE_plot, maxE_plot = None, None

    alat = alat_from_scf(scf_path)
    latVecs = latVecs_from_scf(scf_path)

    if args.DFT_only:
        Hr = None
    else:
        Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
        Hr = extractHr(Hr_path)

    bands_dir = os.path.join(work, "bands")
    bands_path = os.path.join(bands_dir, "{}_bands.dat".format(args.prefix))

    num_bands, num_ks, qe_bands = extractQEBands(bands_path)
    outpath = args.prefix

    if args.group_layer_evecs_soc:
        orbitals_per_X = 6
        orbitals_per_M = 10
        comp_groups = make_comp_groups(orbitals_per_X, orbitals_per_M,
                                       args.num_layers)
    elif args.group_layer_evecs_no_soc:
        orbitals_per_X = 3
        orbitals_per_M = 5
        comp_groups = make_comp_groups(orbitals_per_X, orbitals_per_M,
                                       args.num_layers)
    else:
        comp_groups = None

    plotBands(qe_bands,
              Hr,
              alat,
              latVecs,
              minE_plot,
              maxE_plot,
              outpath,
              show=args.show,
              symList=band_path_labels(),
              fermi_energy=E_F,
              plot_evecs=args.plot_evecs,
              comp_groups=comp_groups,
              fermi_shift=args.fermi_shift,
              plot_band_extrema=args.band_extrema)
コード例 #9
0
def _main():
    parser = argparse.ArgumentParser(
        "Plot band structure for multiple electric field values",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix_E_0",
                        type=str,
                        help="Prefix for E = 0 calculation")
    parser.add_argument("prefix_E_mid",
                        type=str,
                        help="Prefix for E != 0 calculation, middle value")
    parser.add_argument("prefix_E_high",
                        type=str,
                        help="Prefix for E != 0 calculation, high value")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument(
        "--minE",
        type=float,
        default=1.85,
        help="Minimum energy to plot (using original energy zero)")
    parser.add_argument(
        "--maxE",
        type=float,
        default=5.75,
        help="Maximum energy to plot (using original energy zero)")
    parser.add_argument("--load",
                        action='store_true',
                        help="Load stored band data instead of recalculating")
    args = parser.parse_args()

    E_mid_val = args.prefix_E_mid.split('_')[-1]
    E_high_val = args.prefix_E_high.split('_')[-1]

    Gamma_lat = np.array([0.0, 0.0, 0.0])
    M_lat = np.array([1 / 2, 0.0, 0.0])
    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    band_path_lat = [Gamma_lat, M_lat, K_lat, Gamma_lat]
    band_path_labels = ["$\\Gamma$", "$M$", "$K$", "$\\Gamma$"]
    Nk_per_panel = 400

    prefixes = [args.prefix_E_0, args.prefix_E_mid, args.prefix_E_high]
    labels = [
        "$E = 0$", "$E = {}$ V/nm".format(E_mid_val),
        "$E = {}$ V/nm".format(E_high_val)
    ]
    styles = ['r-', 'b-.', 'k--']

    xs, special_xs, Emks = [], [], []
    if args.load:
        with open("Efield_bands.json", 'r') as fp:
            in_data = json.load(fp)

        xs, special_xs, Emks = list(
            map(lambda k: [d[k] for d in in_data],
                ["xs", "special_xs", "Emks"]))

        E_Gamma_Eperp_0 = in_data[0]["E_Gamma_Eperp_0"]
    else:
        out_data = []

        for prefix_index, prefix in enumerate(prefixes):
            work = _get_work(args.subdir, prefix)
            wannier_dir = os.path.join(work, "wannier")
            scf_path = os.path.join(wannier_dir, "scf.out")

            latVecs = latVecs_from_scf(scf_path)

            Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
            Hr = extractHr(Hr_path)

            if prefix_index == 0:
                E_F = fermi_from_scf(scf_path)
                E_Gamma_Eperp_0 = get_E_Gamma(Hr, E_F)

            this_xs, this_special_xs, this_Emks = calculate_bands(
                Hr, latVecs, band_path_lat, Nk_per_panel)

            this_Emks = shift_Emks(this_Emks, E_Gamma_Eperp_0)

            xs.append(this_xs)
            special_xs.append(this_special_xs)
            Emks.append(this_Emks)

            out_data.append({
                "prefix": prefix,
                "xs": this_xs,
                "special_xs": this_special_xs,
                "band_path_labels": band_path_labels,
                "Emks": this_Emks,
                "E_Gamma_Eperp_0": E_Gamma_Eperp_0
            })

        with open("Efield_bands.json", 'w') as fp:
            json.dump(out_data, fp)

    full_min_x, full_max_x = 0.0, 1.0
    full_minE, full_maxE = args.minE - E_Gamma_Eperp_0, args.maxE - E_Gamma_Eperp_0

    print("full_minE = ", full_minE)
    print("full_maxE = ", full_maxE)

    for this_xs, this_Emks, path_suffix in zip(xs, Emks,
                                               ["0.0", "0.5", "1.0"]):
        out_path = "Efield_bands_E_{}.csv".format(path_suffix)
        write_bands_csv(this_xs, this_Emks, out_path)

    write_bands_aux(special_xs[0], band_path_labels, "Efield_bands_aux.csv")

    plot_bands([xs[0], xs[-1]], special_xs[0], band_path_labels,
               [Emks[0], Emks[-1]], [labels[0], labels[-1]],
               [styles[0], styles[-1]], [full_min_x, full_max_x],
               [full_minE, full_maxE], "full")

    x_K = special_xs[0][2]
    zoom_xlim = [x_K - 0.05, x_K + 0.05]
    zoom_special_xs = [zoom_xlim[0], x_K, zoom_xlim[-1]]
    zoom_band_path_labels = [
        "$\\leftarrow M$", "$K$", "$\\rightarrow \\Gamma$"
    ]
    zoom_ylim = [-0.3, 0.1]

    print("zoom_xlim = ", zoom_xlim)
    print("zoom_ylim = ", zoom_ylim)

    plot_bands(xs, zoom_special_xs, zoom_band_path_labels, Emks, labels,
               styles, zoom_xlim, zoom_ylim, "zoom")
コード例 #10
0
def _main():
    np.set_printoptions(threshold=np.inf)

    parser = argparse.ArgumentParser(
        "TMD multilayer response to electric field",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument("--num_layers",
                        type=int,
                        default=3,
                        help="Number of layers")
    parser.add_argument("--holes",
                        type=float,
                        default=8e12,
                        help="Hole concentration [cm^{-2}]")
    parser.add_argument("--screened",
                        action='store_true',
                        help="Include screening by holes")
    parser.add_argument(
        "--initial_mass",
        action='store_true',
        help=
        "Use effective mass at E_perp = 0, p = 0 instead of recalculating for each phi"
    )
    parser.add_argument(
        "--plot_initial",
        action='store_true',
        help=
        "Plot initial band structure with max applied field, before charge convergence"
    )
    args = parser.parse_args()

    if args.num_layers != 3:
        assert ("num_layers != 3 not implemented")

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(args.prefix))

    E_F_base = fermi_from_scf(scf_path)
    latVecs = latVecs_from_scf(scf_path)
    R = 2 * np.pi * np.linalg.inv(latVecs.T)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
    Hr = extractHr(Hr_path)

    d_A = 6.488  # Angstrom
    d_bohr = _bohr_per_Angstrom * d_A

    hole_density_cm2 = args.holes
    hole_density_bohr2 = hole_density_cm2 / (10**8 * _bohr_per_Angstrom)**2

    #print("hole_density_bohr2")
    #print(hole_density_bohr2)

    # Choose initial potential assuming holes are distributed uniformally.
    sigma_layer_initial = (1 / 3) * _e_C * hole_density_bohr2

    sigmas_initial = sigma_layer_initial * np.array([1.0, 1.0, 1.0])
    #print("sigmas_initial [C/bohr^2]")
    #print(sigmas_initial)

    # Dielectric constant of WSe2:
    # Kim et al., ACS Nano 9, 4527 (2015).
    # http://pubs.acs.org/doi/abs/10.1021/acsnano.5b01114
    #epsilon_r = 7.2

    # Effective dielectric constant from DFT (LDA).
    # avg(K^high_{top - bottom}, Gamma_{top - bottom})
    epsilon_r = 7.87

    Pzs = get_layer_projections(wout_path, args.num_layers)

    E_V_nms = np.linspace(0.0, 1.2, 84)

    if args.plot_initial:
        E_V_bohr = E_V_nms[-1] / (10 * _bohr_per_Angstrom)
        phis_initial_max = get_phis(sigmas_initial, d_bohr, E_V_bohr,
                                    epsilon_r, args.screened)
        plot_H_k0_phis(H_k0s, phis_initial, Pzs, band_indices, E_F_base)
        return

    if hole_density_cm2 > 0.0:
        tol_abs = 1e-6 * sum(sigmas_initial)
    else:
        tol_abs = 1e-12 * _e_C

    tol_rel = 1e-6

    distr_args = []
    for E_V_nm in E_V_nms:
        distr_args.append([
            E_V_nm, R, Hr, latVecs, E_F_base, sigmas_initial, Pzs,
            hole_density_bohr2, d_bohr, epsilon_r, tol_abs, tol_rel,
            args.initial_mass, args.screened
        ])

    with Pool() as p:
        nh_Es = p.starmap(hole_distribution, distr_args)

    plot_results(nh_Es, hole_density_bohr2, hole_density_cm2, epsilon_r,
                 args.screened, E_V_nms)
コード例 #11
0
def _main():
    np.set_printoptions(threshold=np.inf)

    parser = argparse.ArgumentParser(
        "Plot band structure",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument("--num_layers",
                        type=int,
                        default=3,
                        help="Number of layers")
    args = parser.parse_args()

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(args.prefix))

    E_F = fermi_from_scf(scf_path)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
    Hr = extractHr(Hr_path)

    Gamma = np.array([0.0, 0.0, 0.0])
    K = np.array([1 / 3, 1 / 3, 0.0])

    upto_factor = 0.3
    num_ks = 100

    ks = vec_linspace(Gamma, upto_factor * K, num_ks)
    xs = np.linspace(0.0, upto_factor, num_ks)

    assert (Hr[(0, 0, 0)][0].shape[0] == get_total_orbitals(args.num_layers))

    Pzs = get_layer_projections(wout_path, args.num_layers)

    num_top_bands = 2 * args.num_layers

    for k in ks:
        print("k = {}".format(k))

        Hk = Hk_recip(k, Hr)
        Es, U = np.linalg.eigh(Hk)

        top = top_valence_indices(E_F, num_top_bands, Es)
        print("top orbitals = ", top, "energies = ", [Es[t] for t in top])

        tb_states = []
        for restricted_index_n, band_n in enumerate(top):
            state_n = U[:, [band_n]]
            print("orbital", band_n)
            for i, v in enumerate(state_n[:, 0]):
                print(i, v)

            tb_states.append(state_n)

        dm = density_matrix(tb_states, [1] * len(tb_states))

        for z, Pz in enumerate(Pzs):
            print("z = {}".format(z))

            proj_dm = np.dot(Pz, np.dot(dm, Pz))

            proj_dm_evals, proj_dm_evecs = np.linalg.eigh(proj_dm)

            print("proj_dm_evals")
            print(proj_dm_evals)

            print("proj_dm_evecs")

            for i in range(proj_dm_evecs.shape[1]):
                for j in range(proj_dm_evecs.shape[0]):
                    print(j, proj_dm_evecs[j, i])
コード例 #12
0
def _main():
    np.set_printoptions(threshold=np.inf)

    parser = argparse.ArgumentParser(
        "Plot band structure",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument("--num_layers",
                        type=int,
                        default=3,
                        help="Number of layers")
    args = parser.parse_args()

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(args.prefix))

    E_F = fermi_from_scf(scf_path)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
    Hr = extractHr(Hr_path)

    K = np.array([1 / 3, 1 / 3, 0.0])

    reduction_factor = 0.7
    num_ks = 100

    ks = vec_linspace(K, reduction_factor * K, num_ks)
    xs = np.linspace(1, reduction_factor, num_ks)

    assert (Hr[(0, 0, 0)][0].shape[0] == get_total_orbitals(args.num_layers))

    Pzs = get_layer_projections(wout_path, args.num_layers)

    spin_operators = Pauli_over_full_basis(get_total_orbitals(args.num_layers))

    num_top_bands = 2 * args.num_layers

    deviations, proj_overlaps, spins = [], [], []
    spins_non_layer_renormalized = []
    for z in range(len(Pzs)):
        deviations.append([])
        proj_overlaps.append([])
        spins.append([])
        spins_non_layer_renormalized.append([])

    for k in ks:
        print("k = {}".format(k))
        for z, Pz in enumerate(Pzs):
            Hk = Hk_recip(k, Hr)
            Es, U = np.linalg.eigh(Hk)

            top = top_valence_indices(E_F, num_top_bands, Es)
            print("top orbitals = ", top, "energies = ", [Es[t] for t in top])

            proj_dms = []  # "dm" == density matrix
            kz_spins = []
            kz_spins_non_layer_renormalized = []

            for restricted_index_n, band_n in enumerate(top):
                state_n = U[:, [band_n]]
                print("orbital", band_n)
                for i, v in enumerate(state_n[:, 0]):
                    print(i, v)

                dm_n = density_matrix([state_n], [1])

                proj_dm = np.dot(Pz, np.dot(dm_n, Pz))
                proj_dms.append(proj_dm)

                kz_spins.append(expectation_normalized(proj_dm,
                                                       spin_operators))
                kz_spins_non_layer_renormalized.append([
                    np.trace(np.dot(proj_dm, sigma))
                    for sigma in spin_operators
                ])

            spins[z].append(kz_spins)
            spins_non_layer_renormalized[z].append(
                kz_spins_non_layer_renormalized)

            proj_overlap = np.zeros([num_top_bands, num_top_bands],
                                    dtype=np.complex128)

            for restricted_index_np in range(len(top)):
                for restricted_index_n in range(len(top)):
                    dm_np, dm_n = proj_dms[restricted_index_np], proj_dms[
                        restricted_index_n]
                    dm_np_norm = dm_np / np.trace(dm_np)
                    dm_n_norm = dm_n / np.trace(dm_n)

                    print(
                        "np, n, Tr rho_np^z, Tr rho_n^z, Tr rho_np^z rho_n^z",
                        restricted_index_np, restricted_index_n,
                        np.trace(dm_np), np.trace(dm_n),
                        np.trace(np.dot(dm_np, dm_n)))

                    proj_overlap[restricted_index_np,
                                 restricted_index_n] = np.trace(
                                     np.dot(dm_np_norm, dm_n_norm))

            print("z = {}".format(z))
            print("overlap = ")
            print(proj_overlap)

            # proj_overlap should be real.
            eps_abs = 1e-12
            assert (all([x.imag < eps_abs for x in np.nditer(proj_overlap)]))

            # Compute deviation from desired 'all ones' value of proj_overlap.
            deviation = sum([abs(1 - x) for x in np.nditer(proj_overlap)])

            print("sum of abs(deviation) = {}".format(deviation))

            proj_overlaps[z].append(proj_overlap)
            deviations[z].append(deviation)

    # Plot deviation from 1-band-per-layer representability.
    for z in range(len(Pzs)):
        plt.plot(xs, deviations[z], label="deviations for layer {}".format(z))

    plt.legend(loc=0)
    plt.savefig("{}_deviation_separability_K.png".format(args.prefix),
                bbox_inches='tight',
                dpi=500)
    plt.clf()

    # Plot layer-projected band overlaps.
    for z in range(len(Pzs)):
        for ip, i in [(0, 1), (1, 2), (0, 2)]:
            ys = [v[ip, i].real for v in proj_overlaps[z]]
            plt.plot(xs, ys, label="({}, {}) overlap".format(ip, i))

        plt.legend(loc=0)
        plt.savefig("{}_overlap_z_{}_separability_K.png".format(
            args.prefix, z),
                    bbox_inches='tight',
                    dpi=500)
        plt.clf()

    # Plot layer-projected spin expectation values.
    for z in range(len(Pzs)):
        colors = ['k', 'g', 'b']
        styles = ['-', '--', '.']

        for band_n, style in zip([0, 1, 2], styles):
            for (spin_index,
                 spin_dir), color in zip(enumerate(['x', 'y', 'z']), colors):
                ys = [
                    spins[z][k][band_n][spin_index].real for k in range(num_ks)
                ]
                plt.plot(xs,
                         ys,
                         '{}{}'.format(color, style),
                         label="Band {} spin {}".format(band_n, spin_dir))

        plt.legend(loc=0)
        plt.savefig("{}_z_{}_spin_real.png".format(args.prefix, z),
                    bbox_inches='tight',
                    dpi=500)
        plt.clf()

        for band_n, style in zip([0, 1, 2], styles):
            for (spin_index,
                 spin_dir), color in zip(enumerate(['x', 'y', 'z']), colors):
                ys = [
                    spins[z][k][band_n][spin_index].imag for k in range(num_ks)
                ]
                plt.plot(xs,
                         ys,
                         '{}{}'.format(color, style),
                         label="Band {} spin {}".format(band_n, spin_dir))

        plt.legend(loc=0)
        plt.savefig("{}_z_{}_spin_imag.png".format(args.prefix, z),
                    bbox_inches='tight',
                    dpi=500)
        plt.clf()

    # Plot sum of spin expectation values over layers.
    colors = ['k', 'g', 'b']
    styles = ['-', '--', '.']
    for (spin_index, spin_dir), color in zip(enumerate(['x', 'y', 'z']),
                                             colors):
        for band_n, style in zip([0, 1, 2], styles):
            ys = np.zeros([num_ks], dtype=np.float64)

            for z in range(len(Pzs)):
                ys += np.array([
                    spins_non_layer_renormalized[z][k][band_n][spin_index].real
                    for k in range(num_ks)
                ])

            plt.plot(xs,
                     ys,
                     '{}{}'.format(color, style),
                     label="Band {} spin {}".format(band_n, spin_dir))

    plt.legend(loc=0)
    plt.savefig("{}_z_total_spin_real.png".format(args.prefix),
                bbox_inches='tight',
                dpi=500)
    plt.clf()
コード例 #13
0
def _main():
    parser = ArgumentParser(
        description="Plot partial DOS from Wannier Hamiltonian.")
    parser.add_argument('prefix', type=str, help="Name of the system.")
    parser.add_argument(
        '--num',
        action='store_true',
        help=
        "Calculate number of states from tetrahedron method and DOS from n(E)."
    )
    parser.add_argument(
        '--num_electrons',
        type=float,
        default=None,
        help=
        "Number of valence electrons in Wannier bands (must be specified if --num is used)"
    )
    parser.add_argument(
        '--load',
        action='store_true',
        help="Load pre-calculated DOS/n data instead of calculating.")
    parser.add_argument('--spin_polarized',
                        help="Use spin-polarized system.",
                        action='store_true')
    parser.add_argument(
        '--groups',
        type=str,
        default=None,
        help=
        "Partial DOS values to be added together (ex: '0,1,2;3,4,5' reports pdos 0+1+2 and 3+4+5)"
    )
    parser.add_argument('--group_labels',
                        type=str,
                        default=None,
                        help="Labels for groups specified by --groups")
    parser.add_argument('--minE',
                        type=float,
                        help="Minimum energy to plot.",
                        default=None)
    parser.add_argument('--maxE',
                        type=float,
                        help="Maximum energy to plot.",
                        default=None)
    parser.add_argument(
        '--num_dos',
        type=int,
        default=3000,
        help="Number of energy values at which to calculate density of states")
    parser.add_argument('--n0',
                        type=int,
                        default=8,
                        help="Number of k-points in each direction")
    parser.add_argument('--sigma',
                        type=float,
                        default=0.1,
                        help="Gaussian delta-function broadening constant")
    parser.add_argument('--cwannier_path',
                        type=str,
                        default=None,
                        help="Path to cwannier/ directory")
    args = parser.parse_args()

    base_dir = _base_dir()
    cwannier_path = os.path.join(base_dir, "cwannier")
    work_base = os.path.expandvars(_global_config()["work_base"])
    wannier_dir = os.path.join(work_base, args.prefix, "wannier")
    outPath = "{}_{}".format(args.prefix, str(args.n0))

    # Get Fermi energy from SCF output.
    scfPath = os.path.join(wannier_dir, "scf.out")
    fermi = fermi_from_scf(scfPath)
    alat = alat_from_scf(scfPath)
    D = alat * D_from_scf(scfPath)
    R = 2.0 * np.pi * np.linalg.inv(D)

    # Load Wannier Hamiltonian and calculate DOS.
    if not args.spin_polarized:
        spins = [""]
    else:
        spins = ["_up", "_dn"]

    # Calculate PDOS values.
    pdos, Es = [], []
    pnum, n_fermi = [], []
    fermi_from_num = 0.0
    for sp in spins:
        Hr_path = os.path.join(wannier_dir,
                               "{}{}_hr.dat".format(args.prefix, sp))
        if args.num:
            pnum_outpath = outPath + "_pnum_data"
            if not args.load:
                this_pnum, this_Es, n_fermi, fermi_from_num = PartialNum(
                    Hr_path, R, args.minE, args.maxE, args.num_dos,
                    args.num_electrons, args.n0, cwannier_path, pnum_outpath)
            else:
                this_pnum, this_Es, n_fermi, fermi_from_num = _extract_pnum_vals(
                    pnum_outpath)

            this_pdos = pdos_from_num(this_pnum, this_Es)
            pnum.append(this_pnum)
            pdos.append(this_pdos)
            Es.append(this_Es)
        else:
            pdos_outpath = outPath + "_pdos_data"
            if not args.load:
                this_pdos, this_Es = PartialDos(Hr_path, R, args.minE,
                                                args.maxE, args.num_dos,
                                                args.sigma, args.n0,
                                                cwannier_path, pdos_outpath)
            else:
                this_pdos, this_Es = _extract_pdos_vals(pdos_outpath)

            pdos.append(this_pdos)
            Es.append(this_Es)

    # Aggregate groups.
    group_pdos, group_pnum = [], []
    if args.groups != None:
        group_vals = args.groups.split(";")
        num_groups = len(group_vals)
        for sp_index, sp_pdos in enumerate(pdos):
            sp_pnum = pnum[sp_index]
            group_pdos.append([])
            if args.num:
                group_pnum.append([])

            for group_index, group in enumerate(group_vals):
                group_pdos[sp_index].append([])
                if args.num:
                    group_pnum[sp_index].append([])

                group_band_indices = list(map(int, group.split(",")))
                for E_index in range(len(Es[sp_index])):
                    total_dos, total_num = 0.0, 0.0
                    for band_index in group_band_indices:
                        total_dos += sp_pdos[band_index][E_index]
                        if args.num:
                            total_num += sp_pnum[band_index][E_index]

                    group_pdos[sp_index][group_index].append(total_dos)
                    if args.num:
                        group_pnum[sp_index][group_index].append(total_num)
    else:
        group_pdos = pdos
        group_pnum = pnum

    if args.group_labels is not None:
        group_labels_split = args.group_labels.split(";")
    else:
        group_labels_split = None

    if args.num:
        # Echo n(E_Fermi)
        print("Got Fermi energy from n(E) = {}; scf Fermi energy = {}".format(
            str(fermi_from_num), str(fermi)))
        print("n(E) at the E_F from n(E) = {}".format(str(n_fermi)))
        # Make pnum plot.
        plot_pnum_outpath = outPath + "_pnum"
        plot_pvals(group_pnum, Es, fermi_from_num, plot_pnum_outpath, "$n(E)$",
                   args.minE, args.maxE, group_labels_split)

    # Make PDOS plot.
    plot_pdos_outpath = outPath + "_pdos"
    plot_pvals(group_pdos, Es, fermi, plot_pdos_outpath, "PDOS [eV$^{-1}$]",
               args.minE, args.maxE, group_labels_split)

    # Export data to allow plotting with different styling.
    # NOTE - only supports case with non-spin-polarized or noncollinear spin cases.
    # TODO - support collinear spin-polarized case.
    Es_shifted = [E - fermi for E in Es[0]]
    export_pdos_data(outPath, Es_shifted, group_pdos[0], group_labels_split)
コード例 #14
0
def get_occupations(prefix, subdir, screened, d_bohr, hole_density_bohr2,
                    sigmas_initial, epsilon_r):
    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    latVecs = latVecs_from_scf(scf_path)
    alat_Bohr = 1.0
    R = 2 * np.pi * np.linalg.inv(latVecs.T)

    Gamma_cart = np.array([0.0, 0.0, 0.0])
    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    K_cart = np.dot(K_lat, R)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    H_TB_Gamma = Hk(Gamma_cart, Hr, latVecs)
    Es_Gamma, U_Gamma = np.linalg.eigh(H_TB_Gamma)

    H_TB_K = Hk(K_cart, Hr, latVecs)
    Es_K, U_K = np.linalg.eigh(H_TB_K)

    top_Gamma = top_valence_indices(E_F, 2, Es_Gamma)
    top_K = top_valence_indices(E_F, 3, Es_Gamma)
    assert (top_Gamma == [41, 40])
    assert (top_K == [41, 40, 39])

    E_top_Gamma, E_top_K = Es_Gamma[top_Gamma[0]], Es_K[top_K[0]]

    Ediff = E_top_Gamma - E_top_K

    def Hfn(k):
        return Hk(k, Hr, latVecs)

    mstar_top_Gamma = effective_mass_band(Hfn, Gamma_cart, top_Gamma[0],
                                          alat_Bohr)
    mstar_top_K = effective_mass_band(Hfn, K_cart, top_K[0], alat_Bohr)

    mstar_Gamma = mstar_top_Gamma[0]
    mstar_K = mstar_top_K[0]

    num_layers = 3
    Pzs = get_layer_projections(wout_path, num_layers)

    if hole_density_bohr2 > 0.0:
        tol_abs = 1e-6 * sum(sigmas_initial)
    else:
        tol_abs = 1e-12 * _e_C

    tol_rel = 1e-6

    nh_Gamma, nh_K, E_Gamma, E_K = hole_distribution(0.0,
                                                     R,
                                                     Hr,
                                                     latVecs,
                                                     E_F,
                                                     sigmas_initial,
                                                     Pzs,
                                                     hole_density_bohr2,
                                                     d_bohr,
                                                     epsilon_r,
                                                     tol_abs,
                                                     tol_rel,
                                                     screened=screened)

    if hole_density_bohr2 > 0.0:
        nh_Gamma_frac = nh_Gamma / hole_density_bohr2
        nh_K_frac = nh_K / hole_density_bohr2
    else:
        nh_Gamma_frac = 0.0
        nh_K_frac = 0.0

    return Ediff, mstar_Gamma, mstar_K, nh_Gamma_frac, nh_K_frac, E_Gamma, E_K
コード例 #15
0
def _main():
    parser = argparse.ArgumentParser(
        "Plot band structure",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument(
        "--num_layers",
        type=int,
        default=3,
        help="Number of layers (required if group_layer_* options given)")
    args = parser.parse_args()

    if args.num_layers != 3:
        raise ValueError("mirror check not implemented for num_layers != 3")

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")

    E_F = fermi_from_scf(scf_path)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
    Hr = extractHr(Hr_path)

    K = np.array([1 / 3, 1 / 3, 0.0])

    reduction_factor = 0.7
    num_ks = 100

    ks = vec_linspace(K, reduction_factor * K, num_ks)
    xs = np.linspace(1, reduction_factor, num_ks)

    basis = basis_state_labels(args.num_layers)
    M = mirror_op()

    # Assume SOC present and that model has 2*3 X(p) orbitals per layer
    # and 2*5 M(d) in canonical Wannier90 order.
    # Assumes atoms are ordered with all Xs first, then all Ms, and within
    # M/X groups the atoms are in layer order.
    orbitals_per_X = 6
    orbitals_per_M = 10

    # Base index for orbitals of each layer:
    base_orbitals = [
        args.num_layers * 2 * orbitals_per_X + z * orbitals_per_M
        for z in range(args.num_layers)
    ]

    # Orbitals contributing to j = +5/2 state:
    x2y2_up = [base + 6 for base in base_orbitals]
    xy_up = [base + 8 for base in base_orbitals]
    x2y2_dn = [base + 7 for base in base_orbitals]
    xy_dn = [base + 9 for base in base_orbitals]

    num_top_bands = 2 * args.num_layers
    weights = []
    for i in range(num_top_bands):
        weights.append([])

    for k in ks:
        Hk = Hk_recip(k, Hr)
        Es, U = np.linalg.eigh(Hk)

        top = top_valence_indices(E_F, num_top_bands, Es)

        for i, band in enumerate(top):
            total = 0

            state = U[:, band]

            mirror_eval = np.dot(state.conjugate().T, np.dot(M, state))[0, 0]
            print("band {}; mirror <v|M|v> = {}".format(band, mirror_eval))
            print("mirror deviation elements")
            #Mdev = np.dot(M, state) - mirror_signs[i] * state
            #for n, v in enumerate(Mdev):
            #    if abs(v)**2 > 1e-3:
            #        print(n, basis[n], v, abs(v)**2)

            print("band, orb, orb_label, weight, evec comp")
            #for n, v in enumerate(state):
            #    if abs(v)**2 > 1e-2:
            #        print(band, n, basis[n], abs(v)**2, v)
            for n, v in enumerate(state):
                print(band, n, basis[n], abs(v)**2, v)

            for z, (n1_up, n2_up, n1_dn,
                    n2_dn) in enumerate(zip(x2y2_up, xy_up, x2y2_dn, xy_dn)):
                # Appropriate arrangement for K.
                # TODO - swap for -K.
                # U[n, i] = <n|i> --> <i|n> = U[n, i].conjugate()
                if z % 2 == 0:
                    evec_comp = (
                        1 / np.sqrt(2)) * (U[n1_dn, band].conjugate() -
                                           1j * U[n2_dn, band].conjugate())
                else:
                    evec_comp = (
                        1 / np.sqrt(2)) * (U[n1_up, band].conjugate() +
                                           1j * U[n2_up, band].conjugate())

                total += abs(evec_comp)**2

            weights[i].append(1 - total)

    for i, band_weights in enumerate(weights):
        plt.plot(xs, band_weights, label="Band {}".format(i))

    plt.legend(loc=0)
    plt.xlabel("k / K", fontsize='large')
    plt.ylabel("Weight outside l_z = +/- 2, up/down group")
    plt.savefig("model_weights_K.png", bbox_inches='tight', dpi=500)
コード例 #16
0
def _main():
    parser = argparse.ArgumentParser(
        "Plot band structure",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument(
        "--num_layers",
        type=int,
        default=3,
        help="Number of layers (required if group_layer_* options given)")
    args = parser.parse_args()

    if args.num_layers != 3:
        raise ValueError("mirror check not implemented for num_layers != 3")

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")

    E_F = fermi_from_scf(scf_path)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(args.prefix))
    Hr = extractHr(Hr_path)

    Gamma = np.array([0.0, 0.0, 0.0])
    K = np.array([1 / 3, 1 / 3, 0.0])

    max_K_factor = 0.3
    num_ks = 2

    ks = vec_linspace(Gamma, max_K_factor * K, num_ks)
    xs = np.linspace(0.0, max_K_factor, num_ks)

    basis = basis_state_labels(args.num_layers)
    M = mirror_op()

    # Assume SOC present and that model has 2*3 X(p) orbitals per layer
    # and 2*5 M(d) in canonical Wannier90 order.
    # Assumes atoms are ordered with all Xs first, then all Ms, and within
    # M/X groups the atoms are in layer order.
    orbitals_per_X = 6
    orbitals_per_M = 10

    # Base index for orbitals of each layer:
    X_base_orbitals = [
        z * orbitals_per_X for z in range(1, 2 * args.num_layers - 1)
    ]
    M_base_orbitals = [
        args.num_layers * 2 * orbitals_per_X + z * orbitals_per_M
        for z in range(args.num_layers)
    ]

    pz_up = [n for n in X_base_orbitals]
    pz_dn = [n + 1 for n in X_base_orbitals]
    dz2_up = [n for n in M_base_orbitals]
    dz2_dn = [n + 1 for n in M_base_orbitals]
    #print(pz_up)
    #print(pz_dn)
    #print(dz2_up)
    #print(dz2_dn)

    orbital_group = list(itertools.chain(pz_up, pz_dn, dz2_up, dz2_dn))

    num_top_bands = 2 * args.num_layers

    weights = []
    for i in range(num_top_bands):
        weights.append([])

    for k in ks:
        print("k = ", k)
        Hk = Hk_recip(k, Hr)
        Es, U = np.linalg.eigh(Hk)

        top = top_valence_indices(E_F, num_top_bands, Es)
        print("top valence", top, [Es[t] for t in top])

        mirror_signs = [1, 1, -1, -1, 1, 1]

        for i, band in enumerate(top):
            state = U[:, band]

            mirror_eval = np.dot(state.conjugate().T, np.dot(M, state))[0, 0]
            print("band {}; mirror <v|M|v> = {}".format(band, mirror_eval))
            print("mirror deviation elements")
            Mdev = np.dot(M, state) - mirror_signs[i] * state
            for n, v in enumerate(Mdev):
                if abs(v)**2 > 1e-3:
                    print(n, basis[n], v, abs(v)**2)

            print("band, orb, orb_label, weight, evec comp")
            #for n, v in enumerate(state):
            #    if abs(v)**2 > 1e-2:
            #        print(band, n, basis[n], abs(v)**2, v)
            for n, v in enumerate(state):
                print(band, n, basis[n], abs(v)**2, v)

            total = 0

            for n in orbital_group:
                evec_comp = U[n, band].conjugate()
                total += abs(evec_comp)**2

            #print(total)
            weights[i].append(1 - total)

    #for i, band_weights in enumerate(weights):
    #    plt.plot(xs, band_weights, label="Band {}".format(i))
    plt.plot(xs, weights[0], 'b.', label="Band 0")
    plt.plot(xs, weights[1], 'g--', label="Band 1")

    plt.legend(loc=0)
    plt.xlabel("k / K", fontsize='large')
    plt.ylabel("Weight outside inner p_z, dz^2")
    plt.savefig("model_weights_Gamma.png", bbox_inches='tight', dpi=500)
コード例 #17
0
def get_gaps(work, prefix, layer_threshold, k, spin_valence=None, spin_conduction=None,
        use_curvature=True):
    wannier_dir = os.path.join(work, prefix, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    E_F = fermi_from_scf(scf_path)
    alat_Bohr = alat_from_scf(scf_path)
    D = D_from_scf(scf_path)
    R = 2*np.pi*np.linalg.inv(D)
    k_Cart = np.dot(np.array(k), R)

    layer_indices_up = get_layer_indices(work, prefix, 'up')
    layer_indices_down = get_layer_indices(work, prefix, 'down')

    Hr = get_Hr(work, prefix)
    # note:
    # rotated K 2pi/3: K_R2 = (-2/3, 1/3, 0.0)
    # rotated K 4pi/3: K_R4 = (1/3, -2/3, 0.0)
    Hk = Hk_recip(k, Hr)

    w, U = np.linalg.eigh(Hk)

    conduction, valence = layer_band_extrema(w, U, E_F, layer_indices_up, layer_indices_down,
            layer_threshold, spin_valence, spin_conduction)

    conduction_curvature = [None, None]
    valence_curvature = [None, None]

    for l in [0, 1]:
        valence_curvature[l] = get_curvature(D, Hr, k_Cart, valence[l])
        conduction_curvature[l] = get_curvature(D, Hr, k_Cart, conduction[l])

    gaps = {}
    layer_labels = ["0", "1"]
    # Generate gap for each layer pair. Keys have the form: "(0, 1)/(0, 1)".
    for cond_layer_index, cond_layer_label in enumerate(layer_labels):
        for valence_layer_index, valence_layer_label in enumerate(layer_labels):
            k = "{}/{}".format(cond_layer_label, valence_layer_label)
            gaps[k] = float(w[conduction[cond_layer_index]] - w[valence[valence_layer_index]])

    # Generate band extremum energy for each choice of layer and valence or conduction.
    vc_labels = ["valence", "conduction"]
    all_vc_data = [valence, conduction]
    for vc_label, vc_data in zip(vc_labels, all_vc_data):
        for layer_index, layer_label in enumerate(layer_labels):
            k = "{}_{}".format(layer_label, vc_label)
            gaps[k] = float(w[vc_data[layer_index]])

    # Minimum of the spin-orbit split partner of the lowest conduction band.
    # If layer gap is smaller than SO splitting, need to skip a band to find partner.
    conduction_min = min(conduction[0], conduction[1])
    if abs(conduction[0] - conduction[1]) == 1:
        conduction_min_partner = conduction_min + 2
    else:
        conduction_min_partner = conduction_min + 1

    gaps["conduction_min_partner"] = float(w[conduction_min_partner])

    if use_curvature:
        add_curvature(gaps, valence_curvature, conduction_curvature, alat_Bohr)

    return gaps
コード例 #18
0
def _main():
    np.set_printoptions(threshold=np.inf)

    parser = argparse.ArgumentParser(
        "TMD multilayer response to electric field",
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument("prefix", type=str, help="Prefix for calculation")
    parser.add_argument(
        "--subdir",
        type=str,
        default=None,
        help="Subdirectory under work_base where calculation was run")
    parser.add_argument("--holes",
                        type=float,
                        default=8e12,
                        help="Hole concentration [cm^{-2}]")
    parser.add_argument("--screened",
                        action='store_true',
                        help="Include screening by holes")
    parser.add_argument(
        "--diag_mass_only",
        action='store_true',
        help=
        "Include q variation only through qx^2, qy^2 mass terms on diagonal")
    args = parser.parse_args()

    work = _get_work(args.subdir, args.prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")

    E_F_base = fermi_from_scf(scf_path)

    d_A = 6.488  # Angstrom
    d_bohr = _bohr_per_Angstrom * d_A

    hole_density_cm2 = args.holes
    hole_density_bohr2 = hole_density_cm2 / (10**8 * _bohr_per_Angstrom)**2

    #print("hole_density_bohr2")
    #print(hole_density_bohr2)

    # Choose initial potential assuming holes are distributed uniformally.
    sigma_layer_initial = (1 / 3) * _e_C * hole_density_bohr2

    sigmas_initial = sigma_layer_initial * np.array([1.0, 1.0, 1.0])
    #print("sigmas_initial [C/bohr^2]")
    #print(sigmas_initial)

    # Dielectric constant of WSe2:
    # Kim et al., ACS Nano 9, 4527 (2015).
    # http://pubs.acs.org/doi/abs/10.1021/acsnano.5b01114
    #epsilon_r = 7.2

    # Effective dielectric constant from DFT (LDA).
    # avg(K^high_{top - bottom}, Gamma_{top - bottom})
    epsilon_r = 7.87

    H0_tot_Gamma, ps_tot_Gamma, mstar_inv_tot_Gamma = make_effective_Hamiltonian_Gamma(
        args.subdir, args.prefix, top_two_only=False, verbose=False)

    K_lat = np.array([1 / 3, 1 / 3, 0.0])
    H0_tot_K, ps_tot_K, mstar_inv_tot_K = make_effective_Hamiltonian_K(
        K_lat,
        args.subdir,
        args.prefix,
        get_layer_basis_from_dm_K,
        verbose=False)

    Kp_lat = np.array([-1 / 3, -1 / 3, 0.0])
    H0_tot_Kp, ps_tot_Kp, mstar_inv_tot_Kp = make_effective_Hamiltonian_K(
        Kp_lat,
        args.subdir,
        args.prefix,
        get_layer_basis_from_dm_K,
        verbose=False)

    H0s = [H0_tot_Gamma, H0_tot_K, H0_tot_Kp]
    if args.diag_mass_only:
        ps = [
            np.zeros([6, 6], dtype=np.complex128),
            np.zeros([6, 6], dtype=np.complex128),
            np.zeros([6, 6], dtype=np.complex128)
        ]

        def extract_diag(mstar_inv):
            result = {}
            for cp in range(2):
                for c in range(2):
                    result[(cp, c)] = np.zeros([6, 6], dtype=np.complex128)
                    if c == cp:
                        for i in range(6):
                            result[(cp, c)][i, i] = mstar_inv[(cp, c)][i, i]

            return result

        mstar_invs = list(
            map(extract_diag,
                [mstar_inv_tot_Gamma, mstar_inv_tot_K, mstar_inv_tot_Kp]))
    else:
        ps = [ps_tot_Gamma, ps_tot_K, ps_tot_Kp]
        mstar_invs = [mstar_inv_tot_Gamma, mstar_inv_tot_K, mstar_inv_tot_Kp]

    Pzs = layer_projections()

    E_V_nms = np.linspace(0.0, 1.2, 84)

    if hole_density_cm2 > 0.0:
        tol_abs = 1e-6 * sum(sigmas_initial)
    else:
        tol_abs = 1e-12 * _e_C

    tol_rel = 1e-6

    distr_args = []
    for E_V_nm in E_V_nms:
        distr_args.append([
            E_V_nm, H0s, ps, mstar_invs, E_F_base, sigmas_initial, Pzs,
            hole_density_bohr2, d_bohr, epsilon_r, tol_abs, tol_rel,
            args.screened
        ])

    with Pool() as p:
        nh_Es = p.starmap(hole_distribution, distr_args)

    plot_results(nh_Es, hole_density_bohr2, hole_density_cm2, epsilon_r,
                 args.screened, E_V_nms)
コード例 #19
0
def make_effective_Hamiltonian_K(k0_lat,
                                 subdir,
                                 prefix,
                                 get_layer_basis,
                                 verbose=False):
    num_layers = 3

    work = _get_work(subdir, prefix)
    wannier_dir = os.path.join(work, "wannier")
    scf_path = os.path.join(wannier_dir, "scf.out")
    wout_path = os.path.join(wannier_dir, "{}.wout".format(prefix))

    E_F = fermi_from_scf(scf_path)
    latVecs = latVecs_from_scf(scf_path)
    alat_Bohr = 1.0
    R = 2 * np.pi * np.linalg.inv(latVecs.T)

    K_cart = np.dot(k0_lat, R)

    if verbose:
        print(K_cart)
        print(latVecs)

    reduction_factor = 0.7
    num_ks = 100

    ks = vec_linspace(K_cart, reduction_factor * K_cart, num_ks)
    xs = np.linspace(1, reduction_factor, num_ks)

    Hr_path = os.path.join(wannier_dir, "{}_hr.dat".format(prefix))
    Hr = extractHr(Hr_path)

    Pzs = get_layer_projections(wout_path, num_layers)

    H_TB_K = Hk(K_cart, Hr, latVecs)
    Es, U = np.linalg.eigh(H_TB_K)

    top = top_valence_indices(E_F, 2 * num_layers, Es)

    layer_weights, layer_basis = get_layer_basis(U, top, Pzs, verbose)

    complement_basis_mat = nullspace(array_with_rows(layer_basis).conjugate())
    complement_basis = []
    for i in range(complement_basis_mat.shape[1]):
        v = complement_basis_mat[:, [i]]
        complement_basis.append(v / np.linalg.norm(v))

    assert (len(layer_basis) + len(complement_basis) == 22 * num_layers)

    for vl in [v.conjugate().T for v in layer_basis]:
        for vc in complement_basis:
            assert (abs(np.dot(vl, vc)[0, 0]) < 1e-12)

    # 0th order effective Hamiltonian: H(K) in layer basis.
    H_layer_K = layer_Hamiltonian_0th_order(H_TB_K, layer_basis)

    #E_repr = sum([Es[t] for t in top]) / len(top)
    E_repr = Es[top[0]]
    H_correction = correction_Hamiltonian_0th_order(K_cart, Hr, latVecs,
                                                    E_repr, complement_basis,
                                                    layer_basis)

    H0_tot = H_layer_K + H_correction

    H_PQ = correction_Hamiltonian_PQ(K_cart, Hr, latVecs, complement_basis,
                                     layer_basis)

    # Momentum expectation values <z_{lp}| dH/dk_{c}|_K |z_l>
    ps = layer_Hamiltonian_ps(K_cart, Hr, latVecs, layer_basis)

    ps_correction = correction_Hamiltonian_ps(K_cart, Hr, latVecs, E_repr,
                                              complement_basis, layer_basis)

    ps_tot = deepcopy(ps)
    for i, v in enumerate(ps_correction):
        ps_tot[i] += v

    # Inverse effective masses <z_{lp}| d^2H/dk_{cp}dk_{c}|_K |z_l>
    mstar_invs = layer_Hamiltonian_mstar_inverses(K_cart, Hr, latVecs,
                                                  layer_basis)

    mstar_invs_correction_base, mstar_invs_correction_other = correction_Hamiltonian_mstar_inverses(
        K_cart, Hr, latVecs, E_repr, complement_basis, layer_basis)

    mstar_inv_tot = deepcopy(mstar_invs)
    for mstar_contrib in [
            mstar_invs_correction_base, mstar_invs_correction_other
    ]:
        for k, v in mstar_contrib.items():
            mstar_inv_tot[k] += v

    if verbose:
        print("H0")
        print(H_layer_K)

        print("H_correction")
        print(H_correction)
        print("H_correction max")
        print(abs(H_correction).max())

        print("H_PQ max")
        print(abs(H_PQ).max())

        print("ps")
        print(ps)

        print("ps max")
        print(max([abs(x).max() for x in ps]))

        print("ps correction")
        print(ps_correction)

        print("ps_correction max")
        print(max([abs(x).max() for x in ps_correction]))

        print("mstar_inv")
        print(mstar_invs)

        print("mstar_inv max")
        print(max([abs(v).max() for k, v in mstar_invs.items()]))

        print("mstar_inv_correction_base")
        print(mstar_invs_correction_base)

        print("mstar_inv_correction_base max")
        print(
            max([abs(v).max() for k, v in mstar_invs_correction_base.items()]))

        print("mstar_inv_correction_other")
        print(mstar_invs_correction_other)

        print("mstar_inv_correction_other max")
        print(
            max([abs(v).max()
                 for k, v in mstar_invs_correction_other.items()]))

        # Fit quality plots.
        H_layers = []
        for k in ks:
            q = k - K_cart

            H_layers.append(
                H_kdotp(q, H_layer_K, H_correction, ps, ps_correction,
                        mstar_invs, mstar_invs_correction_base,
                        mstar_invs_correction_other))

        Emks, Umks = [], []
        for band_index in range(len(layer_basis)):
            Emks.append([])
            Umks.append([])

        for k_index, Hk_layers in enumerate(H_layers):
            Es, U = np.linalg.eigh(Hk_layers)
            #print(k_index)
            #print("U", U)

            for band_index in range(len(layer_basis)):
                Emks[band_index].append(Es)
                Umks[band_index].append(U)

        for band_index in range(len(layer_basis)):
            plt.plot(xs, Emks[band_index])

        TB_Emks = []
        for m in range(len(top)):
            TB_Emks.append([])

        for k in ks:
            this_H_TB_k = Hk(k, Hr, latVecs)
            this_Es, this_U = np.linalg.eigh(this_H_TB_k)

            for m, i in enumerate(top):
                TB_Emks[m].append(this_Es[i])

        for TB_Em in TB_Emks:
            plt.plot(xs, TB_Em, 'k.')

        plt.show()
        plt.clf()

        # Effective masses.
        print(
            "effective mass, top valence band, TB model: m^*_{xx; yy; xy} / m_e"
        )
        mstar_TB = effective_mass_band(lambda k: Hk(k, Hr, latVecs), K_cart,
                                       top[0], alat_Bohr)
        print(mstar_TB)

        print(
            "effective mass, top valence band, k dot p model: m^*_{xx; yy; xy} / m_e"
        )
        mstar_kdotp = effective_mass_band(
            lambda k:
            H_kdotp(k - K_cart, H_layer_K, H_correction, ps, ps_correction,
                    mstar_invs, mstar_invs_correction_base,
                    mstar_invs_correction_other), K_cart,
            len(layer_basis) - 1, alat_Bohr)
        print(mstar_kdotp)

        # Elements contributing to crossover scale.
        t_K = H0_tot[1, 2]
        t_K_25 = H0_tot[2, 5]
        Delta_K = H0_tot[1, 1] - H0_tot[2, 2]
        lambda_SO = H0_tot[1, 1] - H0_tot[0, 0]

        t_K_direct = H0_tot[1, 5]

        print("t_K, Delta_K, lambda_SO")
        print(t_K, Delta_K, lambda_SO)

        print("t_K_25")
        print(t_K_25)

        print("norm(t_K), norm(t_K_25)")
        print(abs(t_K), abs(t_K_25))

        print("t_K_direct, norm(t_K_direct)")
        print(t_K_direct, abs(t_K_direct))

        print("E_SL_K top")
        print([H0_tot[i, i] for i in [1, 3, 5]])

        print("E_SL_K bottom")
        print([H0_tot[i, i] for i in [0, 2, 4]])

        # Elements contributing to effective dielectric constant.
        print("Layer on-site energy differences:")
        print(
            "Top group of bands: middle layer - bottom layer; top layer - middle layer"
        )
        print(H0_tot[3, 3] - H0_tot[1, 1], H0_tot[5, 5] - H0_tot[3, 3])
        print(
            "Bottom group of bands: middle layer - bottom layer; top layer - middle layer"
        )
        print(H0_tot[2, 2] - H0_tot[0, 0], H0_tot[4, 4] - H0_tot[2, 2])

        H_TB_Gamma = Hk_recip(np.array([0.0, 0.0, 0.0]), Hr)
        Es_Gamma, U_Gamma = np.linalg.eigh(H_TB_Gamma)
        Gamma_valence_max = Es_Gamma[top[0]]

        print("H0")
        print_H0_LaTeX(H_layer_K, Gamma_valence_max)

        print("H0_tot")
        print_H0_LaTeX(H0_tot, Gamma_valence_max)

        dump_model_np("{}_model_K".format(prefix), H0_tot, ps_tot,
                      mstar_inv_tot)

        phases = {(i, j): cmath.phase(H0_tot[i, j])
                  for i, j in [(0, 3), (1, 2), (2, 5), (3, 4)]}

        phase_factors = list(
            map(lambda x: np.exp(-1j * x), [
                -phases[(0, 3)], -phases[(1, 2)], 0.0, 0.0, phases[(3, 4)],
                phases[(2, 5)]
            ]))
        phase_U = np.diag(phase_factors)

        H0_tot_real_hop = np.dot(phase_U.conjugate().T,
                                 np.dot(H0_tot, phase_U))

        print("H0_tot_real_hop")
        print_H0_LaTeX(H0_tot_real_hop, Gamma_valence_max)

    return H0_tot, ps_tot, mstar_inv_tot