Skip to content

Commit

Permalink
chempot handling functions go public
Browse files Browse the repository at this point in the history
  • Loading branch information
alexsquires committed Jul 11, 2024
1 parent 9d8686f commit 12ffa03
Showing 1 changed file with 52 additions and 18 deletions.
70 changes: 52 additions & 18 deletions doped/thermodynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ def bold_print(string: str) -> None:
print("\033[1m" + string + "\033[0m")


def _raise_limit_with_user_chempots_error(no_chempots=True):
def raise_limit_with_user_chempots_error(no_chempots=True):
"""
Raise an error when a user tries to use `limit` with user-specified
chemical potentials (i.e. not in the doped format).
Args:
no_chempots (bool): Whether the user has not supplied any chemical potentials.
"""
problem = (
(
"the supplied chempots are not in the doped format (i.e. with `limits` in the chempots dict), "
Expand All @@ -65,15 +72,26 @@ def _raise_limit_with_user_chempots_error(no_chempots=True):
)


def _parse_limit(chempots: dict, limit: Optional[str] = None):
def parse_limit(chempots: dict, limit: Optional[str] = None):
"""
Parse the limit input, returning the correct limit name to use in analysis
functions.
Args:
chempots (dict): The chempots dict, in the doped format.
limit (str): The limit name to use in analysis functions.
returns:
str: The correct limit name to use in analysis functions.
"""
if limit is not None:
if limit in chempots["limits"]:
return limit # direct match, just return limit name
if "limits" not in chempots or "User Chemical Potentials" in chempots["limits"]:
# user specified chempots
_raise_limit_with_user_chempots_error(no_chempots=True)
raise_limit_with_user_chempots_error(no_chempots=True)
if "No User Chemical Potentials" in chempots["limits"]:
_raise_limit_with_user_chempots_error(no_chempots=False)
raise_limit_with_user_chempots_error(no_chempots=False)
if "rich" in limit:
limit = get_X_rich_limit(limit.split("-")[0], chempots)
elif "poor" in limit:
Expand Down Expand Up @@ -107,7 +125,19 @@ def get_rich_poor_limit_dict(chempots: dict) -> dict:
return limit_dict


def _get_limit_name_from_dict(limit, limit_rich_poor_dict, bracket=False):
def get_limit_name_from_dict(limit, limit_rich_poor_dict, bracket=False):
"""
Get the limit name from a rich/poor limit dictionary, returning the
corresponding rich/poor limit name if it exists.
Args:
limit (str): The limit name to get the rich/poor limit name for.
limit_rich_poor_dict (dict): The rich/poor limit dictionary.
bracket (bool): Whether to return the limit name with the rich/poor limit in brackets.
Returns:
str: The limit name with the rich/poor limit in brackets if bracket is True.
"""
if limit_rich_poor_dict and limit in limit_rich_poor_dict.values():
# get first key with matching value:
x_rich_poor = list(limit_rich_poor_dict.keys())[list(limit_rich_poor_dict.values()).index(limit)]
Expand All @@ -129,14 +159,18 @@ def _update_old_chempots_dict(chempots: dict) -> dict:
return chempots


def _parse_chempots(chempots: Optional[dict] = None, el_refs: Optional[dict] = None):
def parse_chempots(chempots: Optional[dict] = None, el_refs: Optional[dict] = None):
"""
Parse the chemical potentials input, formatting them in the ``doped``
format for use in analysis functions.
Can be either ``doped`` format or user-specified format.
Returns parsed ``chempots`` and ``el_refs``
Args:
chempots (dict): The chempots dict
el_refs (dict): The elemental reference energies
Returns:
parsed ``chempots`` and ``el_refs``
"""
if chempots is not None and "limits_wrt_elt_refs" in chempots:
chempots["limits_wrt_el_refs"] = chempots.pop("limits_wrt_elt_refs")
Expand Down Expand Up @@ -487,7 +521,7 @@ def __init__(
defect_entries = list(defect_entries.values())

self._defect_entries = defect_entries
self._chempots, self._el_refs = _parse_chempots(chempots, el_refs)
self._chempots, self._el_refs = parse_chempots(chempots, el_refs)
self._dist_tol = dist_tol
self.check_compatibility = check_compatibility

Expand Down Expand Up @@ -645,7 +679,7 @@ def _get_chempots(self, chempots: Optional[dict] = None, el_refs: Optional[dict]
Parse chemical potentials, either using input values (after formatting
them in the doped format) or using the class attributes if set.
"""
return _parse_chempots(chempots or self.chempots, el_refs or self.el_refs)
return parse_chempots(chempots or self.chempots, el_refs or self.el_refs)

def _parse_transition_levels(self):
r"""
Expand Down Expand Up @@ -1044,7 +1078,7 @@ def chempots(self, input_chempots):
potentials can also be supplied later in each analysis function.
(Default: None)
"""
self._chempots, self._el_refs = _parse_chempots(input_chempots, self._el_refs)
self._chempots, self._el_refs = parse_chempots(input_chempots, self._el_refs)

@property
def el_refs(self):
Expand All @@ -1070,7 +1104,7 @@ def el_refs(self, input_el_refs):
Unnecessary if ``chempots`` is provided in format generated by ``doped``
(see tutorials).
"""
self._chempots, self._el_refs = _parse_chempots(self._chempots, input_el_refs)
self._chempots, self._el_refs = parse_chempots(self._chempots, input_el_refs)

@property
def defect_names(self):
Expand Down Expand Up @@ -1953,7 +1987,7 @@ def get_dopability_limits(
"DefectThermodynamics.chempots, so dopability limits cannot be calculated."
)

limit = _parse_limit(chempots, limit)
limit = parse_limit(chempots, limit)
limits = [limit] if limit is not None else list(chempots["limits"].keys())

donor_intercepts: list[tuple] = []
Expand Down Expand Up @@ -2034,14 +2068,14 @@ def get_dopability_limits(
return pd.DataFrame(
[
[
_get_limit_name_from_dict(
get_limit_name_from_dict(
limiting_donor_intercept_row["limit"], limit_dict, bracket=True
),
limiting_donor_intercept_row["name"],
round(limiting_donor_intercept_row["intercept"], 3),
],
[
_get_limit_name_from_dict(
get_limit_name_from_dict(
limiting_acceptor_intercept_row["limit"], limit_dict, bracket=True
),
limiting_acceptor_intercept_row["name"],
Expand Down Expand Up @@ -2126,7 +2160,7 @@ def get_doping_windows(
"DefectThermodynamics.chempots, so doping windows cannot be calculated."
)

limit = _parse_limit(chempots, limit)
limit = parse_limit(chempots, limit)
limits = [limit] if limit is not None else list(chempots["limits"].keys())

vbm_donor_intercepts: list[tuple] = []
Expand Down Expand Up @@ -2190,7 +2224,7 @@ def get_doping_windows(
limiting_intercept_row = intercepts_df.iloc[intercepts_df[idx]["intercept"].idxmax()]
limiting_intercept_rows.append(
[
_get_limit_name_from_dict(limiting_intercept_row["limit"], limit_dict, bracket=True),
get_limit_name_from_dict(limiting_intercept_row["limit"], limit_dict, bracket=True),
limiting_intercept_row["name"],
round(limiting_intercept_row["intercept"], 3),
]
Expand Down Expand Up @@ -2337,7 +2371,7 @@ def plot(
"limits": {"No User Chemical Potentials": None}
} # empty chempots dict to allow plotting, user will be warned

limit = _parse_limit(chempots, limit)
limit = parse_limit(chempots, limit)
limits = [limit] if limit is not None else list(chempots["limits"].keys())

if (
Expand Down Expand Up @@ -2645,7 +2679,7 @@ def get_formation_energies(
"limits_wrt_el_refs": {"No User Chemical Potentials": {}}, # empty dict so is iterable
}

limit = _parse_limit(chempots, limit)
limit = parse_limit(chempots, limit)
limits = [limit] if limit is not None else list(chempots["limits"].keys())

list_of_dfs = []
Expand Down

0 comments on commit 12ffa03

Please sign in to comment.