Skip to content

Commit 2094f52

Browse files
authored
matscipy: Add version 1.2.0 (#2538)
1 parent 8554766 commit 2094f52

5 files changed

Lines changed: 291 additions & 0 deletions
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# SPDX-FileCopyrightText: 2026 The RISE Project
2+
# SPDX-License-Identifier: MIT
3+
---
4+
# This workflow is based on the `build` job of
5+
# https://github.com/libAtoms/matscipy/blob/v1.2.0/.github/workflows/wheels.yml
6+
# and the `pytest` step of
7+
# https://github.com/libAtoms/matscipy/blob/v1.2.0/.github/workflows/tests.yml
8+
name: Build matscipy wheels (riscv64)
9+
10+
on:
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: 'Version glob to (re)build; empty builds every version of docs/packages/matscipy.yaml not released yet'
15+
required: false
16+
default: ''
17+
pull_request:
18+
branches: [main]
19+
paths:
20+
- '.github/workflows/build-matscipy.yml'
21+
- 'docs/packages/matscipy.yaml'
22+
- 'patches/matscipy/**'
23+
push:
24+
branches: [main]
25+
paths:
26+
- '.github/workflows/build-matscipy.yml'
27+
- 'docs/packages/matscipy.yaml'
28+
- 'patches/matscipy/**'
29+
30+
concurrency:
31+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
32+
cancel-in-progress: true
33+
34+
permissions:
35+
contents: read # to fetch code (actions/checkout)
36+
37+
jobs:
38+
setup:
39+
uses: $/.github/workflows/_setup.yml
40+
with:
41+
package: matscipy
42+
version: ${{ inputs.version }}
43+
44+
build_wheels:
45+
needs: [setup]
46+
if: needs.setup.outputs.versions != '[]'
47+
name: Build matscipy ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
48+
runs-on: ubuntu-24.04-riscv
49+
timeout-minutes: 180
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
version: ${{ fromJSON(needs.setup.outputs.versions) }}
54+
python: ["cp312", "cp313", "cp314"]
55+
56+
env:
57+
MATSCIPY_VERSION: ${{ matrix.version }}
58+
59+
steps:
60+
- name: Checkout matscipy v${{ env.MATSCIPY_VERSION }}
61+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
62+
with:
63+
repository: libAtoms/matscipy
64+
ref: v${{ env.MATSCIPY_VERSION }}
65+
fetch-depth: 0
66+
persist-credentials: false
67+
68+
- name: Checkout python-wheels
69+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
70+
with:
71+
path: python-wheels
72+
persist-credentials: false
73+
74+
- name: Patch matscipy source
75+
run: |
76+
git apply python-wheels/patches/matscipy/${{ env.MATSCIPY_VERSION }}/*.patch
77+
# meson-python reads the wheel version from `git describe` on this tree; a
78+
# dirty tree gives "1.2.0.dirty", which packaging.version.Version rejects
79+
# outright (InvalidVersion), failing the build before compilation even
80+
# starts. Hide just the patched files from dirty-detection instead.
81+
git diff --name-only | xargs git update-index --skip-worktree
82+
83+
- name: Build wheels
84+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
85+
with:
86+
only: ${{ matrix.python }}-manylinux_riscv64
87+
env:
88+
CIBW_BUILD_FRONTEND: build
89+
CIBW_BEFORE_BUILD: pip install meson meson-python ninja
90+
CIBW_ENVIRONMENT: >-
91+
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
92+
PIP_ONLY_BINARY=numpy,scipy,matplotlib,contourpy,kiwisolver,pillow
93+
# Upstream's wheel job only imports the extension; run its tests.yml suite instead.
94+
# ase.constraints.UnitCellFilter (and friends), which this v1.2.0 tag's tests/
95+
# still imports, was a @deprecated re-export from ase.filters through 3.26.0;
96+
# 3.27.0 drops the re-export entirely (checked gitlab.com/ase/ase directly,
97+
# tag by tag). matscipy's pyproject.toml floor (ase>=3.26.0) doesn't cap the
98+
# other end, so an unconstrained resolve picks today's ase and breaks 29
99+
# tests / errors on 12 modules. ase<3.27 is its own space-separated token
100+
# here (no quote characters anywhere in this YAML scalar), resolved together
101+
# with matscipy's own floor by the same `pip install` that installs the wheel.
102+
CIBW_TEST_REQUIRES: pytest pytest-subtests pytest-timeout pytest-xdist sympy ase<3.27
103+
# Upstream's --timeout=600 is sized for x86; test_bop/test_dislocation cases take 350-600s here.
104+
CIBW_TEST_COMMAND: cd {project}/tests && pytest -v --durations=20 --timeout=1800 -n auto
105+
106+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
107+
with:
108+
name: matscipy-${{ env.MATSCIPY_VERSION }}-${{ matrix.python }}-manylinux_riscv64
109+
path: ./wheelhouse/*.whl
110+
if-no-files-found: error
111+
112+
publish:
113+
name: Publish matscipy ${{ matrix.version }}
114+
needs: [setup, build_wheels]
115+
if: needs.setup.outputs.versions != '[]'
116+
strategy:
117+
fail-fast: false
118+
matrix:
119+
version: ${{ fromJSON(needs.setup.outputs.versions) }}
120+
permissions:
121+
contents: write
122+
pull-requests: write
123+
uses: $/.github/workflows/_publish-wheel.yml
124+
secrets:
125+
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
126+
with:
127+
artifact-pattern: matscipy-${{ matrix.version }}-*-manylinux_riscv64

‎docs/packages/matscipy.yaml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package-name: matscipy
2+
source-code: https://github.com/libAtoms/matscipy
3+
license: LGPL-2.1-only
4+
versions:
5+
- version: 1.2.0
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 01 Oct 2026 00:00:00 +0000
4+
Subject: [PATCH] eam/io: index 1-element arrays before int()/float()
5+
6+
write_eam's "eam" (DYNAMO funcfl) branch calls int(atomic_numbers) and
7+
float(atomic_masses)/float(lattice_parameters) directly on the
8+
EAMParameters fields, which read_eam builds as 1-element numpy arrays
9+
(np.array((int(words[0]),), dtype=int), etc.), not scalars - the
10+
function's own "# FIXME: atomic numbers etc are now arrays, and not
11+
scalars" comment already says as much. NumPy 2.x turned the implicit
12+
conversion of a non-0-d array into a hard TypeError: "only
13+
0-dimensional arrays can be converted to Python scalars", so
14+
test_eam_io.py::test_eam_read_write's round-trip through this branch
15+
fails outright. Indexing [0] before the int()/float() calls is what
16+
the FIXME already describes as the fix; upstream made the same change
17+
in 255201ab (released in 1.3.0).
18+
19+
Upstream-Status: Backport [https://github.com/libAtoms/matscipy/commit/255201aba4d827bb97dead8964c80e7276161603]
20+
21+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
22+
---
23+
--- a/matscipy/calculators/eam/io.py
24+
+++ b/matscipy/calculators/eam/io.py
25+
@@ -548,7 +548,7 @@
26+
# parameters unpacked
27+
# FIXME: atomic numbers etc are now arrays, and not scalars
28+
crystal_structures_str = ' '.join(s for s in crystal_structures)
29+
- atline = f"{int(atomic_numbers)} {float(atomic_masses)} {float(lattice_parameters)} {crystal_structures_str}"
30+
+ atline = f"{int(atomic_numbers[0])} {float(atomic_masses[0])} {float(lattice_parameters[0])} {crystal_structures_str}"
31+
parameterline = f'{int(Nrho)}\t{float(drho):.16e}\t{int(Nr)}\t{float(dr):.16e}\t{float(cutoff):.10e}'
32+
potheader = f"# EAM potential from : # {source} \n {atline} \n {parameterline}"
33+
# --- Writing new EAM alloy pot file --- #
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 01 Oct 2026 00:00:00 +0000
4+
Subject: [PATCH] cauchy_born: drop the removed sqrtm(disp=) keyword
5+
6+
SciPy 1.18 removed the deprecated disp= keyword of scipy.linalg.sqrtm,
7+
so CubicCauchyBorn's two sqrtm(Usqr, disp=True) calls raise
8+
"TypeError: sqrtm() got an unexpected keyword argument 'disp'" and all
9+
nine test_cauchy_born_corrector.py::TestPredictCauchyBornShifts tests
10+
fail. disp=True was the default, so sqrtm(Usqr) is unchanged on older
11+
SciPy. Upstream made the same change in 75f077ff (released in 1.3.0).
12+
13+
Upstream-Status: Backport [https://github.com/libAtoms/matscipy/commit/75f077ff7de629fc65814b760d6ebd225b630d64]
14+
15+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
16+
---
17+
diff --git a/matscipy/cauchy_born.py b/matscipy/cauchy_born.py
18+
index c84a2534..ad973424 100644
19+
--- a/matscipy/cauchy_born.py
20+
+++ b/matscipy/cauchy_born.py
21+
@@ -268,7 +268,7 @@ class CubicCauchyBorn:
22+
# get U^2
23+
Usqr = 2 * E + np.eye(3)
24+
# square root matrix to get U
25+
- U = sqrtm(Usqr, disp=True)
26+
+ U = sqrtm(Usqr)
27+
28+
# this is just the symmetric stretch tensor, exactly what we need.
29+
x = U
30+
@@ -1330,7 +1330,7 @@ class CubicCauchyBorn:
31+
# get U^2
32+
Usqr = 2 * E + np.eye(3)
33+
# square root matrix
34+
- U = sqrtm(Usqr, disp=True)
35+
+ U = sqrtm(Usqr)
36+
37+
# this is just the symmetric stretch tensor, exactly what we need.
38+
x = U
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 01 Oct 2026 00:00:00 +0000
4+
Subject: [PATCH] molecules, io/lammpsdata: replace ndarray.resize for Python 3.14
5+
6+
From NumPy 2.4 on, ndarray.resize(refcheck=True) on Python >= 3.14 uses
7+
PyUnstable_Object_IsUniquelyReferenced, which an attribute-held array
8+
never satisfies, so Molecules.__init__ and LAMMPSData's setter/reader
9+
raise "ValueError: cannot resize an array that may be referenced by
10+
another object" on cp314 only (test_newmb.py, test_neighbours.py,
11+
test_io.py collection errors, test_manybody_molecules.py setup errors).
12+
Upstream replaced every such resize with a fresh np.empty of the same
13+
dtype in libAtoms/matscipy#312 (commits 1b006eb4 and 3a1ec1dc, released
14+
in 1.3.0); this is those two hunks unchanged.
15+
16+
Upstream-Status: Backport [https://github.com/libAtoms/matscipy/pull/312]
17+
18+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
19+
---
20+
diff --git a/matscipy/io/lammpsdata.py b/matscipy/io/lammpsdata.py
21+
index 4525a786..e7200f0a 100644
22+
--- a/matscipy/io/lammpsdata.py
23+
+++ b/matscipy/io/lammpsdata.py
24+
@@ -193,10 +193,15 @@ class LAMMPSData:
25+
"""Set data component."""
26+
if name in self._type_names:
27+
name = self._type_names[name]
28+
- self.__data[name].resize(len(value))
29+
+ old = self.__data[name]
30+
+ new_arr = np.empty(len(value), dtype=self._dtypes[name])
31+
+ n = min(len(old), len(value))
32+
+ if n > 0:
33+
+ new_arr[:n] = old[:n]
34+
+ self.__data[name] = new_arr
35+
self.__data[name]['type'] = value
36+
elif name in self._data_names:
37+
- self.__data[name].resize(len(value))
38+
+ self.__data[name] = np.empty(len(value), dtype=self._dtypes[name])
39+
data = self.__data[name]
40+
try:
41+
data[data.dtype.names[-1]] = np.array(value)
42+
@@ -309,16 +314,15 @@ class LAMMPSData:
43+
for linum, line in enumerate(fd):
44+
if 'Masses' in line:
45+
ntypes = type_counts['atom types']
46+
- self['masses'].resize(ntypes)
47+
- self['masses'][:] = \
48+
+ self.__data['masses'] = \
49+
np.genfromtxt(fd, skip_header=1,
50+
- max_rows=ntypes, usecols=(1,))
51+
+ max_rows=ntypes, usecols=(1,), dtype=self._dtypes['masses'])
52+
53+
else:
54+
for label in self._data_names:
55+
if self.__headers[label] in line:
56+
nlines = data_counts[label]
57+
- self[label].resize(nlines)
58+
+ self.__data[label] = np.empty(nlines, dtype=self._dtypes[label])
59+
dtype = self[label].dtype
60+
61+
raw_dtype = np.dtype([('num', np.int32)] + [
62+
diff --git a/matscipy/molecules.py b/matscipy/molecules.py
63+
index 4657da62..d9a88996 100644
64+
--- a/matscipy/molecules.py
65+
+++ b/matscipy/molecules.py
66+
@@ -72,19 +72,19 @@ class Molecules:
67+
self.__dict__[data] = np.array([], dtype=dtype)
68+
69+
if bonds_connectivity is not None:
70+
- self.bonds.resize(len(bonds_connectivity))
71+
+ self.bonds = np.empty(len(bonds_connectivity), dtype=self._dtypes["bonds"])
72+
self.bonds["atoms"][:] = bonds_connectivity
73+
self.bonds["type"][:] = bonds_types \
74+
if bonds_types is not None else default_type
75+
76+
if angles_connectivity is not None:
77+
- self.angles.resize(len(angles_connectivity))
78+
+ self.angles = np.empty(len(angles_connectivity), dtype=self._dtypes["angles"])
79+
self.angles["atoms"][:] = angles_connectivity
80+
self.angles["type"][:] = angles_types \
81+
if angles_types is not None else default_type
82+
83+
if dihedrals_connectivity is not None:
84+
- self.dihedrals.resize(len(dihedrals_connectivity))
85+
+ self.dihedrals = np.empty(len(dihedrals_connectivity), dtype=self._dtypes["dihedrals"])
86+
self.dihedrals["atoms"][:] = dihedrals_connectivity
87+
self.dihedrals["type"][:] = dihedrals_types \
88+
if dihedrals_types is not None else default_type

0 commit comments

Comments
 (0)