Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0704c51
Fix CMake build system and remove legacy build files
andersx Feb 16, 2026
f7f82c5
Add pybind11 bindings for Fortran solver functions
andersx Feb 16, 2026
1123b89
Refactor fsolvers.f90 to eliminate code duplication
andersx Feb 16, 2026
d914edb
Add pybind11 bindings for representations and utils modules
andersx Feb 16, 2026
e02c9d4
Add input validation back to representation functions
andersx Feb 16, 2026
e953de5
Add comprehensive input validation to all representation functions
andersx Feb 16, 2026
6fbefac
Remove example kernel files and build configuration
andersx Feb 16, 2026
e01dad2
Restore compiler optimization flags for all modules
andersx Feb 16, 2026
94ed569
Merge pull request #1 from andersx/fix/cmake-build-system
andersx Feb 16, 2026
6c70f21
Add pybind11 bindings for kernels
andersx Feb 16, 2026
2ab7e37
Convert gradient kernels from f2py to pybind11 (#3)
andersx Feb 16, 2026
f12aa9e
Convert SLATM to pybind11 and remove ARAD representation (#4)
andersx Feb 16, 2026
1e09b07
WIP: Migrate FCHL representations from f2py to pybind11 (#5)
andersx Feb 16, 2026
97ead18
Complete FCHL migration from f2py to pybind11 (#6)
andersx Feb 17, 2026
0eafc3b
Fix BLAS linking for _fgradient_kernels and skip optional dependency …
andersx Feb 17, 2026
365f6b3
Fix distance function wrappers to match pybind11 signatures
andersx Feb 17, 2026
f28babe
Migrate fsvd_solve from f2py to pybind11
andersx Feb 17, 2026
bcf7290
Fix local kernel functions to handle arbitrary representation sizes
andersx Feb 17, 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
227 changes: 227 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
cmake_minimum_required(VERSION 3.18)
project(qmllib LANGUAGES C CXX Fortran)

# Python + pybind11
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
find_package(pybind11 CONFIG REQUIRED)

# Create a common interface target for kernels that need pybind11 headers
add_library(qmllib_common INTERFACE)
target_link_libraries(qmllib_common INTERFACE pybind11::headers Python::Module)

# Fortran solvers as an object library
add_library(qmllib_solvers OBJECT src/qmllib/solvers/fsolvers.f90)
set_property(TARGET qmllib_solvers PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran representations as an object library
add_library(qmllib_representations OBJECT src/qmllib/representations/frepresentations.f90)
set_property(TARGET qmllib_representations PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran utils as an object library
add_library(qmllib_utils OBJECT src/qmllib/utils/fsettings.f90)
set_property(TARGET qmllib_utils PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran kernels as an object library
add_library(qmllib_fkernels OBJECT
src/qmllib/kernels/fkpca.f90
src/qmllib/kernels/fkwasserstein.f90
src/qmllib/kernels/fkernels.f90
)
set_property(TARGET qmllib_fkernels PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran distance functions as an object library
add_library(qmllib_fdistance OBJECT src/qmllib/kernels/fdistance.f90)
set_property(TARGET qmllib_fdistance PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran gradient kernels as an object library
add_library(qmllib_fgradient_kernels OBJECT src/qmllib/kernels/fgradient_kernels.f90)
set_property(TARGET qmllib_fgradient_kernels PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran ACSF/FCHL representations as an object library
add_library(qmllib_facsf OBJECT src/qmllib/representations/facsf.f90)
set_property(TARGET qmllib_facsf PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran SLATM representations as an object library
add_library(qmllib_fslatm OBJECT src/qmllib/representations/fslatm.f90)
set_property(TARGET qmllib_fslatm PROPERTY POSITION_INDEPENDENT_CODE ON)

# Fortran FCHL representations as an object library
add_library(qmllib_ffchl OBJECT
src/qmllib/representations/fchl/ffchl_kernel_types.f90
src/qmllib/representations/fchl/ffchl_kernels.f90
src/qmllib/representations/fchl/ffchl_module.f90
src/qmllib/representations/fchl/ffchl_scalar_kernels.f90
src/qmllib/representations/fchl/ffchl_gradient_kernels.f90
src/qmllib/representations/fchl/ffchl_hessian_kernels.f90
src/qmllib/representations/fchl/ffchl_gaussian_process_kernels.f90
src/qmllib/representations/fchl/ffchl_atomic_local_kernels.f90
src/qmllib/representations/fchl/ffchl_force_alphas.f90
)
set_property(TARGET qmllib_ffchl PROPERTY POSITION_INDEPENDENT_CODE ON)

# Build the Python extension module for solvers
pybind11_add_module(_solvers MODULE
src/qmllib/solvers/bindings_solvers.cpp
$<TARGET_OBJECTS:qmllib_solvers>
)

set_target_properties(_solvers PROPERTIES OUTPUT_NAME "_solvers")

# Build the Python extension module for representations
pybind11_add_module(_representations MODULE
src/qmllib/representations/bindings_representations.cpp
$<TARGET_OBJECTS:qmllib_representations>
)

set_target_properties(_representations PROPERTIES OUTPUT_NAME "_representations")

# Build the Python extension module for utils
pybind11_add_module(_utils MODULE
src/qmllib/utils/bindings_utils.cpp
$<TARGET_OBJECTS:qmllib_utils>
)

set_target_properties(_utils PROPERTIES OUTPUT_NAME "_utils")

# Build the Python extension module for kernels (kpca and wasserstein)
pybind11_add_module(_fkernels MODULE
src/qmllib/kernels/bindings_fkernels.cpp
$<TARGET_OBJECTS:qmllib_fkernels>
)

set_target_properties(_fkernels PROPERTIES OUTPUT_NAME "_fkernels")

# Build the Python extension module for distance functions
pybind11_add_module(_fdistance MODULE
src/qmllib/kernels/bindings_fdistance.cpp
$<TARGET_OBJECTS:qmllib_fdistance>
)

set_target_properties(_fdistance PROPERTIES OUTPUT_NAME "_fdistance")

# Build the Python extension module for gradient kernels
pybind11_add_module(_fgradient_kernels MODULE
src/qmllib/kernels/bindings_fgradient_kernels.cpp
$<TARGET_OBJECTS:qmllib_fgradient_kernels>
)

set_target_properties(_fgradient_kernels PROPERTIES OUTPUT_NAME "_fgradient_kernels")

# Build the Python extension module for ACSF/FCHL representations
pybind11_add_module(_facsf MODULE
src/qmllib/representations/bindings_facsf.cpp
$<TARGET_OBJECTS:qmllib_facsf>
)

set_target_properties(_facsf PROPERTIES OUTPUT_NAME "_facsf")

# Build the Python extension module for SLATM representations
pybind11_add_module(_fslatm MODULE
src/qmllib/representations/bindings_fslatm.cpp
$<TARGET_OBJECTS:qmllib_fslatm>
)

set_target_properties(_fslatm PROPERTIES OUTPUT_NAME "_fslatm")

# Build the Python extension module for FCHL representations
pybind11_add_module(ffchl_module MODULE
src/qmllib/representations/fchl/bindings_fchl_simple.cpp
$<TARGET_OBJECTS:qmllib_ffchl>
)

set_target_properties(ffchl_module PROPERTIES OUTPUT_NAME "ffchl_module")

find_package(OpenMP)
if (OpenMP_Fortran_FOUND)
target_link_libraries(_solvers PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_representations PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_utils PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_fkernels PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_fdistance PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_fgradient_kernels PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_facsf PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(_fslatm PRIVATE OpenMP::OpenMP_Fortran)
target_link_libraries(ffchl_module PRIVATE OpenMP::OpenMP_Fortran)
endif()

# Optional BLAS/LAPACK backends
if(APPLE)
find_library(ACCELERATE Accelerate REQUIRED)
target_link_libraries(_solvers PRIVATE ${ACCELERATE})
target_link_libraries(_representations PRIVATE ${ACCELERATE})
target_link_libraries(_fkernels PRIVATE ${ACCELERATE})
target_link_libraries(_fgradient_kernels PRIVATE ${ACCELERATE})
target_link_libraries(ffchl_module PRIVATE ${ACCELERATE})
elseif(WIN32)
find_package(MKL CONFIG REQUIRED)
target_link_libraries(_solvers PRIVATE MKL::MKL)
target_link_libraries(_representations PRIVATE MKL::MKL)
target_link_libraries(_fkernels PRIVATE MKL::MKL)
target_link_libraries(_fgradient_kernels PRIVATE MKL::MKL)
target_link_libraries(ffchl_module PRIVATE MKL::MKL)
else()
find_package(BLAS REQUIRED)
target_link_libraries(_solvers PRIVATE BLAS::BLAS)
target_link_libraries(_representations PRIVATE BLAS::BLAS)
target_link_libraries(_fkernels PRIVATE BLAS::BLAS)
target_link_libraries(_fgradient_kernels PRIVATE BLAS::BLAS)
target_link_libraries(ffchl_module PRIVATE BLAS::BLAS)
endif()

# Note: _fdistance doesn't need BLAS/LAPACK

# Compiler optimization flags (portable wheels)
if (CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM" OR CMAKE_Fortran_COMPILER_ID STREQUAL "Intel")
set(FORTRAN_OPT_FLAGS -O3 -ipo -xHost -fp-model fast=2 -no-prec-div -fno-alias -qopenmp)
elseif (CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
set(FORTRAN_OPT_FLAGS -O3 -fopenmp -mcpu=native -mtune=native -ffast-math -ftree-vectorize)
endif()

if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CXX_OPT_FLAGS -O3 -march=native -ffast-math -fopenmp -mtune=native -ftree-vectorize)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
set(CXX_OPT_FLAGS -O3 -qopt-report=3 -qopenmp -xHost)
endif()

# Apply optimization flags to Fortran object libraries
if(FORTRAN_OPT_FLAGS)
target_compile_options(qmllib_solvers PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_representations PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_utils PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_fkernels PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_fdistance PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_fgradient_kernels PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_facsf PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_fslatm PRIVATE ${FORTRAN_OPT_FLAGS})
target_compile_options(qmllib_ffchl PRIVATE ${FORTRAN_OPT_FLAGS})
endif()

# Apply optimization flags to C++ binding modules
if(CXX_OPT_FLAGS)
target_compile_options(_solvers PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_representations PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_utils PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_fkernels PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_fdistance PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_fgradient_kernels PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_facsf PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(_fslatm PRIVATE ${CXX_OPT_FLAGS})
target_compile_options(ffchl_module PRIVATE ${CXX_OPT_FLAGS})
endif()

# Install the compiled extension into the Python package and the Python shim
install(TARGETS _solvers _representations _utils _fkernels _fdistance _fgradient_kernels _facsf _fslatm
LIBRARY DESTINATION qmllib # Linux/macOS
RUNTIME DESTINATION qmllib # Windows (.pyd)
)

# Install FCHL module to the fchl subdirectory
install(TARGETS ffchl_module
LIBRARY DESTINATION qmllib/representations/fchl # Linux/macOS
RUNTIME DESTINATION qmllib/representations/fchl # Windows (.pyd)
)
install(DIRECTORY src/qmllib/ DESTINATION qmllib
FILES_MATCHING PATTERN "*.py"
PATTERN "__pycache__" EXCLUDE
)

3 changes: 0 additions & 3 deletions MANIFEST.in

This file was deleted.

131 changes: 5 additions & 126 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,129 +1,8 @@
env=env
python=./${env}/bin/python
python_version=3.12
conda=mamba
pkg=qmllib
pip=./env/bin/pip
pytest=pytest
j=1

version_file=src/qmllib/version.py

.PHONY: build

all: ${env}

## Setup

env:
echo "TODO"

env_uv:
which uv
uv venv ${env} --python ${python_version}
uv pip install -r requirements.txt --python ${python}
uv pip install -e . --python ${python}
make .git/hooks/pre-commit python=${python}

env_conda:
which ${conda}
${conda} env create -f ./environment.yaml -p ./${env} --quiet
${python} -m pip install -e .
make .git/hooks/pre-commit python=${python}

./.git/hooks/pre-commit:
${python} -m pre_commit install

## Development

format:
${python} -m pre_commit run --all-files
install:
pip install -e .[test] --verbose

test:
${python} -m pytest -rs ./tests

test-dist:
${python} -m twine check dist/*

types:
${python} -m monkeytype run $$(which ${pytest}) ./tests
${python} -m monkeytype list-modules | grep ${pkg} | parallel -j${j} "${python} -m monkeytype apply {} > /dev/null && echo {}"

cov:
${python} -m pytest --cov=${pkg} --cov-config .coveragerc --cov-report html tests

compile:
${python} _compile.py

build:
${python} -m build --sdist --skip-dependency-check .

upload:
${python} -m twine upload ./dist/*.tar.gz

## Version

VERSION=$(shell cat ${version_file} | egrep -o "([0-9]{1,}\.)+[0-9]{1,}")
VERSION_PATCH=$(shell echo ${VERSION} | cut -d'.' -f3)
VERSION_MINOR=$(shell echo ${VERSION} | cut -d'.' -f2)
VERSION_MAJOR=$(shell echo ${VERSION} | cut -d'.' -f1)
GIT_COMMIT=$(shell git rev-parse --short HEAD)

version:
echo ${VERSION}

bump-version-auto:
test $(git diff HEAD^ HEAD tests | grep -q "+def") && make bump-version-minor || make bump-version-patch

bump-version-dev:
test ! -z "${VERSION}"
test ! -z "${GIT_COMMIT}"
exit 1 # Not Implemented

bump-version-patch:
test ! -z "${VERSION_PATCH}"
echo "__version__ = \"${VERSION_MAJOR}.${VERSION_MINOR}.$(shell awk 'BEGIN{print ${VERSION_PATCH}+1}')\"" > ${version_file}

bump-version-minor:
test ! -z "${VERSION_MINOR}"
echo "__version__ = \"${VERSION_MAJOR}.$(shell awk 'BEGIN{print ${VERSION_MINOR}+1}').0\"" > ${version_file}

bump-version-major:
test ! -z "${VERSION_MAJOR}"
echo "__version__ = \"$(shell awk 'BEGIN{print ${VERSION_MAJOR}+1}').0.0\"" > ${version_file}

commit-version-tag:
# git tag --list | grep -qix "${VERSION}"
git commit -m "Release ${VERSION}" --no-verify ${version_file}
git tag 'v${VERSION}'

gh-release:
gh release create "v${VERSION}" \
--repo="$${GITHUB_REPOSITORY}" \
--title="$${GITHUB_REPOSITORY#*/} ${VERSION}" \
--generate-notes

gh-has-src-changed:
git diff HEAD^ HEAD src | grep -q "+"

gh-cancel:
gh run cancel $${GH_RUN_ID}
gh run watch $${GH_RUN_ID}

## Clean

clean:
find ./src/ -type f \
-name "*.so" \
-name "*.pyc" \
-name ".pyo" \
-name ".mod" \
-delete
rm -rf ./src/*.egg-info/
rm -rf *.whl
rm -rf ./build/ ./__pycache__/
rm -rf ./dist/
pytest

clean-env:
rm -rf ./env/
rm ./.git/hooks/pre-commit
environment:
conda env create -f environments/environment-dev.yaml
Loading
Loading