build(python): gridfire uses fourdst wheel in python mode
This commit is contained in:
@@ -130,7 +130,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* @brief Check whether the scratchpad has been initialized.
|
||||
* @return true if initialized with a valid SUNContext, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_initialized() const override { return has_initialized; }
|
||||
[[nodiscard]] bool is_initialized() const override;
|
||||
|
||||
/**
|
||||
* @brief Initialize the scratchpad by creating a SUNDIALS context.
|
||||
@@ -150,16 +150,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* SUNContext ctx = scratch.sun_ctx;
|
||||
* @endcode
|
||||
*/
|
||||
void initialize() {
|
||||
if (has_initialized) return;
|
||||
|
||||
const int flag = SUNContext_Create(SUN_COMM_NULL, &sun_ctx);
|
||||
if (flag != 0) {
|
||||
throw std::runtime_error("Failed to create SUNContext in MultiscalePartitioningEngineViewScratchPad.");
|
||||
}
|
||||
|
||||
has_initialized = true;
|
||||
}
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* @brief Destructor that properly releases SUNDIALS resources.
|
||||
@@ -167,13 +158,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* Clears all QSE solvers before freeing the SUNContext to ensure
|
||||
* proper cleanup order and avoid dangling references.
|
||||
*/
|
||||
~MultiscalePartitioningEngineViewScratchPad() override {
|
||||
qse_solvers.clear();
|
||||
if (sun_ctx != nullptr) {
|
||||
SUNContext_Free(&sun_ctx);
|
||||
sun_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
~MultiscalePartitioningEngineViewScratchPad() override;
|
||||
|
||||
/**
|
||||
* @brief Create a partial copy of this scratchpad.
|
||||
@@ -196,20 +181,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<AbstractScratchPad> clone() const override {
|
||||
auto clone_pad = std::make_unique<MultiscalePartitioningEngineViewScratchPad>();
|
||||
clone_pad->qse_groups = this->qse_groups;
|
||||
clone_pad->dynamic_species = this->dynamic_species;
|
||||
clone_pad->algebraic_species = this->algebraic_species;
|
||||
clone_pad->composition_cache = this->composition_cache;
|
||||
|
||||
clone_pad->initialize();
|
||||
clone_pad->qse_solvers.reserve(this->qse_solvers.size());
|
||||
for (const auto& solver : qse_solvers) {
|
||||
clone_pad->qse_solvers.push_back(solver->clone(clone_pad->sun_ctx)); // Must rebind context to new SUNContext
|
||||
}
|
||||
return clone_pad;
|
||||
}
|
||||
[[nodiscard]] std::unique_ptr<AbstractScratchPad> clone() const override;
|
||||
};
|
||||
|
||||
} // namespace gridfire::engine::scratch
|
||||
|
||||
52
src/lib/engine/scratchpads/engine_multiscale_scratchpad.cpp
Normal file
52
src/lib/engine/scratchpads/engine_multiscale_scratchpad.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "gridfire/engine/views/engine_multiscale.h"
|
||||
#include "gridfire/engine/scratchpads/scratchpad_abstract.h"
|
||||
#include "gridfire/engine/scratchpads/types.h"
|
||||
#include "gridfire/engine/scratchpads/engine_multiscale_scratchpad.h"
|
||||
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "sundials/sundials_context.h"
|
||||
|
||||
|
||||
namespace gridfire::engine::scratch {
|
||||
bool MultiscalePartitioningEngineViewScratchPad::is_initialized() const{ return has_initialized; }
|
||||
|
||||
void MultiscalePartitioningEngineViewScratchPad::initialize() {
|
||||
if (has_initialized) return;
|
||||
|
||||
const int flag = SUNContext_Create(SUN_COMM_NULL, &sun_ctx);
|
||||
if (flag != 0) {
|
||||
throw std::runtime_error("Failed to create SUNContext in MultiscalePartitioningEngineViewScratchPad.");
|
||||
}
|
||||
|
||||
has_initialized = true;
|
||||
}
|
||||
|
||||
MultiscalePartitioningEngineViewScratchPad::~MultiscalePartitioningEngineViewScratchPad() {
|
||||
qse_solvers.clear();
|
||||
if (sun_ctx != nullptr) {
|
||||
SUNContext_Free(&sun_ctx);
|
||||
sun_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractScratchPad> MultiscalePartitioningEngineViewScratchPad::clone() const {
|
||||
auto clone_pad = std::make_unique<MultiscalePartitioningEngineViewScratchPad>();
|
||||
clone_pad->qse_groups = this->qse_groups;
|
||||
clone_pad->dynamic_species = this->dynamic_species;
|
||||
clone_pad->algebraic_species = this->algebraic_species;
|
||||
clone_pad->composition_cache = this->composition_cache;
|
||||
|
||||
clone_pad->initialize();
|
||||
clone_pad->qse_solvers.reserve(this->qse_solvers.size());
|
||||
for (const auto& solver : qse_solvers) {
|
||||
clone_pad->qse_solvers.push_back(solver->clone(clone_pad->sun_ctx)); // Must rebind context to new SUNContext
|
||||
}
|
||||
return clone_pad;
|
||||
}
|
||||
|
||||
}
|
||||
108
src/meson.build
108
src/meson.build
@@ -12,6 +12,7 @@ gridfire_sources = files(
|
||||
'lib/engine/procedures/construction.cpp',
|
||||
'lib/engine/diagnostics/dynamic_engine_diagnostics.cpp',
|
||||
'lib/engine/types/jacobian.cpp',
|
||||
'lib/engine/scratchpads/engine_multiscale_scratchpad.cpp',
|
||||
'lib/reaction/reaction.cpp',
|
||||
'lib/reaction/reaclib.cpp',
|
||||
'lib/reaction/weak/weak.cpp',
|
||||
@@ -67,39 +68,97 @@ gridfire_link_args = cpp.get_supported_link_arguments(
|
||||
)
|
||||
|
||||
if get_option('build_python')
|
||||
gridfire_link_whole += [libcomposition, libconst, liblogging]
|
||||
if get_option('plugin_support')
|
||||
gridfire_link_whole += [libplugin]
|
||||
error('plugin_support is not available when build_python=true: '
|
||||
+ 'the fourdst wheel does not ship libplugin, and bundling it '
|
||||
+ 'would break cross-package type compatibility.')
|
||||
endif
|
||||
|
||||
# ---- rpaths ---------------------------------------------------------
|
||||
# Wheel layout (both packages share one site-packages):
|
||||
# <site-packages>/gridfire/_gridfire.<tag>.so
|
||||
# <site-packages>/gridfire/lib/libgridfire.{so,dylib}
|
||||
# <site-packages>/fourdst/lib/lib{composition,logging,const}.*
|
||||
# <site-packages>/fourdst/lib/vendor/libreflect_cpp.*
|
||||
#
|
||||
# libgridfire (in gridfire/lib/) needs: itself-dir, ../../fourdst/lib{,/vendor}
|
||||
# _gridfire (in gridfire/) needs: ./lib, ../fourdst/lib{,/vendor}
|
||||
#
|
||||
# Platform split:
|
||||
# * macOS / Mach-O: LC_RPATH cannot hold colon-separated lists,
|
||||
# meson carries a user-supplied build_rpath as a single string, and
|
||||
# install_rpath is only applied by `meson install` (which
|
||||
# meson-python never runs). So on darwin we emit one raw
|
||||
# `-Wl,-rpath,<path>` link arg per path, and deliberately do NOT
|
||||
# set build_rpath/install_rpath (a real `meson install` would then
|
||||
# add install_rpath on top of the link args, producing duplicate
|
||||
# LC_RPATH entries, which macOS 26+ dyld treats as a hard load
|
||||
# error).
|
||||
# * Linux / ELF: colon-joined DT_RUNPATH is the native format, and
|
||||
# install_rpath is baked into the binary at link time, so the
|
||||
# kwargs work for both meson-python wheels and `meson install`.
|
||||
#
|
||||
# NOTE: compose paths with '+', never the '/' join operator —
|
||||
# 'x' / '/y' silently discards 'x' in Meson.
|
||||
#
|
||||
# gridfire_ext_rpath_args / gridfire_ext_rpath are consumed later by
|
||||
# build-python/meson.build for the _gridfire extension module (this
|
||||
# subdir is processed before build-python in the root meson.build).
|
||||
if host_machine.system() == 'darwin'
|
||||
gridfire_lib_rpath_args = [
|
||||
'-Wl,-rpath,@loader_path',
|
||||
'-Wl,-rpath,@loader_path/../../fourdst/lib',
|
||||
'-Wl,-rpath,@loader_path/../../fourdst/lib/vendor',
|
||||
]
|
||||
gridfire_lib_rpath = ''
|
||||
|
||||
gridfire_ext_rpath_args = [
|
||||
'-Wl,-rpath,@loader_path/lib',
|
||||
'-Wl,-rpath,@loader_path/../fourdst/lib',
|
||||
'-Wl,-rpath,@loader_path/../fourdst/lib/vendor',
|
||||
]
|
||||
gridfire_ext_rpath = ''
|
||||
else
|
||||
gridfire_lib_rpath_args = []
|
||||
gridfire_lib_rpath = '$ORIGIN:' + '$ORIGIN/../../fourdst/lib:' + '$ORIGIN/../../fourdst/lib/vendor'
|
||||
|
||||
gridfire_ext_rpath_args = []
|
||||
gridfire_ext_rpath = '$ORIGIN/lib:' + '$ORIGIN/../fourdst/lib:' + '$ORIGIN/../fourdst/lib/vendor'
|
||||
endif
|
||||
|
||||
libgridfire = shared_library('gridfire',
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
cpp_args: gridfire_args,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
install: true,
|
||||
install_dir: gridfire_libdir)
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
cpp_args: gridfire_args,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args + gridfire_lib_rpath_args,
|
||||
install: true,
|
||||
install_dir: gridfire_libdir,
|
||||
build_rpath: gridfire_lib_rpath,
|
||||
install_rpath: gridfire_lib_rpath,
|
||||
)
|
||||
else
|
||||
libgridfire = library('gridfire',
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
cpp_args: gridfire_args,
|
||||
install : true)
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
cpp_args: gridfire_args,
|
||||
install : true
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('build_python')
|
||||
gridfire_iface_deps = []
|
||||
foreach d : gridfire_build_dependencies
|
||||
gridfire_iface_deps += d.partial_dependency(compile_args: true, includes: true)
|
||||
endforeach
|
||||
gridfire_iface_dep = declare_dependency(
|
||||
dependencies: gridfire_build_dependencies,
|
||||
).partial_dependency(compile_args: true, includes: true)
|
||||
|
||||
gridfire_dep = declare_dependency(
|
||||
include_directories: include_directories('include'),
|
||||
link_with: libgridfire,
|
||||
dependencies: gridfire_iface_deps,
|
||||
dependencies: [gridfire_iface_dep],
|
||||
compile_args: gridfire_args,
|
||||
)
|
||||
else
|
||||
@@ -114,8 +173,8 @@ endif
|
||||
meson.override_dependency('gridfire', gridfire_dep)
|
||||
|
||||
install_subdir('include/gridfire',
|
||||
install_dir: gridfire_includedir,
|
||||
exclude_files: ['utils/config.h.in'],
|
||||
install_dir: gridfire_includedir,
|
||||
exclude_files: ['utils/config.h.in'],
|
||||
)
|
||||
|
||||
|
||||
@@ -126,4 +185,3 @@ if get_option('build_c_api')
|
||||
message('Configuring C API...')
|
||||
subdir('extern')
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
try:
|
||||
import fourdst as fst
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"gridfire requires the fourdst package (its C++ types and shared "
|
||||
"libraries come from there). pip install fourdst."
|
||||
) from e
|
||||
|
||||
from ._gridfire import *
|
||||
|
||||
from ._gridfire import *
|
||||
import sys
|
||||
|
||||
@@ -70,4 +80,49 @@ def gf_credits():
|
||||
"Emily M. Boudreaux - Lead Developer",
|
||||
"Aaron Dotter - Co-Developer",
|
||||
"4D-STAR Collaboration - Contributors"
|
||||
]
|
||||
]
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
_PACKAGE_DIR = Path(__file__).resolve().parent
|
||||
def gf_get_include_dirs():
|
||||
return [
|
||||
os.fspath(_PACKAGE_DIR / "include"),
|
||||
os.fspath(_PACKAGE_DIR / "include" / "gridfire" / "vendor"),
|
||||
]
|
||||
|
||||
def gf_get_lib_dirs():
|
||||
return [
|
||||
os.fspath(_PACKAGE_DIR / "lib"),
|
||||
]
|
||||
|
||||
def gf_get_rpath_flags() -> List[str]:
|
||||
return ["-Wl,-rpath," + os.fspath(_PACKAGE_DIR / "lib")]
|
||||
|
||||
|
||||
def gf_get_lib_flags() -> List[str]:
|
||||
flags = ["-L" + d for d in gf_get_lib_dirs()]
|
||||
flags += ["-lgridfire"]
|
||||
return flags
|
||||
|
||||
def gf_get_include_flags() -> List[str]:
|
||||
return ["-I" + d for d in gf_get_include_dirs()]
|
||||
|
||||
def gf_get_extra_flags() -> List[str]:
|
||||
return ['--std=c++23', '-fPIC']
|
||||
def gf_compiler_flags(just_gridfire=False):
|
||||
flags = []
|
||||
if not just_gridfire:
|
||||
flags.extend(fourdst_flags = fst.get_compiler_flags())
|
||||
flags.extend(gf_get_rpath_flags())
|
||||
flags.extend(gf_get_lib_flags())
|
||||
flags.extend(gf_get_include_flags())
|
||||
flags.extend(gf_get_extra_flags())
|
||||
return flags
|
||||
|
||||
def gf_get_compiler_flags_formatted(just_gridfire=False) -> int:
|
||||
flags = gf_compiler_flags(just_gridfire)
|
||||
print(" ".join(flags))
|
||||
return 0
|
||||
|
||||
@@ -17,14 +17,6 @@ namespace py = pybind11;
|
||||
void register_solver_bindings(const py::module &m) {
|
||||
auto py_cvode_timestep_context = py::class_<gridfire::solver::PointSolverTimestepContext>(m, "PointSolverTimestepContext");
|
||||
py_cvode_timestep_context.def_readonly("t", &gridfire::solver::PointSolverTimestepContext::t);
|
||||
py_cvode_timestep_context.def_property_readonly(
|
||||
"state",
|
||||
[](const gridfire::solver::PointSolverTimestepContext& self) -> std::vector<double> {
|
||||
const sunrealtype* nvec_data = N_VGetArrayPointer(self.state);
|
||||
const sunindextype length = N_VGetLength(self.state);
|
||||
return {nvec_data, nvec_data + length};
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def_readonly("dt", &gridfire::solver::PointSolverTimestepContext::dt);
|
||||
py_cvode_timestep_context.def_readonly("last_step_time", &gridfire::solver::PointSolverTimestepContext::last_step_time);
|
||||
py_cvode_timestep_context.def_readonly("T9", &gridfire::solver::PointSolverTimestepContext::T9);
|
||||
@@ -57,6 +49,20 @@ void register_solver_bindings(const py::module &m) {
|
||||
return self.getPhysicalComposition();
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def_property_readonly(
|
||||
"rawState",
|
||||
[](const gridfire::solver::PointSolverTimestepContext& self) -> std::vector<double> {
|
||||
const std::span<const double> s = self.rawState();
|
||||
return std::vector<double>(s.begin(), s.end());
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def("abundance",
|
||||
py::overload_cast<size_t>(&gridfire::solver::PointSolverTimestepContext::abundance, py::const_),
|
||||
py::arg("species_index"));
|
||||
py_cvode_timestep_context.def("abundance",
|
||||
py::overload_cast<const fourdst::atomic::Species&>(&gridfire::solver::PointSolverTimestepContext::abundance, py::const_),
|
||||
py::arg("species"));
|
||||
py_cvode_timestep_context.def_property_readonly("accumulatedSpecificEnergy", &gridfire::solver::PointSolverTimestepContext::accumulatedSpecificEnergy);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user