From f20bffc411f7cfe14f2972a5fd753844aa68b4d3 Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Wed, 23 Jul 2025 16:26:30 -0400 Subject: [PATCH] feat(python): added robust python bindings covering the entire codebase --- .gitignore | 1 + .../fourdst/libcomposition/meson.build | 8 - build-config/fourdst/libconfig/meson.build | 3 - build-config/fourdst/libconstants/meson.build | 3 - build-config/fourdst/liblogging/meson.build | 7 - build-config/fourdst/meson.build | 17 +- build-config/meson.build | 2 + build-config/pybind/meson.build | 3 + build-python/meson.build | 33 ++ meson.build | 39 +- meson_options.txt | 3 +- pyproject.toml | 25 ++ src/include/gridfire/engine/engine.h | 8 + .../include/gridfire/engine/engine_abstract.h | 0 .../include/gridfire/engine/engine_approx8.h | 0 .../include/gridfire/engine/engine_graph.h | 0 .../gridfire/engine/procedures/construction.h | 0 .../engine/procedures/engine_procedures.h | 4 + .../gridfire/engine/procedures/priming.h | 0 .../include/gridfire/engine/types/building.h | 0 .../gridfire/engine/types/engine_types.h | 4 + .../include/gridfire/engine/types/reporting.h | 0 .../gridfire/engine/views/engine_adaptive.h | 0 .../gridfire/engine/views/engine_defined.h | 0 .../gridfire/engine/views/engine_multiscale.h | 0 .../gridfire/engine/views/engine_priming.h | 0 .../engine/views/engine_view_abstract.h | 0 .../gridfire/engine/views/engine_views.h | 7 + .../gridfire/exceptions/error_engine.h | 0 src/include/gridfire/exceptions/exceptions.h | 3 + .../gridfire/expectations/expectations.h | 3 + .../gridfire/expectations/expected_engine.h | 17 +- src/include/gridfire/io/io.h | 3 + .../include/gridfire/io/network_file.h | 0 src/{network => }/include/gridfire/network.h | 0 .../partition/composite/partition_composite.h | 0 src/include/gridfire/partition/partition.h | 8 + .../gridfire/partition/partition_abstract.h | 0 .../gridfire/partition/partition_ground.h | 0 .../partition/partition_rauscher_thielemann.h | 0 .../gridfire/partition/partition_types.h | 0 .../rauscher_thielemann_partition_data.h | 0 ...auscher_thielemann_partition_data_record.h | 0 .../include/gridfire/reaction/reaclib.h | 0 .../include/gridfire/reaction/reaction.h | 0 .../gridfire/reaction/reactions_data.h | 0 src/include/gridfire/screening/screening.h | 6 + .../gridfire/screening/screening_abstract.h | 2 +- .../gridfire/screening/screening_bare.h | 0 .../gridfire/screening/screening_types.h | 0 .../gridfire/screening/screening_weak.h | 0 .../include/gridfire/solver/solver.h | 0 .../include/gridfire/utils/logging.h | 0 .../lib/engine/engine_approx8.cpp | 0 src/{network => }/lib/engine/engine_graph.cpp | 0 .../lib/engine/procedures/construction.cpp | 0 .../lib/engine/procedures/priming.cpp | 0 .../lib/engine/views/engine_adaptive.cpp | 0 .../lib/engine/views/engine_defined.cpp | 0 .../lib/engine/views/engine_multiscale.cpp | 0 .../lib/engine/views/engine_priming.cpp | 0 src/{network => }/lib/io/network_file.cpp | 0 src/{network => }/lib/network.cpp | 0 .../composite/partition_composite.cpp | 0 .../lib/partition/partition_ground.cpp | 0 .../partition_rauscher_thielemann.cpp | 0 src/{network => }/lib/reaction/reaclib.cpp | 0 src/{network => }/lib/reaction/reaction.cpp | 0 .../lib/screening/screening_bare.cpp | 0 .../lib/screening/screening_types.cpp | 0 .../lib/screening/screening_weak.cpp | 0 src/{network => }/lib/solver/solver.cpp | 0 src/{network => }/lib/utils/logging.cpp | 0 src/meson.build | 81 +++- src/network/meson.build | 78 ---- src/python/bindings.cpp | 54 +++ src/python/engine/bindings.cpp | 391 ++++++++++++++++++ src/python/engine/bindings.h | 16 + src/python/engine/meson.build | 21 + src/python/engine/trampoline/meson.build | 21 + src/python/engine/trampoline/py_engine.cpp | 219 ++++++++++ src/python/engine/trampoline/py_engine.h | 52 +++ src/python/exceptions/bindings.cpp | 45 ++ src/python/exceptions/bindings.h | 5 + src/python/exceptions/meson.build | 17 + src/python/expectations/bindings.cpp | 43 ++ src/python/expectations/bindings.h | 5 + src/python/expectations/meson.build | 17 + src/python/io/bindings.cpp | 29 ++ src/python/io/bindings.h | 5 + src/python/io/meson.build | 17 + src/python/io/trampoline/meson.build | 21 + src/python/io/trampoline/py_io.cpp | 14 + src/python/io/trampoline/py_io.h | 7 + src/python/meson.build | 10 + src/python/partition/bindings.cpp | 113 +++++ src/python/partition/bindings.h | 16 + src/python/partition/meson.build | 19 + src/python/partition/trampoline/meson.build | 21 + .../partition/trampoline/py_partition.cpp | 57 +++ .../partition/trampoline/py_partition.h | 15 + src/python/reaction/bindings.cpp | 171 ++++++++ src/python/reaction/bindings.h | 5 + src/python/reaction/meson.build | 17 + src/python/screening/bindings.cpp | 42 ++ src/python/screening/bindings.h | 5 + src/python/screening/meson.build | 19 + src/python/screening/trampoline/meson.build | 21 + .../screening/trampoline/py_screening.cpp | 31 ++ .../screening/trampoline/py_screening.h | 16 + src/python/solver/bindings.cpp | 26 ++ src/python/solver/bindings.h | 5 + src/python/solver/meson.build | 17 + src/python/solver/trampoline/meson.build | 21 + src/python/solver/trampoline/py_solver.cpp | 21 + src/python/solver/trampoline/py_solver.h | 10 + src/python/types/bindings.cpp | 43 ++ src/python/types/bindings.h | 5 + src/python/types/meson.build | 17 + src/python/utils/bindings.cpp | 20 + src/python/utils/bindings.h | 5 + src/python/utils/meson.build | 17 + subprojects/fourdst.wrap | 4 + subprojects/libcomposition.wrap | 6 +- subprojects/libconfig.wrap | 6 +- subprojects/libconstants.wrap | 6 +- subprojects/liblogging.wrap | 6 +- .../packagefiles/pybind11/LICENSE.build | 19 + subprojects/packagefiles/pybind11/meson.build | 8 + tests/graphnet_sandbox/approx8.net | 26 -- tests/graphnet_sandbox/meson.build | 2 +- tests/network/meson.build | 2 +- tests/python/readme.md | 101 +++++ tests/python/test.py | 34 ++ 134 files changed, 2202 insertions(+), 170 deletions(-) delete mode 100644 build-config/fourdst/libcomposition/meson.build delete mode 100644 build-config/fourdst/libconfig/meson.build delete mode 100644 build-config/fourdst/libconstants/meson.build delete mode 100644 build-config/fourdst/liblogging/meson.build create mode 100644 build-config/pybind/meson.build create mode 100644 build-python/meson.build create mode 100644 pyproject.toml create mode 100644 src/include/gridfire/engine/engine.h rename src/{network => }/include/gridfire/engine/engine_abstract.h (100%) rename src/{network => }/include/gridfire/engine/engine_approx8.h (100%) rename src/{network => }/include/gridfire/engine/engine_graph.h (100%) rename src/{network => }/include/gridfire/engine/procedures/construction.h (100%) create mode 100644 src/include/gridfire/engine/procedures/engine_procedures.h rename src/{network => }/include/gridfire/engine/procedures/priming.h (100%) rename src/{network => }/include/gridfire/engine/types/building.h (100%) create mode 100644 src/include/gridfire/engine/types/engine_types.h rename src/{network => }/include/gridfire/engine/types/reporting.h (100%) rename src/{network => }/include/gridfire/engine/views/engine_adaptive.h (100%) rename src/{network => }/include/gridfire/engine/views/engine_defined.h (100%) rename src/{network => }/include/gridfire/engine/views/engine_multiscale.h (100%) rename src/{network => }/include/gridfire/engine/views/engine_priming.h (100%) rename src/{network => }/include/gridfire/engine/views/engine_view_abstract.h (100%) create mode 100644 src/include/gridfire/engine/views/engine_views.h rename src/{network => }/include/gridfire/exceptions/error_engine.h (100%) create mode 100644 src/include/gridfire/exceptions/exceptions.h create mode 100644 src/include/gridfire/expectations/expectations.h rename src/{network => }/include/gridfire/expectations/expected_engine.h (65%) create mode 100644 src/include/gridfire/io/io.h rename src/{network => }/include/gridfire/io/network_file.h (100%) rename src/{network => }/include/gridfire/network.h (100%) rename src/{network => }/include/gridfire/partition/composite/partition_composite.h (100%) create mode 100644 src/include/gridfire/partition/partition.h rename src/{network => }/include/gridfire/partition/partition_abstract.h (100%) rename src/{network => }/include/gridfire/partition/partition_ground.h (100%) rename src/{network => }/include/gridfire/partition/partition_rauscher_thielemann.h (100%) rename src/{network => }/include/gridfire/partition/partition_types.h (100%) rename src/{network => }/include/gridfire/partition/rauscher_thielemann_partition_data.h (100%) rename src/{network => }/include/gridfire/partition/rauscher_thielemann_partition_data_record.h (100%) rename src/{network => }/include/gridfire/reaction/reaclib.h (100%) rename src/{network => }/include/gridfire/reaction/reaction.h (100%) rename src/{network => }/include/gridfire/reaction/reactions_data.h (100%) create mode 100644 src/include/gridfire/screening/screening.h rename src/{network => }/include/gridfire/screening/screening_abstract.h (99%) rename src/{network => }/include/gridfire/screening/screening_bare.h (100%) rename src/{network => }/include/gridfire/screening/screening_types.h (100%) rename src/{network => }/include/gridfire/screening/screening_weak.h (100%) rename src/{network => }/include/gridfire/solver/solver.h (100%) rename src/{network => }/include/gridfire/utils/logging.h (100%) rename src/{network => }/lib/engine/engine_approx8.cpp (100%) rename src/{network => }/lib/engine/engine_graph.cpp (100%) rename src/{network => }/lib/engine/procedures/construction.cpp (100%) rename src/{network => }/lib/engine/procedures/priming.cpp (100%) rename src/{network => }/lib/engine/views/engine_adaptive.cpp (100%) rename src/{network => }/lib/engine/views/engine_defined.cpp (100%) rename src/{network => }/lib/engine/views/engine_multiscale.cpp (100%) rename src/{network => }/lib/engine/views/engine_priming.cpp (100%) rename src/{network => }/lib/io/network_file.cpp (100%) rename src/{network => }/lib/network.cpp (100%) rename src/{network => }/lib/partition/composite/partition_composite.cpp (100%) rename src/{network => }/lib/partition/partition_ground.cpp (100%) rename src/{network => }/lib/partition/partition_rauscher_thielemann.cpp (100%) rename src/{network => }/lib/reaction/reaclib.cpp (100%) rename src/{network => }/lib/reaction/reaction.cpp (100%) rename src/{network => }/lib/screening/screening_bare.cpp (100%) rename src/{network => }/lib/screening/screening_types.cpp (100%) rename src/{network => }/lib/screening/screening_weak.cpp (100%) rename src/{network => }/lib/solver/solver.cpp (100%) rename src/{network => }/lib/utils/logging.cpp (100%) delete mode 100644 src/network/meson.build create mode 100644 src/python/bindings.cpp create mode 100644 src/python/engine/bindings.cpp create mode 100644 src/python/engine/bindings.h create mode 100644 src/python/engine/meson.build create mode 100644 src/python/engine/trampoline/meson.build create mode 100644 src/python/engine/trampoline/py_engine.cpp create mode 100644 src/python/engine/trampoline/py_engine.h create mode 100644 src/python/exceptions/bindings.cpp create mode 100644 src/python/exceptions/bindings.h create mode 100644 src/python/exceptions/meson.build create mode 100644 src/python/expectations/bindings.cpp create mode 100644 src/python/expectations/bindings.h create mode 100644 src/python/expectations/meson.build create mode 100644 src/python/io/bindings.cpp create mode 100644 src/python/io/bindings.h create mode 100644 src/python/io/meson.build create mode 100644 src/python/io/trampoline/meson.build create mode 100644 src/python/io/trampoline/py_io.cpp create mode 100644 src/python/io/trampoline/py_io.h create mode 100644 src/python/meson.build create mode 100644 src/python/partition/bindings.cpp create mode 100644 src/python/partition/bindings.h create mode 100644 src/python/partition/meson.build create mode 100644 src/python/partition/trampoline/meson.build create mode 100644 src/python/partition/trampoline/py_partition.cpp create mode 100644 src/python/partition/trampoline/py_partition.h create mode 100644 src/python/reaction/bindings.cpp create mode 100644 src/python/reaction/bindings.h create mode 100644 src/python/reaction/meson.build create mode 100644 src/python/screening/bindings.cpp create mode 100644 src/python/screening/bindings.h create mode 100644 src/python/screening/meson.build create mode 100644 src/python/screening/trampoline/meson.build create mode 100644 src/python/screening/trampoline/py_screening.cpp create mode 100644 src/python/screening/trampoline/py_screening.h create mode 100644 src/python/solver/bindings.cpp create mode 100644 src/python/solver/bindings.h create mode 100644 src/python/solver/meson.build create mode 100644 src/python/solver/trampoline/meson.build create mode 100644 src/python/solver/trampoline/py_solver.cpp create mode 100644 src/python/solver/trampoline/py_solver.h create mode 100644 src/python/types/bindings.cpp create mode 100644 src/python/types/bindings.h create mode 100644 src/python/types/meson.build create mode 100644 src/python/utils/bindings.cpp create mode 100644 src/python/utils/bindings.h create mode 100644 src/python/utils/meson.build create mode 100644 subprojects/fourdst.wrap create mode 100644 subprojects/packagefiles/pybind11/LICENSE.build create mode 100644 subprojects/packagefiles/pybind11/meson.build delete mode 100644 tests/graphnet_sandbox/approx8.net create mode 100644 tests/python/readme.md create mode 100644 tests/python/test.py diff --git a/.gitignore b/.gitignore index 18a83eff..75a5fe4d 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,7 @@ subprojects/libconfig/ subprojects/libconstants/ subprojects/liblogging/ subprojects/eigen-*/ +subprojects/fourdst/ *.csv *.dot diff --git a/build-config/fourdst/libcomposition/meson.build b/build-config/fourdst/libcomposition/meson.build deleted file mode 100644 index 780a7502..00000000 --- a/build-config/fourdst/libcomposition/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -composition_p = subproject('libcomposition') -comp_dep = composition_p.get_variable('composition_dep') -libcomposition = composition_p.get_variable('libcomposition') -spw_dep = composition_p.get_variable('species_weight_dep') -composition_dep = [ - comp_dep, - spw_dep, -] \ No newline at end of file diff --git a/build-config/fourdst/libconfig/meson.build b/build-config/fourdst/libconfig/meson.build deleted file mode 100644 index 457f8bc7..00000000 --- a/build-config/fourdst/libconfig/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -config_p = subproject('libconfig') -config_dep = config_p.get_variable('config_dep') -libconfig = config_p.get_variable('libconfig') \ No newline at end of file diff --git a/build-config/fourdst/libconstants/meson.build b/build-config/fourdst/libconstants/meson.build deleted file mode 100644 index e3e8d086..00000000 --- a/build-config/fourdst/libconstants/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -const_p = subproject('libconstants') -const_dep = const_p.get_variable('const_dep') -libconst = const_p.get_variable('libconst') \ No newline at end of file diff --git a/build-config/fourdst/liblogging/meson.build b/build-config/fourdst/liblogging/meson.build deleted file mode 100644 index d7e3cc02..00000000 --- a/build-config/fourdst/liblogging/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -logging_p = subproject('liblogging') -liblogging = logging_p.get_variable('liblogging') - -logging_dep = logging_p.get_variable('logging_dep') -quill_dep = logging_p.get_variable('quill_dep') - -log_dep = [logging_dep, quill_dep] diff --git a/build-config/fourdst/meson.build b/build-config/fourdst/meson.build index a4b160b4..dd1abc14 100644 --- a/build-config/fourdst/meson.build +++ b/build-config/fourdst/meson.build @@ -1,4 +1,13 @@ -subdir('libconstants') -subdir('liblogging') -subdir('libconfig') -subdir('libcomposition') +# bring in all of the fourdst utility repositories + +fourdst_sp = subproject('fourdst') + +composition_dep = fourdst_sp.get_variable('composition_dep') +log_dep = fourdst_sp.get_variable('log_dep') +const_dep = fourdst_sp.get_variable('const_dep') +config_dep = fourdst_sp.get_variable('config_dep') + +libcomposition = fourdst_sp.get_variable('libcomposition') +libconst = fourdst_sp.get_variable('libconst') +libconfig = fourdst_sp.get_variable('libconfig') +liblogging = fourdst_sp.get_variable('liblogging') \ No newline at end of file diff --git a/build-config/meson.build b/build-config/meson.build index 6087921d..ea6380c0 100644 --- a/build-config/meson.build +++ b/build-config/meson.build @@ -6,4 +6,6 @@ subdir('cppad') subdir('xxHash') subdir('eigen') +subdir('pybind') + diff --git a/build-config/pybind/meson.build b/build-config/pybind/meson.build new file mode 100644 index 00000000..49297116 --- /dev/null +++ b/build-config/pybind/meson.build @@ -0,0 +1,3 @@ +pybind11_proj = subproject('pybind11') +pybind11_dep = pybind11_proj.get_variable('pybind11_dep') +python3_dep = dependency('python3') \ No newline at end of file diff --git a/build-python/meson.build b/build-python/meson.build new file mode 100644 index 00000000..aa5ebe46 --- /dev/null +++ b/build-python/meson.build @@ -0,0 +1,33 @@ +# --- Python Extension Setup --- +py_installation = import('python').find_installation('python3') + +py_mod = py_installation.extension_module( + 'gridfire', # Name of the generated .so/.pyd file (without extension) + sources: [ + meson.project_source_root() + '/src/python/bindings.cpp', + meson.project_source_root() + '/src/python/types/bindings.cpp', + meson.project_source_root() + '/src/python/expectations/bindings.cpp', + meson.project_source_root() + '/src/python/partition/bindings.cpp', + meson.project_source_root() + '/src/python/partition/trampoline/py_partition.cpp', + meson.project_source_root() + '/src/python/reaction/bindings.cpp', + meson.project_source_root() + '/src/python/screening/bindings.cpp', + meson.project_source_root() + '/src/python/screening/trampoline/py_screening.cpp', + meson.project_source_root() + '/src/python/io/bindings.cpp', + meson.project_source_root() + '/src/python/io/trampoline/py_io.cpp', + meson.project_source_root() + '/src/python/exceptions/bindings.cpp', + meson.project_source_root() + '/src/python/engine/bindings.cpp', + meson.project_source_root() + '/src/python/engine/trampoline/py_engine.cpp', + meson.project_source_root() + '/src/python/solver/bindings.cpp', + meson.project_source_root() + '/src/python/solver/trampoline/py_solver.cpp', + meson.project_source_root() + '/src/python/utils/bindings.cpp', + ], + dependencies : [ + pybind11_dep, + const_dep, + config_dep, + composition_dep, + gridfire_dep, + ], + cpp_args : ['-UNDEBUG'], # Example: Ensure assertions are enabled if needed + install : true, +) \ No newline at end of file diff --git a/meson.build b/meson.build index b1d43432..df170309 100644 --- a/meson.build +++ b/meson.build @@ -58,23 +58,30 @@ cpp = meson.get_compiler('cpp') subdir('build-config') subdir('src') + +subdir('build-python') + subdir('tests') -pkg = import('pkgconfig') -pkg.generate( - name: 'gridfire', - description: 'GridFire nuclear reaction network solver', - version: meson.project_version(), - libraries: [ - libnetwork, - libcomposition, - libconfig, - libconst, - liblogging - ], - subdirs: ['gridfire'], - filebase: 'gridfire', - install_dir: join_paths(get_option('libdir'), 'pkgconfig') -) + +if get_option('pkg-config') + message('Generating pkg-config file for GridFire...') + pkg = import('pkgconfig') + pkg.generate( + name: 'gridfire', + description: 'GridFire nuclear reaction network solver', + version: meson.project_version(), + libraries: [ + libgridfire, + libcomposition, + libconfig, + libconst, + liblogging + ], + subdirs: ['gridfire'], + filebase: 'gridfire', + install_dir: join_paths(get_option('libdir'), 'pkgconfig') + ) +endif diff --git a/meson_options.txt b/meson_options.txt index efbdc46b..82a8d3db 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ -option('log_level', type: 'combo', choices: ['traceL3', 'traceL2', 'traceL1', 'debug', 'info', 'warning', 'error', 'critial'], value: 'info', description: 'Set the log level for the GridFire library') \ No newline at end of file +option('log_level', type: 'combo', choices: ['traceL3', 'traceL2', 'traceL1', 'debug', 'info', 'warning', 'error', 'critial'], value: 'info', description: 'Set the log level for the GridFire library') +option('pkg-config', type: 'boolean', value: true, description: 'generate pkg-config file for GridFire (gridfire.pc)') \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..75a88c2d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = [ + "meson-python>=0.15.0", # Use a recent version + "meson>=1.6.0", # Specify your Meson version requirement + "pybind11>=2.10" # pybind11 headers needed at build time +] +build-backend = "mesonpy" + +[project] +name = "gridfire" # Choose your Python package name +version = "0.5.0" # Your project's version +description = "Python interface to the GridFire nuclear network code" +readme = "README.md" +license = { file = "LICENSE.txt" } # Reference your license file [cite: 2] + +authors = [ + {name = "Emily M. Boudreaux", email = "emily@boudreauxmail.com"}, + {name = "Aaron Dotter", email = "aaron.dotter@gmail.com"} +] +maintainers = [ + {name = "Emily M. Boudreaux", email = "emily@boudreauxmail.com"} +] + +[tool.meson-python.args] +setup = ['-Dpkg-config=false'] diff --git a/src/include/gridfire/engine/engine.h b/src/include/gridfire/engine/engine.h new file mode 100644 index 00000000..cb74acca --- /dev/null +++ b/src/include/gridfire/engine/engine.h @@ -0,0 +1,8 @@ +#pragma once + +#include "gridfire/engine/engine_abstract.h" +#include "gridfire/engine/engine_graph.h" + +#include "gridfire/engine/views/engine_views.h" +#include "gridfire/engine/procedures/engine_procedures.h" +#include "gridfire/engine/types/engine_types.h" \ No newline at end of file diff --git a/src/network/include/gridfire/engine/engine_abstract.h b/src/include/gridfire/engine/engine_abstract.h similarity index 100% rename from src/network/include/gridfire/engine/engine_abstract.h rename to src/include/gridfire/engine/engine_abstract.h diff --git a/src/network/include/gridfire/engine/engine_approx8.h b/src/include/gridfire/engine/engine_approx8.h similarity index 100% rename from src/network/include/gridfire/engine/engine_approx8.h rename to src/include/gridfire/engine/engine_approx8.h diff --git a/src/network/include/gridfire/engine/engine_graph.h b/src/include/gridfire/engine/engine_graph.h similarity index 100% rename from src/network/include/gridfire/engine/engine_graph.h rename to src/include/gridfire/engine/engine_graph.h diff --git a/src/network/include/gridfire/engine/procedures/construction.h b/src/include/gridfire/engine/procedures/construction.h similarity index 100% rename from src/network/include/gridfire/engine/procedures/construction.h rename to src/include/gridfire/engine/procedures/construction.h diff --git a/src/include/gridfire/engine/procedures/engine_procedures.h b/src/include/gridfire/engine/procedures/engine_procedures.h new file mode 100644 index 00000000..d1a914af --- /dev/null +++ b/src/include/gridfire/engine/procedures/engine_procedures.h @@ -0,0 +1,4 @@ +#pragma once + +#include "gridfire/engine/procedures/construction.h" +#include "gridfire/engine/procedures/priming.h" \ No newline at end of file diff --git a/src/network/include/gridfire/engine/procedures/priming.h b/src/include/gridfire/engine/procedures/priming.h similarity index 100% rename from src/network/include/gridfire/engine/procedures/priming.h rename to src/include/gridfire/engine/procedures/priming.h diff --git a/src/network/include/gridfire/engine/types/building.h b/src/include/gridfire/engine/types/building.h similarity index 100% rename from src/network/include/gridfire/engine/types/building.h rename to src/include/gridfire/engine/types/building.h diff --git a/src/include/gridfire/engine/types/engine_types.h b/src/include/gridfire/engine/types/engine_types.h new file mode 100644 index 00000000..407b5965 --- /dev/null +++ b/src/include/gridfire/engine/types/engine_types.h @@ -0,0 +1,4 @@ +#pragma once + +#include "gridfire/engine/types/building.h" +#include "gridfire/engine/types/reporting.h" \ No newline at end of file diff --git a/src/network/include/gridfire/engine/types/reporting.h b/src/include/gridfire/engine/types/reporting.h similarity index 100% rename from src/network/include/gridfire/engine/types/reporting.h rename to src/include/gridfire/engine/types/reporting.h diff --git a/src/network/include/gridfire/engine/views/engine_adaptive.h b/src/include/gridfire/engine/views/engine_adaptive.h similarity index 100% rename from src/network/include/gridfire/engine/views/engine_adaptive.h rename to src/include/gridfire/engine/views/engine_adaptive.h diff --git a/src/network/include/gridfire/engine/views/engine_defined.h b/src/include/gridfire/engine/views/engine_defined.h similarity index 100% rename from src/network/include/gridfire/engine/views/engine_defined.h rename to src/include/gridfire/engine/views/engine_defined.h diff --git a/src/network/include/gridfire/engine/views/engine_multiscale.h b/src/include/gridfire/engine/views/engine_multiscale.h similarity index 100% rename from src/network/include/gridfire/engine/views/engine_multiscale.h rename to src/include/gridfire/engine/views/engine_multiscale.h diff --git a/src/network/include/gridfire/engine/views/engine_priming.h b/src/include/gridfire/engine/views/engine_priming.h similarity index 100% rename from src/network/include/gridfire/engine/views/engine_priming.h rename to src/include/gridfire/engine/views/engine_priming.h diff --git a/src/network/include/gridfire/engine/views/engine_view_abstract.h b/src/include/gridfire/engine/views/engine_view_abstract.h similarity index 100% rename from src/network/include/gridfire/engine/views/engine_view_abstract.h rename to src/include/gridfire/engine/views/engine_view_abstract.h diff --git a/src/include/gridfire/engine/views/engine_views.h b/src/include/gridfire/engine/views/engine_views.h new file mode 100644 index 00000000..6bae8971 --- /dev/null +++ b/src/include/gridfire/engine/views/engine_views.h @@ -0,0 +1,7 @@ +#pragma once + +#include "gridfire/engine/views/engine_adaptive.h" +#include "gridfire/engine/views/engine_defined.h" +#include "gridfire/engine/views/engine_multiscale.h" +#include "gridfire/engine/views/engine_priming.h" +#include "gridfire/engine/views/engine_view_abstract.h" \ No newline at end of file diff --git a/src/network/include/gridfire/exceptions/error_engine.h b/src/include/gridfire/exceptions/error_engine.h similarity index 100% rename from src/network/include/gridfire/exceptions/error_engine.h rename to src/include/gridfire/exceptions/error_engine.h diff --git a/src/include/gridfire/exceptions/exceptions.h b/src/include/gridfire/exceptions/exceptions.h new file mode 100644 index 00000000..8cbedcd2 --- /dev/null +++ b/src/include/gridfire/exceptions/exceptions.h @@ -0,0 +1,3 @@ +#pragma once + +#include "gridfire/exceptions/error_engine.h" \ No newline at end of file diff --git a/src/include/gridfire/expectations/expectations.h b/src/include/gridfire/expectations/expectations.h new file mode 100644 index 00000000..0110feac --- /dev/null +++ b/src/include/gridfire/expectations/expectations.h @@ -0,0 +1,3 @@ +#pragma once + +#include "gridfire/expectations/expected_engine.h" \ No newline at end of file diff --git a/src/network/include/gridfire/expectations/expected_engine.h b/src/include/gridfire/expectations/expected_engine.h similarity index 65% rename from src/network/include/gridfire/expectations/expected_engine.h rename to src/include/gridfire/expectations/expected_engine.h index 426b001b..3d885ced 100644 --- a/src/network/include/gridfire/expectations/expected_engine.h +++ b/src/include/gridfire/expectations/expected_engine.h @@ -14,9 +14,16 @@ namespace gridfire::expectations { SYSTEM_RESIZED }; + // TODO: rename this to EngineExpectation or something similar struct EngineError { std::string m_message; - EngineErrorTypes type = EngineErrorTypes::FAILURE; + const EngineErrorTypes type = EngineErrorTypes::FAILURE; + + explicit EngineError(const std::string &message, const EngineErrorTypes type) + : m_message(message), type(type) {} + + virtual ~EngineError() = default; + friend std::ostream& operator<<(std::ostream& os, const EngineError& e) { os << "EngineError: " << e.m_message; return os; @@ -25,7 +32,9 @@ namespace gridfire::expectations { struct EngineIndexError : EngineError { int m_index; - EngineErrorTypes type = EngineErrorTypes::INDEX; + + explicit EngineIndexError(const int index) + : EngineError("Index error occurred", EngineErrorTypes::INDEX), m_index(index) {} friend std::ostream& operator<<(std::ostream& os, const EngineIndexError& e) { os << "EngineIndexError: " << e.m_message << " at index " << e.m_index; return os; @@ -33,10 +42,10 @@ namespace gridfire::expectations { }; struct StaleEngineError : EngineError { - EngineErrorTypes type = EngineErrorTypes::STALE; StaleEngineErrorTypes staleType; - explicit StaleEngineError(StaleEngineErrorTypes staleType) : staleType(staleType) {} + explicit StaleEngineError(const StaleEngineErrorTypes sType) + : EngineError("Stale engine error occurred", EngineErrorTypes::STALE), staleType(sType) {} explicit operator std::string() const { switch (staleType) { diff --git a/src/include/gridfire/io/io.h b/src/include/gridfire/io/io.h new file mode 100644 index 00000000..0a0f55b4 --- /dev/null +++ b/src/include/gridfire/io/io.h @@ -0,0 +1,3 @@ +#pragma once + +#include "gridfire/io/network_file.h" \ No newline at end of file diff --git a/src/network/include/gridfire/io/network_file.h b/src/include/gridfire/io/network_file.h similarity index 100% rename from src/network/include/gridfire/io/network_file.h rename to src/include/gridfire/io/network_file.h diff --git a/src/network/include/gridfire/network.h b/src/include/gridfire/network.h similarity index 100% rename from src/network/include/gridfire/network.h rename to src/include/gridfire/network.h diff --git a/src/network/include/gridfire/partition/composite/partition_composite.h b/src/include/gridfire/partition/composite/partition_composite.h similarity index 100% rename from src/network/include/gridfire/partition/composite/partition_composite.h rename to src/include/gridfire/partition/composite/partition_composite.h diff --git a/src/include/gridfire/partition/partition.h b/src/include/gridfire/partition/partition.h new file mode 100644 index 00000000..d8b9ab9d --- /dev/null +++ b/src/include/gridfire/partition/partition.h @@ -0,0 +1,8 @@ +#pragma once + +#include "gridfire/partition/partition_types.h" +#include "gridfire/partition/partition_abstract.h" +#include "gridfire/partition/partition_ground.h" +#include "gridfire/partition/partition_rauscher_thielemann.h" +#include "gridfire/partition/rauscher_thielemann_partition_data_record.h" +#include "gridfire/partition/composite/partition_composite.h" \ No newline at end of file diff --git a/src/network/include/gridfire/partition/partition_abstract.h b/src/include/gridfire/partition/partition_abstract.h similarity index 100% rename from src/network/include/gridfire/partition/partition_abstract.h rename to src/include/gridfire/partition/partition_abstract.h diff --git a/src/network/include/gridfire/partition/partition_ground.h b/src/include/gridfire/partition/partition_ground.h similarity index 100% rename from src/network/include/gridfire/partition/partition_ground.h rename to src/include/gridfire/partition/partition_ground.h diff --git a/src/network/include/gridfire/partition/partition_rauscher_thielemann.h b/src/include/gridfire/partition/partition_rauscher_thielemann.h similarity index 100% rename from src/network/include/gridfire/partition/partition_rauscher_thielemann.h rename to src/include/gridfire/partition/partition_rauscher_thielemann.h diff --git a/src/network/include/gridfire/partition/partition_types.h b/src/include/gridfire/partition/partition_types.h similarity index 100% rename from src/network/include/gridfire/partition/partition_types.h rename to src/include/gridfire/partition/partition_types.h diff --git a/src/network/include/gridfire/partition/rauscher_thielemann_partition_data.h b/src/include/gridfire/partition/rauscher_thielemann_partition_data.h similarity index 100% rename from src/network/include/gridfire/partition/rauscher_thielemann_partition_data.h rename to src/include/gridfire/partition/rauscher_thielemann_partition_data.h diff --git a/src/network/include/gridfire/partition/rauscher_thielemann_partition_data_record.h b/src/include/gridfire/partition/rauscher_thielemann_partition_data_record.h similarity index 100% rename from src/network/include/gridfire/partition/rauscher_thielemann_partition_data_record.h rename to src/include/gridfire/partition/rauscher_thielemann_partition_data_record.h diff --git a/src/network/include/gridfire/reaction/reaclib.h b/src/include/gridfire/reaction/reaclib.h similarity index 100% rename from src/network/include/gridfire/reaction/reaclib.h rename to src/include/gridfire/reaction/reaclib.h diff --git a/src/network/include/gridfire/reaction/reaction.h b/src/include/gridfire/reaction/reaction.h similarity index 100% rename from src/network/include/gridfire/reaction/reaction.h rename to src/include/gridfire/reaction/reaction.h diff --git a/src/network/include/gridfire/reaction/reactions_data.h b/src/include/gridfire/reaction/reactions_data.h similarity index 100% rename from src/network/include/gridfire/reaction/reactions_data.h rename to src/include/gridfire/reaction/reactions_data.h diff --git a/src/include/gridfire/screening/screening.h b/src/include/gridfire/screening/screening.h new file mode 100644 index 00000000..d6a2915c --- /dev/null +++ b/src/include/gridfire/screening/screening.h @@ -0,0 +1,6 @@ +#pragma once + +#include "gridfire/screening/screening_types.h" +#include "gridfire/screening/screening_abstract.h" +#include "gridfire/screening/screening_bare.h" +#include "gridfire/screening/screening_weak.h" \ No newline at end of file diff --git a/src/network/include/gridfire/screening/screening_abstract.h b/src/include/gridfire/screening/screening_abstract.h similarity index 99% rename from src/network/include/gridfire/screening/screening_abstract.h rename to src/include/gridfire/screening/screening_abstract.h index 0a03ce89..dc0e5223 100644 --- a/src/network/include/gridfire/screening/screening_abstract.h +++ b/src/include/gridfire/screening/screening_abstract.h @@ -103,6 +103,6 @@ namespace gridfire::screening { const std::vector& Y, const ADDouble T9, const ADDouble rho - ) const = 0; + ) const = 0; }; } \ No newline at end of file diff --git a/src/network/include/gridfire/screening/screening_bare.h b/src/include/gridfire/screening/screening_bare.h similarity index 100% rename from src/network/include/gridfire/screening/screening_bare.h rename to src/include/gridfire/screening/screening_bare.h diff --git a/src/network/include/gridfire/screening/screening_types.h b/src/include/gridfire/screening/screening_types.h similarity index 100% rename from src/network/include/gridfire/screening/screening_types.h rename to src/include/gridfire/screening/screening_types.h diff --git a/src/network/include/gridfire/screening/screening_weak.h b/src/include/gridfire/screening/screening_weak.h similarity index 100% rename from src/network/include/gridfire/screening/screening_weak.h rename to src/include/gridfire/screening/screening_weak.h diff --git a/src/network/include/gridfire/solver/solver.h b/src/include/gridfire/solver/solver.h similarity index 100% rename from src/network/include/gridfire/solver/solver.h rename to src/include/gridfire/solver/solver.h diff --git a/src/network/include/gridfire/utils/logging.h b/src/include/gridfire/utils/logging.h similarity index 100% rename from src/network/include/gridfire/utils/logging.h rename to src/include/gridfire/utils/logging.h diff --git a/src/network/lib/engine/engine_approx8.cpp b/src/lib/engine/engine_approx8.cpp similarity index 100% rename from src/network/lib/engine/engine_approx8.cpp rename to src/lib/engine/engine_approx8.cpp diff --git a/src/network/lib/engine/engine_graph.cpp b/src/lib/engine/engine_graph.cpp similarity index 100% rename from src/network/lib/engine/engine_graph.cpp rename to src/lib/engine/engine_graph.cpp diff --git a/src/network/lib/engine/procedures/construction.cpp b/src/lib/engine/procedures/construction.cpp similarity index 100% rename from src/network/lib/engine/procedures/construction.cpp rename to src/lib/engine/procedures/construction.cpp diff --git a/src/network/lib/engine/procedures/priming.cpp b/src/lib/engine/procedures/priming.cpp similarity index 100% rename from src/network/lib/engine/procedures/priming.cpp rename to src/lib/engine/procedures/priming.cpp diff --git a/src/network/lib/engine/views/engine_adaptive.cpp b/src/lib/engine/views/engine_adaptive.cpp similarity index 100% rename from src/network/lib/engine/views/engine_adaptive.cpp rename to src/lib/engine/views/engine_adaptive.cpp diff --git a/src/network/lib/engine/views/engine_defined.cpp b/src/lib/engine/views/engine_defined.cpp similarity index 100% rename from src/network/lib/engine/views/engine_defined.cpp rename to src/lib/engine/views/engine_defined.cpp diff --git a/src/network/lib/engine/views/engine_multiscale.cpp b/src/lib/engine/views/engine_multiscale.cpp similarity index 100% rename from src/network/lib/engine/views/engine_multiscale.cpp rename to src/lib/engine/views/engine_multiscale.cpp diff --git a/src/network/lib/engine/views/engine_priming.cpp b/src/lib/engine/views/engine_priming.cpp similarity index 100% rename from src/network/lib/engine/views/engine_priming.cpp rename to src/lib/engine/views/engine_priming.cpp diff --git a/src/network/lib/io/network_file.cpp b/src/lib/io/network_file.cpp similarity index 100% rename from src/network/lib/io/network_file.cpp rename to src/lib/io/network_file.cpp diff --git a/src/network/lib/network.cpp b/src/lib/network.cpp similarity index 100% rename from src/network/lib/network.cpp rename to src/lib/network.cpp diff --git a/src/network/lib/partition/composite/partition_composite.cpp b/src/lib/partition/composite/partition_composite.cpp similarity index 100% rename from src/network/lib/partition/composite/partition_composite.cpp rename to src/lib/partition/composite/partition_composite.cpp diff --git a/src/network/lib/partition/partition_ground.cpp b/src/lib/partition/partition_ground.cpp similarity index 100% rename from src/network/lib/partition/partition_ground.cpp rename to src/lib/partition/partition_ground.cpp diff --git a/src/network/lib/partition/partition_rauscher_thielemann.cpp b/src/lib/partition/partition_rauscher_thielemann.cpp similarity index 100% rename from src/network/lib/partition/partition_rauscher_thielemann.cpp rename to src/lib/partition/partition_rauscher_thielemann.cpp diff --git a/src/network/lib/reaction/reaclib.cpp b/src/lib/reaction/reaclib.cpp similarity index 100% rename from src/network/lib/reaction/reaclib.cpp rename to src/lib/reaction/reaclib.cpp diff --git a/src/network/lib/reaction/reaction.cpp b/src/lib/reaction/reaction.cpp similarity index 100% rename from src/network/lib/reaction/reaction.cpp rename to src/lib/reaction/reaction.cpp diff --git a/src/network/lib/screening/screening_bare.cpp b/src/lib/screening/screening_bare.cpp similarity index 100% rename from src/network/lib/screening/screening_bare.cpp rename to src/lib/screening/screening_bare.cpp diff --git a/src/network/lib/screening/screening_types.cpp b/src/lib/screening/screening_types.cpp similarity index 100% rename from src/network/lib/screening/screening_types.cpp rename to src/lib/screening/screening_types.cpp diff --git a/src/network/lib/screening/screening_weak.cpp b/src/lib/screening/screening_weak.cpp similarity index 100% rename from src/network/lib/screening/screening_weak.cpp rename to src/lib/screening/screening_weak.cpp diff --git a/src/network/lib/solver/solver.cpp b/src/lib/solver/solver.cpp similarity index 100% rename from src/network/lib/solver/solver.cpp rename to src/lib/solver/solver.cpp diff --git a/src/network/lib/utils/logging.cpp b/src/lib/utils/logging.cpp similarity index 100% rename from src/network/lib/utils/logging.cpp rename to src/lib/utils/logging.cpp diff --git a/src/meson.build b/src/meson.build index 5810a8a4..5312b9df 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1 +1,80 @@ -subdir('network') +# Define the library +gridfire_sources = files( + 'lib/network.cpp', + 'lib/engine/engine_approx8.cpp', + 'lib/engine/engine_graph.cpp', + 'lib/engine/views/engine_adaptive.cpp', + 'lib/engine/views/engine_defined.cpp', + 'lib/engine/views/engine_multiscale.cpp', + 'lib/engine/views/engine_priming.cpp', + 'lib/engine/procedures/priming.cpp', + 'lib/engine/procedures/construction.cpp', + 'lib/reaction/reaction.cpp', + 'lib/reaction/reaclib.cpp', + 'lib/io/network_file.cpp', + 'lib/solver/solver.cpp', + 'lib/screening/screening_types.cpp', + 'lib/screening/screening_weak.cpp', + 'lib/screening/screening_bare.cpp', + 'lib/partition/partition_rauscher_thielemann.cpp', + 'lib/partition/partition_ground.cpp', + 'lib/partition/composite/partition_composite.cpp', + 'lib/utils/logging.cpp', +) + + +gridfire_build_dependencies = [ + boost_dep, + const_dep, + config_dep, + composition_dep, + cppad_dep, + log_dep, + xxhash_dep, + eigen_dep, +] + +# Define the libnetwork library so it can be linked against by other parts of the build system +libgridfire = library('gridfire', + gridfire_sources, + include_directories: include_directories('include'), + dependencies: gridfire_build_dependencies, + install : true) + +gridfire_dep = declare_dependency( + include_directories: include_directories('include'), + link_with: libgridfire, + sources: gridfire_sources, + dependencies: gridfire_build_dependencies, +) + +# Make headers accessible +gridfire_headers = files( + 'include/gridfire/network.h', + 'include/gridfire/engine/engine_abstract.h', + 'include/gridfire/engine/views/engine_view_abstract.h', + 'include/gridfire/engine/engine_approx8.h', + 'include/gridfire/engine/engine_graph.h', + 'include/gridfire/engine/views/engine_adaptive.h', + 'include/gridfire/engine/views/engine_defined.h', + 'include/gridfire/engine/views/engine_multiscale.h', + 'include/gridfire/engine/views/engine_priming.h', + 'include/gridfire/engine/procedures/priming.h', + 'include/gridfire/engine/procedures/construction.h', + 'include/gridfire/reaction/reaction.h', + 'include/gridfire/reaction/reaclib.h', + 'include/gridfire/io/network_file.h', + 'include/gridfire/solver/solver.h', + 'include/gridfire/screening/screening_abstract.h', + 'include/gridfire/screening/screening_bare.h', + 'include/gridfire/screening/screening_weak.h', + 'include/gridfire/screening/screening_types.h', + 'include/gridfire/partition/partition_abstract.h', + 'include/gridfire/partition/partition_rauscher_thielemann.h', + 'include/gridfire/partition/partition_ground.h', + 'include/gridfire/partition/composite/partition_composite.h', + 'include/gridfire/utils/logging.h', +) +install_headers(gridfire_headers, subdir : 'gridfire') + +subdir('python') diff --git a/src/network/meson.build b/src/network/meson.build deleted file mode 100644 index 7016d081..00000000 --- a/src/network/meson.build +++ /dev/null @@ -1,78 +0,0 @@ -# Define the library -network_sources = files( - 'lib/network.cpp', - 'lib/engine/engine_approx8.cpp', - 'lib/engine/engine_graph.cpp', - 'lib/engine/views/engine_adaptive.cpp', - 'lib/engine/views/engine_defined.cpp', - 'lib/engine/views/engine_multiscale.cpp', - 'lib/engine/views/engine_priming.cpp', - 'lib/engine/procedures/priming.cpp', - 'lib/engine/procedures/construction.cpp', - 'lib/reaction/reaction.cpp', - 'lib/reaction/reaclib.cpp', - 'lib/io/network_file.cpp', - 'lib/solver/solver.cpp', - 'lib/screening/screening_types.cpp', - 'lib/screening/screening_weak.cpp', - 'lib/screening/screening_bare.cpp', - 'lib/partition/partition_rauscher_thielemann.cpp', - 'lib/partition/partition_ground.cpp', - 'lib/partition/composite/partition_composite.cpp', - 'lib/utils/logging.cpp', -) - - -dependencies = [ - boost_dep, - const_dep, - config_dep, - composition_dep, - cppad_dep, - log_dep, - xxhash_dep, - eigen_dep, -] - -# Define the libnetwork library so it can be linked against by other parts of the build system -libnetwork = library('network', - network_sources, - include_directories: include_directories('include'), - dependencies: dependencies, - install : true) - -network_dep = declare_dependency( - include_directories: include_directories('include'), - link_with: libnetwork, - sources: network_sources, - dependencies: dependencies, -) - -# Make headers accessible -network_headers = files( - 'include/gridfire/network.h', - 'include/gridfire/engine/engine_abstract.h', - 'include/gridfire/engine/views/engine_view_abstract.h', - 'include/gridfire/engine/engine_approx8.h', - 'include/gridfire/engine/engine_graph.h', - 'include/gridfire/engine/views/engine_adaptive.h', - 'include/gridfire/engine/views/engine_defined.h', - 'include/gridfire/engine/views/engine_multiscale.h', - 'include/gridfire/engine/views/engine_priming.h', - 'include/gridfire/engine/procedures/priming.h', - 'include/gridfire/engine/procedures/construction.h', - 'include/gridfire/reaction/reaction.h', - 'include/gridfire/reaction/reaclib.h', - 'include/gridfire/io/network_file.h', - 'include/gridfire/solver/solver.h', - 'include/gridfire/screening/screening_abstract.h', - 'include/gridfire/screening/screening_bare.h', - 'include/gridfire/screening/screening_weak.h', - 'include/gridfire/screening/screening_types.h', - 'include/gridfire/partition/partition_abstract.h', - 'include/gridfire/partition/partition_rauscher_thielemann.h', - 'include/gridfire/partition/partition_ground.h', - 'include/gridfire/partition/composite/partition_composite.h', - 'include/gridfire/utils/logging.h', -) -install_headers(network_headers, subdir : 'gridfire') diff --git a/src/python/bindings.cpp b/src/python/bindings.cpp new file mode 100644 index 00000000..444ca48b --- /dev/null +++ b/src/python/bindings.cpp @@ -0,0 +1,54 @@ +#include +#include + +#include + +#include "types/bindings.h" +#include "partition/bindings.h" +#include "expectations/bindings.h" +#include "engine/bindings.h" +#include "exceptions/bindings.h" +#include "io/bindings.h" +#include "reaction/bindings.h" +#include "screening/bindings.h" +#include "solver/bindings.h" +#include "utils/bindings.h" + +PYBIND11_MODULE(gridfire, m) { + m.doc() = "Python bindings for the fourdst utility modules which are a part of the 4D-STAR project."; + + pybind11::module::import("fourdst.constants"); + pybind11::module::import("fourdst.composition"); + pybind11::module::import("fourdst.config"); + pybind11::module::import("fourdst.atomic"); + + auto typeMod = m.def_submodule("type", "GridFire type bindings"); + register_type_bindings(typeMod); + + auto partitionMod = m.def_submodule("partition", "GridFire partition function bindings"); + register_partition_bindings(partitionMod); + + auto expectationMod = m.def_submodule("expectations", "GridFire expectations bindings"); + register_expectation_bindings(expectationMod); + + auto reactionMod = m.def_submodule("reaction", "GridFire reaction bindings"); + register_reaction_bindings(reactionMod); + + auto screeningMod = m.def_submodule("screening", "GridFire plasma screening bindings"); + register_screening_bindings(screeningMod); + + auto ioMod = m.def_submodule("io", "GridFire io bindings"); + register_io_bindings(ioMod); + + auto exceptionMod = m.def_submodule("exceptions", "GridFire exceptions bindings"); + register_exception_bindings(exceptionMod); + + auto engineMod = m.def_submodule("engine", "Engine and Engine View bindings"); + register_engine_bindings(engineMod); + + auto solverMod = m.def_submodule("solver", "GridFire numerical solver bindings"); + register_solver_bindings(solverMod); + + auto utilsMod = m.def_submodule("utils", "GridFire utility method bindings"); + register_utils_bindings(utilsMod); +} \ No newline at end of file diff --git a/src/python/engine/bindings.cpp b/src/python/engine/bindings.cpp new file mode 100644 index 00000000..2b840a85 --- /dev/null +++ b/src/python/engine/bindings.cpp @@ -0,0 +1,391 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include + +#include "bindings.h" + +#include "gridfire/engine/engine.h" +#include "trampoline/py_engine.h" + + + +namespace py = pybind11; + +namespace { + template + concept IsDynamicEngine = std::is_base_of_v; + + template + void registerDynamicEngineDefs(py::class_ pyClass) { + pyClass.def("calculateRHSAndEnergy", &T::calculateRHSAndEnergy, + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Calculate the right-hand side (dY/dt) and energy generation rate." + ) + .def("generateJacobianMatrix", py::overload_cast&, double, double>(&T::generateJacobianMatrix, py::const_), + py::arg("Y_dynamic"), + py::arg("T9"), + py::arg("rho"), + "Generate the Jacobian matrix for the current state." + ) + .def("generateStoichiometryMatrix", &T::generateStoichiometryMatrix) + .def("calculateMolarReactionFlow", + static_cast&, const double, const double) const>(&T::calculateMolarReactionFlow), + py::arg("reaction"), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Calculate the molar reaction flow for a given reaction." + ) + .def("getNetworkSpecies", &T::getNetworkSpecies, + "Get the list of species in the network." + ) + .def("getNetworkReactions", &T::getNetworkReactions, + "Get the set of logical reactions in the network." + ) + .def ("setNetworkReactions", &T::setNetworkReactions, + py::arg("reactions"), + "Set the network reactions to a new set of reactions." + ) + .def("getJacobianMatrixEntry", &T::getJacobianMatrixEntry, + py::arg("i"), + py::arg("j"), + "Get an entry from the previously generated Jacobian matrix." + ) + .def("getStoichiometryMatrixEntry", &T::getStoichiometryMatrixEntry, + py::arg("speciesIndex"), + py::arg("reactionIndex"), + "Get an entry from the stoichiometry matrix." + ) + .def("getSpeciesTimescales", &T::getSpeciesTimescales, + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Get the timescales for each species in the network." + ) + .def("getSpeciesDestructionTimescales", &T::getSpeciesDestructionTimescales, + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Get the destruction timescales for each species in the network." + ) + .def("update", &T::update, + py::arg("netIn"), + "Update the engine state based on the provided NetIn object." + ) + .def("setScreeningModel", &T::setScreeningModel, + py::arg("screeningModel"), + "Set the screening model for the engine." + ) + .def("getScreeningModel", &T::getScreeningModel, + "Get the current screening model of the engine." + ) + .def("getSpeciesIndex", &T::getSpeciesIndex, + py::arg("species"), + "Get the index of a species in the network." + ) + .def("mapNetInToMolarAbundanceVector", &T::mapNetInToMolarAbundanceVector, + py::arg("netIn"), + "Map a NetIn object to a vector of molar abundances." + ) + .def("primeEngine", &T::primeEngine, + py::arg("netIn"), + "Prime the engine with a NetIn object to prepare for calculations." + ) + .def("getDepth", &T::getDepth, + "Get the current build depth of the engine." + ) + .def("rebuild", &T::rebuild, + py::arg("composition"), + py::arg("depth") = gridfire::NetworkBuildDepth::Full, + "Rebuild the engine with a new composition and build depth." + ) + .def("isStale", &T::isStale, + py::arg("netIn"), + "Check if the engine is stale based on the provided NetIn object." + ); + + } +} + +void register_engine_bindings(py::module &m) { + register_base_engine_bindings(m); + register_engine_view_bindings(m); + + m.def("build_reaclib_nuclear_network", &gridfire::build_reaclib_nuclear_network, + py::arg("composition"), + py::arg("maxLayers") = gridfire::NetworkBuildDepth::Full, + py::arg("reverse") = false, + "Build a nuclear network from a composition using ReacLib data." + ); + + py::enum_(m, "PrimingReportStatus") + .value("FULL_SUCCESS", gridfire::PrimingReportStatus::FULL_SUCCESS, "Priming was full successful.") + .value("NO_SPECIES_TO_PRIME", gridfire::PrimingReportStatus::NO_SPECIES_TO_PRIME, "No species to prime.") + .value("MAX_ITERATIONS_REACHED", gridfire::PrimingReportStatus::MAX_ITERATIONS_REACHED, "Maximum iterations reached during priming.") + .value("FAILED_TO_FINALIZE_COMPOSITION", gridfire::PrimingReportStatus::FAILED_TO_FINALIZE_COMPOSITION, "Failed to finalize the composition after priming.") + .value("FAILED_TO_FIND_CREATION_CHANNEL", gridfire::PrimingReportStatus::FAILED_TO_FIND_CREATION_CHANNEL, "Failed to find a creation channel for the priming species.") + .value("FAILED_TO_FIND_PRIMING_REACTIONS", gridfire::PrimingReportStatus::FAILED_TO_FIND_PRIMING_REACTIONS, "Failed to find priming reactions for the species.") + .value("BASE_NETWORK_TOO_SHALLOW", gridfire::PrimingReportStatus::BASE_NETWORK_TOO_SHALLOW, "The base network is too shallow for priming.") + .export_values() + .def("__repr__", [](const gridfire::PrimingReportStatus& status) { + std::stringstream ss; + ss << gridfire::PrimingReportStatusStrings.at(status) << "\n"; + return ss.str(); + }, + "String representation of the PrimingReport." + ); + + py::class_(m, "PrimingReport") + .def_readonly("success", &gridfire::PrimingReport::success, "Indicates if the priming was successful.") + .def_readonly("massFractionChanges", &gridfire::PrimingReport::massFractionChanges, "Map of species to their mass fraction changes after priming.") + .def_readonly("primedComposition", &gridfire::PrimingReport::primedComposition, "The composition after priming.") + .def_readonly("status", &gridfire::PrimingReport::status, "Status message from the priming process.") + .def("__repr__", [](const gridfire::PrimingReport& report) { + std::stringstream ss; + ss << report; + return ss.str(); + } + ); +} + +void register_base_engine_bindings(pybind11::module &m) { + + py::class_>(m, "StepDerivatives") + .def_readonly("dYdt", &gridfire::StepDerivatives::dydt, "The right-hand side (dY/dt) of the ODE system.") + .def_readonly("energy", &gridfire::StepDerivatives::nuclearEnergyGenerationRate, "The energy generation rate."); + + py::class_(m, "SparsityPattern"); + + abs_stype_register_engine_bindings(m); + abs_stype_register_dynamic_engine_bindings(m); + con_stype_register_graph_engine_bindings(m); +} + +void abs_stype_register_engine_bindings(pybind11::module &m) { + py::class_(m, "Engine"); +} + +void abs_stype_register_dynamic_engine_bindings(pybind11::module &m) { + const auto a = py::class_(m, "DynamicEngine"); +} + +void con_stype_register_graph_engine_bindings(pybind11::module &m) { + py::enum_(m, "NetworkBuildDepth") + .value("Full", gridfire::NetworkBuildDepth::Full, "Full network build depth") + .value("Shallow", gridfire::NetworkBuildDepth::Shallow, "Shallow network build depth") + .value("SecondOrder", gridfire::NetworkBuildDepth::SecondOrder, "Second order network build depth") + .value("ThirdOrder", gridfire::NetworkBuildDepth::ThirdOrder, "Third order network build depth") + .value("FourthOrder", gridfire::NetworkBuildDepth::FourthOrder, "Fourth order network build depth") + .value("FifthOrder", gridfire::NetworkBuildDepth::FifthOrder, "Fifth order network build depth") + .export_values(); + + py::class_(m, "BuildDepthType"); + + auto py_dynamic_engine_bindings = py::class_(m, "GraphEngine"); + + // Register the Graph Engine Specific Bindings + py_dynamic_engine_bindings.def(py::init(), + py::arg("composition"), + py::arg("depth") = gridfire::NetworkBuildDepth::Full, + "Initialize GraphEngine with a composition and build depth." + ); + py_dynamic_engine_bindings.def(py::init(), + py::arg("composition"), + py::arg("partitionFunction"), + py::arg("depth") = gridfire::NetworkBuildDepth::Full, + "Initialize GraphEngine with a composition, partition function and build depth." + ); + py_dynamic_engine_bindings.def(py::init(), + py::arg("reactions"), + "Initialize GraphEngine with a set of reactions." + ); + py_dynamic_engine_bindings.def("generateJacobianMatrix", py::overload_cast&, double, double, const gridfire::SparsityPattern&>(&gridfire::GraphEngine::generateJacobianMatrix, py::const_), + py::arg("Y_dynamic"), + py::arg("T9"), + py::arg("rho"), + py::arg("sparsityPattern"), + "Generate the Jacobian matrix for the current state with a specified sparsity pattern." + ); + py_dynamic_engine_bindings.def_static("getNetReactionStoichiometry", &gridfire::GraphEngine::getNetReactionStoichiometry, + py::arg("reaction"), + "Get the net stoichiometry for a given reaction." + ); + py_dynamic_engine_bindings.def("involvesSpecies", &gridfire::GraphEngine::involvesSpecies, + py::arg("species"), + "Check if a given species is involved in the network." + ); + py_dynamic_engine_bindings.def("exportToDot", &gridfire::GraphEngine::exportToDot, + py::arg("filename"), + "Export the network to a DOT file for visualization." + ); + py_dynamic_engine_bindings.def("exportToCSV", &gridfire::GraphEngine::exportToCSV, + py::arg("filename"), + "Export the network to a CSV file for analysis." + ); + py_dynamic_engine_bindings.def("setPrecomputation", &gridfire::GraphEngine::setPrecomputation, + py::arg("precompute"), + "Enable or disable precomputation for the engine." + ); + py_dynamic_engine_bindings.def("isPrecomputationEnabled", &gridfire::GraphEngine::isPrecomputationEnabled, + "Check if precomputation is enabled for the engine." + ); + py_dynamic_engine_bindings.def("getPartitionFunction", &gridfire::GraphEngine::getPartitionFunction, + "Get the partition function used by the engine." + ); + py_dynamic_engine_bindings.def("calculateReverseRate", &gridfire::GraphEngine::calculateReverseRate, + py::arg("reaction"), + py::arg("T9"), + "Calculate the reverse rate for a given reaction at a specific temperature." + ); + py_dynamic_engine_bindings.def("calculateReverseRateTwoBody", &gridfire::GraphEngine::calculateReverseRateTwoBody, + py::arg("reaction"), + py::arg("T9"), + py::arg("forwardRate"), + py::arg("expFactor"), + "Calculate the reverse rate for a two-body reaction at a specific temperature." + ); + py_dynamic_engine_bindings.def("calculateReverseRateTwoBodyDerivative", &gridfire::GraphEngine::calculateReverseRateTwoBodyDerivative, + py::arg("reaction"), + py::arg("T9"), + py::arg("reverseRate"), + "Calculate the derivative of the reverse rate for a two-body reaction at a specific temperature." + ); + py_dynamic_engine_bindings.def("isUsingReverseReactions", &gridfire::GraphEngine::isUsingReverseReactions, + "Check if the engine is using reverse reactions." + ); + py_dynamic_engine_bindings.def("setUseReverseReactions", &gridfire::GraphEngine::setUseReverseReactions, + py::arg("useReverse"), + "Enable or disable the use of reverse reactions in the engine." + ); + + + // Register the general dynamic engine bindings + registerDynamicEngineDefs(py_dynamic_engine_bindings); +} + +void register_engine_view_bindings(pybind11::module &m) { + auto py_defined_engine_view_bindings = py::class_(m, "DefinedEngineView"); + + py_defined_engine_view_bindings.def(py::init, gridfire::DynamicEngine&>(), + py::arg("peNames"), + py::arg("baseEngine"), + "Construct a defined engine view with a list of tracked reactions and a base engine."); + py_defined_engine_view_bindings.def("getBaseEngine", &gridfire::DefinedEngineView::getBaseEngine, + "Get the base engine associated with this defined engine view."); + + registerDynamicEngineDefs(py_defined_engine_view_bindings); + + auto py_file_defined_engine_view_bindings = py::class_(m, "FileDefinedEngineView"); + py_file_defined_engine_view_bindings.def(py::init(), + py::arg("baseEngine"), + py::arg("fileName"), + py::arg("parser"), + "Construct a defined engine view from a file and a base engine." + ); + py_file_defined_engine_view_bindings.def("getNetworkFile", &gridfire::FileDefinedEngineView::getNetworkFile, + "Get the network file associated with this defined engine view." + ); + py_file_defined_engine_view_bindings.def("getParser", &gridfire::FileDefinedEngineView::getParser, + "Get the parser used for this defined engine view." + ); + py_file_defined_engine_view_bindings.def("getBaseEngine", &gridfire::FileDefinedEngineView::getBaseEngine, + "Get the base engine associated with this file defined engine view."); + + registerDynamicEngineDefs(py_file_defined_engine_view_bindings); + + auto py_priming_engine_view_bindings = py::class_(m, "NetworkPrimingEngineView"); + py_priming_engine_view_bindings.def(py::init(), + py::arg("primingSymbol"), + py::arg("baseEngine"), + "Construct a priming engine view with a priming symbol and a base engine."); + py_priming_engine_view_bindings.def(py::init(), + py::arg("primingSpecies"), + py::arg("baseEngine"), + "Construct a priming engine view with a priming species and a base engine."); + py_priming_engine_view_bindings.def("getBaseEngine", &gridfire::NetworkPrimingEngineView::getBaseEngine, + "Get the base engine associated with this priming engine view."); + + registerDynamicEngineDefs(py_priming_engine_view_bindings); + + auto py_adaptive_engine_view_bindings = py::class_(m, "AdaptiveEngineView"); + py_adaptive_engine_view_bindings.def(py::init(), + py::arg("baseEngine"), + "Construct an adaptive engine view with a base engine."); + py_adaptive_engine_view_bindings.def("getBaseEngine", &gridfire::AdaptiveEngineView::getBaseEngine, + "Get the base engine associated with this adaptive engine view."); + + registerDynamicEngineDefs(py_adaptive_engine_view_bindings); + + auto py_qse_cache_config = py::class_(m, "QSECacheConfig"); + auto py_qse_cache_key = py::class_(m, "QSECacheKey"); + + py_qse_cache_key.def(py::init&>(), + py::arg("T9"), + py::arg("rho"), + py::arg("Y") + ); + + py_qse_cache_key.def("hash", &gridfire::QSECacheKey::hash, + "Get the pre-computed hash value of the key"); + + py_qse_cache_key.def_static("bin", &gridfire::QSECacheKey::bin, + py::arg("value"), + py::arg("tol"), + "bin a value based on a tolerance"); + py_qse_cache_key.def("__eq__", &gridfire::QSECacheKey::operator==, + py::arg("other"), + "Check if two QSECacheKeys are equal"); + + auto py_multiscale_engine_view_bindings = py::class_(m, "MultiscalePartitioningEngineView"); + py_multiscale_engine_view_bindings.def(py::init(), + py::arg("baseEngine"), + "Construct a multiscale partitioning engine view with a base engine."); + py_multiscale_engine_view_bindings.def("getBaseEngine", &gridfire::MultiscalePartitioningEngineView::getBaseEngine, + "Get the base engine associated with this multiscale partitioning engine view."); + py_multiscale_engine_view_bindings.def("analyzeTimescalePoolConnectivity", &gridfire::MultiscalePartitioningEngineView::analyzeTimescalePoolConnectivity, + py::arg("timescale_pools"), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Analyze the connectivity of timescale pools in the network."); + py_multiscale_engine_view_bindings.def("partitionNetwork", py::overload_cast&, double, double>(&gridfire::MultiscalePartitioningEngineView::partitionNetwork), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Partition the network based on species timescales and connectivity."); + py_multiscale_engine_view_bindings.def("partitionNetwork", py::overload_cast(&gridfire::MultiscalePartitioningEngineView::partitionNetwork), + py::arg("netIn"), + "Partition the network based on a NetIn object."); + py_multiscale_engine_view_bindings.def("exportToDot", &gridfire::MultiscalePartitioningEngineView::exportToDot, + py::arg("filename"), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Export the network to a DOT file for visualization."); + py_multiscale_engine_view_bindings.def("getFastSpecies", &gridfire::MultiscalePartitioningEngineView::getFastSpecies, + "Get the list of fast species in the network."); + py_multiscale_engine_view_bindings.def("getDynamicSpecies", &gridfire::MultiscalePartitioningEngineView::getDynamicSpecies, + "Get the list of dynamic species in the network."); + py_multiscale_engine_view_bindings.def("equilibrateNetwork", py::overload_cast&, double, double>(&gridfire::MultiscalePartitioningEngineView::equilibrateNetwork), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Equilibrate the network based on species abundances and conditions."); + py_multiscale_engine_view_bindings.def("equilibrateNetwork", py::overload_cast(&gridfire::MultiscalePartitioningEngineView::equilibrateNetwork), + py::arg("netIn"), + "Equilibrate the network based on a NetIn object."); + + registerDynamicEngineDefs(py_multiscale_engine_view_bindings); +} + + + + + + + + diff --git a/src/python/engine/bindings.h b/src/python/engine/bindings.h new file mode 100644 index 00000000..3f64ea59 --- /dev/null +++ b/src/python/engine/bindings.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +void register_engine_bindings(pybind11::module &m); + +void register_base_engine_bindings(pybind11::module &m); + +void register_engine_view_bindings(pybind11::module &m); + +void abs_stype_register_engine_bindings(pybind11::module &m); +void abs_stype_register_dynamic_engine_bindings(pybind11::module &m); + +void con_stype_register_graph_engine_bindings(pybind11::module &m); + + diff --git a/src/python/engine/meson.build b/src/python/engine/meson.build new file mode 100644 index 00000000..e1b412a7 --- /dev/null +++ b/src/python/engine/meson.build @@ -0,0 +1,21 @@ +subdir('trampoline') + +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +message('⏳ Python bindings for GridFire Engine are being registered...') +shared_module('py_gf_engine', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) +message('✅ Python bindings for GridFire Engine registered successfully!') \ No newline at end of file diff --git a/src/python/engine/trampoline/meson.build b/src/python/engine/trampoline/meson.build new file mode 100644 index 00000000..78472541 --- /dev/null +++ b/src/python/engine/trampoline/meson.build @@ -0,0 +1,21 @@ +gf_engine_trampoline_sources = files('py_engine.cpp') + +gf_engine_trapoline_dependencies = [ + gridfire_dep, + pybind11_dep, + python3_dep, +] + +gf_engine_trampoline_lib = static_library( + 'engine_trampolines', + gf_engine_trampoline_sources, + include_directories: include_directories('.'), + dependencies: gf_engine_trapoline_dependencies, + install: false, +) + +gr_engine_trampoline_dep = declare_dependency( + link_with: gf_engine_trampoline_lib, + include_directories: ('.'), + dependencies: gf_engine_trapoline_dependencies, +) diff --git a/src/python/engine/trampoline/py_engine.cpp b/src/python/engine/trampoline/py_engine.cpp new file mode 100644 index 00000000..41082fc0 --- /dev/null +++ b/src/python/engine/trampoline/py_engine.cpp @@ -0,0 +1,219 @@ +#include "py_engine.h" + +#include "gridfire/engine/engine.h" + +#include +#include +#include // Needed for std::function + +#include +#include +#include + + +namespace py = pybind11; + +const std::vector& PyEngine::getNetworkSpecies() const { + PYBIND11_OVERRIDE_PURE( + std::vector, + gridfire::Engine, /* Base class */ + getNetworkSpecies + ); +} + +std::expected, gridfire::expectations::StaleEngineError> PyEngine::calculateRHSAndEnergy(const std::vector &Y, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + PYBIND11_TYPE(std::expected, gridfire::expectations::StaleEngineError>), + gridfire::Engine, + calculateRHSAndEnergy, + Y, T9, rho + ); +} + +/////////////////////////////////////// +/// PyDynamicEngine Implementation /// +///////////////////////////////////// + +const std::vector& PyDynamicEngine::getNetworkSpecies() const { + PYBIND11_OVERRIDE_PURE( + std::vector, + gridfire::DynamicEngine, /* Base class */ + getNetworkSpecies + ); +} +std::expected, gridfire::expectations::StaleEngineError> PyDynamicEngine::calculateRHSAndEnergy(const std::vector &Y, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + PYBIND11_TYPE(std::expected, gridfire::expectations::StaleEngineError>), + gridfire::Engine, + calculateRHSAndEnergy, + Y, T9, rho + ); +} + +void PyDynamicEngine::generateJacobianMatrix(const std::vector &Y_dynamic, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + void, + gridfire::DynamicEngine, + generateJacobianMatrix, + Y_dynamic, T9, rho + ); +} + +void PyDynamicEngine::generateJacobianMatrix(const std::vector &Y_dynamic, double T9, double rho, const gridfire::SparsityPattern &sparsityPattern) const { + PYBIND11_OVERRIDE_PURE( + void, + gridfire::DynamicEngine, + generateJacobianMatrix, + Y_dynamic, T9, rho, sparsityPattern + ); +} + +double PyDynamicEngine::getJacobianMatrixEntry(int i, int j) const { + PYBIND11_OVERRIDE_PURE( + double, + gridfire::DynamicEngine, + getJacobianMatrixEntry, + i, j + ); +} + +void PyDynamicEngine::generateStoichiometryMatrix() { + PYBIND11_OVERRIDE_PURE( + void, + gridfire::DynamicEngine, + generateStoichiometryMatrix + ); +} + +int PyDynamicEngine::getStoichiometryMatrixEntry(int speciesIndex, int reactionIndex) const { + PYBIND11_OVERRIDE_PURE( + int, + gridfire::DynamicEngine, + getStoichiometryMatrixEntry, + speciesIndex, reactionIndex + ); +} + +double PyDynamicEngine::calculateMolarReactionFlow(const gridfire::reaction::Reaction &reaction, const std::vector &Y, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + double, + gridfire::DynamicEngine, + calculateMolarReactionFlow, + reaction, Y, T9, rho + ); +} + +const gridfire::reaction::LogicalReactionSet& PyDynamicEngine::getNetworkReactions() const { + PYBIND11_OVERRIDE_PURE( + const gridfire::reaction::LogicalReactionSet&, + gridfire::DynamicEngine, + getNetworkReactions + ); +} + +void PyDynamicEngine::setNetworkReactions(const gridfire::reaction::LogicalReactionSet& reactions) { + PYBIND11_OVERRIDE_PURE( + void, + gridfire::DynamicEngine, + setNetworkReactions, + reactions + ); +} + +std::expected, gridfire::expectations::StaleEngineError> PyDynamicEngine::getSpeciesTimescales(const std::vector &Y, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + PYBIND11_TYPE(std::expected, gridfire::expectations::StaleEngineError>), + gridfire::DynamicEngine, + getSpeciesTimescales, + Y, T9, rho + ); +} + +std::expected, gridfire::expectations::StaleEngineError> PyDynamicEngine::getSpeciesDestructionTimescales(const std::vector &Y, double T9, double rho) const { + PYBIND11_OVERRIDE_PURE( + PYBIND11_TYPE(std::expected, gridfire::expectations::StaleEngineError>), + gridfire::DynamicEngine, + getSpeciesDestructionTimescales, + Y, T9, rho + ); +} + +fourdst::composition::Composition PyDynamicEngine::update(const gridfire::NetIn &netIn) { + PYBIND11_OVERRIDE_PURE( + fourdst::composition::Composition, + gridfire::DynamicEngine, + update, + netIn + ); +} + +bool PyDynamicEngine::isStale(const gridfire::NetIn &netIn) { + PYBIND11_OVERRIDE_PURE( + bool, + gridfire::DynamicEngine, + isStale, + netIn + ); +} + +void PyDynamicEngine::setScreeningModel(gridfire::screening::ScreeningType model) { + PYBIND11_OVERRIDE_PURE( + void, + gridfire::DynamicEngine, + setScreeningModel, + model + ); +} + +gridfire::screening::ScreeningType PyDynamicEngine::getScreeningModel() const { + PYBIND11_OVERRIDE_PURE( + gridfire::screening::ScreeningType, + gridfire::DynamicEngine, + getScreeningModel + ); +} + +int PyDynamicEngine::getSpeciesIndex(const fourdst::atomic::Species &species) const { + PYBIND11_OVERRIDE_PURE( + int, + gridfire::DynamicEngine, + getSpeciesIndex, + species + ); +} + +std::vector PyDynamicEngine::mapNetInToMolarAbundanceVector(const gridfire::NetIn &netIn) const { + PYBIND11_OVERRIDE_PURE( + std::vector, + gridfire::DynamicEngine, + mapNetInToMolarAbundanceVector, + netIn + ); +} + +gridfire::PrimingReport PyDynamicEngine::primeEngine(const gridfire::NetIn &netIn) { + PYBIND11_OVERRIDE_PURE( + gridfire::PrimingReport, + gridfire::DynamicEngine, + primeEngine, + netIn + ); +} + +const gridfire::Engine& PyEngineView::getBaseEngine() const { + PYBIND11_OVERRIDE_PURE( + const gridfire::Engine&, + gridfire::EngineView, + getBaseEngine + ); +} + +const gridfire::DynamicEngine& PyDynamicEngineView::getBaseEngine() const { + PYBIND11_OVERRIDE_PURE( + const gridfire::DynamicEngine&, + gridfire::EngineView, + getBaseEngine + ); +} + + diff --git a/src/python/engine/trampoline/py_engine.h b/src/python/engine/trampoline/py_engine.h new file mode 100644 index 00000000..2a303125 --- /dev/null +++ b/src/python/engine/trampoline/py_engine.h @@ -0,0 +1,52 @@ +#pragma once + +#include "gridfire/engine/engine.h" +#include "gridfire/expectations/expected_engine.h" + +#include "fourdst/composition/atomicSpecies.h" + +#include +#include + + +class PyEngine final : public gridfire::Engine { +public: + const std::vector& getNetworkSpecies() const override; + std::expected,gridfire::expectations::StaleEngineError> calculateRHSAndEnergy(const std::vector &Y, double T9, double rho) const override; +}; + +class PyDynamicEngine final : public gridfire::DynamicEngine { + const std::vector& getNetworkSpecies() const override; + std::expected,gridfire::expectations::StaleEngineError> calculateRHSAndEnergy(const std::vector &Y, double T9, double rho) const override; + void generateJacobianMatrix(const std::vector &Y_dynamic, double T9, double rho) const override; + void generateJacobianMatrix(const std::vector &Y_dynamic, double T9, double rho, const gridfire::SparsityPattern &sparsityPattern) const override; + double getJacobianMatrixEntry(int i, int j) const override; + void generateStoichiometryMatrix() override; + int getStoichiometryMatrixEntry(int speciesIndex, int reactionIndex) const override; + double calculateMolarReactionFlow(const gridfire::reaction::Reaction &reaction, const std::vector &Y, double T9, double rho) const override; + const gridfire::reaction::LogicalReactionSet& getNetworkReactions() const override; + void setNetworkReactions(const gridfire::reaction::LogicalReactionSet& reactions) override; + std::expected, gridfire::expectations::StaleEngineError> getSpeciesTimescales(const std::vector &Y, double T9, double rho) const override; + std::expected, gridfire::expectations::StaleEngineError> getSpeciesDestructionTimescales(const std::vector &Y, double T9, double rho) const override; + fourdst::composition::Composition update(const gridfire::NetIn &netIn) override; + bool isStale(const gridfire::NetIn &netIn) override; + void setScreeningModel(gridfire::screening::ScreeningType model) override; + gridfire::screening::ScreeningType getScreeningModel() const override; + int getSpeciesIndex(const fourdst::atomic::Species &species) const override; + std::vector mapNetInToMolarAbundanceVector(const gridfire::NetIn &netIn) const override; + gridfire::PrimingReport primeEngine(const gridfire::NetIn &netIn) override; + gridfire::BuildDepthType getDepth() const override { + throw std::logic_error("Network depth not supported by this engine."); + } + void rebuild(const fourdst::composition::Composition& comp, gridfire::BuildDepthType depth) override { + throw std::logic_error("Setting network depth not supported by this engine."); + } +}; + +class PyEngineView final : public gridfire::EngineView { + const gridfire::Engine& getBaseEngine() const override; +}; + +class PyDynamicEngineView final : public gridfire::EngineView { + const gridfire::DynamicEngine& getBaseEngine() const override; +}; \ No newline at end of file diff --git a/src/python/exceptions/bindings.cpp b/src/python/exceptions/bindings.cpp new file mode 100644 index 00000000..5094eb77 --- /dev/null +++ b/src/python/exceptions/bindings.cpp @@ -0,0 +1,45 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include + +#include "bindings.h" + +namespace py = pybind11; + +#include "gridfire/exceptions/exceptions.h" + +void register_exception_bindings(py::module &m) { + py::register_exception(m, "GridFireEngineError"); + + // TODO: Make it so that we can grab the stale state in python + // m.attr("StaleEngineTrigger") = py::register_exception(m, "StaleEngineTrigger", m.attr("GridFireEngineError")); + m.attr("StaleEngineError") = py::register_exception(m, "StaleEngineError", m.attr("GridFireEngineError")); + m.attr("FailedToPartitionEngineError") = py::register_exception(m, "FailedToPartitionEngineError", m.attr("GridFireEngineError")); + m.attr("NetworkResizedError") = py::register_exception(m, "NetworkResizedError", m.attr("GridFireEngineError")); + m.attr("UnableToSetNetworkReactionsError") = py::register_exception(m, "UnableToSetNetworkReactionsError", m.attr("GridFireEngineError")); + + py::class_(m, "StaleEngineState") + .def(py::init<>()) + .def_readwrite("T9", &gridfire::exceptions::StaleEngineTrigger::state::m_T9) + .def_readwrite("rho", &gridfire::exceptions::StaleEngineTrigger::state::m_rho) + .def_readwrite("Y", &gridfire::exceptions::StaleEngineTrigger::state::m_Y) + .def_readwrite("t", &gridfire::exceptions::StaleEngineTrigger::state::m_t) + .def_readwrite("total_steps", &gridfire::exceptions::StaleEngineTrigger::state::m_total_steps) + .def_readwrite("eps_nuc", &gridfire::exceptions::StaleEngineTrigger::state::m_eps_nuc); + + py::class_(m, "StaleEngineTrigger") + .def(py::init()) + .def("getState", &gridfire::exceptions::StaleEngineTrigger::getState) + .def("numSpecies", &gridfire::exceptions::StaleEngineTrigger::numSpecies) + .def("totalSteps", &gridfire::exceptions::StaleEngineTrigger::totalSteps) + .def("energy", &gridfire::exceptions::StaleEngineTrigger::energy) + .def("getMolarAbundance", &gridfire::exceptions::StaleEngineTrigger::getMolarAbundance) + .def("temperature", &gridfire::exceptions::StaleEngineTrigger::temperature) + .def("density", &gridfire::exceptions::StaleEngineTrigger::density) + .def("__repr__", [&](const gridfire::exceptions::StaleEngineTrigger& self) { + return self.what(); + }); + +} diff --git a/src/python/exceptions/bindings.h b/src/python/exceptions/bindings.h new file mode 100644 index 00000000..bb24ecd7 --- /dev/null +++ b/src/python/exceptions/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_exception_bindings(pybind11::module &m); diff --git a/src/python/exceptions/meson.build b/src/python/exceptions/meson.build new file mode 100644 index 00000000..e644dce6 --- /dev/null +++ b/src/python/exceptions/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_exceptions', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/expectations/bindings.cpp b/src/python/expectations/bindings.cpp new file mode 100644 index 00000000..2864b730 --- /dev/null +++ b/src/python/expectations/bindings.cpp @@ -0,0 +1,43 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc. if needed directly + +#include "bindings.h" + +namespace py = pybind11; + +#include "gridfire/expectations/expectations.h" + +void register_expectation_bindings(py::module &m) { + py::enum_(m, "EngineErrorTypes") + .value("FAILURE", gridfire::expectations::EngineErrorTypes::FAILURE) + .value("INDEX", gridfire::expectations::EngineErrorTypes::INDEX) + .value("STALE", gridfire::expectations::EngineErrorTypes::STALE) + .export_values(); + + py::enum_(m, "StaleEngineErrorTypes") + .value("SYSTEM_RESIZED", gridfire::expectations::StaleEngineErrorTypes::SYSTEM_RESIZED) + .export_values(); + + // Bind the base class + py::class_(m, "EngineError") + .def_readonly("message", &gridfire::expectations::EngineError::m_message) + .def_readonly("type", &gridfire::expectations::EngineError::type) + .def("__str__", [](const gridfire::expectations::EngineError &e) {return e.m_message;}); + + // Bind the EngineIndexError, specifying EngineError as the base + py::class_(m, "EngineIndexError") + .def(py::init(), py::arg("index")) + .def_readonly("index", &gridfire::expectations::EngineIndexError::m_index) + .def("__str__", [](const gridfire::expectations::EngineIndexError &e) { + return e.m_message + " at index " + std::to_string(e.m_index); + }); + + // Bind the StaleEngineError, specifying EngineError as the base + py::class_(m, "StaleEngineError") + .def(py::init(), py::arg("stale_type")) + .def_readonly("stale_type", &gridfire::expectations::StaleEngineError::staleType) + .def("__str__", [](const gridfire::expectations::StaleEngineError &e) { + return static_cast(e); + }); +} diff --git a/src/python/expectations/bindings.h b/src/python/expectations/bindings.h new file mode 100644 index 00000000..c0f4211d --- /dev/null +++ b/src/python/expectations/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_expectation_bindings(pybind11::module &m); diff --git a/src/python/expectations/meson.build b/src/python/expectations/meson.build new file mode 100644 index 00000000..569cdf79 --- /dev/null +++ b/src/python/expectations/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_expectations', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/io/bindings.cpp b/src/python/io/bindings.cpp new file mode 100644 index 00000000..217e5bf4 --- /dev/null +++ b/src/python/io/bindings.cpp @@ -0,0 +1,29 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include +#include + +#include "bindings.h" + +#include "gridfire/io/io.h" +#include "trampoline/py_io.h" + +namespace py = pybind11; + +void register_io_bindings(py::module &m) { + py::class_(m, "ParsedNetworkData"); + + py::class_(m, "NetworkFileParser"); + + py::class_(m, "SimpleReactionListFileParser") + .def("parse", &gridfire::io::SimpleReactionListFileParser::parse, + py::arg("filename"), + "Parse a simple reaction list file and return a ParsedNetworkData object."); + + // py::class_(m, "MESANetworkFileParser") + // .def("parse", &gridfire::io::MESANetworkFileParser::parse, + // py::arg("filename"), + // "Parse a MESA network file and return a ParsedNetworkData object."); +} \ No newline at end of file diff --git a/src/python/io/bindings.h b/src/python/io/bindings.h new file mode 100644 index 00000000..32ccfef9 --- /dev/null +++ b/src/python/io/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_io_bindings(pybind11::module &m); diff --git a/src/python/io/meson.build b/src/python/io/meson.build new file mode 100644 index 00000000..998cd712 --- /dev/null +++ b/src/python/io/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_io', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/io/trampoline/meson.build b/src/python/io/trampoline/meson.build new file mode 100644 index 00000000..8fc8552c --- /dev/null +++ b/src/python/io/trampoline/meson.build @@ -0,0 +1,21 @@ +gf_io_trampoline_sources = files('py_io.cpp') + +gf_io_trapoline_dependencies = [ + gridfire_dep, + pybind11_dep, + python3_dep, +] + +gf_io_trampoline_lib = static_library( + 'io_trampolines', + gf_io_trampoline_sources, + include_directories: include_directories('.'), + dependencies: gf_io_trapoline_dependencies, + install: false, +) + +gr_io_trampoline_dep = declare_dependency( + link_with: gf_io_trampoline_lib, + include_directories: ('.'), + dependencies: gf_io_trapoline_dependencies, +) diff --git a/src/python/io/trampoline/py_io.cpp b/src/python/io/trampoline/py_io.cpp new file mode 100644 index 00000000..c2025f81 --- /dev/null +++ b/src/python/io/trampoline/py_io.cpp @@ -0,0 +1,14 @@ +#include "gridfire/io/io.h" +#include "py_io.h" + +#include + +namespace py = pybind11; + +gridfire::io::ParsedNetworkData PyNetworkFileParser::parse(const std::string &filename) const { + PYBIND11_OVERLOAD_PURE( + gridfire::io::ParsedNetworkData, + gridfire::io::NetworkFileParser, + parse // Method name + ); +} \ No newline at end of file diff --git a/src/python/io/trampoline/py_io.h b/src/python/io/trampoline/py_io.h new file mode 100644 index 00000000..fa174706 --- /dev/null +++ b/src/python/io/trampoline/py_io.h @@ -0,0 +1,7 @@ +#pragma once + +#include "gridfire/io/io.h" + +class PyNetworkFileParser final : public gridfire::io::NetworkFileParser { + gridfire::io::ParsedNetworkData parse(const std::string &filename) const override; +}; \ No newline at end of file diff --git a/src/python/meson.build b/src/python/meson.build new file mode 100644 index 00000000..ec84b6be --- /dev/null +++ b/src/python/meson.build @@ -0,0 +1,10 @@ +subdir('types') +subdir('utils') +subdir('expectations') +subdir('exceptions') +subdir('io') +subdir('partition') +subdir('reaction') +subdir('screening') +subdir('engine') +subdir('solver') diff --git a/src/python/partition/bindings.cpp b/src/python/partition/bindings.cpp new file mode 100644 index 00000000..c5144eb8 --- /dev/null +++ b/src/python/partition/bindings.cpp @@ -0,0 +1,113 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include +#include + +#include "bindings.h" + +#include "gridfire/partition/partition.h" + +PYBIND11_DECLARE_HOLDER_TYPE(T, std::unique_ptr, true) // Declare unique_ptr as a holder type for pybind11 + +#include "trampoline/py_partition.h" + + +namespace py = pybind11; + + +void register_partition_bindings(pybind11::module &m) { + using PF = gridfire::partition::PartitionFunction; + py::class_(m, "PartitionFunction"); + + register_partition_types_bindings(m); + register_ground_state_partition_bindings(m); + register_rauscher_thielemann_partition_data_record_bindings(m); + register_rauscher_thielemann_partition_bindings(m); + + register_composite_partition_bindings(m); +} + +void register_partition_types_bindings(pybind11::module &m) { + py::enum_(m, "BasePartitionType") + .value("RauscherThielemann", gridfire::partition::BasePartitionType::RauscherThielemann) + .value("GroundState", gridfire::partition::BasePartitionType::GroundState) + .export_values(); + + m.def("basePartitionTypeToString", [](gridfire::partition::BasePartitionType type) { + return gridfire::partition::basePartitionTypeToString[type]; + }, py::arg("type"), "Convert BasePartitionType to string."); + + m.def("stringToBasePartitionType", [](const std::string &typeStr) { + return gridfire::partition::stringToBasePartitionType[typeStr]; + }, py::arg("typeStr"), "Convert string to BasePartitionType."); +} + +void register_ground_state_partition_bindings(pybind11::module &m) { + using GSPF = gridfire::partition::GroundStatePartitionFunction; + using PF = gridfire::partition::PartitionFunction; + py::class_(m, "GroundStatePartitionFunction") + .def(py::init<>()) + .def("evaluate", &gridfire::partition::GroundStatePartitionFunction::evaluate, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the ground state partition function for given Z, A, and T9.") + .def("evaluateDerivative", &gridfire::partition::GroundStatePartitionFunction::evaluateDerivative, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the derivative of the ground state partition function for given Z, A, and T9.") + .def("supports", &gridfire::partition::GroundStatePartitionFunction::supports, + py::arg("z"), py::arg("a"), + "Check if the ground state partition function supports given Z and A.") + .def("get_type", &gridfire::partition::GroundStatePartitionFunction::type, + "Get the type of the partition function (should return 'GroundState')."); +} + +void register_rauscher_thielemann_partition_data_record_bindings(pybind11::module &m) { + py::class_(m, "RauscherThielemannPartitionDataRecord") + .def_readonly("z", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::z, "Atomic number") + .def_readonly("a", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::a, "Mass number") + .def_readonly("ground_state_spin", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::ground_state_spin, "Ground state spin") + .def_readonly("normalized_g_values", &gridfire::partition::record::RauscherThielemannPartitionDataRecord::normalized_g_values, "Normalized g-values for the first 24 energy levels"); +} + + +void register_rauscher_thielemann_partition_bindings(pybind11::module &m) { + using RTPF = gridfire::partition::RauscherThielemannPartitionFunction; + using PF = gridfire::partition::PartitionFunction; + py::class_(m, "RauscherThielemannPartitionFunction") + .def(py::init<>()) + .def("evaluate", &gridfire::partition::RauscherThielemannPartitionFunction::evaluate, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the Rauscher-Thielemann partition function for given Z, A, and T9.") + .def("evaluateDerivative", &gridfire::partition::RauscherThielemannPartitionFunction::evaluateDerivative, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the derivative of the Rauscher-Thielemann partition function for given Z, A, and T9.") + .def("supports", &gridfire::partition::RauscherThielemannPartitionFunction::supports, + py::arg("z"), py::arg("a"), + "Check if the Rauscher-Thielemann partition function supports given Z and A.") + .def("get_type", &gridfire::partition::RauscherThielemannPartitionFunction::type, + "Get the type of the partition function (should return 'RauscherThielemann')."); +} + +void register_composite_partition_bindings(pybind11::module &m) { + py::class_(m, "CompositePartitionFunction") + .def(py::init&>(), + py::arg("partitionFunctions"), + "Create a composite partition function from a list of base partition types.") + .def(py::init(), + "Copy constructor for CompositePartitionFunction.") + .def("evaluate", &gridfire::partition::CompositePartitionFunction::evaluate, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the composite partition function for given Z, A, and T9.") + .def("evaluateDerivative", &gridfire::partition::CompositePartitionFunction::evaluateDerivative, + py::arg("z"), py::arg("a"), py::arg("T9"), + "Evaluate the derivative of the composite partition function for given Z, A, and T9.") + .def("supports", &gridfire::partition::CompositePartitionFunction::supports, + py::arg("z"), py::arg("a"), + "Check if the composite partition function supports given Z and A.") + .def("get_type", &gridfire::partition::CompositePartitionFunction::type, + "Get the type of the partition function (should return 'Composite')."); +} + + + diff --git a/src/python/partition/bindings.h b/src/python/partition/bindings.h new file mode 100644 index 00000000..3677e50d --- /dev/null +++ b/src/python/partition/bindings.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +void register_partition_bindings(pybind11::module &m); + +void register_partition_types_bindings(pybind11::module &m); + +void register_ground_state_partition_bindings(pybind11::module &m); + +void register_rauscher_thielemann_partition_data_record_bindings(pybind11::module &m); + +void register_rauscher_thielemann_partition_bindings(pybind11::module &m); + +void register_composite_partition_bindings(pybind11::module &m); + diff --git a/src/python/partition/meson.build b/src/python/partition/meson.build new file mode 100644 index 00000000..2dc31349 --- /dev/null +++ b/src/python/partition/meson.build @@ -0,0 +1,19 @@ +subdir('trampoline') + +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_partition', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/partition/trampoline/meson.build b/src/python/partition/trampoline/meson.build new file mode 100644 index 00000000..1115b683 --- /dev/null +++ b/src/python/partition/trampoline/meson.build @@ -0,0 +1,21 @@ +gf_partition_trampoline_sources = files('py_partition.cpp') + +gf_partition_trapoline_dependencies = [ + gridfire_dep, + pybind11_dep, + python3_dep, +] + +gf_partition_trampoline_lib = static_library( + 'partition_trampolines', + gf_partition_trampoline_sources, + include_directories: include_directories('.'), + dependencies: gf_partition_trapoline_dependencies, + install: false, +) + +gr_partition_trampoline_dep = declare_dependency( + link_with: gf_partition_trampoline_lib, + include_directories: ('.'), + dependencies: gf_partition_trapoline_dependencies, +) diff --git a/src/python/partition/trampoline/py_partition.cpp b/src/python/partition/trampoline/py_partition.cpp new file mode 100644 index 00000000..a91a7138 --- /dev/null +++ b/src/python/partition/trampoline/py_partition.cpp @@ -0,0 +1,57 @@ +#include "py_partition.h" + +#include "gridfire/partition/partition.h" + +#include "pybind11/pybind11.h" +#include "pybind11/stl.h" + +#include +#include + + +namespace py = pybind11; + + +double PyPartitionFunction::evaluate(int z, int a, double T9) const { + PYBIND11_OVERRIDE_PURE( + double, + gridfire::partition::PartitionFunction, + evaluate, + z, a, T9 + ); +} + +double PyPartitionFunction::evaluateDerivative(int z, int a, double T9) const { + PYBIND11_OVERRIDE_PURE( + double, + gridfire::partition::PartitionFunction, + evaluateDerivative, + z, a, T9 + ); +} + +bool PyPartitionFunction::supports(int z, int a) const { + PYBIND11_OVERRIDE_PURE( + bool, + gridfire::partition::PartitionFunction, + supports, + z, a + ); +} + +std::string PyPartitionFunction::type() const { + PYBIND11_OVERRIDE_PURE( + std::string, + gridfire::partition::PartitionFunction, + type + ); +} + +std::unique_ptr PyPartitionFunction::clone() const { + PYBIND11_OVERRIDE_PURE( + std::unique_ptr, + gridfire::partition::PartitionFunction, + clone + ); +} + diff --git a/src/python/partition/trampoline/py_partition.h b/src/python/partition/trampoline/py_partition.h new file mode 100644 index 00000000..63c698e1 --- /dev/null +++ b/src/python/partition/trampoline/py_partition.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "gridfire/partition/partition.h" + + +class PyPartitionFunction final : public gridfire::partition::PartitionFunction { + double evaluate(int z, int a, double T9) const override; + double evaluateDerivative(int z, int a, double T9) const override; + bool supports(int z, int a) const override; + std::string type() const override; + std::unique_ptr clone() const override; +}; \ No newline at end of file diff --git a/src/python/reaction/bindings.cpp b/src/python/reaction/bindings.cpp new file mode 100644 index 00000000..f107adf1 --- /dev/null +++ b/src/python/reaction/bindings.cpp @@ -0,0 +1,171 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include +#include + +#include "bindings.h" + +#include "gridfire/reaction/reaction.h" +#include "gridfire/reaction/reaclib.h" + +namespace py = pybind11; + + +void register_reaction_bindings(py::module &m) { + py::class_(m, "RateCoefficientSet") + .def(py::init(), + py::arg("a0"), py::arg("a1"), py::arg("a2"), py::arg("a3"), + py::arg("a4"), py::arg("a5"), py::arg("a6"), + "Construct a RateCoefficientSet with the given parameters." + ); + + using fourdst::atomic::Species; + py::class_(m, "Reaction") + .def(py::init&, const std::vector&, double, std::string_view, gridfire::reaction::RateCoefficientSet, bool>(), + py::arg("id"), py::arg("peName"), py::arg("chapter"), + py::arg("reactants"), py::arg("products"), py::arg("qValue"), + py::arg("label"), py::arg("sets"), py::arg("reverse") = false, + "Construct a Reaction with the given parameters.") + .def("calculate_rate", static_cast(&gridfire::reaction::Reaction::calculate_rate), + py::arg("T9"), "Calculate the reaction rate at a given temperature T9 (in units of 10^9 K).") + .def("peName", &gridfire::reaction::Reaction::peName, + "Get the reaction name in (projectile, ejectile) notation (e.g., 'p(p,g)d').") + .def("chapter", &gridfire::reaction::Reaction::chapter, + "Get the REACLIB chapter number defining the reaction structure.") + .def("sourceLabel", &gridfire::reaction::Reaction::sourceLabel, + "Get the source label for the rate data (e.g., 'wc12w', 'st08').") + .def("rateCoefficients", &gridfire::reaction::Reaction::rateCoefficients, + "get the set of rate coefficients.") + .def("contains", &gridfire::reaction::Reaction::contains, + py::arg("species"), "Check if the reaction contains a specific species.") + .def("contains_reactant", &gridfire::reaction::Reaction::contains_reactant, + "Check if the reaction contains a specific reactant species.") + .def("contains_product", &gridfire::reaction::Reaction::contains_product, + "Check if the reaction contains a specific product species.") + .def("all_species", &gridfire::reaction::Reaction::all_species, + "Get all species involved in the reaction (both reactants and products) as a set.") + .def("reactant_species", &gridfire::reaction::Reaction::reactant_species, + "Get the reactant species of the reaction as a set.") + .def("product_species", &gridfire::reaction::Reaction::product_species, + "Get the product species of the reaction as a set.") + .def("num_species", &gridfire::reaction::Reaction::num_species, + "Count the number of species in the reaction.") + .def("stoichiometry", static_cast(&gridfire::reaction::Reaction::stoichiometry), + py::arg("species"), + "Get the stoichiometry of the reaction as a map from species to their coefficients.") + .def("stoichiometry", static_cast (gridfire::reaction::Reaction::*)() const>(&gridfire::reaction::Reaction::stoichiometry), + "Get the stoichiometry of the reaction as a map from species to their coefficients.") + .def("id", &gridfire::reaction::Reaction::id, + "Get the unique identifier of the reaction.") + .def("qValue", &gridfire::reaction::Reaction::qValue, + "Get the Q-value of the reaction in MeV.") + .def("reactants", &gridfire::reaction::Reaction::reactants, + "Get a list of reactant species in the reaction.") + .def("products", &gridfire::reaction::Reaction::products, + "Get a list of product species in the reaction.") + .def("is_reverse", &gridfire::reaction::Reaction::is_reverse, + "Check if this is a reverse reaction rate.") + .def("excess_energy", &gridfire::reaction::Reaction::excess_energy, + "Calculate the excess energy from the mass difference of reactants and products.") + .def("__eq__", &gridfire::reaction::Reaction::operator==, + "Equality operator for reactions based on their IDs.") + .def("__neq__", &gridfire::reaction::Reaction::operator!=, + "Inequality operator for reactions based on their IDs.") + .def("hash", &gridfire::reaction::Reaction::hash, + py::arg("seed") = 0, + "Compute a hash for the reaction based on its ID.") + .def("__repr__", [](const gridfire::reaction::Reaction& self) { + std::stringstream ss; + ss << self; // Use the existing operator<< for Reaction + return ss.str(); + }); + + py::class_(m, "LogicalReaction") + .def(py::init>(), + py::arg("reactions"), + "Construct a LogicalReaction from a vector of Reaction objects.") + .def("add_reaction", &gridfire::reaction::LogicalReaction::add_reaction, + py::arg("reaction"), + "Add another Reaction source to this logical reaction.") + .def("size", &gridfire::reaction::LogicalReaction::size, + "Get the number of source rates contributing to this logical reaction.") + .def("__len__", &gridfire::reaction::LogicalReaction::size, + "Overload len() to return the number of source rates.") + .def("sources", &gridfire::reaction::LogicalReaction::sources, + "Get the list of source labels for the aggregated rates.") + .def("calculate_rate", static_cast(&gridfire::reaction::LogicalReaction::calculate_rate), + py::arg("T9"), "Calculate the reaction rate at a given temperature T9 (in units of 10^9 K).") + .def("calculate_forward_rate_log_derivative", &gridfire::reaction::LogicalReaction::calculate_forward_rate_log_derivative, + py::arg("T9"), "Calculate the forward rate log derivative at a given temperature T9 (in units of 10^9 K)."); + + py::class_(m, "LogicalReactionSet") + .def(py::init>(), + py::arg("reactions"), + "Construct a LogicalReactionSet from a vector of LogicalReaction objects.") + .def(py::init<>(), + "Default constructor for an empty LogicalReactionSet.") + .def(py::init(), + py::arg("other"), + "Copy constructor for LogicalReactionSet.") + .def("add_reaction", &gridfire::reaction::LogicalReactionSet::add_reaction, + py::arg("reaction"), + "Add a LogicalReaction to the set.") + .def("remove_reaction", &gridfire::reaction::LogicalReactionSet::remove_reaction, + py::arg("reaction"), + "Remove a LogicalReaction from the set.") + .def("contains", py::overload_cast(&gridfire::reaction::LogicalReactionSet::contains, py::const_), + py::arg("id"), + "Check if the set contains a specific LogicalReaction.") + .def("contains", py::overload_cast(&gridfire::reaction::LogicalReactionSet::contains, py::const_), + py::arg("reaction"), + "Check if the set contains a specific Reaction.") + .def("size", &gridfire::reaction::LogicalReactionSet::size, + "Get the number of LogicalReactions in the set.") + .def("__len__", &gridfire::reaction::LogicalReactionSet::size, + "Overload len() to return the number of LogicalReactions.") + .def("clear", &gridfire::reaction::LogicalReactionSet::clear, + "Remove all LogicalReactions from the set.") + .def("containes_species", &gridfire::reaction::LogicalReactionSet::contains_species, + py::arg("species"), + "Check if any reaction in the set involves the given species.") + .def("contains_reactant", &gridfire::reaction::LogicalReactionSet::contains_reactant, + py::arg("species"), + "Check if any reaction in the set has the species as a reactant.") + .def("contains_product", &gridfire::reaction::LogicalReactionSet::contains_product, + py::arg("species"), + "Check if any reaction in the set has the species as a product.") + .def("__getitem__", py::overload_cast(&gridfire::reaction::LogicalReactionSet::operator[], py::const_), + py::arg("index"), + "Get a LogicalReaction by index.") + .def("__getitem___", py::overload_cast(&gridfire::reaction::LogicalReactionSet::operator[], py::const_), + py::arg("id"), + "Get a LogicalReaction by its ID.") + .def("__eq__", &gridfire::reaction::LogicalReactionSet::operator==, + py::arg("LogicalReactionSet"), + "Equality operator for LogicalReactionSets based on their contents.") + .def("__ne__", &gridfire::reaction::LogicalReactionSet::operator!=, + py::arg("LogicalReactionSet"), + "Inequality operator for LogicalReactionSets based on their contents.") + .def("hash", &gridfire::reaction::LogicalReactionSet::hash, + py::arg("seed") = 0, + "Compute a hash for the LogicalReactionSet based on its contents." + ) + .def("__repr__", [](const gridfire::reaction::LogicalReactionSet& self) { + std::stringstream ss; + ss << self; + return ss.str(); + }) + .def("getReactionSetSpecies", &gridfire::reaction::LogicalReactionSet::getReactionSetSpecies, + "Get all species involved in the reactions of the set as a set of Species objects."); + + m.def("packReactionSetToLogicalReactionSet", + &gridfire::reaction::packReactionSetToLogicalReactionSet, + py::arg("reactionSet"), + "Convert a ReactionSet to a LogicalReactionSet by aggregating reactions with the same peName." + ); + + m.def("get_all_reactions", &gridfire::reaclib::get_all_reactions, + "Get all reactions from the REACLIB database."); +} diff --git a/src/python/reaction/bindings.h b/src/python/reaction/bindings.h new file mode 100644 index 00000000..8626b279 --- /dev/null +++ b/src/python/reaction/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_reaction_bindings(pybind11::module &m); diff --git a/src/python/reaction/meson.build b/src/python/reaction/meson.build new file mode 100644 index 00000000..ca4dc8ee --- /dev/null +++ b/src/python/reaction/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_reaction', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/screening/bindings.cpp b/src/python/screening/bindings.cpp new file mode 100644 index 00000000..742aa2cb --- /dev/null +++ b/src/python/screening/bindings.cpp @@ -0,0 +1,42 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include +#include + +#include "bindings.h" + +#include "gridfire/screening/screening.h" +#include "trampoline/py_screening.h" + +namespace py = pybind11; + +void register_screening_bindings(py::module &m) { + py::class_(m, "ScreeningModel"); + + py::enum_(m, "ScreeningType") + .value("BARE", gridfire::screening::ScreeningType::BARE) + .value("WEAK", gridfire::screening::ScreeningType::WEAK) + .export_values(); + + m.def("selectScreeningModel", &gridfire::screening::selectScreeningModel, + py::arg("type"), + "Select a screening model based on the specified type. Returns a pointer to the selected model."); + + py::class_(m, "BareScreeningModel") + .def(py::init<>()) + .def("calculateScreeningFactors", + py::overload_cast&, const std::vector&, double, double>(&gridfire::screening::BareScreeningModel::calculateScreeningFactors, py::const_), + py::arg("reactions"), py::arg("species"), py::arg("Y"), py::arg("T9"), py::arg("rho"), + "Calculate the bare plasma screening factors. This always returns 1.0 (bare)" + ); + + py::class_(m, "WeakScreeningModel") + .def(py::init<>()) + .def("calculateScreeningFactors", + py::overload_cast&, const std::vector&, double, double>(&gridfire::screening::WeakScreeningModel::calculateScreeningFactors, py::const_), + py::arg("reactions"), py::arg("species"), py::arg("Y"), py::arg("T9"), py::arg("rho"), + "Calculate the weak plasma screening factors using the Salpeter (1954) model." + ); +} \ No newline at end of file diff --git a/src/python/screening/bindings.h b/src/python/screening/bindings.h new file mode 100644 index 00000000..06a114b4 --- /dev/null +++ b/src/python/screening/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_screening_bindings(pybind11::module &m); diff --git a/src/python/screening/meson.build b/src/python/screening/meson.build new file mode 100644 index 00000000..99f7dd89 --- /dev/null +++ b/src/python/screening/meson.build @@ -0,0 +1,19 @@ +subdir('trampoline') + +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_screening', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/screening/trampoline/meson.build b/src/python/screening/trampoline/meson.build new file mode 100644 index 00000000..45552332 --- /dev/null +++ b/src/python/screening/trampoline/meson.build @@ -0,0 +1,21 @@ +gf_screening_trampoline_sources = files('py_screening.cpp') + +gf_screening_trapoline_dependencies = [ + gridfire_dep, + pybind11_dep, + python3_dep, +] + +gf_screening_trampoline_lib = static_library( + 'screening_trampolines', + gf_screening_trampoline_sources, + include_directories: include_directories('.'), + dependencies: gf_screening_trapoline_dependencies, + install: false, +) + +gr_screening_trampoline_dep = declare_dependency( + link_with: gf_screening_trampoline_lib, + include_directories: ('.'), + dependencies: gf_screening_trapoline_dependencies, +) diff --git a/src/python/screening/trampoline/py_screening.cpp b/src/python/screening/trampoline/py_screening.cpp new file mode 100644 index 00000000..0b32d00a --- /dev/null +++ b/src/python/screening/trampoline/py_screening.cpp @@ -0,0 +1,31 @@ +#include "gridfire/screening/screening.h" + +#include +#include +#include // Needed for std::function + +#include + +#include "py_screening.h" + +#include "cppad/cppad.hpp" + + +namespace py = pybind11; + +std::vector PyScreening::calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector &species, const std::vector &Y, const double T9, const double rho) const { + PYBIND11_OVERLOAD_PURE( + std::vector, // Return type + gridfire::screening::ScreeningModel, + calculateScreeningFactors // Method name + ); +} + +using ADDouble = gridfire::screening::ScreeningModel::ADDouble; +std::vector PyScreening::calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector &species, const std::vector &Y, const ADDouble T9, const ADDouble rho) const { + PYBIND11_OVERLOAD_PURE( + std::vector, // Return type + gridfire::screening::ScreeningModel, + calculateScreeningFactors // Method name + ); +} diff --git a/src/python/screening/trampoline/py_screening.h b/src/python/screening/trampoline/py_screening.h new file mode 100644 index 00000000..653538b5 --- /dev/null +++ b/src/python/screening/trampoline/py_screening.h @@ -0,0 +1,16 @@ +#pragma once + +#include "gridfire/screening/screening.h" + +#include +#include +#include // Needed for std::function + +#include + +#include "cppad/cppad.hpp" + +class PyScreening final : public gridfire::screening::ScreeningModel { + std::vector calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector &species, const std::vector &Y, const double T9, const double rho) const override; + std::vector calculateScreeningFactors(const gridfire::reaction::LogicalReactionSet &reactions, const std::vector &species, const std::vector &Y, const ADDouble T9, const ADDouble rho) const override; +}; \ No newline at end of file diff --git a/src/python/solver/bindings.cpp b/src/python/solver/bindings.cpp new file mode 100644 index 00000000..099caa8f --- /dev/null +++ b/src/python/solver/bindings.cpp @@ -0,0 +1,26 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc if needed directly + +#include "bindings.h" + +#include "gridfire/solver/solver.h" +#include "trampoline/py_solver.h" + +namespace py = pybind11; + + +void register_solver_bindings(py::module &m) { + auto py_dynamic_network_solving_strategy = py::class_(m, "DynamicNetworkSolverStrategy"); + auto py_direct_network_solver = py::class_(m, "DirectNetworkSolver"); + + py_direct_network_solver.def(py::init(), + py::arg("engine"), + "Constructor for the DirectNetworkSolver. Takes a DynamicEngine instance to use for evaluating the network."); + + py_direct_network_solver.def("evaluate", + &gridfire::solver::DirectNetworkSolver::evaluate, + py::arg("netIn"), + "Evaluate the network for a given timestep. Returns the output conditions after the timestep."); +} + diff --git a/src/python/solver/bindings.h b/src/python/solver/bindings.h new file mode 100644 index 00000000..4d781891 --- /dev/null +++ b/src/python/solver/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_solver_bindings(pybind11::module &m); diff --git a/src/python/solver/meson.build b/src/python/solver/meson.build new file mode 100644 index 00000000..e21ee519 --- /dev/null +++ b/src/python/solver/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_solver', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/solver/trampoline/meson.build b/src/python/solver/trampoline/meson.build new file mode 100644 index 00000000..b252dba6 --- /dev/null +++ b/src/python/solver/trampoline/meson.build @@ -0,0 +1,21 @@ +gf_solver_trampoline_sources = files('py_solver.cpp') + +gf_solver_trapoline_dependencies = [ + gridfire_dep, + pybind11_dep, + python3_dep, +] + +gf_solver_trampoline_lib = static_library( + 'solver_trampolines', + gf_solver_trampoline_sources, + include_directories: include_directories('.'), + dependencies: gf_solver_trapoline_dependencies, + install: false, +) + +gr_solver_trampoline_dep = declare_dependency( + link_with: gf_solver_trampoline_lib, + include_directories: ('.'), + dependencies: gf_solver_trapoline_dependencies, +) diff --git a/src/python/solver/trampoline/py_solver.cpp b/src/python/solver/trampoline/py_solver.cpp new file mode 100644 index 00000000..9b250c19 --- /dev/null +++ b/src/python/solver/trampoline/py_solver.cpp @@ -0,0 +1,21 @@ +#include "gridfire/solver/solver.h" + +#include +#include +#include // Needed for std::function + +#include + +#include "py_solver.h" + + +namespace py = pybind11; + +gridfire::NetOut PyDynamicNetworkSolverStrategy::evaluate(const gridfire::NetIn &netIn) { + PYBIND11_OVERRIDE_PURE( + gridfire::NetOut, // Return type + gridfire::solver::DynamicNetworkSolverStrategy, // Base class + evaluate, // Method name + netIn // Arguments + ); +} diff --git a/src/python/solver/trampoline/py_solver.h b/src/python/solver/trampoline/py_solver.h new file mode 100644 index 00000000..9a87a854 --- /dev/null +++ b/src/python/solver/trampoline/py_solver.h @@ -0,0 +1,10 @@ +#pragma once + +#include "gridfire/solver/solver.h" + +#include + +class PyDynamicNetworkSolverStrategy final : public gridfire::solver::DynamicNetworkSolverStrategy { + explicit PyDynamicNetworkSolverStrategy(gridfire::DynamicEngine &engine) : gridfire::solver::DynamicNetworkSolverStrategy(engine) {} + gridfire::NetOut evaluate(const gridfire::NetIn &netIn) override; +}; \ No newline at end of file diff --git a/src/python/types/bindings.cpp b/src/python/types/bindings.cpp new file mode 100644 index 00000000..7e477a1d --- /dev/null +++ b/src/python/types/bindings.cpp @@ -0,0 +1,43 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc. if needed directly + +#include "bindings.h" + +namespace py = pybind11; + +#include "gridfire/network.h" + +void register_type_bindings(pybind11::module &m) { + py::class_(m, "NetIn") + .def(py::init<>()) + .def_readwrite("composition", &gridfire::NetIn::composition) + .def_readwrite("tMax", &gridfire::NetIn::tMax) + .def_readwrite("dt0", &gridfire::NetIn::dt0) + .def_readwrite("temperature", &gridfire::NetIn::temperature) + .def_readwrite("density", &gridfire::NetIn::density) + .def_readwrite("energy", &gridfire::NetIn::energy) + .def("__repr__", [](const gridfire::NetIn &netIn) { + std::stringstream ss; + ss << "NetIn(composition=" << netIn.composition + << ", tMax=" << netIn.tMax + << ", dt0=" << netIn.dt0 + << ", temperature=" << netIn.temperature + << ", density=" << netIn.density + << ", energy=" << netIn.energy << ")"; + return ss.str(); + }); + + py::class_(m, "NetOut") + .def_readonly("composition", &gridfire::NetOut::composition) + .def_readonly("num_steps", &gridfire::NetOut::num_steps) + .def_readonly("energy", &gridfire::NetOut::energy) + .def("__repr__", [](const gridfire::NetOut &netOut) { + std::stringstream ss; + ss << "NetOut(composition=" << netOut.composition + << ", num_steps=" << netOut.num_steps + << ", energy=" << netOut.energy << ")"; + return ss.str(); + }); + +} diff --git a/src/python/types/bindings.h b/src/python/types/bindings.h new file mode 100644 index 00000000..dcba467a --- /dev/null +++ b/src/python/types/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_type_bindings(pybind11::module &m); diff --git a/src/python/types/meson.build b/src/python/types/meson.build new file mode 100644 index 00000000..d76e8b6e --- /dev/null +++ b/src/python/types/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_types', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/src/python/utils/bindings.cpp b/src/python/utils/bindings.cpp new file mode 100644 index 00000000..7792ec17 --- /dev/null +++ b/src/python/utils/bindings.cpp @@ -0,0 +1,20 @@ +#include +#include // Needed for vectors, maps, sets, strings +#include // Needed for binding std::vector, std::map etc. if needed directly + +#include "bindings.h" + +namespace py = pybind11; + +#include "gridfire/utils/logging.h" + +void register_utils_bindings(py::module &m) { + m.def("formatNuclearTimescaleLogString", + &gridfire::utils::formatNuclearTimescaleLogString, + py::arg("engine"), + py::arg("Y"), + py::arg("T9"), + py::arg("rho"), + "Format a string for logging nuclear timescales based on temperature, density, and energy generation rate." + ); +} diff --git a/src/python/utils/bindings.h b/src/python/utils/bindings.h new file mode 100644 index 00000000..2def079b --- /dev/null +++ b/src/python/utils/bindings.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void register_utils_bindings(pybind11::module &m); diff --git a/src/python/utils/meson.build b/src/python/utils/meson.build new file mode 100644 index 00000000..5c97a3a5 --- /dev/null +++ b/src/python/utils/meson.build @@ -0,0 +1,17 @@ +# Define the library +bindings_sources = files('bindings.cpp') +bindings_headers = files('bindings.h') + +dependencies = [ + gridfire_dep, + python3_dep, + pybind11_dep, +] + +shared_module('py_gf_utils', + bindings_sources, + cpp_args: ['-fvisibility=default'], + install : true, + dependencies: dependencies, + include_directories: include_directories('.') +) diff --git a/subprojects/fourdst.wrap b/subprojects/fourdst.wrap new file mode 100644 index 00000000..28348f18 --- /dev/null +++ b/subprojects/fourdst.wrap @@ -0,0 +1,4 @@ +[wrap-git] +url = https://github.com/4D-STAR/fourdst +revision = v0.5.0 +depth = 1 \ No newline at end of file diff --git a/subprojects/libcomposition.wrap b/subprojects/libcomposition.wrap index cd3facd8..45996330 100644 --- a/subprojects/libcomposition.wrap +++ b/subprojects/libcomposition.wrap @@ -1,4 +1,2 @@ -[wrap-git] -url = https://github.com/4D-STAR/libcomposition.git -revision = v1.4.1 -depth = 1 \ No newline at end of file +[wrap-redirect] +filename = fourdst/subprojects/libcomposition.wrap diff --git a/subprojects/libconfig.wrap b/subprojects/libconfig.wrap index 97fd475a..14be20ac 100644 --- a/subprojects/libconfig.wrap +++ b/subprojects/libconfig.wrap @@ -1,4 +1,2 @@ -[wrap-git] -url = https://github.com/4D-STAR/libconfig.git -revision = v1.0.8 -depth = 1 \ No newline at end of file +[wrap-redirect] +filename = fourdst/subprojects/libconfig.wrap diff --git a/subprojects/libconstants.wrap b/subprojects/libconstants.wrap index 04e94d49..71ae4cbb 100644 --- a/subprojects/libconstants.wrap +++ b/subprojects/libconstants.wrap @@ -1,4 +1,2 @@ -[wrap-git] -url = https://github.com/4D-STAR/libconstants.git -revision = v1.0.6 -depth = 1 +[wrap-redirect] +filename = fourdst/subprojects/libconstants.wrap diff --git a/subprojects/liblogging.wrap b/subprojects/liblogging.wrap index 5f8ea775..ab4e3a38 100644 --- a/subprojects/liblogging.wrap +++ b/subprojects/liblogging.wrap @@ -1,4 +1,2 @@ -[wrap-git] -url = https://github.com/4D-STAR/liblogging.git -revision = v1.0.8 -depth = 1 \ No newline at end of file +[wrap-redirect] +filename = fourdst/subprojects/liblogging.wrap diff --git a/subprojects/packagefiles/pybind11/LICENSE.build b/subprojects/packagefiles/pybind11/LICENSE.build new file mode 100644 index 00000000..b59833de --- /dev/null +++ b/subprojects/packagefiles/pybind11/LICENSE.build @@ -0,0 +1,19 @@ +Copyright (c) 2021 The Meson development team + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/subprojects/packagefiles/pybind11/meson.build b/subprojects/packagefiles/pybind11/meson.build new file mode 100644 index 00000000..cf873c37 --- /dev/null +++ b/subprojects/packagefiles/pybind11/meson.build @@ -0,0 +1,8 @@ +project('pybind11', 'cpp', + version : 'v3.0.0', + license : 'BSD-3-Clause') + +pybind11_incdir = include_directories('include') + +pybind11_dep = declare_dependency( + include_directories : pybind11_incdir) diff --git a/tests/graphnet_sandbox/approx8.net b/tests/graphnet_sandbox/approx8.net deleted file mode 100644 index 995adb66..00000000 --- a/tests/graphnet_sandbox/approx8.net +++ /dev/null @@ -1,26 +0,0 @@ -# Reaction network definition for the approx8 network. -# This file lists the reactions to be included for a direct -# comparison with the hard-coded approx8 network. - -# --- PP Chain --- -p(p,e+)d -d(p,g)he3 -he3(he3,2p)he4 - -# --- CNO Cycle --- -# Note: approx8 simplifies the CNO cycle using branching fractions, -# but these are the primary gateway reactions. -c12(p,g)n13 -n14(p,g)o15 -n14(a,g)f18 -o16(p,g)f17 - -# --- Alpha Captures & Triple Alpha --- -c12(a,g)o16 -n14(a,g)f18 -o16(a,g)ne20 -ne20(a,g)mg24 - -# --- Carbon & Oxygen Burning --- -c12(c12,a)ne20 -o16(c12,a)mg24 \ No newline at end of file diff --git a/tests/graphnet_sandbox/meson.build b/tests/graphnet_sandbox/meson.build index 1c823c61..49b92e35 100644 --- a/tests/graphnet_sandbox/meson.build +++ b/tests/graphnet_sandbox/meson.build @@ -1,5 +1,5 @@ executable( 'graphnet_sandbox', 'main.cpp', - dependencies: [network_dep, composition_dep], + dependencies: [gridfire_dep, composition_dep], ) diff --git a/tests/network/meson.build b/tests/network/meson.build index ad3d7203..aa09943d 100644 --- a/tests/network/meson.build +++ b/tests/network/meson.build @@ -11,7 +11,7 @@ foreach test_file : test_sources test_exe = executable( exe_name, test_file, - dependencies: [gtest_dep, gtest_main, network_dep, composition_dep], + dependencies: [gtest_dep, gtest_main, gridfire_dep, composition_dep], install_rpath: '@loader_path/../../src' # Ensure runtime library path resolves correctly ) diff --git a/tests/python/readme.md b/tests/python/readme.md new file mode 100644 index 00000000..2d235346 --- /dev/null +++ b/tests/python/readme.md @@ -0,0 +1,101 @@ +# Python example +GridFire includes robust python bindings. test.py includes a basic example of how to use them. + +Generally the concepts are as similar to the C++ API as possible (i.e GridFire code written in C++ and Python will look *very* similar). + +```python +from gridfire.engine import GraphEngine, MultiscalePartitioningEngineView, AdaptiveEngineView +from gridfire.solver import DirectNetworkSolver +from gridfire.type import NetIn + +from fourdst.composition import Composition + +symbols : list[str] = ["H-1", "He-3", "He-4", "C-12", "N-14", "O-16", "Ne-20", "Mg-24"] +X : list[float] = [0.708, 2.94e-5, 0.276, 0.003, 0.0011, 9.62e-3, 1.62e-3, 5.16e-4] + +comp = Composition(); +comp.registerSymbol(symbols) +comp.setMassFraction(symbols, X) +comp.finalize(True) + +netIn = NetIn() +netIn.composition = comp +netIn.temperature = 1.5e7 +netIn.density = 1.5e2 +netIn.tMax = 3e14 +netIn.dt0 = 1e-12 + +baseEngine = GraphEngine(comp, 2) + +baseEngine.setUseReverseReactions(False) + +qseEngine = MultiscalePartitioningEngineView(baseEngine) +adaptiveEngine = AdaptiveEngineView(qseEngine) + +solver = DirectNetworkSolver(adaptiveEngine) +results = solver.evaluate(netIn); +print(results.composition.getMassFraction("H-1")) +``` + +compare this to the C++ example and note how similar it is +```c++ +#include + +#include "gridfire/engine/engine.h" +#include "gridfire/solver/solver.h" +#include "gridfire/network.h" +#include "fourdst/composition/composition.h" + +int main() { + using namespace gridfire; + + const std::vector symbols = {"H-1", "He-3", "He-4", "C-12", "N-14", "O-16", "Ne-20", "Mg-24"}; + const std::vector comp = {0.708, 2.94e-5, 0.276, 0.003, 0.0011, 9.62e-3, 1.62e-3, 5.16e-4}; + + + fourdst::composition::Composition composition; + composition.registerSymbol(symbols, true); + composition.setMassFraction(symbols, comp); + composition.finalize(true); + + NetIn netIn; + netIn.composition = composition; + netIn.temperature = 1.5e7; + netIn.density = 1.5e2; + netIn.tMax = 3e14; + netIn.dt0 = 1e-12; + + GraphEngine ReaclibEngine(composition, NetworkBuildDepth::SecondOrder); + + ReaclibEngine.setUseReverseReactions(false); + MultiscalePartitioningEngineView partitioningView(ReaclibEngine); + AdaptiveEngineView adaptiveView(partitioningView); + + solver::DirectNetworkSolver solver(adaptiveView); + NetOut netOut; + netOut = solver.evaluate(netIn); + std::cout << "H-1 mass fraction: " << netOut.composition.getMassFraction("H-1") << "\n"; + +} +``` + +> **Note (1):** The python binding are just that, bindings. They do not include any additional code and simply directly call the underlying C++ code. This means that you inherit almost all of the speed of the C++ code. + +## Installing the python bindings +Installing the bindings is as simple as running the following command in the root of the repository: +```bash +pip install . +``` +This will use the `mesonpy` build backend to setup and compile the meson project, and then install the python bindings into your current python environment. + +> **Note (2):** This will run meson setup and then meson compile to build the project and therefor may take some time and will not produce much output. If you want to see more output during the installation process, you can use the `-v` flag to get verbose output: + +If you are a developer and you would like a more convenient edit - compile - test cycle you can install the binding in editable mode +```bash +pip install -e . --no-build-isolation -vv +``` +> **Note (3):** Installing in editable mode with `mesonpy` requires that you install the `meson-python' package with pip. + +> **Note (4):** The `-vv` flag is optional, but it will give you more verbose output during the installation process, which can be helpful for debugging. + +> **Note (5):** The `--no-build-isolation` flag is used to force `mesonpy` to not rebuild the entire project every time and instead to just do incremental builds. meson setup will however **always** run. \ No newline at end of file diff --git a/tests/python/test.py b/tests/python/test.py new file mode 100644 index 00000000..a3a1cc24 --- /dev/null +++ b/tests/python/test.py @@ -0,0 +1,34 @@ +from gridfire.engine import GraphEngine, MultiscalePartitioningEngineView, AdaptiveEngineView +from gridfire.solver import DirectNetworkSolver +from gridfire.type import NetIn + +from fourdst.composition import Composition + +symbols : list[str] = ["H-1", "He-3", "He-4", "C-12", "N-14", "O-16", "Ne-20", "Mg-24"] +X : list[float] = [0.708, 2.94e-5, 0.276, 0.003, 0.0011, 9.62e-3, 1.62e-3, 5.16e-4] + +comp = Composition(); +comp.registerSymbol(symbols) +comp.setMassFraction(symbols, X) +comp.finalize(True) + +netIn = NetIn() +netIn.composition = comp +netIn.temperature = 1.5e7 +netIn.density = 1.5e2 +netIn.tMax = 3e14 +netIn.dt0 = 1e-12 + +baseEngine = GraphEngine(comp, 2) + +baseEngine.setUseReverseReactions(False) + +qseEngine = MultiscalePartitioningEngineView(baseEngine) +adaptiveEngine = AdaptiveEngineView(qseEngine) + +solver = DirectNetworkSolver(adaptiveEngine) +results = solver.evaluate(netIn); +print(results.composition.getMassFraction("H-1")) + + +