Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
52c92e5
Update C-13 from Fisher (2008)
Feb 13, 2026
7824152
Default tolerance to 0.1 for neutron scattering consistency tables
Feb 13, 2026
6f8c7c4
Correct author name
Feb 13, 2026
a54aef2
fix doc formatting issues
Feb 13, 2026
7f5059c
Fix more typing errors; fix multilayer formula calculator
Feb 13, 2026
cc4ef84
Change natural abundance of free neutrons to 0%
Feb 18, 2026
ad72a50
Create an html table generator with up-to-date neutron scattering len…
Feb 18, 2026
34627f9
fix table comparisons: now using measured vs calculated for σ_coh table
Feb 18, 2026
0a747a1
use correct column for b- imaginary data
Feb 18, 2026
ad4871a
Merge branch 'update-C-13' into html-tables
Feb 18, 2026
bb0a6fc
add sticky header styles and anchor tags to each element
bmaranville Feb 18, 2026
6673bae
Point to periodictable package for data source citations for now
Feb 18, 2026
e22511c
use absorption attribute as indicator of whether there is nuclear data
Feb 18, 2026
62afaf7
More literature search
Feb 19, 2026
5570505
More literature search
Feb 19, 2026
3e434b5
Add 'not critical evaluation' disclaimer to neutron data table
Feb 19, 2026
41b7194
Merge pull request #117 from python-periodictable/html-tables
pkienzle Feb 24, 2026
105d660
Merge branch 'master' into update-C-13
pkienzle Feb 25, 2026
d448b6d
fix mypy errors
Feb 25, 2026
c232789
fix mypy errors
Feb 25, 2026
a01d1f3
fix doc build
Feb 25, 2026
b6b0339
fix py 3.10 syntax error
Feb 25, 2026
ee3f04a
fix py 3.10 syntax error
Feb 25, 2026
4d39bef
fix py 3.10 syntax error
Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ Known issues
Change history
==============

2026-02-13 R2.0.3
-----------------

Modified:

* Update b_c bp bm and incoherent attributes for C-13
* Update nuclear_spin for Se-77 Hf-177 W-182
* Add comparison tables checking b_c and σ_i against b+ and b-
* Add type hinting to many of the functions

2024-12-19 R2.0.2
-----------------

Expand Down
2 changes: 2 additions & 0 deletions doc/sphinx/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
('py:class', 'type'),
('py:class', 'object'),

('py:class', 'collections.abc.Buffer'),
('py:class', 'collections.abc.Callable'),
('py:class', 'collections.abc.Iterator'),
('py:class', 'collections.abc.Sequence'),
Expand All @@ -59,6 +60,7 @@
('py:class', 'numpy.ndarray'),
('py:class', 'numpy.float64'),
('py:class', 'numpy._typing._array_like._Buffer'),
('py:class', 'numpy._typing._array_like._ScalarType_co'),
('py:class', 'numpy._typing._array_like._SupportsArray'),
('py:class', 'numpy._typing._array_like._ScalarT'),
('py:class', 'numpy._typing._nested_sequence._NestedSequence'),
Expand Down
3 changes: 1 addition & 2 deletions periodictable/activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,8 +972,7 @@ def init(table, reload=False):
columns = row.split('\t')
if columns[0].strip() in ('', 'xx'):
continue
columns = [c[1:-1] if c.startswith('"') else c
for c in columns]
columns = [c[1:-1] if c.startswith('"') else c for c in columns]
#print columns
for c in INT_COLUMNS:
columns[c] = int(columns[c])
Expand Down
18 changes: 10 additions & 8 deletions periodictable/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
__docformat__ = 'restructuredtext en'
__all__ = ['delayed_load', 'define_elements', 'get_data_path',
'default_table', 'change_table',
'Ion', 'Isotope', 'Element', 'PeriodicTable',
'Ion', 'IonSet', 'Isotope', 'Element', 'PeriodicTable',
'isatom', 'iselement', 'isisotope', 'ision']

from pathlib import Path
Expand Down Expand Up @@ -376,16 +376,18 @@ def __repr__(self) -> str:
return repr(self.element)+'.ion[%d]'%self.charge
def __reduce__(self):
if isinstance(self.element, Isotope):
return _make_isotope_ion, (self.element.table,
self.element.number,
self.element.isotope,
self.charge)
iso = cast("Isotope", self.element)
return _make_isotope_ion, (iso.table, iso.number, iso.isotope, self.charge)
else:
return _make_ion, (self.element.table,
self.element.number,
self.charge)
el = cast("Element", self.element)
return _make_ion, (el.table, el.number, self.charge)

class IonSet:
"""
The set of ions associated with an element or isotope.

This is a dictionary interface indexed by ion charge.
"""
element_or_isotope: Element|Isotope
ionset: dict[int, Ion]

Expand Down
39 changes: 20 additions & 19 deletions periodictable/cromermann.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@

import os

import numpy
from numpy.typing import ArrayLike
import numpy as np
from numpy.typing import NDArray

from . import core

Expand All @@ -64,7 +64,7 @@ def getCMformula(symbol: str) -> "CromerMannFormula":
return _cmformulas[symbol]


def fxrayatq(symbol: str, Q: ArrayLike, charge: int|None=None) -> ArrayLike:
def fxrayatq(symbol: str, Q: float|NDArray, charge: int|None=None) -> NDArray:
"""
Return x-ray scattering factors of an element at a given Q.

Expand All @@ -77,12 +77,12 @@ def fxrayatq(symbol: str, Q: ArrayLike, charge: int|None=None) -> ArrayLike:

Return float or numpy array.
"""
stol = numpy.array(Q) / (4 * numpy.pi)
stol = np.asarray(Q) / (4 * np.pi)
rv = fxrayatstol(symbol, stol, charge)
return rv


def fxrayatstol(symbol: str, stol: ArrayLike, charge: int|None=None) -> ArrayLike:
def fxrayatstol(symbol: str, stol: float|NDArray, charge: int|None=None) -> NDArray:
"""
Calculate x-ray scattering factors at specified sin(theta)/lambda

Expand All @@ -93,7 +93,7 @@ def fxrayatstol(symbol: str, stol: ArrayLike, charge: int|None=None) -> ArrayLik
*charge* : int
ion charge, overrides any valence suffixes such as "-", "+", "3+".

Return float or numpy.array.
Return NDArray.
"""
# resolve lookup symbol smbl, by default symbol
smbl = symbol
Expand Down Expand Up @@ -137,8 +137,8 @@ class CromerMannFormula:
# D. Waasmaier, A. Kirfel, Acta Cryst. (1995). A51, 416-413
# http://dx.doi.org/10.1107/S0108767394013292
stollimit: float = 6
a: numpy.ndarray
b: numpy.ndarray
a: NDArray
b: NDArray
c: float
symbol: str

Expand All @@ -149,30 +149,30 @@ def __init__(self, symbol, a, b, c):
No return value
"""
self.symbol = symbol
self.a = numpy.asarray(a, dtype=float)
self.b = numpy.asarray(b, dtype=float)
self.a = np.asarray(a, dtype=float)
self.b = np.asarray(b, dtype=float)
self.c = float(c)

def atstol(self, stol: ArrayLike) -> ArrayLike:
def atstol(self, stol: float|NDArray) -> NDArray:
"""
Calculate x-ray scattering factors at specified sin(theta)/lambda

*stol* : float or [float] | |1/Ang|
sin(theta)/lambda

Return float or numpy.array.
Return NDArray.
"""
stolflat = numpy.array(stol).flatten()
stolflat = np.asarray(stol).flatten()
n = len(stolflat)
stol2row = numpy.reshape(stolflat ** 2, (1, n))
stol2row = np.reshape(stolflat ** 2, (1, n))
bcol = self.b.reshape((len(self.a), 1))
bstol2 = numpy.dot(bcol, stol2row)
adiag = numpy.diag(self.a)
rvrows = numpy.dot(adiag, numpy.exp(-bstol2))
bstol2 = np.dot(bcol, stol2row)
adiag = np.diag(self.a)
rvrows = np.dot(adiag, np.exp(-bstol2))
rvflat = rvrows.sum(axis=0) + self.c
rvflat[stolflat > self.stollimit] = numpy.nan
rvflat[stolflat > self.stollimit] = np.nan
# when stol is scalar, addition of zero converts the rv array to float
rv = rvflat.reshape(numpy.shape(stol)) + 0.0
rv = rvflat.reshape(np.shape(stol)) + 0.0
return rv

# class CromerMannFormula
Expand All @@ -190,6 +190,7 @@ def _update_cmformulas() -> None:
# #N 11
# #L a1 a2 a3 a4 a5 c b1 b2 b3 b4 b5
# <a1 a2 a3 a4 a5> <c> <b1 b2 b3 b4 b5>
symbol = None
with open(path) as fp:
for line in fp:
if line.startswith("#S"):
Expand Down
8 changes: 6 additions & 2 deletions periodictable/formulas.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def mix_by_weight(*args, **kw) -> "Formula":
return result

def _mix_by_weight_pairs(pairs: list[tuple["Formula", float]]) -> "Formula":
from .formulas import Formula # For running as __main__

# Drop pairs with zero quantity
# Note: must be first statement in order to accept iterators
Expand Down Expand Up @@ -175,6 +176,7 @@ def mix_by_volume(*args, **kw) -> "Formula":
return result

def _mix_by_volume_pairs(pairs: list[tuple["Formula", float]]) -> "Formula":
from .formulas import Formula # For running as __main__

# Drop pairs with zero quantity
# Note: must be first statement in order to accept iterators
Expand Down Expand Up @@ -285,6 +287,8 @@ def formula(
The representations are simple, but preserve some of the structure for
display purposes.
"""
from .formulas import Formula # For running as __main__

structure: Structure
if compound is None or compound == '':
structure = tuple()
Expand Down Expand Up @@ -708,7 +712,7 @@ def _isotope_substitution(compound: "Formula", source: Atom, target: Atom, porti

# TODO: Grammar should be independent of table
# TODO: Parser can't handle meters as 'm' because it conflicts with the milli prefix
LENGTH_UNITS = {'nm': 1e-9, 'um': 1e-6, 'mm': 1e-3, 'cm': 1e-2}
LENGTH_UNITS = {'nm': 1e-9, 'um': 1e-6, 'μm': 1e-6, 'mm': 1e-3, 'cm': 1e-2}
MASS_UNITS = {'ng': 1e-9, 'ug': 1e-6, 'mg': 1e-3, 'g': 1e+0, 'kg': 1e+3}
VOLUME_UNITS = {'nL': 1e-9, 'uL': 1e-6, 'mL': 1e-3, 'L': 1e+0}
LENGTH_RE = '('+'|'.join(LENGTH_UNITS.keys())+')'
Expand Down Expand Up @@ -913,7 +917,7 @@ def convert_by_layer(string, location, tokens):
fract = []
for p1, p2 in zip(tokens[0::2], tokens[1::2]):
if isinstance(p1, Formula):
f = p1.absthick * float(p2)
f = p1.thickness * float(p2)
p = p1
else:
f = float(p1[0]) * LENGTH_UNITS[p1[1]]
Expand Down
22 changes: 11 additions & 11 deletions periodictable/magnetic_ff.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@
"""
from __future__ import division

import numpy
import numpy as np
from numpy import pi, exp
from numpy.typing import ArrayLike
from numpy.typing import NDArray

from .core import PeriodicTable

JnCoeff = tuple[float, float, float, float, float, float, float]

def formfactor_0(j0: JnCoeff, q: ArrayLike) -> numpy.ndarray:
def formfactor_0(j0: JnCoeff, q: float|NDArray) -> NDArray:
"""
Returns the scattering potential for form factor *j0* at the given *q*.
"""
q = numpy.asarray(q)
q = np.asarray(q)
s_sq = (q/(4*pi))**2
A, a, B, b, C, c, D = j0
return A * exp(-a*s_sq) + B * exp(-b*s_sq) + C * exp(-c*s_sq) + D

def formfactor_n(jn: JnCoeff, q: ArrayLike):
def formfactor_n(jn: JnCoeff, q: float|NDArray) -> NDArray:
"""
Returns the scattering potential for form factor *jn* at the given *q*.
"""
q = numpy.asarray(q)
q = np.asarray(q)
s_sq = (q/(4*pi))**2
A, a, B, b, C, c, D = jn
return s_sq * (A * exp(-a*s_sq) + B * exp(-b*s_sq) + C * exp(-c*s_sq) + D)
Expand Down Expand Up @@ -85,23 +85,23 @@ def M(self) -> JnCoeff:
"""j0"""
return self.j0

def j0_Q(self, Q: ArrayLike) -> ArrayLike:
def j0_Q(self, Q: float|NDArray) -> NDArray:
"""Returns *j0* scattering potential at *Q* |1/Ang|"""
return formfactor_0(self.j0, Q)

def j2_Q(self, Q: ArrayLike) -> ArrayLike:
def j2_Q(self, Q: float|NDArray) -> NDArray:
"""Returns *j2* scattering potential at *Q* |1/Ang|"""
return formfactor_n(self.j2, Q)

def j4_Q(self, Q: ArrayLike) -> ArrayLike:
def j4_Q(self, Q: float|NDArray) -> NDArray:
"""Returns *j4* scattering potential at *Q* |1/Ang|"""
return formfactor_n(self.j4, Q)

def j6_Q(self, Q: ArrayLike) -> ArrayLike:
def j6_Q(self, Q: float|NDArray) -> NDArray:
"""Returns j6 scattering potential at *Q* |1/Ang|"""
return formfactor_n(self.j6, Q)

def J_Q(self, Q: ArrayLike) -> ArrayLike:
def J_Q(self, Q: float|NDArray) -> NDArray:
"""Returns J scattering potential at *Q* |1/Ang|"""
return formfactor_0(self.J, Q)

Expand Down
2 changes: 1 addition & 1 deletion periodictable/mass.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def init(table: PeriodicTable, reload: bool=False) -> None:
el._mass, el._mass_unc = neutron_mass, neutron_mass_unc
iso = el.add_isotope(1)
iso._mass, iso._mass_unc = neutron_mass, neutron_mass_unc
iso._abundance, iso._abundance_unc = 100, 0
iso._abundance, iso._abundance_unc = 0, 0

# Parse element mass table where each line looks like:
# z El element mass(unc)|[low,high]|- note note ...
Expand Down
Loading