Skip to content

Commit

Permalink
Merge branch 'refs/heads/develop' into dopey_fermi
Browse files Browse the repository at this point in the history
  • Loading branch information
kavanase committed Jul 30, 2024
2 parents 761dab5 + 773d1d6 commit 17bfdf2
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 57 deletions.
8 changes: 4 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ v.2.3.3
----------
- General robustness updates:
- Updated file parsing to avoid hidden files.
- Sanity check in `DefectsGenerator` if input symmetry is `P1`.
- Add `NKRED` to `INCAR` mismatch tests.
- Sanity check in ``DefectsGenerator`` if input symmetry is ``P1``.
- Add ``NKRED`` to ``INCAR`` mismatch tests.
- Re-parse config & spin degeneracies in concentration/symmetry functions if data not already present
(if user is porting `DefectEntry`s from older `doped` versions or manually).
- Avoid unnecessary `DeprecationWarning`s
(if user is porting ``DefectEntry``s from older ``doped`` versions or manually).
- Avoid unnecessary ``DeprecationWarning``s
- Updated docs and linting
v.2.3.2
Expand Down
2 changes: 2 additions & 0 deletions docs/Tips.rst
Original file line number Diff line number Diff line change
Expand Up @@ -500,10 +500,12 @@ In the typical defect calculation workflow with ``doped`` (exemplified in the tu
``DefectsParser(output_path=".")`` – written to ``output_path``. The JSON filename can be set with e.g.
``DefectsParser(json_filename="custom_name.json")``, but the default is
``{Host Chemical Formula}_defect_dict.json``.

- Additionally, a ``voronoi_nodes.json`` file is saved to the bulk supercell calculation directory if
any interstitial defects are parsed. This contains information about the Voronoi tessellation nodes
in the host structure, which are used for analysing interstitial positions but can be somewhat costly
to calculate – so are automatically saved to file once initially computed to reduce parsing times.

- Additionally, if following the recommended structure-searching approach with ``ShakeNBreak`` as shown in
the tutorials, ``distortion_metadata.json`` files will be written to the top directory (``output_path``,
containing distortion information about all defects) and to each defect directory (containing just the
Expand Down
9 changes: 5 additions & 4 deletions docs/docs_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
sphinx
myst-nb
sphinx>=7
myst-nb>=1.0
recommonmark
renku-sphinx-theme
renku-sphinx-theme>=0.4.0 # can update to >0.5.0 when https://github.com/SwissDataScienceCenter/renku-sphinx-theme/pull/26 merged
sphinx_rtd_theme>=1.3.0 # can update to >2.0 when https://github.com/SwissDataScienceCenter/renku-sphinx-theme/pull/26 merged
sphinx_click
sphinx_design
ase
Expand All @@ -22,4 +23,4 @@ shakenbreak>=3.3.1
packaging
pandas>=1.1.0
pydefect>=0.8.1
vise>=0.9.0
vise>=0.9.0
13 changes: 6 additions & 7 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ Studies using ``doped``, so far
- Z\. Yuan & G. Hautier **First-principles study of defects and doping limits in CaO** `Applied Physics Letters <https://doi.org/10.1063/5.0211707>`_ 2024
- B\. E. Murdock et al. **Li-Site Defects Induce Formation of Li-Rich Impurity Phases: Implications for Charge Distribution and Performance of LiNi** :sub:`0.5-x` **M** :sub:`x` **Mn** :sub:`1.5` **O** :sub:`4` **Cathodes (M = Fe and Mg; x = 0.05–0.2)** `Advanced Materials <https://doi.org/10.1002/adma.202400343>`_ 2024
- A\. G. Squires et al. **Oxygen dimerization as a defect-driven process in bulk LiNiO₂** `ChemRxiv <https://doi.org/10.26434/chemrxiv-2024-lcmkj>`_ 2024
- A\. G. Squires et al. **Oxygen dimerization as a defect-driven process in bulk LiNiO₂** `ChemRxiv <https://doi.org/10.26434/chemrxiv-2024-lcmkj>`__ 2024
- Y\. Fu & H. Lohan et al. **Factors Enabling Delocalized Charge-Carriers in Pnictogen-Based Solar Absorbers: In-depth Investigation into CuSbSe<sub>2</sub>** `arXiv <https://doi.org/10.48550/arXiv.2401.02257>`_ 2024
- S\. Hachmioune et al. **Exploring the Thermoelectric Potential of MgB4: Electronic Band Structure, Transport Properties, and Defect Chemistry** `Chemistry of Materials <https://doi.org/10.1021/acs.chemmater.4c00584>`_ 2024
- J\. Hu et al. **Enabling ionic transport in Li3AlP2 the roles of defects and disorder** `ChemRxiv <https://doi.org/10.26434/chemrxiv-2024-3s0kh>`_ 2024
- S\. Hachmioune et al. **Exploring the Thermoelectric Potential of MgB4: Electronic Band Structure, Transport Properties, and Defect Chemistry** `Chemistry of Materials <https://doi.org/10.1021/acs.chemmater.4c00584>`__ 2024
- J\. Hu et al. **Enabling ionic transport in Li3AlP2 the roles of defects and disorder** `ChemRxiv <https://doi.org/10.26434/chemrxiv-2024-3s0kh>`__ 2024
- X\. Wang et al. **Upper efficiency limit of Sb₂Se₃ solar cells** `Joule <https://doi.org/10.1016/j.joule.2024.05.004>`_ 2024
- I\. Mosquera-Lois et al. **Machine-learning structural reconstructions for accelerated point defect calculations** `npj Computational Materials <https://doi.org/10.1038/s41524-024-01303-9>`_ 2024
- I\. Mosquera-Lois et al. **Machine-learning structural reconstructions for accelerated point defect calculations** `npj Computational Materials <https://doi.org/10.1038/s41524-024-01303-9>`__ 2024
- W\. Dou et al. **Band Degeneracy and Anisotropy Enhances Thermoelectric Performance from Sb₂Si₂Te₆ to Sc₂Si₂Te₆** `Journal of the American Chemical Society <https://doi.org/10.1021/jacs.4c01838>`_ 2024
- K\. Li et al. **Computational Prediction of an Antimony-based n-type Transparent Conducting Oxide: F-doped Sb₂O₅** `Chemistry of Materials <https://doi.org/10.1021/acs.chemmater.3c03257>`_ 2024
- K\. Li et al. **Computational Prediction of an Antimony-based n-type Transparent Conducting Oxide: F-doped Sb₂O₅** `Chemistry of Materials <https://doi.org/10.1021/acs.chemmater.3c03257>`__ 2024
- X\. Wang et al. **Four-electron negative-U vacancy defects in antimony selenide** `Physical Review B <https://journals.aps.org/prb/abstract/10.1103/PhysRevB.108.134102>`_ 2023
- Y\. Kumagai et al. **Alkali Mono-Pnictides: A New Class of Photovoltaic Materials by Element Mutation** `PRX Energy <http://dx.doi.org/10.1103/PRXEnergy.2.043002>`__ 2023
- S\. M. Liga & S. R. Kavanagh, A. Walsh, D. O. Scanlon, G. Konstantatos **Mixed-Cation Vacancy-Ordered Perovskites (Cs₂Ti** :sub:`1–x` **Sn** :sub:`x` **X₆; X = I or Br): Low-Temperature Miscibility, Additivity, and Tunable Stability** `Journal of Physical Chemistry C`_ 2023
Expand All @@ -111,7 +111,7 @@ Studies using ``doped``, so far
- J\. Willis, K. B. Spooner, D. O. Scanlon. **On the possibility of p-type doping in barium stannate** `Applied Physics Letters <https://doi.org/10.1063/5.0170552>`__ 2023
- J\. Cen et al. **Cation disorder dominates the defect chemistry of high-voltage LiMn** :sub:`1.5` **Ni** :sub:`0.5` **O₄ (LMNO) spinel cathodes** `Journal of Materials Chemistry A`_ 2023
- J\. Willis & R. Claes et al. **Limits to Hole Mobility and Doping in Copper Iodide** `Chemistry of Materials <https://doi.org/10.1021/acs.chemmater.3c01628>`__ 2023
- I\. Mosquera-Lois & S. R. Kavanagh, A. Walsh, D. O. Scanlon **Identifying the ground state structures of point defects in solids** `npj Computational Materials`_ 2023
- I\. Mosquera-Lois & S. R. Kavanagh, A. Walsh, D. O. Scanlon **Identifying the ground state structures of point defects in solids** `npj Computational Materials <https://www.nature.com/articles/s41524-023-00973-1>`__ 2023
- Y\. T. Huang & S. R. Kavanagh et al. **Strong absorption and ultrafast localisation in NaBiS₂ nanocrystals with slow charge-carrier recombination** `Nature Communications`_ 2022
- S\. R. Kavanagh, D. O. Scanlon, A. Walsh, C. Freysoldt **Impact of metastable defect structures on carrier recombination in solar cells** `Faraday Discussions`_ 2022
- Y-S\. Choi et al. **Intrinsic Defects and Their Role in the Phase Transition of Na-Ion Anode Na₂Ti₃O₇** `ACS Applied Energy Materials <https://doi.org/10.1021/acsaem.2c03466>`__ 2022
Expand All @@ -129,7 +129,6 @@ Studies using ``doped``, so far
.. _Journal of Physical Chemistry C: https://doi.org/10.1021/acs.jpcc.3c05204
.. _Journal of Materials Chemistry A: https://doi.org/10.1039/D3TA00532A
.. _npj Computational Materials: https://www.nature.com/articles/s41524-023-00973-1
.. _Nature Communications: https://www.nature.com/articles/s41467-022-32669-3
.. _Faraday Discussions: https://doi.org/10.1039/D2FD00043A
.. _Chemical Science: https://doi.org/10.1039/D1SC03775G
Expand Down
113 changes: 103 additions & 10 deletions doped/thermodynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,41 @@ def _parse_chempots(chempots: Optional[dict] = None, el_refs: Optional[dict] = N
return chempots, chempots.get("elemental_refs")


def raw_energy_from_chempots(composition: Union[str, dict, Composition], chempots: dict) -> float:
"""
Given an input composition (as a ``str``, ``dict`` or ``pymatgen``
``Composition`` object) and chemical potentials dictionary, get the
corresponding raw energy of the composition (i.e. taking the energies given
in the ``'limits'`` subdicts of ``chempots``, in the ``doped`` chemical
potentials dictionary format).
Args:
composition (Union[str, dict, Composition]):
Composition to get the raw energy of.
chempots (dict):
Chemical potentials dictionary.
Returns:
Raw energy of the composition.
"""
if not isinstance(composition, Composition):
composition = Composition(composition)

if "limits" not in chempots:
chempots, _el_refs = _parse_chempots(chempots)

raw_energies_dict = dict(next(iter(chempots["limits"].values())))

if any(el.symbol not in raw_energies_dict for el in composition.elements):
raise ValueError(
f"The chemical potentials dictionary (with elements {list(raw_energies_dict.keys())} does not "
f"contain all the elements in the host composition "
f"({[el.symbol for el in composition.elements]})!"
)

return sum(raw_energies_dict.get(el.symbol, 0) * stoich for el, stoich in composition.items())


def group_defects_by_distance(
entry_list: list[DefectEntry], dist_tol: float = 1.5
) -> dict[str, dict[tuple, list[DefectEntry]]]:
Expand Down Expand Up @@ -540,7 +575,7 @@ def _raise_VBM_band_gap_value_error(vals, type="VBM"):
)

# order entries for deterministic behaviour (particularly for plotting)
self._sort_parse_and_check_entries(check_compatibility=check_compatibility)
self._sort_parse_and_check_entries()

bulk_entry = self.defect_entries[0].bulk_entry
if bulk_entry is not None:
Expand All @@ -550,10 +585,11 @@ def _raise_VBM_band_gap_value_error(vals, type="VBM"):
else:
self.bulk_formula = None

def _sort_parse_and_check_entries(self, check_compatibility: bool = True):
def _sort_parse_and_check_entries(self):
"""
Sort the defect entries, parse the transition levels, and check the
compatibility of the bulk entries (if check_compatibility is True).
compatibility of the bulk entries (if ``self.check_compatibility`` is
``True``).
"""
defect_entries_dict: dict[str, DefectEntry] = {}
for entry in self.defect_entries: # rename defect entry names in dict if necessary ("_a", "_b"...)
Expand All @@ -572,8 +608,9 @@ def _sort_parse_and_check_entries(self, check_compatibility: bool = True):
with warnings.catch_warnings(): # ignore formation energies chempots warning when just parsing TLs
warnings.filterwarnings("ignore", message="No chemical potentials")
self._parse_transition_levels()
if check_compatibility:
if self.check_compatibility:
self._check_bulk_compatibility()
self._check_bulk_chempots_compatibility(self._chempots)

def as_dict(self):
"""
Expand Down Expand Up @@ -661,7 +698,11 @@ 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)
chempots, el_refs = _parse_chempots(chempots or self.chempots, el_refs or self.el_refs)
if self.check_compatibility:
self._check_bulk_chempots_compatibility(chempots)

return chempots, el_refs

def _parse_transition_levels(self):
r"""
Expand Down Expand Up @@ -890,7 +931,7 @@ def _check_bulk_compatibility(self):
"""
Helper function to quickly check if all entries have compatible bulk
calculation settings, by checking that the energy of
defect_entry.bulk_entry is the same for all defect entries.
``defect_entry.bulk_entry`` is the same for all defect entries.
By proxy checks that same bulk/defect calculation settings were used in
all cases, from each bulk/defect combination already being checked when
Expand All @@ -907,8 +948,8 @@ def _check_bulk_compatibility(self):
f"eV. This can lead to inaccuracies in predicted formation energies! The bulk energies of "
f"defect entries in `defect_entries` are:\n"
f"{[(entry.name, entry.bulk_entry.energy) for entry in self.defect_entries]}\n"
f"You can suppress this warning by setting `check_compatibility=False` in "
"`DefectThermodynamics` initialisation."
f"You can suppress this warning by setting `DefectThermodynamics.check_compatibility = "
f"False`."
)

def _check_bulk_defects_compatibility(self):
Expand All @@ -918,7 +959,7 @@ def _check_bulk_defects_compatibility(self):
Currently not used, as the bulk/defect compatibility is checked when
parsing, and the compatibility across bulk calculations is checked with
_check_bulk_compatibility().
``_check_bulk_compatibility()``.
"""
# check each defect entry against its own bulk, and also check each bulk against each other
reference_defect_entry = self.defect_entries[0]
Expand Down Expand Up @@ -964,6 +1005,55 @@ def _check_bulk_defects_compatibility(self):
f"{defect_entry.name}: \n{concatenated_warnings}"
)

def _check_bulk_chempots_compatibility(self, chempots: Optional[dict] = None):
r"""
Helper function to quickly check if the supplied chemical potentials
dictionary matches the bulk supercell used for the defect calculations,
by comparing the raw energies (from the bulk supercell calculation, and
that corresponding to the chemical potentials supplied).
Args:
chempots (dict, optional):
Dictionary of chemical potentials to check compatibility with
the bulk supercell calculations (``DefectEntry.bulk_entry``\s),
in the ``doped`` format.
If ``None`` (default), will use ``self.chempots`` (= 0 for all
chemical potentials by default).
This can have the form of ``{"limits": [{'limit': [chempot_dict]}]}``
(the format generated by ``doped``\'s chemical potential parsing
functions (see tutorials)), or alternatively a dictionary of chemical
potentials for a single limit (``limit``), in the format:
``{element symbol: chemical potential}``.
If manually specifying chemical potentials this way, you can set the
``el_refs`` option with the DFT reference energies of the elemental phases,
in which case it is the formal chemical potentials (i.e. relative to the
elemental references) that should be given here, otherwise the absolute
(DFT) chemical potentials should be given.
"""
if chempots is None and self.chempots is None:
return

bulk_entry = next(entry.bulk_entry for entry in self.defect_entries)
bulk_supercell_energy_per_atom = bulk_entry.energy / bulk_entry.composition.num_atoms
bulk_chempot_energy_per_atom = (
raw_energy_from_chempots(bulk_entry.composition, chempots or self.chempots)
/ bulk_entry.composition.num_atoms
)

if abs(bulk_supercell_energy_per_atom - bulk_chempot_energy_per_atom) > 0.025:
warnings.warn( # 0.05 eV intrinsic defect formation energy error tolerance, taking per-atom
# chempot error and multiplying by 2 to account for how this would affect antisite
# formation energies (extreme case)
f"Note that the raw (DFT) energy of the bulk supercell calculation ("
f"{bulk_supercell_energy_per_atom:.2f} eV/atom) differs from that expected from the "
f"supplied chemical potentials ({bulk_chempot_energy_per_atom:.2f} eV/atom) by >0.025 eV. "
f"This will likely give inaccuracies of similar magnitude in the predicted formation "
f"energies! \n"
f"You can suppress this warning by setting `DefectThermodynamics.check_compatibility = "
f"False`."
)

def add_entries(
self,
defect_entries: Union[list[DefectEntry], dict[str, DefectEntry]],
Expand All @@ -986,6 +1076,7 @@ def add_entries(
entry (i.e. that all reference bulk energies are the same).
(Default: True)
"""
self.check_compatibility = check_compatibility
if isinstance(defect_entries, dict):
defect_entries = list(defect_entries.values())

Expand All @@ -996,7 +1087,7 @@ def add_entries(
)

self._defect_entries += defect_entries
self._sort_parse_and_check_entries(check_compatibility=check_compatibility)
self._sort_parse_and_check_entries()

@property
def defect_entries(self):
Expand Down Expand Up @@ -1061,6 +1152,8 @@ def chempots(self, input_chempots):
(Default: None)
"""
self._chempots, self._el_refs = _parse_chempots(input_chempots, self._el_refs)
if self.check_compatibility:
self._check_bulk_chempots_compatibility(self._chempots)

@property
def el_refs(self):
Expand Down
2 changes: 1 addition & 1 deletion doped/utils/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def format_defect_name(
Format defect name for plot titles.
(i.e. from Cd_i_C3v_0 to $Cd_{i}^{0}$ or $Cd_{i_{C3v}}^{0}$).
Note this assumes "V_" means vacancy not Vanadium.
Note this assumes "V_..." means vacancy not Vanadium.
Args:
defect_species (:obj:`str`):
Expand Down
Loading

0 comments on commit 17bfdf2

Please sign in to comment.