Skip to content

Commit 8c58508

Browse files
committed
Fix _min_max_X_line (zoomed chempots used arbitrary and potentially unphysical bounds (+/-0.1 eV), now uses midpoints as for grid function, and return target_df placed in while loop but should be outside)
1 parent 8300587 commit 8c58508

File tree

1 file changed

+32
-21
lines changed

1 file changed

+32
-21
lines changed

doped/thermodynamics.py

+32-21
Original file line numberDiff line numberDiff line change
@@ -5890,12 +5890,9 @@ def _min_max_X_line(
58905890
"""
58915891
# Assuming 1D space, focus on one label and get the Rich/Poor limits:
58925892
el_refs = chempots["elemental_refs"]
5893-
chempots_label = list(el_refs.keys()) # Assuming 1D space, focus on one label.
5894-
chempots_labels = [f"μ_{label}" for label in chempots_label]
5895-
5896-
# Initial line scan: Rich to Poor limit
5897-
rich = self._get_single_chempot_dict(f"{chempots_label[0]}-rich")
5898-
poor = self._get_single_chempot_dict(f"{chempots_label[0]}-poor")
5893+
unformatted_chempots_labels = list(el_refs.keys())
5894+
rich = self._get_single_chempot_dict(f"{unformatted_chempots_labels[0]}-rich")
5895+
poor = self._get_single_chempot_dict(f"{unformatted_chempots_labels[0]}-poor")
58995896
starting_line = self._get_interpolated_chempots(rich[0], poor[0], n_points)
59005897

59015898
previous_value = None
@@ -5942,17 +5939,24 @@ def _min_max_X_line(
59425939
and abs((current_value - previous_value) / previous_value) < tolerance
59435940
):
59445941
break
5945-
previous_value = current_value
5946-
target_chempot = target_chempot.drop_duplicates(ignore_index=True)
59475942

5943+
previous_value = current_value # otherwise update
5944+
5945+
# get midpoints of starting_line and target_chempot, and use these:
5946+
midpoint_chempots = [
5947+
{k: (starting_line_chempot_dict[k] + v) / 2 for k, v in target_chempot.iloc[0].items()}
5948+
for starting_line_chempot_dict in [starting_line[0], starting_line[-1]]
5949+
]
5950+
# Note that this is a 'safe' option for zooming in the search grid. If it was a linear
5951+
# function, then we could just take the closest vertices around ``target_chempot`` and use
5952+
# these, but we know that chempots & temperature & other constraints -> defect concentrations
5953+
# can be highly non-linear (e.g. CdTe concentrations in SK thesis, 10.1016/j.joule.2024.05.004,
5954+
# 10.1002/smll.202102429, 10.1021/acsenergylett.4c02722), so best to use this safe (but slower)
5955+
# approach to ensure we don't miss the true minimum/maximum. Same in both min_max functions.
59485956
starting_line = self._get_interpolated_chempots(
5949-
chempot_start={
5950-
k: v - 0.1 for k, v in target_chempot.iloc[0].items() if k in chempots_labels
5951-
},
5952-
chempot_end={
5953-
k: v + 0.1 for k, v in target_chempot.iloc[0].items() if k in chempots_labels
5954-
},
5955-
n_points=100,
5957+
chempot_start=midpoint_chempots[0],
5958+
chempot_end=midpoint_chempots[1],
5959+
n_points=n_points,
59565960
)
59575961

59585962
return target_df # TODO: Check and update tests, previously wrongly within the while block
@@ -5980,8 +5984,7 @@ def _min_max_X_grid(
59805984
"""
59815985
chempots, el_refs = self._parse_and_check_grid_like_chempots(chempots)
59825986
starting_grid = ChemicalPotentialGrid(chempots)
5983-
current_vertices = starting_grid.vertices
5984-
chempots_labels = list(current_vertices.columns)
5987+
59855988
previous_value = None
59865989
while True:
59875990
if annealing_temperature is not None:
@@ -6027,15 +6030,23 @@ def _min_max_X_grid(
60276030
and abs((current_value - previous_value) / previous_value) < tolerance
60286031
):
60296032
break
6030-
previous_value = current_value
6031-
target_chempot = target_chempot.drop_duplicates(ignore_index=True)
6033+
6034+
previous_value = current_value # otherwise update
60326035

60336036
new_vertices = [ # get midpoint between current vertices and target_chempot
6034-
(current_vertices + row[1]) / 2 for row in target_chempot.iterrows()
6037+
(starting_grid.vertices + row[1]) / 2 for row in target_chempot.iterrows()
60356038
]
6039+
# Note that this is a 'safe' option for zooming in the search grid. If it was a linear
6040+
# function, then we could just take the closest vertices around ``target_chempot`` and use
6041+
# these, but we know that chempots & temperature & other constraints -> defect concentrations
6042+
# can be highly non-linear (e.g. CdTe concentrations in SK thesis, 10.1016/j.joule.2024.05.004,
6043+
# 10.1002/smll.202102429, 10.1021/acsenergylett.4c02722), so best to use this safe (but slower)
6044+
# approach to ensure we don't miss the true minimum/maximum. Same in both min_max functions.
6045+
60366046
# Generate a new grid around the target_chempot that
60376047
# does not go outside the bounds of the starting grid
6038-
new_vertices_df = pd.DataFrame(new_vertices[0], columns=chempots_labels)
6048+
new_vertices_df = pd.DataFrame(new_vertices[0], columns=list(new_vertices[0].columns))
6049+
# TODO: Is the columns parameter necessary here? Check! (print and check)
60396050
starting_grid = ChemicalPotentialGrid(new_vertices_df.to_dict("index"))
60406051

60416052
return target_df

0 commit comments

Comments
 (0)