@@ -5890,12 +5890,9 @@ def _min_max_X_line(
5890
5890
"""
5891
5891
# Assuming 1D space, focus on one label and get the Rich/Poor limits:
5892
5892
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" )
5899
5896
starting_line = self ._get_interpolated_chempots (rich [0 ], poor [0 ], n_points )
5900
5897
5901
5898
previous_value = None
@@ -5942,17 +5939,24 @@ def _min_max_X_line(
5942
5939
and abs ((current_value - previous_value ) / previous_value ) < tolerance
5943
5940
):
5944
5941
break
5945
- previous_value = current_value
5946
- target_chempot = target_chempot .drop_duplicates (ignore_index = True )
5947
5942
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.
5948
5956
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 ,
5956
5960
)
5957
5961
5958
5962
return target_df # TODO: Check and update tests, previously wrongly within the while block
@@ -5980,8 +5984,7 @@ def _min_max_X_grid(
5980
5984
"""
5981
5985
chempots , el_refs = self ._parse_and_check_grid_like_chempots (chempots )
5982
5986
starting_grid = ChemicalPotentialGrid (chempots )
5983
- current_vertices = starting_grid .vertices
5984
- chempots_labels = list (current_vertices .columns )
5987
+
5985
5988
previous_value = None
5986
5989
while True :
5987
5990
if annealing_temperature is not None :
@@ -6027,15 +6030,23 @@ def _min_max_X_grid(
6027
6030
and abs ((current_value - previous_value ) / previous_value ) < tolerance
6028
6031
):
6029
6032
break
6030
- previous_value = current_value
6031
- target_chempot = target_chempot . drop_duplicates ( ignore_index = True )
6033
+
6034
+ previous_value = current_value # otherwise update
6032
6035
6033
6036
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 ()
6035
6038
]
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
+
6036
6046
# Generate a new grid around the target_chempot that
6037
6047
# 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)
6039
6050
starting_grid = ChemicalPotentialGrid (new_vertices_df .to_dict ("index" ))
6040
6051
6041
6052
return target_df
0 commit comments