Skip to content

Commit 74284d9

Browse files
Merge pull request #11 from kirk0830/VLSI2026
Feature&Refactor: support SCF restarts from given density matrices and several minor fixes
2 parents aa98a8e + eae6290 commit 74284d9

4 files changed

Lines changed: 76 additions & 57 deletions

File tree

dpnegf/negf/lead_property.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,8 @@ def write_to_hdf5(h5_path, k, e, se):
705705
group_name = f"E_{e:.8f}"
706706
dset_name = f"k_{k[0]}_{k[1]}_{k[2]}"
707707
grp = f.require_group(group_name)
708-
if dset_name in grp:
709-
log.warning(f"Dataset {dset_name} already exists in group {group_name}. Skipping it.")
708+
# if dset_name in grp:
709+
# log.warning(f"Dataset {dset_name} already exists in group {group_name}. Skipping it.")
710710
grp.create_dataset(dset_name, data=se.cpu().numpy(), compression="gzip")
711711
f.flush()
712712

@@ -740,7 +740,7 @@ def merge_hdf5_files(tmp_dir, output_path, pattern, remove=True):
740740

741741
for dset_name in fin_group:
742742
if dset_name in fout_group:
743-
log.warning(f"Dataset '{dset_name}' already exists in group '{group_name}'. Skipping.")
743+
# log.warning(f"Dataset '{dset_name}' already exists in group '{group_name}'. Skipping.")
744744
continue
745745
fin_group.copy(dset_name, fout_group)
746746

dpnegf/negf/poisson_init.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ class Interface3D(object):
246246
Interface3D(grid, Dirichlet_group, dielectric_group)
247247
A class to handle the initialization and solution of the 3D Poisson equation
248248
on a structured grid with support for Dirichlet and dielectric regions.
249+
249250
Parameters
250251
----------
251252
grid : Grid
@@ -254,6 +255,7 @@ class Interface3D(object):
254255
List of Dirichlet region objects specifying boundary conditions.
255256
dielectric_group : list of Dielectric
256257
List of Dielectric region objects specifying spatially varying permittivity.
258+
257259
Attributes
258260
----------
259261
Dirichlet_group : list

dpnegf/runner/NEGF.py

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def __init__(self,
182182
meshgrid=self.stru_options[lead_tag]["kmesh_lead_Ef"],
183183
AtomicData_options=AtomicData_options,
184184
smearing_method=self.stru_options.get("e_fermi_smearing", "FD"),
185-
temp=100.0,
185+
temp=self.ele_T,
186186
eig_solver=self.stru_options.get("eig_solver", "torch"),)
187187
else:
188188
e_fermi["lead_L"] = self.e_fermi
@@ -342,64 +342,81 @@ def generate_energy_grid(self):
342342
xu = torch.tensor(max(v_list)+8*self.kBT)
343343
self.int_grid, self.int_weight = gauss_xw(xl=xl, xu=xu, n=int(self.density_options["n_gauss"]))
344344

345-
def compute(self):
345+
def compute(self,
346+
pcond: Optional[Interface3D]=None) -> Optional[Interface3D]:
347+
'''
348+
compute the NEGF calculation, can also from the given Poisson
349+
'''
346350

347351
if self.scf:
352+
if pcond is None:
353+
# create real-space grid
354+
grid = self.get_grid(self.poisson_options["grid"],self.deviceprop.structure)
355+
356+
# create Dirichlet boundary condition region
357+
Dirichlet_group = []
358+
for idx in range(len(self.Dirichlet_region)):
359+
Dirichlet_init = Dirichlet(self.Dirichlet_region[idx].get("x_range",None).split(':'),\
360+
self.Dirichlet_region[idx].get("y_range",None).split(':'),\
361+
self.Dirichlet_region[idx].get("z_range",None).split(':'))
362+
#TODO: when heterogenous Dirichlet conditions are set, the voltage should be set as electrochemical potential(Fermi level + voltage)
363+
Dirichlet_init.Ef = -1*float(self.Dirichlet_region[idx].get("voltage",None)) # in unit of eV
364+
Dirichlet_group.append(Dirichlet_init)
365+
366+
# create dielectric region
367+
dielectric_group = []
368+
for dd in range(len(self.dielectric_region)):
369+
dielectric_init = Dielectric(self.dielectric_region[dd].get("x_range",None).split(':'),\
370+
self.dielectric_region[dd].get("y_range",None).split(':'),\
371+
self.dielectric_region[dd].get("z_range",None).split(':'))
372+
dielectric_init.eps = float(self.dielectric_region[dd].get("relative permittivity",None))
373+
dielectric_group.append(dielectric_init)
374+
375+
# create interface
376+
pcond = Interface3D(grid,Dirichlet_group,dielectric_group)
377+
pcond.get_potential_eps(Dirichlet_group+dielectric_group)
378+
atom_gridpoint_index = list(pcond.grid.atom_index_dict.values()) # atomic site index in the grid
379+
for dp in range(len(self.doped_region)):
380+
pcond.get_fixed_charge(self.doped_region[dp].get("x_range",None).split(':'),\
381+
self.doped_region[dp].get("y_range",None).split(':'),\
382+
self.doped_region[dp].get("z_range",None).split(':'),\
383+
self.doped_region[dp].get("charge",None),\
384+
atom_gridpoint_index)
385+
386+
#initial guess for electrostatic potential
387+
log.info(msg="-----Initial guess for electrostatic potential----")
388+
pcond.solve_poisson_NRcycle(method=self.poisson_options['solver'],\
389+
tolerance=self.poisson_options['tolerance'],\
390+
dtype=self.poisson_options['poisson_dtype'])
391+
log.info(msg="-------------------------------------------\n")
348392

349-
# create real-space grid
350-
grid = self.get_grid(self.poisson_options["grid"],self.deviceprop.structure)
351-
352-
# create Dirichlet boundary condition region
353-
Dirichlet_group = []
354-
for idx in range(len(self.Dirichlet_region)):
355-
Dirichlet_init = Dirichlet(self.Dirichlet_region[idx].get("x_range",None).split(':'),\
356-
self.Dirichlet_region[idx].get("y_range",None).split(':'),\
357-
self.Dirichlet_region[idx].get("z_range",None).split(':'))
358-
#TODO: when heterogenous Dirichlet conditions are set, the voltage should be set as electrochemical potential(Fermi level + voltage)
359-
Dirichlet_init.Ef = -1*float(self.Dirichlet_region[idx].get("voltage",None)) # in unit of eV
360-
Dirichlet_group.append(Dirichlet_init)
393+
else:
394+
log.info(msg="Using the given Poisson condition for NEGF-Poisson SCF")
395+
396+
assert isinstance(pcond, Interface3D)
397+
self.poisson_negf_scf(interface_poisson=pcond,
398+
atom_gridpoint_index=list(pcond.grid.atom_index_dict.values()),
399+
err=self.poisson_options['err'],
400+
max_iter=self.poisson_options['max_iter'],
401+
mix_rate=self.poisson_options['mix_rate'],
402+
tolerance=self.poisson_options['tolerance'])
361403

362-
# create dielectric region
363-
dielectric_group = []
364-
for dd in range(len(self.dielectric_region)):
365-
dielectric_init = Dielectric( self.dielectric_region[dd].get("x_range",None).split(':'),\
366-
self.dielectric_region[dd].get("y_range",None).split(':'),\
367-
self.dielectric_region[dd].get("z_range",None).split(':'))
368-
dielectric_init.eps = float(self.dielectric_region[dd].get("relative permittivity",None))
369-
dielectric_group.append(dielectric_init)
370-
371-
# create interface
372-
interface_poisson = Interface3D(grid,Dirichlet_group,dielectric_group)
373-
interface_poisson.get_potential_eps(Dirichlet_group+dielectric_group)
374-
atom_gridpoint_index = list(interface_poisson.grid.atom_index_dict.values()) # atomic site index in the grid
375-
for dp in range(len(self.doped_region)):
376-
interface_poisson.get_fixed_charge( self.doped_region[dp].get("x_range",None).split(':'),\
377-
self.doped_region[dp].get("y_range",None).split(':'),\
378-
self.doped_region[dp].get("z_range",None).split(':'),\
379-
self.doped_region[dp].get("charge",None),\
380-
atom_gridpoint_index)
381-
382-
#initial guess for electrostatic potential
383-
log.info(msg="-----Initial guess for electrostatic potential----")
384-
interface_poisson.solve_poisson_NRcycle(method=self.poisson_options['solver'],\
385-
tolerance=self.poisson_options['tolerance'],\
386-
dtype=self.poisson_options['poisson_dtype'])
387-
log.info(msg="-------------------------------------------\n")
388-
389-
self.poisson_negf_scf( interface_poisson=interface_poisson,atom_gridpoint_index=atom_gridpoint_index,\
390-
err=self.poisson_options['err'],max_iter=self.poisson_options['max_iter'],\
391-
mix_rate=self.poisson_options['mix_rate'],tolerance=self.poisson_options['tolerance'])
392404
# calculate transport properties with converged potential
393405
self.negf_compute(scf_require=False,Vbias=self.potential_at_orb)
394406

395-
else:
396-
profiler = Profiler()
397-
profiler.start()
398-
self.negf_compute(scf_require=False,Vbias=None)
399-
profiler.stop()
400-
output_path = os.path.join(self.results_path, "profile_report.html")
401-
with open(output_path, 'w') as report_file:
402-
report_file.write(profiler.output_html())
407+
return pcond
408+
409+
# otherwise, the non-self-consistent calculation is performed
410+
assert not self.scf
411+
profiler = Profiler()
412+
profiler.start()
413+
self.negf_compute(scf_require=False,Vbias=None)
414+
profiler.stop()
415+
output_path = os.path.join(self.results_path, "profile_report.html")
416+
with open(output_path, 'w') as report_file:
417+
report_file.write(profiler.output_html())
418+
419+
return None
403420

404421
def poisson_negf_scf(self,interface_poisson,atom_gridpoint_index,err=1e-6,max_iter=1000,
405422
mix_method:str='linear', mix_rate:float=0.3, tolerance:float=1e-7,Gaussian_sigma:float=3.0):

dpnegf/utils/argcheck.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,7 @@ def pyamg():
12101210
Argument("dielectric_region", dict, optional=False, sub_fields=dielectric(), doc=doc_dielectric),
12111211
*[
12121212
Argument(f"dielectric_region{i}", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric)
1213-
for i in range(2, 6)
1213+
for i in range(2, 7)
12141214
],
12151215
Argument("doped_region", dict, optional=False, sub_fields=doped(), doc=doc_doped)
12161216
]
@@ -1242,7 +1242,7 @@ def scipy():
12421242
Argument("dielectric_region", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric),
12431243
*[
12441244
Argument(f"dielectric_region{i}", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric)
1245-
for i in range(2, 6)
1245+
for i in range(2, 7)
12461246
],
12471247
Argument("doped_region1", dict, optional=True, sub_fields=doped(), doc=doc_doped),
12481248
Argument("doped_region2", dict, optional=True, sub_fields=doped(), doc=doc_doped)

0 commit comments

Comments
 (0)