@@ -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 ):
0 commit comments