def _read_from_H(self, kgrid, kgrid_displ, Erange, nE, E0): """ Calculates the PDOS from a sisl Hamiltonian. """ if not hasattr(self, "H"): self.setup_hamiltonian() # Get the kgrid or generate a default grid by checking the interaction between cells # This should probably take into account how big the cell is. if kgrid is None: kgrid = [3 if nsc > 1 else 1 for nsc in self.H.geometry.nsc] if Erange is None: raise ValueError('You need to provide an energy range to calculate the PDOS from the Hamiltonian') self.E = np.linspace(Erange[0], Erange[-1], nE) + E0 self.mp = sisl.MonkhorstPack(self.H, kgrid, kgrid_displ) # Define the available spins spin_indices = [0] if self.H.spin.is_polarized: spin_indices = [0, 1] # Calculate the PDOS for all available spins PDOS = [] for spin in spin_indices: PDOS.append(self.mp.apply.average.PDOS(self.E, spin=spin, eta=True)) self.PDOS = np.array(PDOS)
def test_gf_write_read(sisl_tmp, sisl_system): tb = sisl.Hamiltonian(sisl_system.gtb) f = sisl_tmp('file.TSGF', _dir) bz = sisl.MonkhorstPack(tb, [3, 3, 1]) E = np.linspace(-2, 2, 20) + 1j * 1e-4 S = np.eye(len(tb), dtype=np.complex128) gf = sisl.io.get_sile(f) gf.write_header(E, bz, tb) for i, (write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, format='array') if write_hs and i % 2 == 0: gf.write_hamiltonian(Hk) elif write_hs: gf.write_hamiltonian(Hk, S) gf.write_self_energy(S * e - Hk) no_u, k, E_file = gf.read_header() assert np.allclose(E, E_file) assert np.allclose(k, bz.k) for i, (write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, format='array') if write_hs and i % 2 == 0: Hk_file, _ = gf.read_hamiltonian() elif write_hs: Hk_file, Sk_file = gf.read_hamiltonian() assert np.allclose(S, Sk_file) assert np.allclose(Hk, Hk_file) SE_file = gf.read_self_energy() assert np.allclose(SE_file, S * e - Hk)
def set_kmesh(self, nkpt=[1, 1, 1]): """ Set the k-mesh for the HubbardHamiltonian Parameters ---------- nkpt : array_like or sisl.physics.BrillouinZone, optional k-mesh to be associated with the `hubbard.HubbardHamiltonian` instance """ if isinstance(nkpt, sisl.BrillouinZone): self.mp = nkpt elif isinstance(nkpt, (np.ndarray, list)): self.mp = sisl.MonkhorstPack(self.H, nkpt) else: raise ValueError(self.__class__.__name__ + '.set_kmesh(...) requires an array_like input')
def test_gf_write(sisl_tmp, sisl_system): tb = sisl.Hamiltonian(sisl_system.gtb) f = sisl_tmp('file.TSGF', _dir) gf = sisl.io.get_sile(f) bz = sisl.MonkhorstPack(tb, [3, 3, 1]) E = np.linspace(-2, 2, 20) + 1j * 1e-4 S = np.eye(len(tb), dtype=np.complex128) gf.write_header(E, bz, tb) for i, (write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, format='array') if write_hs and i % 2 == 0: gf.write_hamiltonian(Hk) elif write_hs: gf.write_hamiltonian(Hk, S) gf.write_self_energy(S * e - Hk)
def _read_from_H(self, kgrid, kgrid_displ, Erange, nE, E0, distribution): """ Calculates the PDOS from a sisl Hamiltonian. """ if not hasattr(self, "H"): self.setup_hamiltonian() if self.H is None: raise ValueError("No hamiltonian found.") # Get the kgrid or generate a default grid by checking the interaction between cells # This should probably take into account how big the cell is. if kgrid is None: kgrid = [3 if nsc > 1 else 1 for nsc in self.H.geometry.nsc] if Erange is None: raise ValueError( 'You need to provide an energy range to calculate the PDOS from the Hamiltonian' ) self.E = np.linspace(Erange[0], Erange[-1], nE) + E0 self.bz = sisl.MonkhorstPack(self.H, kgrid, kgrid_displ) # Define the available spins spin_indices = [0] if self.H.spin.is_polarized: spin_indices = [0, 1] # Calculate the PDOS for all available spins PDOS = [] for spin in spin_indices: with self.bz.apply(pool=_do_parallel_calc) as parallel: spin_PDOS = parallel.average.eigenstate( spin=spin, wrap=lambda eig: eig.PDOS(self.E, distribution=distribution)) PDOS.append(spin_PDOS) if not self.H.spin.is_diagonal: PDOS = PDOS[0] self.PDOS = np.array(PDOS)
def test_gf_write_read_spin(sisl_tmp, sisl_system): f = sisl_tmp('file.TSGF', _dir) tb = sisl.Hamiltonian(sisl_system.gtb, spin=sisl.Spin('P')) tb.construct([(0.1, 1.5), ([0.1, -0.1], [2.7, 1.6])]) bz = sisl.MonkhorstPack(tb, [3, 3, 1]) E = np.linspace(-2, 2, 3) + 1j * 1e-4 S = np.eye(len(tb), dtype=np.complex128) gf = sisl.io.get_sile(f) gf.write_header(bz, E) for i, (ispin, write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, spin=ispin, format='array') if write_hs and i % 2 == 0: gf.write_hamiltonian(Hk) elif write_hs: gf.write_hamiltonian(Hk, S) gf.write_self_energy(S * e - Hk) # Check it isn't opened assert not gf._fortran_is_open() nspin, no_u, k, E_file = gf.read_header() assert nspin == 2 assert np.allclose(E, E_file) assert np.allclose(k, bz.k) for i, (ispin, write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, spin=ispin, format='array') if write_hs and i % 2 == 0: Hk_file, _ = gf.read_hamiltonian() elif write_hs: Hk_file, Sk_file = gf.read_hamiltonian() assert np.allclose(S, Sk_file) assert np.allclose(Hk, Hk_file) SE_file = gf.read_self_energy() assert np.allclose(SE_file, S * e - Hk)
def test_gf_write_read_direct(sisl_tmp, sisl_system): f = sisl_tmp('file.TSGF', _dir) tb = sisl.Hamiltonian(sisl_system.gtb, spin=sisl.Spin('P')) tb.construct([(0.1, 1.5), ([0.1, -0.1], [2.7, 1.6])]) bz = sisl.MonkhorstPack(tb, [3, 3, 1]) E = np.linspace(-2, 2, 3) + 1j * 1e-4 S = np.eye(len(tb), dtype=np.complex128) gf = sisl.io.get_sile(f) gf.write_header(bz, E) for i, (ispin, write_hs, k, e) in enumerate(gf): Hk = tb.Hk(k, spin=ispin, format='array') if write_hs and i % 2 == 0: gf.write_hamiltonian(Hk) elif write_hs: gf.write_hamiltonian(Hk, S) gf.write_self_energy(S * e - Hk) # ensure it is not opened assert not gf._fortran_is_open() # First try from beginning for e in [0, 1, E[1], 0, E[0]]: ie = gf.Eindex(e) SE1 = gf.self_energy(e, bz.k[2, :]) assert gf._state == 1 assert gf._ik == 2 assert gf._iE == ie assert gf._ispin == 0 assert gf._is_read == 1 SE2 = gf.self_energy(e, bz.k[2, :], spin=1) assert gf._state == 1 assert gf._ik == 2 assert gf._iE == ie assert gf._ispin == 1 assert gf._is_read == 1 assert not np.allclose(SE1, SE2) # In the middle we read some hamiltonians H1, S1 = gf.HkSk(bz.k[2, :], spin=0) assert gf._state == 0 assert gf._ik == 2 assert gf._iE == 0 assert gf._ispin == 0 assert gf._is_read == 1 assert np.allclose(S, S1) H2, S1 = gf.HkSk(bz.k[2, :], spin=1) assert gf._state == 0 assert gf._ik == 2 assert gf._iE == 0 assert gf._ispin == 1 assert gf._is_read == 1 assert np.allclose(S, S1) assert not np.allclose(H1, H2) assert not np.allclose(H1, SE1) H2, S1 = gf.HkSk(bz.k[2, :], spin=0) assert gf._state == 0 assert gf._ik == 2 assert gf._iE == 0 assert gf._ispin == 0 assert gf._is_read == 1 assert np.allclose(S, S1) assert np.allclose(H1, H2) # Now read self-energy SE2 = gf.self_energy(e, bz.k[2, :], spin=0) assert gf._state == 1 assert gf._ik == 2 assert gf._iE == ie assert gf._ispin == 0 assert gf._is_read == 1 assert np.allclose(SE1, SE2)
def run( bulk_hs, surface_hs, surface_tile, bulk_rsi_direction, mp_grid, energy_linspace, energy_imag, out_dir, k_axes, surf_nsc, bulk_nsc, matrix_fmt, zfp_tolerance, example_submit ): mprint("Reading hamiltonians") He = si.get_sile(bulk_hs).read_hamiltonian() Hs = si.get_sile(surface_hs).read_hamiltonian() if bulk_nsc is not None: He.set_nsc(bulk_nsc) if surf_nsc is not None: Hs.set_nsc(surf_nsc) with pick_a_rank() as r: mprint(f"Writing hamiltonians ({r})", printer=r) if rank == r: He.write(out_dir / "bulk_hamiltonian.nc") Hs.write(out_dir / "surface_hamiltonian.nc") rsi = si.physics.RecursiveSI(He, bulk_rsi_direction) rssi = si.physics.RealSpaceSI(rsi, Hs, k_axes, unfold=surface_tile) coupling_geom, se_indices = rssi.real_space_coupling(True) with pick_a_rank() as r: mprint(f"Saving coupling geometry ({r})", printer=r) if rank == r: coupling_geom.write(out_dir / "coupling_geometry.nc") np.save(out_dir / "coupling_geometry_indices", se_indices) parenths = rssi.real_space_parent() new_order = np.concatenate((se_indices, np.delete(np.arange(parenths.na), se_indices))) parenths = parenths.sub(new_order) with pick_a_rank() as r: mprint(f"Saving parent geometry ({r})", printer=r) if rank == r: parenths.geometry.write(out_dir / f"full_geometry.fdf") parenths.write(out_dir / f"full_geometry.nc") del parenths mp = np.array([1, 1, 1], dtype=int) mp[k_axes] = mp_grid rssi.set_options(bz=si.MonkhorstPack(coupling_geom, mp)) E, dE = np.linspace(*energy_linspace[:2], int(energy_linspace[2]), retstep=True) nE = len(E) E = E + 1j*energy_imag with pick_a_rank() as r: mprint(f"Saving energy grid ({r})", printer=r) if rank == r: np.save(out_dir / "energy_grid", E) si.io.TableSile(out_dir / "energy_grid.table", "w").write_data(E.real, E.imag, np.full(E.shape, dE)) nperrank = ceil(nE / comm.size) local_eidx = np.arange(rank * nperrank, min((rank + 1) * nperrank, nE)) mprint("Energy grid distribution:", nperrank, "energy points per processor.") if (nE % nperrank): mprint(f"One process only has {nE % nperrank} energy points.") mprint(f"To assess processing progress, use `echo $(( 100 * $(find {out_dir} -type f -name 'SE_E*.npz' | wc -l) / {nE} ))%`") mprint(f"Note that these files due to the parallelism are probably created in bunches of {comm.size} and each bunch may take long to finish.") for ie, e in zip(local_eidx, E[local_eidx]): se = rssi.self_energy(e, bulk=True, coupling=True) mprint(f"SE{ie:>03d} calculated", printer=rank) if matrix_fmt == "npz": np.savez_compressed(out_dir / f"SE_E{ie:>03d}.npz", se) elif matrix_fmt == "zfp": bs = zfpy.compress_numpy(se.real, tolerance=zfp_tolerance) (out_dir / f"SE_E{ie:>03d}_REAL.zfp").write_bytes(bs) bs = zfpy.compress_numpy(se.imag, tolerance=zfp_tolerance) (out_dir / f"SE_E{ie:>03d}_IMAG.zfp").write_bytes(bs) del bs del se mprint(f"SE{ie:>03d} saved", printer=rank) gc.collect() mprint(f"MPI-rank {rank} done.", printer=rank) comm.Barrier() mprint(( f"All done! Use `easySE gfdir2gf {out_dir}` to convert the parallel results" " into the tbtgf needed for Siesta/tbtrans." ))
def add_levels(bz, nks, ns, fast=False, as_index=False, debug=False): """ Add different levels according to the length of `ns` """ global nlvls lvl = nlvls - len(nks) nreps = 0 if fast: # we need to copy the bz since for each ik, the new_bz gets # changed in add_levels. # If there was only 1 ik per level, then all would work fine. bz = bz.copy() from io import StringIO s = StringIO() def print_s(force=True): nonlocal s out = s.getvalue() spaces = " " * (lvl * 2) out = spaces + out.replace("\n", f"\n{spaces}") if force: print(out) # reset s s = StringIO() if debug: print(f"lvl = {lvl}", file=s) print_s() if len(nks) > 0: # calculate the size of the current BZ dsize = bz._size / bz._diag # pop the last items nk = get_nk(nks[-1]) n = ns[-1] assert n < len(bz), "Too loong n" iks = [ik for ik in yield_kpoint(bz, n)] if debug: print("size", bz._size, file=s) print("dsize", dsize, file=s) print("iks", iks, file=s) print("len(bz): ", len(bz), file=s) print("ks:", file=s) print(bz.k[iks], file=s) print("weights:", bz.weight.min(), bz.weight[iks].sum(), file=s) print(bz.weight[iks], file=s) print("sum(weights): ", bz.weight.sum(), file=s) print_s() # create the single monkhorst pack we will use for replacements if fast: new_bz = sisl.MonkhorstPack(bz.parent, nk, size=dsize, trs=False) new, reps = add_levels(new_bz, nks[:-1], ns[:-1], fast, as_index, debug=debug) if as_index: bz.replace(iks, new, displacement=True, as_index=True) else: bz.replace(bz.k[iks], new, displacement=True, as_index=False) nreps += 1 + reps else: if lvl == 0: iks = tqdm(iks, desc=f"lvl {lvl}") for ik in iks: k = bz.k[ik] if debug: print(f"ik = {ik}", file=s) print(f"k = {k}", file=s) print(f"wk = {bz.weight[ik]}", file=s) print_s() # Recursively add a new level # create the single monkhorst pack we will use for replacements new_bz = sisl.MonkhorstPack(bz.parent, nk, size=dsize, trs=False, displacement=k) new, reps = add_levels(new_bz, nks[:-1], ns[:-1], fast, as_index, debug=debug) # calculate number of replaced k-points if debug: bz_nk = len(bz) if debug: print(f"ik = {ik}", file=s) print(f"k = {k}", file=s) print(f"wk = {bz.weight[ik]}", file=s) print_s() if False: import matplotlib.pyplot as plt plt.figure() plt.scatter(bz.k[:, 0], bz.k[:, 1]) plt.title(f"{lvl} and {ik}") plt.show() if as_index: bz.replace(ik, new, displacement=fast, as_index=True) else: bz.replace(k, new, displacement=fast) if debug: rep_nk = len(new) - (len(bz) - bz_nk) print("replaced k-points ", rep_nk, file=s) print_s() #print(len(bz)*4 * 8 / 1024**3) del new nreps += 1 + reps del new_bz return bz, nreps
del new nreps += 1 + reps del new_bz return bz, nreps gr = sisl.geom.graphene(1.44) H = sisl.Hamiltonian(gr) H.construct([[0, 1.44], [0, -2.7]]) # Now create the k-input # this is number of k-points trs = False bz = sisl.MonkhorstPack(H, get_nk(nks[-1]), trs=trs) debug = False # Now add *many* points for fast, as_index in [(True, False), (True, True), (False, False), (False, True)]: # Always fix the random seed to make each profiling concurrent np.random.seed(1234567890) b = bz.copy() print(f"running fast={fast} as_index={as_index}") pr = cProfile.Profile() pr.enable() _, nreps = add_levels(b, nks, ns, fast, as_index, debug=debug) pr.disable()