|
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