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
2 changes: 1 addition & 1 deletion .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
matrix:
# os: ["ubuntu-latest", "windows-latest", "macos-latest"]
os: ["ubuntu-latest", "windows-latest"]
py: ["3.9", "3.10", "3.11", "3.12", "3.13"]
py: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: "actions/checkout@v6"
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ classifiers = [
'Intended Audience :: Science/Research',
"Intended Audience :: Education",
"Natural Language :: English",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.9 is listed in the classifiers but has been removed from the CI testing matrix. Consider removing the "Programming Language :: Python :: 3.9" classifier to match the testing and dependency requirements, as the minimum scipy version 1.15.0 and numpy 1.23.5 may not fully support Python 3.9 or there may be other compatibility reasons for dropping it.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

]
dependencies = [
"numpy>=1.16",
"numpy>=1.23.5",
"pytest>=8.0.0",
"scipy>=1.4",
"scipy>=1.15.0",
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions "SciPy ≥1.17" but the dependency specifies "scipy>=1.15.0". If sph_harm_y was introduced in SciPy 1.17, the minimum version should be updated to 1.17.0 to ensure compatibility. Verify which SciPy version introduced sph_harm_y and update the minimum version accordingly.

Suggested change
"scipy>=1.15.0",
"scipy>=1.17.0",

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sph_harm_y first appear on scipy==1.15.0

"importlib_resources",
"sympy",
]
Expand Down
3 changes: 2 additions & 1 deletion src/grid/tests/test_atomgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
assert_raises,
)
from scipy.spatial.transform import Rotation as R
from scipy.integrate import trapezoid

from grid.angular import LEBEDEV_DEGREES, AngularGrid
from grid.atomgrid import AtomGrid, _get_rgrid_size
Expand Down Expand Up @@ -688,7 +689,7 @@ def func(sph_points):

# Test the integral of spherical average is the integral of Gaussian e^(-x^2)e^(-y^2)...
# from -infinity to infinity which is equal to pi^(3/2)
integral = 4.0 * np.pi * np.trapz(y=spherical_avg(oned_grid) * oned_grid**2.0, x=oned_grid)
integral = 4.0 * np.pi * trapezoid(y=spherical_avg(oned_grid) * oned_grid**2.0, x=oned_grid)
actual_integral = np.sqrt(np.pi) ** 3.0
assert_allclose(actual_integral, integral)

Expand Down
31 changes: 17 additions & 14 deletions src/grid/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"""Utility Module."""

import numpy as np
from scipy.special import sph_harm
from scipy.special import sph_harm_y

_bragg = np.array(
[
Expand Down Expand Up @@ -560,21 +560,23 @@ def generate_real_spherical_harmonics_scipy(l_max: int, theta: np.ndarray, phi:
l_list = np.arange(l_max + 1)
for l_val in l_list:
# generate m=0 real spherical harmonic
zero_real_sph = sph_harm(0, l_val, theta, phi).real
zero_real_sph = sph_harm_y(l_val, 0, phi, theta).real

# generate order m=positive real spherical harmonic
m_list_p = np.arange(1, l_val + 1, dtype=float)
# generate order m=positive real spherical harmonic: sqrt(2) * (-1)^m * Re(Y_l^m)
m_list_p = np.arange(1, l_val + 1, dtype=int)
pos_real_sph = (
sph_harm(m_list_p[:, None], l_val, theta, phi).real
* np.sqrt(2)
* (-1) ** m_list_p[:, None] # Remove Conway phase from SciPy
np.sqrt(2)
* (-1) ** m_list_p[:, None]
* sph_harm_y(l_val, m_list_p[:, None], phi, theta).real
# Remove Conway phase from SciPy
)
# generate order m=negative real spherical harmonic
m_list_n = np.arange(-1, -l_val - 1, -1, dtype=float)
# generate order m=negative real spherical harmonic: sqrt(2) * (-1)^m * Im(Y_l^m)
neg_real_sph = (
sph_harm(m_list_p[:, None], l_val, theta, phi).imag
* np.sqrt(2)
* (-1) ** m_list_n[:, None] # Remove Conway phase from SciPy
np.sqrt(2)
* (-1) ** m_list_p[:, None]
* sph_harm_y(
l_val, m_list_p[:, None], phi, theta
).imag # Remove Conway phase from SciPy
)

# Convert to horton 2 order
Expand Down Expand Up @@ -753,7 +755,8 @@ def generate_derivative_real_spherical_harmonics(l_max: int, theta: np.ndarray,
sph_harm_vals = generate_real_spherical_harmonics(l_max, theta, phi)
i_output = 0
for l_val in l_list:
for m in [0, *sum([[x, -x] for x in range(1, l_val + 1)], [])]:
m_values = [0] + [m for x in range(1, l_val + 1) for m in (x, -x)]
for m in m_values:
# Take all spherical harmonics at degree l_val
sph_harm_degree = sph_harm_vals[(l_val) ** 2 : (l_val + 1) ** 2, :]

Expand All @@ -777,7 +780,7 @@ def index_m(m):
# Compute it using SciPy, removing conway phase (-1)^m and multiply by 2^0.5.
sph_harm_m = (
fac
* sph_harm(np.abs(float(m)) + 1, l_val, theta, phi)
* sph_harm_y(l_val, np.abs(int(m)) + 1, phi, theta)
* np.sqrt(2)
* (-1.0) ** float(m)
)
Expand Down
Loading