Skip to content

Commit

Permalink
Merge pull request #8 from benrich37/period_table_edits
Browse files Browse the repository at this point in the history
Periodic table edits
  • Loading branch information
benrich37 authored Oct 22, 2024
2 parents 26a69d1 + 359261d commit f06b447
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 32 deletions.
95 changes: 66 additions & 29 deletions src/pymatgen/core/periodic_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

from pymatgen.util.typing import SpeciesLike


# Load element data from JSON file
with open(Path(__file__).absolute().parent / "periodic_table.json", encoding="utf-8") as ptable_json:
_pt_data = json.load(ptable_json)
Expand Down Expand Up @@ -204,7 +205,8 @@ def __getattr__(self, item: str) -> Any:
if val is None or str(val).startswith("no data"):
warnings.warn(f"No data available for {item} for {self.symbol}")
val = None
elif isinstance(val, list | dict):
# elif isinstance(val, dict | list):
elif type(val) in [list, dict]: # pre-commit fix
pass
else:
try:
Expand Down Expand Up @@ -475,28 +477,35 @@ def n_electrons(self) -> int:
return sum(t[-1] for t in self.full_electronic_structure)

@property
def valence(self) -> tuple[int | np.nan, int]:
def valences(self) -> list[tuple[int | np.nan, int]]:
"""Valence subshell angular moment (L) and number of valence e- (v_e),
obtained from full electron config, where L=0, 1, 2, or 3 for s, p, d,
and f orbitals, respectively.
"""
if self.group == 18:
return np.nan, 0 # The number of valence of noble gas is 0
return [(np.nan, 0)] # The number of valence of noble gas is 0

L_symbols = "SPDFGHIKLMNOQRTUVWXYZ"
valence: list[tuple[int, int]] = []
valences: list[tuple[int | np.nan, int]] = []
full_electron_config = self.full_electronic_structure
last_orbital = full_electron_config[-1]
for n, l_symbol, ne in full_electron_config:
idx = L_symbols.lower().index(l_symbol)
if ne < (2 * idx + 1) * 2 or (
(n, l_symbol, ne) == last_orbital and ne == (2 * idx + 1) * 2 and len(valence) == 0
(n, l_symbol, ne) == last_orbital and ne == (2 * idx + 1) * 2 and len(valences) == 0
): # check for full last shell (e.g. column 2)
valence.append((idx, ne))
if len(valence) > 1:
raise ValueError(f"{self} has ambiguous valence")
valences.append((idx, ne))
return valences

return valence[0]
@property
def valence(self) -> tuple[int | np.nan, int]:
"""Valence subshell angular moment (L) and number of valence e- (v_e),
obtained from full electron config, where L=0, 1, 2, or 3 for s, p, d,
and f orbitals, respectively.
"""
if len(self.valences) > 1:
raise ValueError(f"{self} has ambiguous valence")
return self.valences[0]

@property
def term_symbols(self) -> list[list[str]]:
Expand All @@ -523,7 +532,8 @@ def term_symbols(self) -> list[list[str]]:
# Total ML = sum(ml1, ml2), Total MS = sum(ms1, ms2)
TL = [sum(ml_ms[comb[e]][0] for e in range(v_e)) for comb in e_config_combs]
TS = [sum(ml_ms[comb[e]][1] for e in range(v_e)) for comb in e_config_combs]
comb_counter = Counter(zip(TL, TS, strict=True))
# comb_counter: Counter = Counter(zip(TL, TS, strict=True))
comb_counter: Counter = Counter([(TL[i], TS[i]) for i in range(len(TL))]) # pre-commit edit

term_symbols = []
L_symbols = "SPDFGHIKLMNOQRTUVWXYZ"
Expand Down Expand Up @@ -1180,29 +1190,40 @@ def n_electrons(self) -> int:

# NOTE - copied exactly from Element. Refactoring / inheritance may improve
# robustness
@property
def valences(self) -> list[tuple[int | np.nan, int]]:
"""List of valence subshell angular moment (L) and number of valence e- (v_e),
obtained from full electron config, where L=0, 1, 2, or 3 for s, p, d,
and f orbitals, respectively.
"""
return self.element.valences
# if self.group == 18:
# return [(np.nan, 0)] # The number of valence of noble gas is 0

# L_symbols = "SPDFGHIKLMNOQRTUVWXYZ"
# valences: list[tuple[int, int]] = []
# full_electron_config = self.full_electronic_structure
# last_orbital = full_electron_config[-1]
# for n, l_symbol, ne in full_electron_config:
# idx = L_symbols.lower().index(l_symbol)
# if ne < (2 * idx + 1) * 2 or (
# (n, l_symbol, ne) == last_orbital and ne == (2 * idx + 1) * 2 and len(valences) == 0
# ): # check for full last shell (e.g. column 2)
# valences.append((idx, ne))
# return valences

@property
def valence(self) -> tuple[int | np.nan, int]:
"""Valence subshell angular moment (L) and number of valence e- (v_e),
obtained from full electron config, where L=0, 1, 2, or 3 for s, p, d,
and f orbitals, respectively.
"""
if self.group == 18:
return np.nan, 0 # The number of valence of noble gas is 0

L_symbols = "SPDFGHIKLMNOQRTUVWXYZ"
valence: list[tuple[int, int]] = []
full_electron_config = self.full_electronic_structure
last_orbital = full_electron_config[-1]
for n, l_symbol, ne in full_electron_config:
idx = L_symbols.lower().index(l_symbol)
if ne < (2 * idx + 1) * 2 or (
(n, l_symbol, ne) == last_orbital and ne == (2 * idx + 1) * 2 and len(valence) == 0
): # check for full last shell (e.g. column 2)
valence.append((idx, ne))
if len(valence) > 1:
raise ValueError(f"{self} has ambiguous valence")

return valence[0]
return self.element.valence
# if len(self.valences) > 1:
# raise ValueError(f"{self} has ambiguous valence")
# return self.valences[0]

@property
def ionic_radius(self) -> float | None:
Expand Down Expand Up @@ -1631,10 +1652,26 @@ def get_el_sp(obj: int | SpeciesLike) -> Element | Species | DummySpecies:
of properties that can be determined.
"""
# If obj is already an Element or Species, return as is
if isinstance(obj, Element | Species | DummySpecies):
# Note: the below three if statements are functionally equivalent to the commented out
# code. They only exist due to a bug in mypy that doesn't allow the commented out code.
# This should be fixed once mypy fixes this bug.
if isinstance(obj, Element):
if getattr(obj, "_is_named_isotope", None):
return Element(obj.name)
return obj
if isinstance(obj, Species):
if getattr(obj, "_is_named_isotope", None):
return Species(str(obj))
return obj
if isinstance(obj, Species):
if getattr(obj, "_is_named_isotope", None):
return Element(obj.name) if isinstance(obj, Element) else Species(str(obj))
return Species(str(obj))
return obj
# if isinstance(obj, Element | Species | DummySpecies):
# if type(obj) in [Element, Species, DummySpecies]:
# if getattr(obj, "_is_named_isotope", None):
# return Element(obj.name) if isinstance(obj, Element) else Species(str(obj))
# return obj

# If obj is an integer, return the Element with atomic number obj
try:
Expand Down
6 changes: 3 additions & 3 deletions src/pymatgen/io/jdftx/jdftxoutfileslice.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from pymatgen.core.periodic_table import Element
from pymatgen.core.trajectory import Trajectory
from pymatgen.core.units import Ha_to_eV, ang_to_bohr
from pymatgen.io.jdftx.data import get_atom_valence_electrons
from pymatgen.io.jdftx.jminsettings import (
JMinSettings,
JMinSettingsElectronic,
Expand Down Expand Up @@ -860,8 +859,9 @@ def set_pseudo_vars_t1(self, text: list[str]) -> None:
# total_elec_dict = dict(zip(self.atom_types, atom_total_elec, strict=False))
# Explicit zipping due to pre-commit in three lines below
element_total_electrons = np.array([total_elec_dict[x] for x in self.atom_elements])
element_valence_electrons = np.array([get_atom_valence_electrons(x) for x in self.atom_elements])
# element_valence_electrons = np.array([Element(x).valence[1] for x in self.atom_elements])
pmg_elements = [Element(x) for x in self.atom_elements]
# element_valence_electrons = np.array([get_atom_valence_electrons(x) for x in self.atom_elements])
element_valence_electrons = np.array([np.sum(np.array([v[1] for v in el.valences])) for el in pmg_elements])
# element_valence_electrons = np.array([atom_valence_electrons[x] for x in self.atom_elements])
element_semicore_electrons = element_total_electrons - element_valence_electrons
self.total_electrons_uncharged = np.sum(element_total_electrons)
Expand Down

0 comments on commit f06b447

Please sign in to comment.