Skip to content
Draft
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
126 changes: 126 additions & 0 deletions .github/workflows/build-matscipy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on the `build` job of
# https://github.com/libAtoms/matscipy/blob/v1.2.0/.github/workflows/wheels.yml
# and the `pytest` step of
# https://github.com/libAtoms/matscipy/blob/v1.2.0/.github/workflows/tests.yml
name: Build matscipy wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/matscipy.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-matscipy.yml'
- 'docs/packages/matscipy.yaml'
- 'patches/matscipy/**'
push:
branches: [main]
paths:
- '.github/workflows/build-matscipy.yml'
- 'docs/packages/matscipy.yaml'
- 'patches/matscipy/**'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: matscipy
version: ${{ inputs.version }}

build_wheels:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
name: Build matscipy ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python: ["cp312", "cp313", "cp314"]

env:
MATSCIPY_VERSION: ${{ matrix.version }}

steps:
- name: Checkout matscipy v${{ env.MATSCIPY_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: libAtoms/matscipy
ref: v${{ env.MATSCIPY_VERSION }}
fetch-depth: 0
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Patch matscipy source
run: |
git apply python-wheels/patches/matscipy/${{ env.MATSCIPY_VERSION }}/*.patch
# meson-python reads the wheel version from `git describe` on this tree; a
# dirty tree gives "1.2.0.dirty", which packaging.version.Version rejects
# outright (InvalidVersion), failing the build before compilation even
# starts. Hide just the patched file from dirty-detection instead.
git update-index --skip-worktree matscipy/calculators/eam/io.py

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
only: ${{ matrix.python }}-manylinux_riscv64
env:
CIBW_BUILD_FRONTEND: build
CIBW_BEFORE_BUILD: pip install meson meson-python ninja
CIBW_ENVIRONMENT: >-
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/
PIP_ONLY_BINARY=numpy,scipy,matplotlib,contourpy,kiwisolver,pillow
# Upstream's wheel job only imports the extension; run its tests.yml suite instead.
# ase.constraints.UnitCellFilter (and friends), which this v1.2.0 tag's tests/
# still imports, was a @deprecated re-export from ase.filters through 3.26.0;
# 3.27.0 drops the re-export entirely (checked gitlab.com/ase/ase directly,
# tag by tag). matscipy's pyproject.toml floor (ase>=3.26.0) doesn't cap the
# other end, so an unconstrained resolve picks today's ase and breaks 29
# tests / errors on 12 modules. ase<3.27 is its own space-separated token
# here (no quote characters anywhere in this YAML scalar), resolved together
# with matscipy's own floor by the same `pip install` that installs the wheel.
CIBW_TEST_REQUIRES: pytest pytest-subtests pytest-timeout pytest-xdist sympy ase<3.27
CIBW_TEST_COMMAND: cd {project}/tests && pytest -v --durations=20 --timeout=600 -n auto

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: matscipy-${{ env.MATSCIPY_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: ./wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish matscipy ${{ matrix.version }}
needs: [setup, build_wheels]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: matscipy-${{ matrix.version }}-*-manylinux_riscv64
5 changes: 5 additions & 0 deletions docs/packages/matscipy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: matscipy
source-code: https://github.com/libAtoms/matscipy
license: LGPL-2.1-only
versions:
- version: 1.2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Thu, 01 Oct 2026 00:00:00 +0000
Subject: [PATCH] eam/io: index 1-element arrays before int()/float()

write_eam's "eam" (DYNAMO funcfl) branch calls int(atomic_numbers) and
float(atomic_masses)/float(lattice_parameters) directly on the
EAMParameters fields, which read_eam builds as 1-element numpy arrays
(np.array((int(words[0]),), dtype=int), etc.), not scalars - the
function's own "# FIXME: atomic numbers etc are now arrays, and not
scalars" comment already says as much. NumPy 2.x turned the implicit
conversion of a non-0-d array into a hard TypeError: "only
0-dimensional arrays can be converted to Python scalars", so
test_eam_io.py::test_eam_read_write's round-trip through this branch
fails outright. Indexing [0] before the int()/float() calls is what
the FIXME already describes as the fix.

Upstream-Status: To upstream [not yet submitted; a NumPy-2.x correctness fix, not riscv64-specific]

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
--- a/matscipy/calculators/eam/io.py
+++ b/matscipy/calculators/eam/io.py
@@ -548,7 +548,7 @@
# parameters unpacked
# FIXME: atomic numbers etc are now arrays, and not scalars
crystal_structures_str = ' '.join(s for s in crystal_structures)
- atline = f"{int(atomic_numbers)} {float(atomic_masses)} {float(lattice_parameters)} {crystal_structures_str}"
+ atline = f"{int(atomic_numbers[0])} {float(atomic_masses[0])} {float(lattice_parameters[0])} {crystal_structures_str}"
parameterline = f'{int(Nrho)}\t{float(drho):.16e}\t{int(Nr)}\t{float(dr):.16e}\t{float(cutoff):.10e}'
potheader = f"# EAM potential from : # {source} \n {atline} \n {parameterline}"
# --- Writing new EAM alloy pot file --- #
Loading