|
26 | 26 | from pymatgen.util.string import Stringify, formula_double_format
|
27 | 27 |
|
28 | 28 | if TYPE_CHECKING:
|
29 |
| - from collections.abc import Callable |
| 29 | + from collections.abc import Callable, Sequence |
30 | 30 | from typing import Any, Literal
|
31 | 31 |
|
32 | 32 | from typing_extensions import Self
|
33 | 33 |
|
34 | 34 | from pymatgen.util.typing import SpeciesLike
|
35 | 35 |
|
36 |
| -# Load element data from JSON file |
| 36 | +# Load element data (periodic table) from JSON file |
37 | 37 | with open(Path(__file__).absolute().parent / "periodic_table.json", encoding="utf-8") as ptable_json:
|
38 |
| - _pt_data = json.load(ptable_json) |
| 38 | + _pt_data: dict = json.load(ptable_json) |
39 | 39 |
|
40 |
| -_pt_row_sizes = (2, 8, 8, 18, 18, 32, 32) |
| 40 | +_pt_row_sizes: tuple[int, ...] = (2, 8, 8, 18, 18, 32, 32) |
41 | 41 |
|
42 |
| -_madelung = [ |
| 42 | +_madelung: list[tuple[int, str]] = [ |
43 | 43 | (1, "s"),
|
44 | 44 | (2, "s"),
|
45 | 45 | (2, "p"),
|
@@ -144,8 +144,8 @@ def __init__(self, symbol: SpeciesLike) -> None:
|
144 | 144 |
|
145 | 145 | self._is_named_isotope = data.get("Is named isotope", False)
|
146 | 146 | if self._is_named_isotope:
|
147 |
| - for sym in _pt_data: |
148 |
| - if _pt_data[sym]["Atomic no"] == self.Z and not _pt_data[sym].get("Is named isotope", False): |
| 147 | + for sym, info in _pt_data.items(): |
| 148 | + if info["Atomic no"] == self.Z and not info.get("Is named isotope", False): |
149 | 149 | self.symbol = sym
|
150 | 150 | break
|
151 | 151 | # For specified/named isotopes, treat the same as named element
|
@@ -452,32 +452,47 @@ def icsd_oxidation_states(self) -> tuple[int, ...]:
|
452 | 452 |
|
453 | 453 | @property
|
454 | 454 | def full_electronic_structure(self) -> list[tuple[int, str, int]]:
|
455 |
| - """Full electronic structure as list of tuples, in order of increasing |
| 455 | + """Full electronic structure in order of increasing |
456 | 456 | energy level (according to the Madelung rule). Therefore, the final
|
457 | 457 | element in the list gives the electronic structure of the valence shell.
|
458 | 458 |
|
459 |
| - For example, the electronic structure for Fe is represented as: |
460 |
| - [(1, "s", 2), (2, "s", 2), (2, "p", 6), (3, "s", 2), (3, "p", 6), |
461 |
| - (4, "s", 2), (3, "d", 6)]. |
| 459 | + For example, the full electronic structure for Fe is: |
| 460 | + [(1, "s", 2), (2, "s", 2), (2, "p", 6), (3, "s", 2), (3, "p", 6), |
| 461 | + (4, "s", 2), (3, "d", 6)]. |
462 | 462 |
|
463 | 463 | References:
|
464 | 464 | Kramida, A., Ralchenko, Yu., Reader, J., and NIST ASD Team (2023). NIST
|
465 | 465 | Atomic Spectra Database (ver. 5.11). https://physics.nist.gov/asd [2024,
|
466 | 466 | June 3]. National Institute of Standards and Technology, Gaithersburg,
|
467 | 467 | MD. DOI: https://doi.org/10.18434/T4W30F
|
| 468 | +
|
| 469 | + Returns: |
| 470 | + list[tuple[int, str, int]]: A list of tuples representing each subshell, |
| 471 | + where each tuple contains: |
| 472 | + - `n` (int): Principal quantum number. |
| 473 | + - `orbital_type` (str): Orbital type (e.g., "s", "p", "d", "f"). |
| 474 | + - `electron_count` (int): Number of electrons in the subshell. |
468 | 475 | """
|
469 |
| - e_str = self.electronic_structure |
| 476 | + e_str: str = self.electronic_structure |
470 | 477 |
|
471 |
| - def parse_orbital(orb_str): |
| 478 | + def parse_orbital(orb_str: str) -> str | tuple[int, str, int]: |
| 479 | + """Parse orbital information from split electron configuration string.""" |
| 480 | + # Parse valence subshell notation (e.g., "3d6" -> (3, "d", 6)) |
472 | 481 | if match := re.match(r"(\d+)([spdfg]+)(\d+)", orb_str):
|
473 | 482 | return int(match[1]), match[2], int(match[3])
|
| 483 | + |
| 484 | + # Return core-electron configuration as-is (e.g. "[Ar]") |
474 | 485 | return orb_str
|
475 | 486 |
|
476 |
| - data = [parse_orbital(s) for s in e_str.split(".")] |
477 |
| - if data[0][0] == "[": |
478 |
| - sym = data[0].replace("[", "").replace("]", "") |
| 487 | + # Split e_str (e.g. for Fe "[Ar].3d6.4s2" into ["[Ar]", "3d6", "4s2"]) |
| 488 | + data: Sequence[str | tuple[int, str, int]] = [parse_orbital(s) for s in e_str.split(".")] |
| 489 | + |
| 490 | + # Fully expand core-electron configuration (replace noble gas notation string) |
| 491 | + if isinstance(data[0], str): |
| 492 | + sym: str = data[0].replace("[", "").replace("]", "") |
479 | 493 | data = list(Element(sym).full_electronic_structure) + data[1:]
|
480 |
| - # sort the final electronic structure by increasing energy level |
| 494 | + |
| 495 | + # Sort the final electronic structure by increasing energy level |
481 | 496 | return sorted(data, key=lambda x: _madelung.index((x[0], x[1])))
|
482 | 497 |
|
483 | 498 | @property
|
|
0 commit comments