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
48 changes: 48 additions & 0 deletions .github/workflows/python_publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build/publish Python Package

on: push

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install build twine
- name: Build package
run: |
python -m build --sdist --wheel
- name: Check package
run: |
python -m twine check dist/*
- name: Store the distribution packages
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/

publish-to-pypi:
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download distribution packages
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: tests

on: [push, pull_request]

jobs:
pytest:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13"]

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install .[test]
- name: Test with pytest
run: |
pytest -vv tests
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ pyfeltor/dg/geo/__pycache__
.eggs
dist
pyfeltor/_version.py

uv.lock

# ignore visual studio .vs table
/.vs

# CMake output
build
out
75 changes: 75 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
## Inspired from https://github.com/pybind/scikit_build_example/blob/master/CMakeLists.txt

# Require CMake 3.15+ (matching scikit-build-core) Use new versions of all
# policies up to CMake 3.27
cmake_minimum_required( VERSION "3.26")


# Scikit-build-core sets these values for you, or you can just hard-code the
# name and version.
project(
${SKBUILD_PROJECT_NAME}
VERSION ${SKBUILD_PROJECT_VERSION}
LANGUAGES CXX)

include(cmake/CPM.cmake)
set( CCCL_THRUST_DEVICE_SYSTEM "CPP")
CPMAddPackage(
NAME feltor
GITHUB_REPOSITORY "feltor-dev/feltor"
VERSION 8.2
SYSTEM ON
EXCLUDE_FROM_ALL ON
OPTIONS "FELTOR_DG_WITH_MATRIX OFF" "FELTOR_FILE_WITH_NETCDF OFF"
)


# Find the module development requirements (requires FindPython from 3.17 or
# scikit-build-core's built-in backport)
# MW: https://cmake.org/cmake/help/latest/module/FindPython.html
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
# Install pyprojects pybind11
find_package(pybind11 CONFIG REQUIRED)

# Needs to come after feltor because json is already included there
# unless we use CPM_USE_LOCAL_PACKAGES
CPMAddPackage( "gh:pybind/pybind11_json#0.2.15")


# Follow the Makefile approach and compile each cpp into its own so lib

set( PYFELTOR_LIBS
geometries
polynomial
solovev
guenter
circular
flux
mod
toroidal
utility
)

# Add a library using FindPython's tooling (pybind11 also provides a helper like
# this)
foreach( lib IN LISTS PYFELTOR_LIBS)
python_add_library(${lib} MODULE WITH_SOABI "pyfeltor/dg/geo/${lib}.cpp")
target_compile_features(${lib} PRIVATE cxx_std_17)
if (MSVC)
# warning level 4
target_compile_options(${lib} PRIVATE /W4 /permissive- /arch:AVX2 /O2 /EHsc -DFP_FAST_FMA -D_USE_MATH_DEFINES)
else()
# additional warnings
target_compile_options(${lib} PRIVATE -Wall -Wextra -Wpedantic -march=native -O2)
endif()

target_link_libraries(${lib} PRIVATE pybind11::headers)


target_link_libraries(${lib} PRIVATE feltor::dg::geometries)
target_link_libraries(${lib} PRIVATE pybind11_json)
# The install directory is the output (wheel) directory
install(TARGETS ${lib} DESTINATION pyfeltor/dg/geo)
endforeach()


35 changes: 3 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ through python this enables many applications beyond simple simulations
diagnostics. The only downside is of course that all functions are
unparallelized in python.

As a second addition, now also Feltor's geometries extension is available in python.
As a second addition, Feltor's geometries extension is available in python.
However, the geometries functions and classes are not re-implemented in python, but
they are bound to python via the [pybind11](https://github.com/pybind11/pybind11)
they are bound to python via the [pybind11](https://github.com/pybind/pybind11)
library. As such the corresponding C++ binding code must be compiled in order
to generate the module `dg.geo`.
## Installation
### The pyfeltor.dg module
> You need python3 to install this module
> The `pyfeltor.dg.geo` part of the module contains python bindings for the underlying C++ [feltor](https://github.com/feltor-dev/feltor) code using [pybind11](https://github.com/pybind/pybind11). During installation the C++ code will be compiled using cmake, which may take a minute or two.

The simplest way is to install from the python package index [pypi](https://pypi.org/) via the package manager [pip](https://pip.pypa.io/en/stable/) v23.0
```bash
Expand All @@ -45,34 +44,6 @@ cd tests
pytest-3 -s . # run all the unittests with output
```

### The pyfeltor.dg.geo module
Currently, the only way to install this module is via a local, editable install.
Assuming that the pyfeltor.dg module was succesfully installed this way
- the first step is to also install [feltor](https://github.com/feltor-dev/feltor)
following the quick start guide for a base installation.
- Second, instead of jsoncpp we here use the
[nlohmann/json](https://github.com/nlohmann/json) parser available either as a
system package `nlohmann-json3-dev`.
- Next, we follow the first steps guide on [pybind11](https://github.com/pybind11/pybind11)
and install it via `python3 -m pip install pybind11`.
- Further, we install the 'python3-dev', `pybind11-dev` and `pybind11-json-dev` system packages for
the corresponding C++ header files.

Finally, invoke the Makefile in this repository
```bash
export FELTOR_PATH=path/to/feltor
make -j 4
```
Replace `path/to/feltor` with the path to the Feltor library relative to the current
directory. By default `FELTOR_PATH=../feltor`.

That's it. With the editable install the `pyfeltor.dg.geo` module is now automatically
imported together with `pyfeltor.dg`.
You can test if it works by executing the test
```bash
cd tests
pytest -s test_geometries
```
## Usage

Generally, pyfeltor is built to mimic the `dg` library in feltor.
Expand Down
24 changes: 24 additions & 0 deletions cmake/CPM.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MIT
#
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors

set(CPM_DOWNLOAD_VERSION 0.41.0)
set(CPM_HASH_SUM "e570f03806b9aae2082ca5b950a9e6b3b41ad56972a78a876aedcaad16653116")

if(CPM_SOURCE_CACHE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()

# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)

file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
)

include(${CPM_DOWNLOAD_LOCATION})
17 changes: 9 additions & 8 deletions pyfeltor/dg/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# docstring displayed by help(pyfeltor)
""" The python version of the dg library
"""
from . import create
from .enums import bc, direction, inverse_bc, inverse_dir
from .grid import Grid
from .evaluation import evaluate, integrate
try:
from . import geo
except ImportError:
pass
from . import create as create
from . import geo as geo
from .enums import bc as bc
from .enums import direction as direction
from .enums import inverse_bc as inverse_bc
from .enums import inverse_dir as inverse_dir
from .evaluation import evaluate as evaluate
from .evaluation import integrate as integrate
from .grid import Grid as Grid
12 changes: 8 additions & 4 deletions pyfeltor/dg/create/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# docstring displayed by help(pyfeltor)
""" The python version of the dg library, creation
"""
from .weights import weights, abscissas, grid_from_abscissas
from .derivative import dx, jump
from .elliptic import elliptic
from .interpolation import interpolation, projection
from .derivative import dx as dx
from .derivative import jump as jump
from .elliptic import elliptic as elliptic
from .interpolation import interpolation as interpolation
from .interpolation import projection as projection
from .weights import abscissas as abscissas
from .weights import grid_from_abscissas as grid_from_abscissas
from .weights import weights as weights
3 changes: 2 additions & 1 deletion pyfeltor/dg/create/derivative.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from .dx import normed, jump_normed
import scipy.sparse

from .dx import jump_normed, normed


def dx(dim, grid, bc, direction):
deriv = normed(grid.n[dim], grid.N[dim], grid.h()[dim], bc, direction)
Expand Down
Loading