From 4cafd9ffe78e0aea49133764ac1983beb053f423 Mon Sep 17 00:00:00 2001 From: kirk0830 Date: Tue, 20 Jan 2026 16:55:23 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor(lead=5Fproperty):=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=87=8D=E5=A4=8D=E6=95=B0=E6=8D=AE=E9=9B=86=E7=9A=84?= =?UTF-8?q?=E8=AD=A6=E5=91=8A=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 不再检查并记录HDF5文件中数据集是否已存在的警告日志,直接覆盖写入 --- dpnegf/negf/lead_property.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dpnegf/negf/lead_property.py b/dpnegf/negf/lead_property.py index dfd9934..b91a4c4 100644 --- a/dpnegf/negf/lead_property.py +++ b/dpnegf/negf/lead_property.py @@ -705,8 +705,8 @@ def write_to_hdf5(h5_path, k, e, se): group_name = f"E_{e:.8f}" dset_name = f"k_{k[0]}_{k[1]}_{k[2]}" grp = f.require_group(group_name) - if dset_name in grp: - log.warning(f"Dataset {dset_name} already exists in group {group_name}. Skipping it.") + # if dset_name in grp: + # log.warning(f"Dataset {dset_name} already exists in group {group_name}. Skipping it.") grp.create_dataset(dset_name, data=se.cpu().numpy(), compression="gzip") f.flush() @@ -740,7 +740,7 @@ def merge_hdf5_files(tmp_dir, output_path, pattern, remove=True): for dset_name in fin_group: if dset_name in fout_group: - log.warning(f"Dataset '{dset_name}' already exists in group '{group_name}'. Skipping.") + # log.warning(f"Dataset '{dset_name}' already exists in group '{group_name}'. Skipping.") continue fin_group.copy(dset_name, fout_group) From 85bd4356ee9d0b6438875fb6647f4b2e9daece78 Mon Sep 17 00:00:00 2001 From: kirk0830 Date: Tue, 20 Jan 2026 16:56:18 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix(argcheck):=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=AF=E9=80=89=E7=9A=84=E4=BB=8B=E7=94=B5=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E4=BB=8E5=E5=88=B06=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dpnegf/utils/argcheck.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dpnegf/utils/argcheck.py b/dpnegf/utils/argcheck.py index 6bb307c..9e09957 100644 --- a/dpnegf/utils/argcheck.py +++ b/dpnegf/utils/argcheck.py @@ -1210,7 +1210,7 @@ def pyamg(): Argument("dielectric_region", dict, optional=False, sub_fields=dielectric(), doc=doc_dielectric), *[ Argument(f"dielectric_region{i}", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric) - for i in range(2, 6) + for i in range(2, 7) ], Argument("doped_region", dict, optional=False, sub_fields=doped(), doc=doc_doped) ] @@ -1242,7 +1242,7 @@ def scipy(): Argument("dielectric_region", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric), *[ Argument(f"dielectric_region{i}", dict, optional=True, sub_fields=dielectric(), doc=doc_dielectric) - for i in range(2, 6) + for i in range(2, 7) ], Argument("doped_region1", dict, optional=True, sub_fields=doped(), doc=doc_doped), Argument("doped_region2", dict, optional=True, sub_fields=doped(), doc=doc_doped) From 46520f94008272082a9038aa52d16eb4a455769e Mon Sep 17 00:00:00 2001 From: kirk0830 Date: Tue, 20 Jan 2026 16:56:53 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=E5=B0=86lead=E7=9A=84temp=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=BB=8E=E5=9B=BA=E5=AE=9A=E5=80=BC=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8ele=5FT=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dpnegf/runner/NEGF.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpnegf/runner/NEGF.py b/dpnegf/runner/NEGF.py index 2681d29..1451ecc 100644 --- a/dpnegf/runner/NEGF.py +++ b/dpnegf/runner/NEGF.py @@ -182,7 +182,7 @@ def __init__(self, meshgrid=self.stru_options[lead_tag]["kmesh_lead_Ef"], AtomicData_options=AtomicData_options, smearing_method=self.stru_options.get("e_fermi_smearing", "FD"), - temp=100.0, + temp=self.ele_T, eig_solver=self.stru_options.get("eig_solver", "torch"),) else: e_fermi["lead_L"] = self.e_fermi From 61878e3bf4bef0d423835c79948a41f694ad0d28 Mon Sep 17 00:00:00 2001 From: kirk0830 Date: Tue, 27 Jan 2026 14:02:06 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat(NEGF):=20=E6=94=AF=E6=8C=81=E4=BB=8E?= =?UTF-8?q?=E5=A4=96=E9=83=A8=E4=BC=A0=E5=85=A5Poisson=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E8=AE=A1=E7=AE=97=E5=B9=B6=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 允许compute方法接收外部Poisson接口对象作为参数,避免重复创建 当scf为true时,可选择使用传入的Poisson接口或新建接口 计算完成后返回Poisson接口对象供后续使用 --- dpnegf/runner/NEGF.py | 118 +++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 52 deletions(-) diff --git a/dpnegf/runner/NEGF.py b/dpnegf/runner/NEGF.py index 1451ecc..390ad30 100644 --- a/dpnegf/runner/NEGF.py +++ b/dpnegf/runner/NEGF.py @@ -342,64 +342,78 @@ def generate_energy_grid(self): xu = torch.tensor(max(v_list)+8*self.kBT) self.int_grid, self.int_weight = gauss_xw(xl=xl, xu=xu, n=int(self.density_options["n_gauss"])) - def compute(self): + def compute(self, + pcond: Optional[Interface3D]=None) -> Optional[Interface3D]: + ''' + compute the NEGF calculation, can also from the given Poisson + ''' if self.scf: - - # create real-space grid - grid = self.get_grid(self.poisson_options["grid"],self.deviceprop.structure) - - # create Dirichlet boundary condition region - Dirichlet_group = [] - for idx in range(len(self.Dirichlet_region)): - Dirichlet_init = Dirichlet(self.Dirichlet_region[idx].get("x_range",None).split(':'),\ - self.Dirichlet_region[idx].get("y_range",None).split(':'),\ - self.Dirichlet_region[idx].get("z_range",None).split(':')) - #TODO: when heterogenous Dirichlet conditions are set, the voltage should be set as electrochemical potential(Fermi level + voltage) - Dirichlet_init.Ef = -1*float(self.Dirichlet_region[idx].get("voltage",None)) # in unit of eV - Dirichlet_group.append(Dirichlet_init) + if pcond is None: + # create real-space grid + grid = self.get_grid(self.poisson_options["grid"],self.deviceprop.structure) + + # create Dirichlet boundary condition region + Dirichlet_group = [] + for idx in range(len(self.Dirichlet_region)): + Dirichlet_init = Dirichlet(self.Dirichlet_region[idx].get("x_range",None).split(':'),\ + self.Dirichlet_region[idx].get("y_range",None).split(':'),\ + self.Dirichlet_region[idx].get("z_range",None).split(':')) + #TODO: when heterogenous Dirichlet conditions are set, the voltage should be set as electrochemical potential(Fermi level + voltage) + Dirichlet_init.Ef = -1*float(self.Dirichlet_region[idx].get("voltage",None)) # in unit of eV + Dirichlet_group.append(Dirichlet_init) + + # create dielectric region + dielectric_group = [] + for dd in range(len(self.dielectric_region)): + dielectric_init = Dielectric(self.dielectric_region[dd].get("x_range",None).split(':'),\ + self.dielectric_region[dd].get("y_range",None).split(':'),\ + self.dielectric_region[dd].get("z_range",None).split(':')) + dielectric_init.eps = float(self.dielectric_region[dd].get("relative permittivity",None)) + dielectric_group.append(dielectric_init) + + # create interface + pcond = Interface3D(grid,Dirichlet_group,dielectric_group) + pcond.get_potential_eps(Dirichlet_group+dielectric_group) + atom_gridpoint_index = list(pcond.grid.atom_index_dict.values()) # atomic site index in the grid + for dp in range(len(self.doped_region)): + pcond.get_fixed_charge(self.doped_region[dp].get("x_range",None).split(':'),\ + self.doped_region[dp].get("y_range",None).split(':'),\ + self.doped_region[dp].get("z_range",None).split(':'),\ + self.doped_region[dp].get("charge",None),\ + atom_gridpoint_index) + + #initial guess for electrostatic potential + log.info(msg="-----Initial guess for electrostatic potential----") + pcond.solve_poisson_NRcycle(method=self.poisson_options['solver'],\ + tolerance=self.poisson_options['tolerance'],\ + dtype=self.poisson_options['poisson_dtype']) + log.info(msg="-------------------------------------------\n") + + assert isinstance(pcond, Interface3D) + self.poisson_negf_scf(interface_poisson=pcond, + atom_gridpoint_index=list(pcond.grid.atom_index_dict.values()), + err=self.poisson_options['err'], + max_iter=self.poisson_options['max_iter'], + mix_rate=self.poisson_options['mix_rate'], + tolerance=self.poisson_options['tolerance']) - # create dielectric region - dielectric_group = [] - for dd in range(len(self.dielectric_region)): - dielectric_init = Dielectric( self.dielectric_region[dd].get("x_range",None).split(':'),\ - self.dielectric_region[dd].get("y_range",None).split(':'),\ - self.dielectric_region[dd].get("z_range",None).split(':')) - dielectric_init.eps = float(self.dielectric_region[dd].get("relative permittivity",None)) - dielectric_group.append(dielectric_init) - - # create interface - interface_poisson = Interface3D(grid,Dirichlet_group,dielectric_group) - interface_poisson.get_potential_eps(Dirichlet_group+dielectric_group) - atom_gridpoint_index = list(interface_poisson.grid.atom_index_dict.values()) # atomic site index in the grid - for dp in range(len(self.doped_region)): - interface_poisson.get_fixed_charge( self.doped_region[dp].get("x_range",None).split(':'),\ - self.doped_region[dp].get("y_range",None).split(':'),\ - self.doped_region[dp].get("z_range",None).split(':'),\ - self.doped_region[dp].get("charge",None),\ - atom_gridpoint_index) - - #initial guess for electrostatic potential - log.info(msg="-----Initial guess for electrostatic potential----") - interface_poisson.solve_poisson_NRcycle(method=self.poisson_options['solver'],\ - tolerance=self.poisson_options['tolerance'],\ - dtype=self.poisson_options['poisson_dtype']) - log.info(msg="-------------------------------------------\n") - - self.poisson_negf_scf( interface_poisson=interface_poisson,atom_gridpoint_index=atom_gridpoint_index,\ - err=self.poisson_options['err'],max_iter=self.poisson_options['max_iter'],\ - mix_rate=self.poisson_options['mix_rate'],tolerance=self.poisson_options['tolerance']) # calculate transport properties with converged potential self.negf_compute(scf_require=False,Vbias=self.potential_at_orb) - else: - profiler = Profiler() - profiler.start() - self.negf_compute(scf_require=False,Vbias=None) - profiler.stop() - output_path = os.path.join(self.results_path, "profile_report.html") - with open(output_path, 'w') as report_file: - report_file.write(profiler.output_html()) + return pcond + + # otherwise, the non-self-consistent calculation is performed + assert not self.scf + profiler = Profiler() + profiler.start() + self.negf_compute(scf_require=False,Vbias=None) + profiler.stop() + output_path = os.path.join(self.results_path, "profile_report.html") + with open(output_path, 'w') as report_file: + report_file.write(profiler.output_html()) + + return None def poisson_negf_scf(self,interface_poisson,atom_gridpoint_index,err=1e-6,max_iter=1000, mix_method:str='linear', mix_rate:float=0.3, tolerance:float=1e-7,Gaussian_sigma:float=3.0): From aac5deda770784fa55969995b0cd2031061ffda0 Mon Sep 17 00:00:00 2001 From: kirk0830 Date: Tue, 27 Jan 2026 14:03:31 +0800 Subject: [PATCH 5/6] =?UTF-8?q?docs(poisson=5Finit):=20=E5=AE=8C=E5=96=84I?= =?UTF-8?q?nterface3D=E7=B1=BB=E7=9A=84=E5=8F=82=E6=95=B0=E5=92=8C?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加缺失的文档说明,包括类参数和属性的详细描述 --- dpnegf/negf/poisson_init.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpnegf/negf/poisson_init.py b/dpnegf/negf/poisson_init.py index 73ed829..e35abb1 100644 --- a/dpnegf/negf/poisson_init.py +++ b/dpnegf/negf/poisson_init.py @@ -246,6 +246,7 @@ class Interface3D(object): Interface3D(grid, Dirichlet_group, dielectric_group) A class to handle the initialization and solution of the 3D Poisson equation on a structured grid with support for Dirichlet and dielectric regions. + Parameters ---------- grid : Grid @@ -254,6 +255,7 @@ class Interface3D(object): List of Dirichlet region objects specifying boundary conditions. dielectric_group : list of Dielectric List of Dielectric region objects specifying spatially varying permittivity. + Attributes ---------- Dirichlet_group : list From eae62900a3dab7c3fb357ccfe9c9ae9f1c4054bc Mon Sep 17 00:00:00 2001 From: AsymmetryChou <181240085@smail.nju.edu.cn> Date: Sun, 19 Apr 2026 10:39:28 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat(NEGF):=20=E6=B7=BB=E5=8A=A0=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E4=BB=A5=E6=8C=87=E7=A4=BA=E4=BD=BF=E7=94=A8=E7=BB=99?= =?UTF-8?q?=E5=AE=9A=E7=9A=84Poisson=E6=9D=A1=E4=BB=B6=E8=BF=9B=E8=A1=8CNE?= =?UTF-8?q?GF-Poisson=20SCF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dpnegf/runner/NEGF.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dpnegf/runner/NEGF.py b/dpnegf/runner/NEGF.py index 390ad30..5069e0e 100644 --- a/dpnegf/runner/NEGF.py +++ b/dpnegf/runner/NEGF.py @@ -390,6 +390,9 @@ def compute(self, dtype=self.poisson_options['poisson_dtype']) log.info(msg="-------------------------------------------\n") + else: + log.info(msg="Using the given Poisson condition for NEGF-Poisson SCF") + assert isinstance(pcond, Interface3D) self.poisson_negf_scf(interface_poisson=pcond, atom_gridpoint_index=list(pcond.grid.atom_index_dict.values()),