def get_pseudo_dir(soc, xc, pp): if pp == 'nc': if soc: if xc == 'lda': return os.path.join(_base_dir(), "pseudo", "lda_soc") else: return os.path.join(_base_dir(), "pseudo", "soc") else: if xc == 'lda': return os.path.join(_base_dir(), "pseudo", "lda_no_soc") else: return os.path.join(_base_dir(), "pseudo", "no_soc") elif pp == 'paw': if soc and xc == 'lda': return os.path.join(_base_dir(), "pseudo", "pslibrary_lda_soc_paw") else: raise ValueError("paw/non-soc not implemented")
def test_qe_config(self): syms = ["WSe2", "WSe2", "WSe2"] soc = True vacuum_dist = 20.0 # Angstrom D = 0.5 # V/nm AB_stacking = True xc = 'lda' pp = 'nc' db_path = os.path.join(_base_dir(), "c2dm.db") db = ase.db.connect(db_path) c_sep = get_c_sep(db, syms[0]) latvecs, at_syms, cartpos = make_cell(db, syms, c_sep, vacuum_dist, AB_stacking) system = Atoms(symbols=at_syms, positions=cartpos, cell=latvecs, pbc=True) system.center(axis=2) wann_valence, num_wann = get_wann_valence( system.get_chemical_symbols(), soc) num_bands = get_num_bands(num_wann) qe_config = make_qe_config(system, D, soc, num_bands, xc, pp) #with open('test_build_qe_config_new.json', 'w') as fp: # json.dump(qe_config, fp) with open('test_build_qe_config.json', 'r') as fp: qe_config_expected = json.load(fp) check_qe_config(self, qe_config, qe_config_expected, soc, xc, pp) prefix = 'test' qe_input = build_qe(system, prefix, 'scf', qe_config) #with open('test_build_qe_input_new', 'w') as fp: # fp.write(qe_input) with open('test_build_qe_input', 'r') as fp: qe_input_expected = fp.read() check_qe_input(self, qe_input, qe_input_expected, soc, xc, pp)
def test_cell_unshifted(self): syms_bilayer = ["WSe2", "WSe2"] syms_trilayer = ["WSe2", "WSe2", "WSe2"] vacuum_dist = 20.0 # Angstrom AB_stacking = True db_path = os.path.join(_base_dir(), "c2dm.db") db = ase.db.connect(db_path) for syms in [syms_bilayer, syms_trilayer]: c_sep = get_c_sep(db, syms[0]) layer_systems = [get_layer_system(db, sym, 'H') for sym in syms] a = a_from_2H(layer_systems[0]) hs = [h_from_2H(layer_system) for layer_system in layer_systems] for AB_stacking in [False, True]: # layer_shifts = None should be the same as specifying # a shift of (0.0, 0.0) for all layers. latvecs_None, at_syms_None, cartpos_None = make_cell( db, syms, c_sep, vacuum_dist, AB_stacking=AB_stacking, layer_shifts=None) shifts_zero = [(0.0, 0.0)] * len(syms) latvecs_zero, at_syms_zero, cartpos_zero = make_cell( db, syms, c_sep, vacuum_dist, AB_stacking=AB_stacking, layer_shifts=shifts_zero) self.assertTrue((latvecs_None == latvecs_zero).all()) self.assertEqual(at_syms_None, at_syms_zero) for at_pos_None, at_pos_zero in zip(cartpos_None, cartpos_zero): assert ((at_pos_None == at_pos_zero).all()) self.assertEqual(at_syms_zero, ["Se", "W", "Se"] * len(syms)) # Should have the correct lattice constant. eps = 1e-12 self.assertTrue(abs(np.linalg.norm(latvecs_None[0]) - a) < eps) self.assertTrue(abs(np.linalg.norm(latvecs_None[1]) - a) < eps) system = Atoms(symbols=at_syms_zero, positions=cartpos_zero, cell=latvecs_zero, pbc=True) system.center(axis=2) A = (0.0, 0.0) B = (1 / 3, 2 / 3) latpos = system.get_scaled_positions() for layer_index in range(len(syms)): # Atoms should have the correct in-plane positions. layer_pos = latpos[3 * layer_index:3 * layer_index + 3] if AB_stacking: if layer_index % 2 == 0: self.assertTrue(has_pos_seq(layer_pos, [A, B, A])) else: self.assertTrue(has_pos_seq(layer_pos, [B, A, B])) else: self.assertTrue(has_pos_seq(layer_pos, [A, B, A])) # Atoms should have the correct vertical positions. h = hs[layer_index] layer_cartpos = cartpos_zero[3 * layer_index:3 * layer_index + 3] zs = [layer_cartpos[i][2] for i in range(3)] self.assertTrue(abs(zs[2] - zs[0] - h) < eps) self.assertTrue(abs(zs[2] - zs[1] - h / 2) < eps) if layer_index != 0: z_below = cartpos_zero[3 * layer_index - 1][2] self.assertTrue(abs(zs[0] - z_below - c_sep) < eps)
def test_cell_shifted(self): syms_bilayer = ["WSe2", "WSe2"] syms_trilayer = ["WSe2", "WSe2", "WSe2"] vacuum_dist = 20.0 # Angstrom AB_stacking = True db_path = os.path.join(_base_dir(), "c2dm.db") db = ase.db.connect(db_path) for syms in [syms_bilayer, syms_trilayer]: c_sep = get_c_sep(db, syms[0]) shifts_zero = [(0.0, 0.0)] * len(syms) num_shifts_l2 = 3 all_shifts_nonzero = make_layer_shifts(len(syms), num_shifts_l2) for AB_stacking in [False, True]: for layer_shifts in all_shifts_nonzero: latvecs_zero, at_syms_zero, cartpos_zero = make_cell( db, syms, c_sep, vacuum_dist, AB_stacking=AB_stacking, layer_shifts=shifts_zero) latvecs_shift, at_syms_shift, cartpos_shift = make_cell( db, syms, c_sep, vacuum_dist, AB_stacking=AB_stacking, layer_shifts=layer_shifts) self.assertTrue((latvecs_zero == latvecs_shift).all()) self.assertEqual(at_syms_zero, at_syms_shift) system_zero = Atoms(symbols=at_syms_zero, positions=cartpos_zero, cell=latvecs_zero, pbc=True) system_zero.center(axis=2) system_shift = Atoms(symbols=at_syms_shift, positions=cartpos_shift, cell=latvecs_shift, pbc=True) system_shift.center(axis=2) latpos_zero = system_zero.get_scaled_positions() latpos_shift = system_shift.get_scaled_positions() for layer_index in range(len(syms)): # Atoms should have the correct in-plane positions. layer_pos_zero = latpos_zero[3 * layer_index:3 * layer_index + 3] layer_pos_shift = latpos_shift[3 * layer_index:3 * layer_index + 3] self.assertTrue( has_pos_shift(layer_pos_zero, layer_pos_shift, layer_shifts[layer_index])) # Atoms should have the correct vertical positions. eps = 1e-12 for i in range(3): self.assertTrue( abs(layer_pos_zero[i][2] - layer_pos_shift[i][2]) < eps)
def _main(): parser = argparse.ArgumentParser( "Build and run calculation over various TMD stacks", 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("--stacking", type=str, default="AB", help="Stacking mode: 'AB' (2H) or 'AA' (1H)") parser.add_argument("--D", type=float, default=None, help="Displacement field (default: no field)") parser.add_argument("--xc", type=str, default="lda", help="Exchange-correlation functional (lda or pbe)") parser.add_argument("--pp", type=str, default="nc", help="Pseudopotential type ('nc' or 'paw')") args = parser.parse_args() soc = True all_syms = get_all_syms() AB_stacking = get_stacking(args.stacking) vacuum_dist = 20.0 # Angstrom db_path = os.path.join(_base_dir(), "c2dm.db") db = ase.db.connect(db_path) prefixes = [] for syms in all_syms: p = set_up_calculation(db, args.subdir, syms, AB_stacking, soc, vacuum_dist, args.D, args.xc, args.pp) prefixes.append(p) global_prefix = "alignment" machine = "stampede2" num_nodes = 2 num_cores = num_nodes * mpi_procs_per_node(machine) queue_config = { "machine": machine, "nodes": num_nodes, "cores": num_cores, "queue": "normal", "hours": 12, "minutes": 0, "wannier": True, "project": "A-ph9", "global_prefix": global_prefix, "max_jobs": 6, "outer_min": -10.0, "outer_max": 5.0, "inner_min": -8.0, "inner_max": 3.0, "subdir": args.subdir, "qe_bands": _global_config()['qe_bands'] } _write_queuefiles(_get_base_path(args.subdir), prefixes, queue_config)
def _main(): parser = argparse.ArgumentParser( "Build and run calculation over displacement field values", 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( "--syms", type=str, default="WSe2;WSe2;WSe2", help= "Semicolon-separated list of atomic composition of layers. Format example: WSe2;MoSe2;MoS2" ) parser.add_argument("--stacking", type=str, default="AB", help="Stacking mode: 'AB' (2H) or 'AA' (1H)") parser.add_argument("--minD", type=float, default=0.01, help="Minimum displacement field in V/nm") parser.add_argument("--maxD", type=float, default=0.5, help="Maximum displacement field in V/nm") parser.add_argument( "--numD", type=int, default=10, help= "Number of displacement field steps. Set to 0 to not use displacement field." ) parser.add_argument( "--shifts_l2", type=int, default=None, help= "Number of interlayer shifts to include for second layer: if specified, include\ calculations with second layer shifts tiling the unit cell.") parser.add_argument( "--interlayer_relax", action="store_true", help="Relax in the out-of-plane direction before performing scf") parser.add_argument("--no_soc", action="store_true", help="Turn off spin-orbit coupling") parser.add_argument("--xc", type=str, default="lda", help="Exchange-correlation functional (lda or pbe)") parser.add_argument("--pp", type=str, default="nc", help="Pseudopotential type ('nc' or 'paw')") args = parser.parse_args() syms = _extract_syms(args.syms) global_prefix = "_".join(syms) print("Generating inputs for {} system {}.".format(num_layers_label(syms), syms)) soc = not args.no_soc db_path = os.path.join(_base_dir(), "c2dm.db") db = ase.db.connect(db_path) # Choose separation between layers as if the system was a bulk system # where all layers are the same as the first layer here. # TODO -- is there a better strategy for this? c_sep = get_c_sep(db, syms[0]) vacuum_dist = 20.0 # Angstrom if args.stacking == 'AB': AB_stacking = True elif args.stacking == 'AA': AB_stacking = False else: raise ValueError("unrecognized value for argument 'stacking'") if args.numD == 0: Ds = [None] else: Ds = np.linspace(args.minD, args.maxD, args.numD) if args.shifts_l2 is None: all_layer_shifts = [None] else: num_layers = len(syms) all_layer_shifts = make_layer_shifts(num_layers, args.shifts_l2) prefixes = [] for layer_shifts in all_layer_shifts: prefixes.extend( make_system_at_shift(global_prefix, args.subdir, db, syms, c_sep, vacuum_dist, AB_stacking, soc, args.interlayer_relax, args.xc, args.pp, Ds, layer_shifts)) machine = "stampede2" num_nodes = 1 num_cores = num_nodes * mpi_procs_per_node(machine) queue_config = { "machine": machine, "cores": num_cores, "nodes": num_nodes, "queue": "normal", "hours": 12, "minutes": 0, "wannier": True, "project": "A-ph9", "global_prefix": global_prefix, "max_jobs": 1, "relax": args.interlayer_relax, "outer_min": -10.0, "outer_max": 6.0, "inner_min": -8.0, "inner_max": 3.0, "subdir": args.subdir, "qe_bands": _global_config()['qe_bands'] } print( "Generating queuefiles for machine {} on {} nodes and {} jobs with max runtime {} hours." .format(machine, num_nodes, queue_config["max_jobs"], queue_config["hours"])) base_path = _get_base_path(args.subdir) prefix_groups = _write_queuefiles(base_path, prefixes, queue_config) if args.run: calc_name = "wan_setup" submit_pw(base_path, queue_config, prefix_groups, calc_name)