def _main(): parser = argparse.ArgumentParser("Run postprocessing to set up Wannier90 calculation", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--subdir", type=str, default=None, help="Subdirectory under work_base to run calculation") parser.add_argument("--global_prefix", type=str, default="MoS2_WS2", help="Prefix for calculation") 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) if "qe_bands" in gconf: qe_bands_dir = os.path.expandvars(gconf["qe_bands"]) qe_bands_path = os.path.join(qe_bands_dir, "bands.x") else: qe_bands_path = "bands.x" calc = "pw_post" prefix_groups = get_prefix_groups(base_path, args.global_prefix) config = {"machine": "ls5", "cores": 24, "nodes": 1, "queue": "normal", "hours": 8, "minutes": 0, "wannier": True, "project": "A-ph9", "global_prefix": args.global_prefix, "max_jobs": 24, "qe_bands": qe_bands_path} submit_dgrid_pw_post(base_path, config, prefix_groups)
def _main(): parser = ArgumentParser("wfc cleanup") parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument( 'global_prefix', type=str, help="System for which wannier/ .save directories will be removed") parser.add_argument( '--confirm', action='store_true', help="Must specify --confirm to confirm .save removal is desired") args = parser.parse_args() if not args.confirm: return gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) for prefix in prefixes: save_path = os.path.join(work, prefix, "wannier", "{}.save".format(prefix)) shutil.rmtree(save_path)
def _main(): parser = argparse.ArgumentParser( description="Plot various quantities as function of displacement") parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument('--global_prefix', type=str, default="MoS2_WS2", help="Calculation global prefix") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) write_out_data = {"_ds": []} for d, prefix in dps: write_out_data["_ds"].append(d) energies = get_energies(work, dps) energies_rel_meV = energies_relative_to(energies, dps, (0.0, 0.0)) E_title = "$\\Delta E$ [meV]" E_plot_name = "{}_energies".format(args.global_prefix) plot_d_vals(E_plot_name, E_title, dps, energies_rel_meV) write_out_data["meV_relative_total_energy"] = energies_rel_meV soc = True Hk_vals = extract_Hk_vals(work, dps, soc) for label, this_vals in Hk_vals.items(): title = label plot_name = "{}_{}".format(args.global_prefix, label) plot_d_vals(plot_name, title, dps, this_vals) write_out_data["eV_{}".format(label)] = this_vals na, nb = 16, 16 num_dos = 1000 E_below_fermi, E_above_fermi = 3.0, 3.0 gaps = find_gaps(work, dps, E_below_fermi, E_above_fermi, num_dos, na, nb) gap_plot_title = "Gaps [eV]" gap_plot_name = "{}_gaps".format(args.global_prefix) plot_d_vals(gap_plot_name, gap_plot_title, dps, gaps) write_out_data["eV_overall_gap"] = gaps with open("{}_plot_ds_data.json".format(args.global_prefix), 'w') as fp: json.dump(write_out_data, fp)
def H_klat_Glat(dps, kGs): '''Integrate by trapezoid method. Lazy way to compute: for each region, compute each Hk at boundaries. Avoid point storage scheme and possible high memory use at cost of 4x runtime. Trapezoid rule in 2D: \int_{x1, x2} dx \int_{y1, y2} dy f(x,y) = (1/4)*(x2-x1)(y2-y1) * (f(x1, y1) + f(x1, y2) + f(x2, y1) + f(x2, y2)) To avoid repeated unecessary loads of Hrs, and to avoid keeping all Hrs in memory, compute integral values for each (k, G) pair simultaneously. ''' gconf = global_config() work = os.path.expandvars(gconf["work_base"]) ds = [] for d, prefix in dps: ds.append(d) d_boundary_indices, delta_a, delta_b = trapezoid_d_regions(ds) # Calculate integral over each region individually. # region_integral_vals is a list (with indices corresponding to regions) # whose elements are dicts {(k, G): region_integral_val, ...} rint_args = [] for region_indices in d_boundary_indices: rint_args.append([region_indices, delta_a, delta_b, kGs, work, dps]) with Pool() as p: region_integral_vals = p.starmap(region_integral, rint_args) # Collect region integrals into totals. integral_totals = [] for kG_i in range(len(kGs)): integral_totals.append(None) for region_list in region_integral_vals: for kG_index, kG_val in enumerate(region_list): if integral_totals[kG_index] is None: integral_totals[kG_index] = kG_val else: integral_totals[kG_index] += kG_val return integral_totals
def _main(): parser = argparse.ArgumentParser( description="Plot TMD band structure result", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument("--global_prefix", type=str, default="MoS2_WS2", help="Calculation global prefix") parser.add_argument("--prefix", type=str, default=None, help="If specified, plot bands for one prefix only") parser.add_argument("--plot_evecs", action='store_true', help="Plot eigenvector components") parser.add_argument("--minE", type=float, default=None, help="Minimum energy to plot (not relative to E_F)") parser.add_argument("--maxE", type=float, default=None, help="Maximum energy to plot (not relative to E_F)") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) if args.prefix is None: prefixes = get_prefixes(work, args.global_prefix) for prefix in prefixes: make_plot(work, prefix, args.plot_evecs, args.minE, args.maxE) else: make_plot(work, args.prefix, args.plot_evecs, args.minE, args.maxE)
def _main(): parser = argparse.ArgumentParser("Moire band structure") parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument("--global_prefix", type=str, default="MoS2_WS2", help="Prefix for calculation") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) scf_0_path = os.path.join(work, prefixes[0], "wannier", "scf.out") D = D_from_scf(scf_0_path) D_2D = D[0:2, 0:2] kpoints = [(0, 0), (1 / 2, 0), (1 / 3, 1 / 3), (0, 0)] ks_per_interval = 10 ktildes = make_kpath(kpoints, ks_per_interval) #ktildes = [(1/3, 1/3, 0)] epsilon = 1 / 2 theta = 0.0 Gcut = 2 Gcut_cart = False Hk_moires = moire_Hamiltonian(dps, ktildes, D_2D, epsilon, theta, Gcut, Gcut_cart) plot_Hk_moire(Hk_moires)
def _main(): parser = argparse.ArgumentParser( "Calculate optical matrix elements", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument('global_prefix', type=str, help="Calculation name") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) write_optical_data(work, dps)
def _main(): parser = argparse.ArgumentParser("Analysis of H(k) symmetry") parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument("--global_prefix", type=str, default="MoS2_WS2", help="Prefix for calculation") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) ordering = "2H" if ordering == "2H": d0_prefix = find_d_val(dps, (2 / 3, 1 / 3)) d1_prefix = find_d_val(dps, (0.0, 0.0)) d2_prefix = find_d_val(dps, (1 / 3, 2 / 3)) elif ordering == "2H_top": d0_prefix = find_d_val(dps, (0.0, 0.0)) d1_prefix = find_d_val(dps, (1 / 3, 2 / 3)) d2_prefix = find_d_val(dps, (2 / 3, 1 / 3)) else: raise ValueError("unrecognized ordering") Ks = (("K0", (1 / 3, 1 / 3, 0.0)), ("K1", (-2 / 3, 1 / 3, 0.0)), ("K2", (1 / 3, -2 / 3, 0.0))) for i_d, prefix in enumerate((d0_prefix, d1_prefix, d2_prefix)): Hr = get_Hr(work, prefix) # H(R = 0) H0 = Hr[(0, 0, 0)][0] / Hr[(0, 0, 0)][1] H0_vals = get_H_orbital_vals(H0, work, prefix) # H(K) Hk_vals = {} for K_label, K in Ks: HK = Hk_recip(K, Hr) Hk_vals[K_label] = get_H_orbital_vals(HK, work, prefix) print("i_d = {}, prefix = {}".format(str(i_d), prefix)) print("H(r = 0, 0, 0)[+,+] = {}".format(str(H0_vals["dp2_M_dp2_Mp"]))) print("H(r = 0, 0, 0)[-,-] = {}".format(str(H0_vals["dm2_M_dm2_Mp"]))) print("H(r = 0, 0, 0)[+,-] = {}".format(str(H0_vals["dp2_M_dm2_Mp"]))) print("H(r = 0, 0, 0)[-,+] = {}".format(str(H0_vals["dm2_M_dp2_Mp"]))) print("H(r = 0, 0, 0)[z2,z2] = {}".format(str( H0_vals["dz2_M_dz2_Mp"]))) for K_label, K in Ks: print("------------") print("<d_+2^M|H({})|d_+2^M'> = {}".format( K_label, str(Hk_vals[K_label]["dp2_M_dp2_Mp"]))) print("<d_-2^M|H({})|d_-2^M'> = {}".format( K_label, str(Hk_vals[K_label]["dm2_M_dm2_Mp"]))) print("<d_+2^M|H({})|d_-2^M'> = {}".format( K_label, str(Hk_vals[K_label]["dp2_M_dm2_Mp"]))) print("<d_-2^M|H({})|d_+2^M'> = {}".format( K_label, str(Hk_vals[K_label]["dm2_M_dp2_Mp"]))) print("<d_z2^M|H({})|d_z2^M'> = {}".format( K_label, str(Hk_vals[K_label]["dz2_M_dz2_Mp"]))) print("===================")
def _main(): parser = argparse.ArgumentParser( "Calculation of gaps", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument( "--threshold", type=float, default=0.9, help="Threshold for deciding if a state is dominated by one layer") parser.add_argument( "--spin_valence", type=str, default=None, help= "Set 'up' or 'down' to choose valence band spin type; closest to E_F is used if not set" ) parser.add_argument( "--spin_conduction", type=str, default=None, help= "Set 'up' or 'down' to choose conduction band spin type; closest to E_F is used if not set" ) parser.add_argument( "--use_QE_evs", action='store_true', help= "Use eigenvalues from QE instead of Wannier H(k); if set, spin_valence and spin_conduction act as if not specified." ) parser.add_argument( "--ev_width", type=int, default=8, help="Number of characters per eigenvalue in QE bands.dat") parser.add_argument('global_prefix', type=str, help="Calculation name") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) K = (1 / 3, 1 / 3, 0.0) Gamma = (0.0, 0.0, 0.0) do_get_curvature_K, do_get_curvature_Gamma = True, False write_gap_data(work, dps, args.threshold, args.spin_valence, args.spin_conduction, args.use_QE_evs, args.ev_width, K, "K", "$K$", do_get_curvature_K) write_gap_data(work, dps, args.threshold, args.spin_valence, args.spin_conduction, args.use_QE_evs, args.ev_width, Gamma, "Gamma", "$\\Gamma$", do_get_curvature_Gamma)
def _main(): parser = argparse.ArgumentParser("Fourier components") parser.add_argument( "--subdir", type=str, default=None, help="Subdirectory under work_base where calculation was run") parser.add_argument("--global_prefix", type=str, default="MoS2_WS2", help="Prefix for calculation") args = parser.parse_args() gconf = global_config() work = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: work = os.path.join(work, args.subdir) soc = False prefixes = get_prefixes(work, args.global_prefix) ds = ds_from_prefixes(prefixes) ds, prefixes = wrap_cell(ds, prefixes) dps = sorted_d_group(ds, prefixes) # Verify all Hr_orders are the same; # after this, assume order is the same for all ds. verify_Hr_orders_identical(work, prefixes) atom_Hr_order = get_atom_order(work, prefixes[0]) orb_type = ("X2", "pz", "up", "X1p", "pz", "up") i_sym, i_orbital, i_spin = orb_type[0], orb_type[1], orb_type[2] j_sym, j_orbital, j_spin = orb_type[3], orb_type[4], orb_type[5] i_index = orbital_index(atom_Hr_order, i_sym, i_orbital, i_spin, soc) j_index = orbital_index(atom_Hr_order, j_sym, j_orbital, j_spin, soc) Gs = [] num_Ga, num_Gb = 5, 5 for Ga in range(num_Ga): for Gb in range(num_Gb): G = (Ga, Gb) Gs.append(G) ks = [(1 / 3, 1 / 3, 0)] kGs = list(itertools.product(ks, Gs)) all_H_vals = H_klat_Glat(dps, kGs) Gas, Gbs = [], [] H_K_re_vals, H_K_im_vals = [], [] for kG_index, val in enumerate(all_H_vals): k, G = kGs[kG_index] # Only one k used. # TODO - check k? H_K_re_vals.append(val[i_index, j_index].real) H_K_im_vals.append(val[i_index, j_index].imag) Gas.append(float(G[0])) Gbs.append(float(G[1])) plt.scatter(Gas, Gbs, c=H_K_re_vals, cmap='viridis', s=50, edgecolors="none") plt.colorbar() plt.savefig("G_K_re.png", bbox_inches='tight', dpi=500) plt.clf() plt.scatter(Gas, Gbs, c=H_K_im_vals, cmap='viridis', s=50, edgecolors="none") plt.colorbar() plt.savefig("G_K_im.png", bbox_inches='tight', dpi=500) plt.clf()
def _main(): parser = argparse.ArgumentParser( "Build and run calculation on grid of d's", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("--run", action="store_true", help="Run calculation after making inputs") parser.add_argument("--subdir", type=str, default=None, help="Subdirectory under work_base to run calculation") parser.add_argument("--symA", type=str, default="MoS2", help="Atomic composition of bottom layer") parser.add_argument("--symB", type=str, default="WS2", help="Atomic composition of top layer") parser.add_argument("--monolayer", action="store_true", help="Use monolayer system instead of bilayer") parser.add_argument( "--ordering", type=str, default="2H", help="Ordering of atoms: '2H' -> BAB/ABA; '2H_top' -> BAB/BAB") parser.add_argument( "--c_sep", type=float, default=None, help= "Separation between layers (use value from bilayer of symA if not specified)" ) parser.add_argument("--soc", action="store_true", help="Use spin-orbit coupling") parser.add_argument("--xc", type=str, default="lda", help="Exchange-correlation functional (lda or pbe)") parser.add_argument("--num_d_a", type=int, default=3, help="Number of d's (shifts) along the a-axis") parser.add_argument("--num_d_b", type=int, default=3, help="Number of d's (shifts) along the b-axis") parser.add_argument("--pp", type=str, default="nc", help="Pseudopotential type ('nc' or 'paw')") parser.add_argument( "--iprelax", action="store_true", help="Vary in-plane lattice constant to search for lowest energy") parser.add_argument("--bands_only", action="store_true", help="Run only scf and bands calc") args = parser.parse_args() symA, symB = args.symA, args.symB if args.monolayer: symB = None tmd_base = _base_dir() db_path = os.path.join(tmd_base, "c2dm.db") gconf = global_config() if not args.monolayer: c_bulk_values = {"MoS2": 12.296, "MoSe2": 12.939} c_bulk = c_bulk_values[symA] else: c_bulk = None dgrid = dgrid_inputs(db_path, symA, symB, c_bulk, args.num_d_a, args.num_d_b, c_sep=args.c_sep, soc=args.soc, xc=args.xc, ordering=args.ordering, iprelax=args.iprelax, pp=args.pp, bands_only=args.bands_only) base_path = os.path.expandvars(gconf["work_base"]) if args.subdir is not None: base_path = os.path.join(base_path, args.subdir) # Recompiled QE to increase precision in bands.dat output file. # (The hard-coded default is 3 decimal places (1 meV) which is too small # for gap variation on the scale of 10 meV). # # Starting with QE 5.4.0, # in PP/src/bands.f90 changed: # Line 470: 10f8.3 --> 10f13.8 # Line 476: 10f8.3 --> 10f13.8 # # To compile QE on LS5, need to specify mpich scalapack. # With module 'espresso/5.4.0' loaded, compile with: # ./configure SCALAPACK_LIBS="-lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64" # make pp if "qe_bands" in gconf: qe_bands_dir = os.path.expandvars(gconf["qe_bands"]) qe_bands_path = os.path.join(qe_bands_dir, "bands.x") else: qe_bands_path = "bands.x" write_dgrid(base_path, dgrid) #config = {"machine": "__local__", "wannier": True} #config = {"machine": "__local__", "wannier": True, "__local_mpi_cmd__": "mpirun"} if symA is not None and symB is not None: global_prefix = "{}_{}".format(symA, symB) elif symB is None: global_prefix = symA elif symA is None: global_prefix = symB else: raise ValueError("symA and symB are None") num_nodes = 1 num_cores = 24 * num_nodes config = { "machine": "ls5", "cores": num_cores, "nodes": num_nodes, "queue": "normal", "hours": 4, "minutes": 0, "wannier": True, "project": "A-ph9", "global_prefix": global_prefix, "max_jobs": 24, "outer_min": -10.0, "outer_max": 7.0, "inner_min": -8.0, "inner_max": 3.0, "subdir": args.subdir, "iprelax": args.iprelax, "bands_only": args.bands_only, "qe_bands": qe_bands_path } prefix_groups = write_dgrid_queuefiles(base_path, dgrid, config) if args.run: if not args.iprelax and not args.bands_only: calc_name = "wan_setup" else: calc_name = "bands_only" submit_dgrid_pw(base_path, config, prefix_groups, calc_name)