diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c33961d..6028a04 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,7 +5,9 @@ on:
inputs:
debug_enabled:
type: boolean
- description: Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)
+ description:
+ Run the build with tmate debugging enabled
+ (https://github.com/marketplace/actions/debugging-with-tmate)
required: false
default: false
pull_request:
@@ -26,9 +28,9 @@ jobs:
geant4-version:
- 11.1.3
python-version:
- - '3.9'
- - '3.10'
- - '3.11'
+ - "3.9"
+ - "3.10"
+ - "3.11"
runs-on: ${{ matrix.platform }}
defaults:
@@ -79,7 +81,9 @@ jobs:
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
- if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
+ if:
+ ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled
+ }}
with:
limit-access-to-actor: false
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7773502..d84fba6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,5 +1,8 @@
-repos:
+ci:
+ autoupdate_commit_msg: "chore: update pre-commit hooks"
+ autofix_commit_msg: "style: pre-commit fixes"
+repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
@@ -45,10 +48,29 @@ repos:
- id: cmake-format
additional_dependencies: [pyyaml]
- - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
- rev: v2.11.0
+ - repo: https://github.com/adamchainz/blacken-docs
+ rev: "1.16.0"
hooks:
- - id: pretty-format-toml
- args: [--autofix]
- - id: pretty-format-yaml
- args: [--autofix, --indent, '2', --offset, '2']
+ - id: blacken-docs
+ additional_dependencies: [black==23.*]
+
+ - repo: https://github.com/pre-commit/mirrors-prettier
+ rev: "v3.1.0"
+ hooks:
+ - id: prettier
+ types_or: [yaml, markdown, html, css, scss, javascript, json]
+ args: [--prose-wrap=always]
+
+ - repo: https://github.com/codespell-project/codespell
+ rev: "v2.2.6"
+ hooks:
+ - id: codespell
+ exclude: ^Gemfile\.lock$
+ args: ["-Lnd", "-w"]
+
+ - repo: https://github.com/pre-commit/pygrep-hooks
+ rev: "v1.10.0"
+ hooks:
+ - id: rst-backticks
+ - id: rst-directive-colons
+ - id: rst-inline-touching-normal
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c764cd..d2d3f4b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,19 +1,23 @@
-cmake_minimum_required(VERSION 3.25)
+cmake_minimum_required(VERSION 3.15...3.27)
project(
- ${SKBUILD_PROJECT_NAME}
- VERSION ${SKBUILD_PROJECT_VERSION}
- LANGUAGES CXX)
+ ${SKBUILD_PROJECT_NAME}
+ VERSION ${SKBUILD_PROJECT_VERSION}
+ LANGUAGES CXX)
+
+set(PYTHON_MODULE_NAME _core)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_EXTENSIONS OFF)
-find_package(Geant4 REQUIRED CONFIG COMPONENTS gdml)
find_package(
- Python3
- COMPONENTS Interpreter Development.Module
- REQUIRED)
+ Python
+ COMPONENTS Interpreter Development.Module
+ REQUIRED)
+find_package(Geant4 REQUIRED CONFIG COMPONENTS gdml)
+
+message(STATUS "Using Geant4 ${Geant4_VERSION} from ${Geant4_DIR}")
+message(STATUS "Using Python ${Python_VERSION} from ${Python_EXECUTABLE}")
add_subdirectory(external/awkward/header-only)
add_subdirectory(external/pybind11)
@@ -21,38 +25,28 @@ add_subdirectory(external/pybind11)
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/src/geant4/*.cpp")
-set(PYTHON_MODULE_NAME _core)
file(GLOB_RECURSE PYTHON_SOURCES CONFIGURE_DEPENDS
"${PROJECT_SOURCE_DIR}/src/python/*.cpp")
-pybind11_add_module(${PYTHON_MODULE_NAME} ${PYTHON_SOURCES})
-target_compile_options(${PYTHON_MODULE_NAME} PRIVATE -fPIC)
+pybind11_add_module(${PYTHON_MODULE_NAME} ${SOURCES} ${PYTHON_SOURCES})
+
target_compile_definitions(${PYTHON_MODULE_NAME}
PRIVATE VERSION_INFO=${PROJECT_VERSION})
+
target_include_directories(
- ${PYTHON_MODULE_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include
- ${Geant4_INCLUDE_DIRS})
-target_sources(${PYTHON_MODULE_NAME} PRIVATE ${SOURCES})
+ ${PYTHON_MODULE_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include
+ ${Geant4_INCLUDE_DIRS})
+
target_link_libraries(
- ${PYTHON_MODULE_NAME}
- PRIVATE ${Geant4_LIBRARIES}
- awkward::layout-builder
- pybind11::embed
- pybind11::module
- ${Python3_LIBRARY}
- Python3::Module
- pybind11::headers)
+ ${PYTHON_MODULE_NAME} PRIVATE ${Geant4_LIBRARIES} awkward::layout-builder
+ pybind11::headers)
set_target_properties(
- ${PYTHON_MODULE_NAME}
- PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
- ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
- CXX_VISIBILITY_PRESET hidden
- VISIBILITY_INLINES_HIDDEN ON
- CXX_EXTENSIONS NO)
+ ${PYTHON_MODULE_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
+ ${PROJECT_BINARY_DIR}/${PROJECT_NAME})
install(
- TARGETS ${PYTHON_MODULE_NAME}
- LIBRARY DESTINATION ${PROJECT_NAME}
- RUNTIME DESTINATION ${PROJECT_NAME}
- ARCHIVE DESTINATION ${PROJECT_NAME})
+ TARGETS ${PYTHON_MODULE_NAME}
+ LIBRARY DESTINATION ${PROJECT_NAME}
+ RUNTIME DESTINATION ${PROJECT_NAME}
+ ARCHIVE DESTINATION ${PROJECT_NAME})
diff --git a/examples/example.ipynb b/examples/example.ipynb
index 26fcad6..a93f49f 100644
--- a/examples/example.ipynb
+++ b/examples/example.ipynb
@@ -5,27 +5,26 @@
"execution_count": null,
"id": "initial_id",
"metadata": {
- "collapsed": true
+ "collapsed": false
},
"outputs": [],
"source": [
- "from geant4 import Application\n",
+ "from geant4_python_application import Application, basic_gdml\n",
"\n",
"app = Application()\n",
"\n",
- "app.random_seed = 0\n",
"app.setup_manager(n_threads=0)\n",
"app.setup_physics()\n",
- "app.setup_detector() # can take a GDML string as argument\n",
+ "app.setup_detector(gdml=basic_gdml)\n",
"app.setup_action()\n",
"\n",
"app.initialize()\n",
"\n",
- "# if the seed is set to 0, the seed will be randomized\n",
"print(f\"Random seed: {app.random_seed}\")\n",
"\n",
- "# launch 100 events\n",
- "events = app.run(100)"
+ "events = app.run(n_events=100)\n",
+ "\n",
+ "print(events)"
]
}
],
diff --git a/pyproject.toml b/pyproject.toml
index 7ad6c2e..c692eaf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,27 +2,63 @@
build-backend = "scikit_build_core.build"
requires = ["scikit-build-core>=0.3.3", "pybind11"]
-[dependencies]
-awkward = {extras = ["arrow"], version = "2.5.0"}
-
[project]
-description = "Geant4 Python Application"
-name = "geant4_python_application"
version = "0.0.1"
+name = "geant4_python_application"
+description = "Geant4 Python Application"
+readme = "README.md"
+requires-python = ">=3.8"
+
+authors = [
+ {name = "Luis Antonio Obis Aparicio", email = "luis.antonio.obis@gmail.com"},
+]
+classifiers = [
+ "Intended Audience :: Developers",
+ "Intended Audience :: Information Technology",
+ "Intended Audience :: Science/Research",
+ "License :: OSI Approved :: BSD License",
+ "Operating System :: MacOS",
+ "Operating System :: POSIX",
+ "Operating System :: Unix",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3 :: Only",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+ "Topic :: Scientific/Engineering",
+ "Topic :: Scientific/Engineering :: Information Analysis",
+ "Topic :: Scientific/Engineering :: Mathematics",
+ "Topic :: Scientific/Engineering :: Physics",
+ "Topic :: Software Development",
+ "Topic :: Utilities"
+]
+
+dependencies = [
+ "awkward",
+ "numpy",
+]
[project.optional-dependencies]
+dev = [
+ "boost_histogram",
+ "hist",
+ "pandas",
+ "awkward-pandas"
+]
test = ["pytest"]
[tool.cibuildwheel]
build-verbosity = 1
-test-command = "pytest /tests"
+test-command = "pytest tests"
test-extras = ["test"]
test-skip = ["*universal2:arm64"]
[tool.pytest.ini_options]
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
filterwarnings = [
- "error"
+ "error"
]
log_cli_level = "INFO"
minversion = "6.0"
@@ -34,31 +70,31 @@ src = ["src"]
[tool.ruff.lint]
extend-select = [
- "B", # flake8-bugbear
- "I", # isort
- "ARG", # flake8-unused-arguments
- "C4", # flake8-comprehensions
- "EM", # flake8-errmsg
- "ICN", # flake8-import-conventions
- "G", # flake8-logging-format
- "PGH", # pygrep-hooks
- "PIE", # flake8-pie
- "PL", # pylint
- "PT", # flake8-pytest-style
- "PTH", # flake8-use-pathlib
- "RET", # flake8-return
- "RUF", # Ruff-specific
- "SIM", # flake8-simplify
- "T20", # flake8-print
- "UP", # pyupgrade
- "YTT", # flake8-2020
- "EXE", # flake8-executable
- "NPY", # NumPy specific rules
- "PD" # pandas-vet
+ "B", # flake8-bugbear
+ "I", # isort
+ "ARG", # flake8-unused-arguments
+ "C4", # flake8-comprehensions
+ "EM", # flake8-errmsg
+ "ICN", # flake8-import-conventions
+ "G", # flake8-logging-format
+ "PGH", # pygrep-hooks
+ "PIE", # flake8-pie
+ "PL", # pylint
+ "PT", # flake8-pytest-style
+ "PTH", # flake8-use-pathlib
+ "RET", # flake8-return
+ "RUF", # Ruff-specific
+ "SIM", # flake8-simplify
+ "T20", # flake8-print
+ "UP", # pyupgrade
+ "YTT", # flake8-2020
+ "EXE", # flake8-executable
+ "NPY", # NumPy specific rules
+ "PD" # pandas-vet
]
ignore = [
- "PLR09", # Too many X
- "PLR2004" # Magic comparison
+ "PLR09", # Too many X
+ "PLR2004" # Magic comparison
]
isort.required-imports = ["from __future__ import annotations"]
diff --git a/src/geant4_python_application/__init__.py b/src/geant4_python_application/__init__.py
index 1eb8960..4ed85c2 100644
--- a/src/geant4_python_application/__init__.py
+++ b/src/geant4_python_application/__init__.py
@@ -1,6 +1,19 @@
from __future__ import annotations
-lib_path = ""
-# sys.path.append(lib_path)
+from geant4_python_application._core import (
+ Application,
+ PrimaryGeneratorAction,
+ StackingAction,
+ __doc__,
+ __version__,
+)
+from geant4_python_application.gdml import basic_gdml
-from ._core import *
+__all__ = [
+ "__doc__",
+ "__version__",
+ "Application",
+ "PrimaryGeneratorAction",
+ "StackingAction",
+ "basic_gdml",
+]
diff --git a/src/geant4_python_application/gdml.py b/src/geant4_python_application/gdml.py
new file mode 100644
index 0000000..ecbef36
--- /dev/null
+++ b/src/geant4_python_application/gdml.py
@@ -0,0 +1,39 @@
+from __future__ import annotations
+
+basic_gdml = R"""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"""
diff --git a/src/python/module.cpp b/src/python/module.cpp
index 8f00d84..eb829d7 100644
--- a/src/python/module.cpp
+++ b/src/python/module.cpp
@@ -1,60 +1,24 @@
+#include
+
#include "geant4/Application.h"
-#include "pybind11/chrono.h"
-#include "pybind11/complex.h"
-#include "pybind11/functional.h"
-#include "pybind11/pybind11.h"
-#include "pybind11/stl.h"
+#define STRINGIFY(x) #x
+#define MACRO_STRINGIFY(x) STRINGIFY(x)
-using namespace geant4_app;
namespace py = pybind11;
+using namespace geant4_app;
-constexpr const char* basicGdml = R"(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-)";
+PYBIND11_MODULE(_core, m) {
+ m.doc() = R"pbdoc(
+ Geant4 Python Application
+ -------------------------
+ )pbdoc";
-void init_Application(py::module& m) {
py::class_(m, "Application")
.def(py::init<>())
.def("setup_manager", &Application::SetupManager, py::arg("n_threads") = 0)
- .def("setup_detector", &Application::SetupDetector, py::arg("gdml") = basicGdml, py::arg("sensitive_volumes") = py::set())
+ .def("setup_detector", &Application::SetupDetector, py::arg("gdml"), py::arg("sensitive_volumes") = py::set())
.def("setup_physics", &Application::SetupPhysics)
.def("setup_action", &Application::SetupAction)
.def("initialize", &Application::Initialize)
@@ -69,7 +33,7 @@ void init_Application(py::module& m) {
.def_property("detector", &Application::GetDetectorConstruction, nullptr, py::return_value_policy::reference_internal)
.def_property("stacking", &Application::GetStackingAction, nullptr, py::return_value_policy::reference_internal);
- py::class_(m, "PrimaryGenerator")
+ py::class_(m, "PrimaryGeneratorAction")
.def_static("set_energy", &PrimaryGeneratorAction::SetEnergy, py::arg("energy"))
.def_static("set_position", &PrimaryGeneratorAction::SetPosition, py::arg("position"))
.def_static("set_direction", &PrimaryGeneratorAction::SetDirection, py::arg("direction"))
@@ -91,8 +55,10 @@ void init_Application(py::module& m) {
.def_static("get_ignored_particles", &StackingAction::GetIgnoredParticles)
.def_static("ignore_particle", &StackingAction::IgnoreParticle, py::arg("name"))
.def_static("ignore_particle_undo", &StackingAction::IgnoreParticleUndo, py::arg("name"));
-}
-rm PYBIND11_MODULE(_core, m) {
- init_Application(m);
+#ifdef VERSION_INFO
+ m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
+#else
+ m.attr("__version__") = "dev";
+#endif
}
diff --git a/tests/test_application.py b/tests/test_application.py
index f005aa4..80a2628 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -4,12 +4,22 @@
import pytest
import geant4_python_application
+from geant4_python_application import Application, basic_gdml
+def test_imports():
+ assert Application
+ assert geant4_python_application
+ assert geant4_python_application.Application
+ assert geant4_python_application.PrimaryGeneratorAction
+ assert geant4_python_application.StackingAction
+ assert geant4_python_application.__doc__
+ assert geant4_python_application.__version__
+
def test_setup_and_run():
app = geant4_python_application.Application()
app.setup_manager()
- app.setup_detector()
+ app.setup_detector(gdml=basic_gdml)
app.setup_physics()
app.setup_action()
app.initialize()
@@ -28,10 +38,10 @@ def test_missing_manager():
app = geant4_python_application.Application()
with pytest.raises(RuntimeError):
+ app.setup_detector(gdml="")
app.setup_detector()
-
-@pytest.mark.skip(reason="TODO")
+@pytest.mark.skip(reason="Fix segfault")
def test_multiple_apps():
# Could this work somehow?
with pytest.raises(RuntimeError):
@@ -44,8 +54,7 @@ def test_multiple_apps():
app.initialize()
app.run()
-
-# This may not hold for all Geant4 versions
+@pytest.mark.skip(reason="Fix segfault")
def test_seed_single_thread():
app = geant4_python_application.Application()
@@ -90,6 +99,7 @@ def test_seed_single_thread():
assert np.allclose(energy, reference_value, atol=1e-5)
+@pytest.mark.skip(reason="Fix segfault")
def test_event_data_is_cleared():
app = geant4_python_application.Application()