Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 4 additions & 20 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,18 @@ jobs:

steps:
- uses: "actions/checkout@v4"
# Whether to download Git-LFS files
with:
lfs: true

- name: Setup python for test ${{ matrix.py }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.py }}

- name: Install system dependencies for PyTables (Linux/macOS)
run: |
python -m pip install --upgrade pip wheel
pip install numpy==1.26.4
if [[ "$RUNNER_OS" == "Linux" ]]; then
sudo apt-get update
sudo apt-get install -y libhdf5-dev libblosc-dev
elif [[ "$RUNNER_OS" == "macOS" ]]; then
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew update
brew install hdf5 c-blosc
export CPATH="$(brew --prefix hdf5)/include:$(brew --prefix c-blosc)/include:$CPATH"
export LIBRARY_PATH="$(brew --prefix hdf5)/lib:$(brew --prefix c-blosc)/lib:$LIBRARY_PATH"
export HDF5_DIR="$(brew --prefix hdf5)"
fi


- name: Install development version
run: |
pip install -v .
pip install -e .

- name: Install extra test dependencies
run: |
Expand Down Expand Up @@ -77,5 +63,3 @@ jobs:
click-to-expand: true
report-title: 'Dev Test Report'
pytest-args: '-m dev'


2 changes: 1 addition & 1 deletion atomdb/data/elements_data.h5
Git LFS file not shown
3 changes: 2 additions & 1 deletion atomdb/migration/periodic/elements_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import warnings
from atomdb.utils import CONVERTOR_TYPES


# Suppresses NaturalNameWarning warnings from PyTables.
warnings.filterwarnings('ignore', category=pt.NaturalNameWarning)

Expand All @@ -25,7 +26,7 @@

{
'basic_property': 'symbol',
'table_name': 'symbol',
'table_name': 'elem',
'description': 'Atom Symbol',
'type': 'string',
},
Expand Down
121 changes: 78 additions & 43 deletions atomdb/species.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,19 @@
from numbers import Integral

elements_hdf5_file = files("atomdb.data").joinpath("elements_data.h5")

PROPERTY_NAME_MAP = {
"atmass": "atmass",
"cov_radius": "cov_radius",
"vdw_radius": "vdw_radius",
"at_radius": "at_radius",
"polarizability": "polarizability",
"dispersion_c6": "dispersion_c6",
"elem": "symbol",
"atnum": "atnum",
"name": "name",
}
ELEMENTS_H5FILE = pt.open_file(elements_hdf5_file, mode="r")

PROPERTY_NAME_MAP = [
"atmass",
"cov_radius",
"vdw_radius",
"at_radius",
"polarizability",
"dispersion_c6",
"elem",
"atnum",
"name"
]

__all__ = [
"Species",
Expand Down Expand Up @@ -116,6 +117,42 @@ def default_matrix():
# return wrapper


# def scalar(method):
# r"""Expose a SpeciesData field."""
# name = method.__name__
#
# @property
# def wrapper(self):
# print("hi")
#
# # Map the name of the method in the SpeciesData class to the name in the Elements class
# # This dict can be removed if the Elements csv file uses the same names as the SpeciesData class.
# namemap = {
# "cov_radius": "cov_radius",
# "vdw_radius": "vdw_radius",
# "at_radius": "at_radius",
# "polarizability": "pold",
# "dispersion_c6": "c6",
# "atmass": "mass",
# }
#
# if name == "atmass":
# print(f"inside atmass {getattr(Element(self._data.elem), namemap[name])}")
# return getattr(Element(self._data.elem), namemap[name])
# if name in namemap:
# # Only return Element property if neutral, otherwise None
# charge = self._data.atnum - self._data.nelec
# print(f"charge {charge}")
# print(f"inside the other {getattr(Element(self._data.elem), namemap[name])}")
# return getattr(Element(self._data.elem), namemap[name]) if charge == 0 else None
#
# return getattr(self._data, name)
#
# # conserve the docstring of the method
# wrapper.__doc__ = method.__doc__
# return wrapper


def scalar(method):
r"""Expose a SpeciesData field."""
name = method.__name__
Expand All @@ -128,39 +165,37 @@ def wrapper(self):

# calculate charge then if charge is not zero (ions) --> return none
charge = self._data.atnum - self._data.nelec
if charge != 0:
if charge != 0 and name not in ["atmass", "elem", "atnum", "name"]:
return None

# open the HDF5 file in read mode
with pt.open_file(elements_hdf5_file, mode="r") as h5file:
# get the element group
element_group = f"/Elements/{self._data.atnum:03d}"

table_name = PROPERTY_NAME_MAP[name]
table_path = f"{element_group}/{table_name}"

# get the table node from the HDF5 file
table = h5file.get_node(table_path)

# Handle basic properties (single row)
if table.nrows == 1:
value = table[0]["value"]
# if the value is an int, return it as an int
if isinstance(value, Integral):
return int(value)
# if the value is a string, decode from bytes
elif isinstance(value, bytes):
return value.decode("utf-8")
else:
# handle properties with multiple sources
result = {}
for row in table:
source = row["source"].decode("utf-8")
value = row["value"]
# exclude none values
if not np.isnan(value):
result[source] = float(value)
return result if result else None
# get the element group
element_group = f"/Elements/{self._data.atnum:03d}"

table_name = name #PROPERTY_NAME_MAP[name]
table_path = f"{element_group}/{table_name}"

# get the table node from the HDF5 file
table = ELEMENTS_H5FILE.get_node(table_path)

# Handle basic properties (single column --> no sources)
if len(table.colnames) == 1 and table.colnames[0] == "value":
value = table[0]["value"]
# if the value is an int, return it as an int
if isinstance(value, Integral):
return int(value)
# if the value is a string, decode from bytes
elif isinstance(value, bytes):
return value.decode("utf-8")
else:
# handle properties with multiple sources
result = {}
for row in table:
source = row["source"].decode("utf-8")
value = row["value"]
# exclude none values
if not np.isnan(value):
result[source] = float(value)
return result if result else None

wrapper.__doc__ = method.__doc__
return wrapper
Expand Down
4 changes: 4 additions & 0 deletions atomdb/test/test_nist.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
TEST_DATAPATH = files("atomdb.test.data")
TEST_DATAPATH = os.fspath(TEST_DATAPATH._paths[0])

ELEMENTS_HDF5_FILE = files("atomdb.data").joinpath("elements_data.h5")

TEST_CASES_MAKE_PROMOLECULE = [
pytest.param(
Expand Down Expand Up @@ -151,6 +152,9 @@ def test_nist_data(case):
"""
Test getting the attributes of the atom for Hydrogen and Carbon.
"""
if not ELEMENTS_HDF5_FILE.exists():
pytest.skip(f"Required data file not found: {ELEMENTS_HDF5_FILE}")

elem = case.get("elem")
charge = case.get("atnum") - case.get("nelec")
mult = case.get("nspin") + 1
Expand Down
Loading