@@ -70,128 +70,6 @@ def calculate_work_functions(averaged_potential: List, fermi_energy, length: flo
7070
7171 return work_function_results
7272
73- def round_coord_pbc1d (a , length ):
74- a /= length
75- return (a - np .floor (a )) * length
76-
77- def dist_pbc1d (a , b , length ):
78- a , b = round_coord_pbc1d (a , length ), round_coord_pbc1d (b , length )
79- if a > b :
80- a , b = b , a
81- return min (b - a , a + length - b )
82-
83- def determine_efield_pos_max (stru : AbacusStru , vacuum_direction : Literal ['x' , 'y' , 'z' ] = 'z' , threshold : float = 3.0 ) -> float :
84- """
85- Automatically determine the maximum position of the applied saw-shape electric field in dipole correction.
86- """
87- def calculate_dist (ref_pos , atom_poses , mode = Literal ['lower' , 'higher' ]):
88- min_dist = None
89- if mode == 'lower' :
90- for atom_pos in atom_poses :
91- if atom_pos < ref_pos :
92- dist = dist_pbc1d (ref_pos , atom_pos , length = cell_length )
93- if min_dist is None :
94- min_dist = dist
95- elif dist < min_dist :
96- min_dist = dist
97- elif mode == 'higher' :
98- if atom_pos > ref_pos :
99- dist = dist_pbc1d (ref_pos , atom_pos , length = cell_length )
100- if min_dist is None :
101- min_dist = dist
102- elif dist < min_dist :
103- min_dist = dist
104- else :
105- raise ValueError ("Invalid mode" )
106-
107- return min_dist
108-
109- direction_map = {'x' : 0 , 'y' : 1 , 'z' : 2 }
110- direction = direction_map [vacuum_direction ]
111- atom_positions_vac_dir = []
112- for atom_idx in range (stru .get_natoms ()):
113- atom_positions_vac_dir .append (stru .get_coord ()[atom_idx ][direction ])
114-
115- cell_length = np .linalg .norm (stru .get_cell ()[direction ]) # Lattice parameter along the given vacuum direction
116-
117- if cell_length - max (atom_positions_vac_dir ) + min (atom_positions_vac_dir ) < threshold :
118- # The slab crosses the boundary, and the vacuum lies with in the cell
119- stepsize = 1.0 # Angstrom
120- # Find lower boundary of the vacuum region
121- trial_pos = 1.0 # Angstrom
122- lower_boundary = None
123- while lower_boundary is None :
124- min_dist = calculate_dist (trial_pos , atom_positions_vac_dir , mode = 'lower' )
125- if min_dist > threshold :
126- lower_boundary = trial_pos
127- elif trial_pos + stepsize < cell_length :
128- trial_pos += stepsize
129- else :
130- raise RuntimeError ("Unable to find the lower boundary of the vacuum region" )
131-
132- trial_pos = cell_length - 1.0
133- upper_boundary = None
134- while upper_boundary is None :
135- min_dist = calculate_dist (trial_pos , atom_positions_vac_dir , mode = 'higher' )
136- if min_dist > threshold :
137- upper_boundary = trial_pos
138- elif trial_pos - stepsize > 0 :
139- trial_pos -= stepsize
140- else :
141- raise RuntimeError ("Unable to find the upper boundary of the vacuum region" )
142-
143- if upper_boundary < lower_boundary - threshold :
144- print ("There seems have no vacuum region. Check your structure and input arguments" )
145- elif upper_boundary < lower_boundary :
146- print ("Warning: The slab is too thick. The vacuum region should be enlarged" )
147- pos = (upper_boundary + lower_boundary ) / 2
148- else :
149- # The slab does not cross the boundary
150- if min (atom_positions_vac_dir ) + cell_length - min (atom_positions_vac_dir ) < threshold * 2 :
151- print ("Warning: The slab is too close to the boundary. The vacuum region should be enlarged" )
152- pos = (min (atom_positions_vac_dir ) + max (atom_positions_vac_dir ) + cell_length ) / 2 # Midpoint of leftmost atom (PBC image in the right cell) and rightmost atom
153- min_dist = pos - max (atom_positions_vac_dir )
154- if pos > cell_length :
155- pos -= cell_length
156-
157- return pos / cell_length , min_dist
158-
159- def determine_efield_pos_max_scan (stru : AbacusStru , vacuum_direction : Literal ['x' , 'y' , 'z' ] = 'z' , threshold : float = 3.0 ):
160- """
161- Using simple scan to automatically determine the maximum position of the applied saw-shape electric field in dipole correction.
162- """
163- direction_map = {'x' : 0 , 'y' : 1 , 'z' : 2 }
164- direction = direction_map [vacuum_direction ]
165- atom_positions_vac_dir = []
166- for atom_idx in range (stru .get_natoms ()):
167- atom_positions_vac_dir .append (stru .get_coord ()[atom_idx ][direction ])
168-
169- cell_length = np .linalg .norm (stru .get_cell ()[direction ]) # Lattice parameter along the given vacuum direction
170-
171- scan_pos , scan_stepsize , scan_min_dist_max = 0.0 , 0.05 , None
172- while scan_pos < 1.0 :
173- min_dist = None
174- for atom_idx in range (stru .get_natoms ()):
175- dist = dist_pbc1d (atom_positions_vac_dir [atom_idx ], scan_pos * cell_length , cell_length )
176- if min_dist is None :
177- min_dist = dist
178- elif dist < min_dist :
179- min_dist = dist
180-
181- if scan_min_dist_max is None :
182- scan_min_dist_max = min_dist
183- scan_min = scan_pos
184- elif scan_min_dist_max < min_dist :
185- scan_min_dist_max = min_dist
186- scan_min = scan_pos
187-
188- scan_pos += scan_stepsize
189-
190- if scan_min_dist_max > threshold :
191- return scan_min , scan_min_dist_max
192- else :
193- raise RuntimeError ("No suitable position for maximum position of the applied saw-shape electric field found" )
194-
19573def plot_averaged_elecstat_pot (
19674 averaged_elecstat_data ,
19775 work_path : Path ,
@@ -244,16 +122,14 @@ def abacus_cal_work_function(
244122 if input_params .get ('nspin' , 1 ) not in [1 , 2 ]:
245123 raise ValueError ('Only non spin-polarized and collinear spin-polarized calculation are supported for calculating electrostatic potential and work function' )
246124
125+ direction_map = {'x' : 0 , 'y' : 1 , 'z' : 2 }
247126 input_params ['calculation' ] = 'scf'
248127 input_params ['out_pot' ] = 2
128+ input_params ['efield_dir' ] = direction_map [vacuum_direction ]
249129
250130 if dipole_correction :
251131 input_params ['efield_flag' ] = 1
252132 input_params ['dip_cor_flag' ] = 1
253-
254- efield_pos_max , min_dist = determine_efield_pos_max (stru , vacuum_direction )
255- input_params ['efield_pos_max' ] = efield_pos_max
256- input_params ['efield_pos_dec' ] = 0.1
257133 input_params ['efield_amp' ] = 0.00
258134
259135 WriteInput (input_params , os .path .join (work_path , 'INPUT' ))
@@ -270,7 +146,6 @@ def abacus_cal_work_function(
270146 profile_result = profile1d (pot , axis = vacuum_direction , average = True )
271147 profile_result ['data' ][:, 1 ] *= RY_TO_EV # Convert from Rydberg to eV
272148
273- direction_map = {'x' : 0 , 'y' : 1 , 'z' : 2 }
274149 length = np .linalg .norm (stru .get_cell ()[direction_map [vacuum_direction ]])
275150 work_function_results = calculate_work_functions (profile_result ['data' ][:, 1 ],
276151 fermi_energy = metrics ['efermi' ],
0 commit comments