Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
2a4147c
initial setup commit
Griger5 May 9, 2025
c442b01
hacky trick relying on cmake undocumented feature, that fixes the iss…
Griger5 May 23, 2025
345ca3e
first util and rand bindings, first passing tests
Griger5 May 23, 2025
1a44871
add: bindings to the rest of the util.cpp
Griger5 May 25, 2025
f8d1cef
WIP: refactored nanobind_json, created bindings for AeroData, AeroDat…
Griger5 May 26, 2025
f6d91c3
refactored AeroData so that the tests are passing
Griger5 May 27, 2025
52b6c52
add: custom nanobind caster for std::valarray
Griger5 May 28, 2025
e0bb9ec
add: BinGrid bindings
Griger5 May 28, 2025
13d407c
revert to old aero_data.hpp thanks to the new caster
Griger5 May 28, 2025
094b5bf
add: missing changes
Griger5 May 28, 2025
73c055f
fix JSON caster so it catches circular reference, add AeroMode bindings
Griger5 May 28, 2025
86939e5
pull main into branch
Griger5 May 29, 2025
c444e5d
add accidentally deleted line
Griger5 May 29, 2025
406b491
delete unused header files
Griger5 May 29, 2025
40fb1c0
add: bindings for AeroData
Griger5 May 29, 2025
5232372
add: pyproject.toml
Griger5 May 30, 2025
73a1543
add: EnvState bindings
Griger5 May 31, 2025
8dc75f3
add: GasData bindings
Griger5 May 31, 2025
1ab9a8a
swith nanobind_json to Gracjan fork
slayoo Jun 4, 2025
69ab2f9
switch to pypartmc branch commit for nanobind_json submodule
slayoo Jun 4, 2025
93943a1
WIP: current working version
Griger5 Jun 13, 2025
8917174
add: semi-working AeroParticle bindings
Griger5 Jun 13, 2025
ca2ea1c
add: AeroState bindigns. README example working
Griger5 Jun 13, 2025
068b682
bindings for GasState and RunPartOpt
Griger5 Jul 3, 2025
3a53b76
add: bindings for condense functions
Griger5 Jul 3, 2025
d58fcdf
add output bindings, fix error in GasData
Griger5 Jul 8, 2025
721f722
add: bindings for run_part functions and Scenario
Griger5 Jul 8, 2025
936b0d8
add: AeroBinned bindings
Griger5 Jul 12, 2025
263dd83
add: RunSectOpt and RunExactOpt bindings
Griger5 Jul 12, 2025
1fc6302
add: missing input bindings
Griger5 Jul 12, 2025
0ad3ee5
add: version attributes
Griger5 Jul 19, 2025
aeec1e0
chore: clean up
Griger5 Jul 19, 2025
02db84a
adding numpy and pytest to dependencies
slayoo Jul 21, 2025
732253b
add pytest-order to test-time dependencies
slayoo Jul 21, 2025
a0f7edf
fail-fast: false
slayoo Jul 23, 2025
b7e2daa
add: try to fix windows issue with snprintf
Griger5 Jul 23, 2025
e9177f6
Merge branch 'bump-to-nanobind' of github.com:Griger5/PyPartMC into b…
Griger5 Jul 23, 2025
139971b
add: example notebook dependencies
Griger5 Jul 23, 2025
8980ce5
fix: typo in pyproject.toml
Griger5 Jul 23, 2025
b2cfa2a
fix: pyproject.toml syntax for platforms in dependencies
Griger5 Jul 23, 2025
43c3742
fix: pyproject.toml syntax for platforms in dependencies
Griger5 Jul 23, 2025
a1e82cd
fix: change os_name to platform_system
Griger5 Jul 24, 2025
034828a
wip: attempt a fix for matlab listings
Griger5 Jul 24, 2025
f8079f6
wip: attempt a fix for matlab listings
Griger5 Jul 24, 2025
66ad3a7
fix: change 'windows' to 'Windows'
Griger5 Jul 24, 2025
4a18391
fix relative README.md include
slayoo Jul 24, 2025
548b52e
remove pybind11 leftovers from Matlab CI workflow
slayoo Jul 24, 2025
db371bb
remove pybind11 Matlab workaround mention from README.md
slayoo Jul 24, 2025
9c4788c
pybind11 -> nanobind in CONTRIBUTING.md
slayoo Jul 24, 2025
6b83dd5
add: comments for walkarounds, small fixes
Griger5 Jul 25, 2025
e2bd59a
bump: cmake version
Griger5 Jul 27, 2025
d1bb57b
drop pip version pins, add setup-python with 3.9 as in other jobs
slayoo Jul 30, 2025
19f0533
go back to pip<23
slayoo Jul 30, 2025
fedc62b
try newer python, --config-settings=build-dir=build flag for scikit-b…
slayoo Jul 30, 2025
98e86a0
fix lcov path
slayoo Jul 30, 2025
e2a1606
silencing pylint
slayoo Jul 30, 2025
aa922a0
Merge branch 'bump-to-nanobind' of github.com:Griger5/PyPartMC into HEAD
slayoo Jul 30, 2025
1e59655
move pylint comment around
slayoo Jul 30, 2025
e0b9158
update precommit config; rerun with never black
slayoo Jul 30, 2025
9a39e94
Merge branch 'main' into bump-to-nanobind
slayoo Jul 30, 2025
8d62e78
move the comment around again
slayoo Jul 30, 2025
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
1 change: 1 addition & 0 deletions .github/workflows/buildwheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-latest, windows-latest]

Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ jobs:
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-python@v1
with:
python-version: "3.12"
- run: sudo apt install -y lcov
- run: |
set -xe
pip install "pip<23" setuptools==65.2
CMAKE_ARGS="-DCMAKE_CXX_FLAGS=--coverage -DCMAKE_C_FLAGS=--coverage -DCMAKE_Fortran_FLAGS=--coverage" pip install -e .[tests]
CMAKE_ARGS="-DCMAKE_CXX_FLAGS=--coverage -DCMAKE_C_FLAGS=--coverage -DCMAKE_Fortran_FLAGS=--coverage" pip install --config-settings=build-dir=build -e .[tests]
pytest -We tests
lcov --capture --directory ./build/*/_PyPartMC/CMakeFiles/_PyPartMC.dir/ --output-file coverage.info --no-external
lcov --capture --directory ./build/CMakeFiles/_PyPartMC.dir/ --output-file coverage.info --no-external
- run: find -name \*.gcno | grep -v pypartmc.cpp | grep -v _PyPartMC.dir | xargs rm
- uses: codecov/[email protected]
with:
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/readme_listings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,6 @@ jobs:
- run: python -c "import pytest_codeblocks; code=pytest_codeblocks.extract_from_file('README.md'); f=open('readme.m', 'w'); f.writelines(block.code for block in code if block.syntax=='Matlab'); f.close()"
- run: cat -n readme.m

# see https://github.com/pybind/cmake_example/pull/164
- run: |
echo "pybind11_type=type" > pybind11_builtins.py
echo "PYTHONPATH=." >> $GITHUB_ENV

- uses: matlab-actions/setup-matlab@v0
with:
release: R2022a
Expand Down
18 changes: 10 additions & 8 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
[submodule "pybind11"]
path = gitmodules/pybind11
url = https://github.com/pybind/pybind11
shallow = true
[submodule "partmc"]
path = gitmodules/partmc
url = https://github.com/compdyn/partmc
shallow = true
[submodule "pybind11_json"]
path = gitmodules/pybind11_json
url = https://github.com/pybind/pybind11_json
shallow = true
[submodule "json"]
path = gitmodules/json
url = https://github.com/nlohmann/json
Expand Down Expand Up @@ -58,3 +50,13 @@
path = gitmodules/hdf5
url = https://github.com/HDFGroup/hdf5.git
shallow = true
[submodule "gitmodules/nanobind"]
path = gitmodules/nanobind
url = https://github.com/wjakob/nanobind
[submodule "gitmodules/nanobind_json"]
path = gitmodules/nanobind_json
url = https://github.com/Griger5/nanobind_json
[submodule "."]
branch = pypartmc
[submodule "nanobind_json"]
branch = pypartmc
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
files: '.py'
exclude: '.git'
default_stages: [commit]
default_stages: [pre-commit]

repos:
- repo: https://github.com/psf/black
rev: 23.1.0
rev: 25.1.0
hooks:
- id: black

- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
rev: 6.0.1
hooks:
- id: isort
args: ["--profile", "black"]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Expand Down
82 changes: 47 additions & 35 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Author: Sylwester Arabas #
####################################################################################################

cmake_minimum_required(VERSION 3.8) # CXX17
cmake_minimum_required(VERSION 3.15) # CXX17

file(GLOB mods RELATIVE ${CMAKE_SOURCE_DIR} gitmodules/*)
foreach(mod ${mods})
Expand All @@ -16,7 +16,10 @@ endforeach()

project(_PyPartMC LANGUAGES C CXX Fortran)

find_package(PythonInterp REQUIRED)
find_package(Python 3.8
REQUIRED COMPONENTS Interpreter Development.Module
OPTIONAL_COMPONENTS Development.SABIModule)
message(STATUS "Python_EXECUTABLE= ${Python_EXECUTABLE}")

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

Expand All @@ -33,6 +36,12 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
add_compile_options($<$<AND:$<COMPILE_LANGUAGE:Fortran>,$<CONFIG:DEBUG>>:-fcheck=bounds>)
endif()

# Shadow the CMake intrinsic install function so that included CMake code from dependency submodules does not
# interfere with "make install" issued by scikit-build (note that our intentional install() call is replaced with
# _install() below - following https://cmake.org/pipermail/cmake/2011-March/043320.html)
macro(install)
endmacro(install)

macro(add_prefix prefix rootlist)
set(outlist)
foreach(root ${${rootlist}})
Expand Down Expand Up @@ -511,15 +520,17 @@ if(DEFINED ENV{MOSAIC_HOME})
)
endif()

### PYBIND11 & PyPartMC ############################################################################
### NANOBIND & PyPartMC ############################################################################
find_package(nanobind CONFIG REQUIRED)

add_subdirectory(gitmodules/pybind11)
pybind11_add_module(_PyPartMC ${PyPartMC_sources})
add_subdirectory(gitmodules/nanobind)
nanobind_add_module(_PyPartMC STABLE_ABI ${PyPartMC_sources})
add_dependencies(_PyPartMC partmclib)
set(PYPARTMC_INCLUDE_DIRS
"${CMAKE_BINARY_DIR}/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/json/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/pybind11_json/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/nanobind/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/nanobind_json/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/span/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/string_view-standalone/include;"
"${CMAKE_SOURCE_DIR}/gitmodules/optional/include;"
Expand All @@ -545,7 +556,7 @@ endif()
foreach(target _PyPartMC)
target_compile_options(${target} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
# $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-unused-parameter>
)
endforeach()
Expand All @@ -555,31 +566,32 @@ file(GLOB PyPartMC_headers ${CMAKE_SOURCE_DIR}/src/*.hpp)
if (NOT "${CMAKE_REQUIRED_INCLUDES}" STREQUAL "")
message("CMAKE_REQUIRED_INCLUDES not empty! (${CMAKE_REQUIRED_INCLUDES})")
endif()
foreach(file ${PyPartMC_headers})
set(CMAKE_REQUIRED_INCLUDES "${PYPARTMC_INCLUDE_DIRS};${pybind11_INCLUDE_DIRS}")
set(CMAKE_REQUIRED_FLAGS "-Werror")
string(REGEX REPLACE "[\-./:]" "_" file_var ${file})
check_cxx_source_compiles("
// https://github.com/nlohmann/json/issues/1408
#if defined(_WIN32) || defined(_WIN64)
# define HAVE_SNPRINTF
#endif
#include \"${file}\"
int main() { return 0;}
"
_header_self_contained_${file_var}
)
unset(CMAKE_REQUIRED_INCLUDES)
unset(CMAKE_REQUIRED_FLAGS)
if (NOT _header_self_contained_${file_var})
message(SEND_ERROR "non-self-contained header: ${file}")
if (${CMAKE_VERSION} VERSION_LESS "3.26.0")
file(READ "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log" tmp)
else()
file(READ "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml" tmp)
endif()
message(FATAL_ERROR ${tmp})
endif()
unset(file_var)
endforeach()

# foreach(file ${PyPartMC_headers})
# set(CMAKE_REQUIRED_INCLUDES "${PYPARTMC_INCLUDE_DIRS};${pybind11_INCLUDE_DIRS}")
# set(CMAKE_REQUIRED_FLAGS "-Werror")
# string(REGEX REPLACE "[\-./:]" "_" file_var ${file})
# check_cxx_source_compiles("
# // https://github.com/nlohmann/json/issues/1408
# #if defined(_WIN32) || defined(_WIN64)
# # define HAVE_SNPRINTF
# #endif
# #include \"${file}\"
# int main() { return 0;}
# "
# _header_self_contained_${file_var}
# )
# unset(CMAKE_REQUIRED_INCLUDES)
# unset(CMAKE_REQUIRED_FLAGS)
# if (NOT _header_self_contained_${file_var})
# message(SEND_ERROR "non-self-contained header: ${file}")
# if (${CMAKE_VERSION} VERSION_LESS "3.26.0")
# file(READ "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log" tmp)
# else()
# file(READ "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeConfigureLog.yaml" tmp)
# endif()
# message(FATAL_ERROR ${tmp})
# endif()
# unset(file_var)
# endforeach()

_install(TARGETS _PyPartMC LIBRARY DESTINATION PyPartMC)
12 changes: 6 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

## Implementation outline

- PyPartMC is written in C++, Fortran and uses [pybind11](https://pybind11.readthedocs.io/en/stable/) and [CMake](https://cmake.org/).
- JSON support is handled with [nlohmann::json](https://github.com/nlohmann/json) and [pybind11_json](https://github.com/pybind/pybind11_json)
- PyPartMC is written in C++, Fortran and uses [nanobind](https://nanobind.readthedocs.io/) and [CMake](https://cmake.org/).
- JSON support is handled with [nlohmann::json](https://github.com/nlohmann/json) and [nanobind_json](https://github.com/ianhbell/nanobind_json)
- PartMC and selected parts of SUNDIALS are statically linked (and compiled in during `pip install` or `python -m build`)
- C (SUNDIALS, netCDF), C++ (pybind11, ...) and Fortran (PartMC, CAMP, netCDF-fortran) dependencies are linked through [git submodules](https://github.com/open-atmos/PyPartMC/blob/main/.gitmodules)
- C (SUNDIALS, netCDF), C++ (nanobind, ...) and Fortran (PartMC, CAMP, netCDF-fortran) dependencies are linked through [git submodules](https://github.com/open-atmos/PyPartMC/blob/main/.gitmodules)
- MOSAIC dependency is optionally linked through setting the environmental variable `MOSAIC_HOME`
- a [drop-in replacement of the PartMC spec file routines](https://github.com/open-atmos/PyPartMC/blob/main/src/spec_file_pypartmc.F90) is used for i/o from/to JSON

Expand All @@ -23,15 +23,15 @@ flowchart TD
end
subgraph P ["Python"]
python_user_code -.-> NumPy
python_user_code["Python user code"] ---> PyPartMC["pubind11-generated\nPyPartMC module"]
python_user_code["Python user code"] ---> PyPartMC["nanobind-generated\nPyPartMC module"]
matlab_python --> PyPartMC
PyCall.jl --> PyPartMC
end
subgraph Cpp ["C++"]
cpp_user_code["C++ user code"] ----> ppmc_cpp
PyPartMC --> ppmc_cpp["PyPartMC-C++"]
ppmc_cpp --> pybind11_json
pybind11_json ---> nlohmann::JSON
ppmc_cpp --> nanobind_json
nanobind_json ---> nlohmann::JSON
spec_file_pypartmc_cpp --> nlohmann::JSON
end
subgraph C ["C"]
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ print(aero_state.masses()'aero_state.num_concs, "# kg/m3")
notes (see the [PyPartMC Matlab CI workflow](https://github.com/open-atmos/PyPartMC/blob/main/.github/workflows/readme_listings.yml) for an example on how to achieve it on Ubuntu 20):
- Matlab ships with convenience copies of C, C++ and Fortran runtime libraries which are `dlopened()` by default; one way to make PyPartMC OK with it is to [pip-]install by compiling from source using the very same version of GCC that Matlab borrowed these libraries from (e.g., [GCC 9 for Matlab R2022a, etc](https://www.mathworks.com/support/requirements/supported-compilers-linux.html));
- Matlab needs to [use the same Python interpretter/venv](https://www.mathworks.com/support/requirements/python-compatibility.html) as the pip invocation used to install PyPartMC;
- a single-line `pybind11_builtins.py` file with just `pybind11_type=type` inside needs to be placed within Matlab's `PYTHONPATH` to sort out a [Matlab-pybind11 incompatibility](https://github.com/pybind/pybind11/issues/3945).

````Matlab
ppmc = py.importlib.import_module('PyPartMC');
Expand Down
1 change: 1 addition & 0 deletions gitmodules/nanobind
Submodule nanobind added at d4b245
1 change: 1 addition & 0 deletions gitmodules/nanobind_json
Submodule nanobind_json added at 6e9e15
1 change: 0 additions & 1 deletion gitmodules/pybind11
Submodule pybind11 deleted from 68a0b2
1 change: 0 additions & 1 deletion gitmodules/pybind11_json
Submodule pybind11_json deleted from 32043f
45 changes: 45 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[tool.setuptools_scm]
local_scheme = "no-local-version"
version_scheme = "post-release"

[build-system]
requires = ["scikit-build-core >=0.4.3", "nanobind >=1.3.2", "setuptools-scm==8.3.1"]
build-backend = "scikit_build_core.build"

[project]
name = "PyPartMC"
dynamic = ["version"]
description = "Python interface to PartMC"
readme = "README.md"
requires-python = ">=3.8"
authors = [
{name = "https://github.com/open-atmos/PyPartMC/graphs/contributors", email = "[email protected]"}
]
classifiers = [
"License :: GPL-3.0",
]
dependencies = [
"numpy",
"nanobind"
]

[project.optional-dependencies]
tests = [
"pytest",
"pytest-order",
]
examples = [
"matplotlib != 3.10.0",
"ipywidgets",
"voila",
"open-atmos-jupyter-utils",
"PySDM",
"PyMieScatt",
"SciPy",
"dustpy; platform_system != 'Windows'"
]

[project.urls]
Documentation = "https://open-atmos.github.io/PyPartMC"
Source = "https://github.com/open-atmos/PyPartMC/"
Tracker = "https://github.com/open-atmos/PyPartMC/issues"
Loading
Loading