Skip to content

Commit 80d0617

Browse files
committed
Use autoset of efield_pos_max and efield_pos_dec in ABACUS
1 parent c91609d commit 80d0617

1 file changed

Lines changed: 2 additions & 127 deletions

File tree

src/abacusagent/modules/submodules/work_function.py

Lines changed: 2 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
19573
def 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

Comments
 (0)