Compare commits

...

10 Commits

Author SHA1 Message Date
6ff4c88aa7 feat(reflection): Bring in new libconfig
This version of fourdst (v0.9.14) brings in the version libconfig which
includes reflection based config filed (v2.0.2).

This is a breaking change as any code which used versions of libconfig <
v2.0.0 will no longer function when linked against this version of
fourdst
2025-12-06 11:04:55 -05:00
979ec80dc4 fix(wasm): propegate all build flags 2025-12-03 11:27:01 -05:00
2caf46c984 docs(meson): version bump v0.9.11 -> v0.9.12
this version bring wasm support
2025-12-03 11:17:13 -05:00
d52795fa48 build(wasm): all fourdst subprojects support wasm
Updated version tags to bring in subproject versions which compile to wasm
2025-12-03 11:16:50 -05:00
86be969729 fix(unity): brought version of libcomposition which works with unity builds
Note that openssl is incompatible with unity builds. This means that
fourdst can only be built as a unity build if libplugin (which is what
brings in openssl) is not build. Generally this will happen when
building only the python bindings which do not depend on openssl or
libplugin
2025-11-28 11:46:39 -05:00
ac76b4ad3b docs(libplugin): version bump
fourdst v0.9.9 -> v0.9.10
libplugin v0.3.6 -> v0.3.7
2025-11-28 11:17:19 -05:00
b9f88d75ce fix(libplugin): Propegate build_python argument to libplugin 2025-11-28 11:02:33 -05:00
ab2ae12281 feat(meson): More granular build options
fourdst's build system now exposes some options to allow fine grained
control of what is built and what is not
2025-11-28 11:00:51 -05:00
6e489d15e5 fix(gcc): Fixed gcc build errors and warnings
Brought in libcomposition v2.2.1 and libplugin v0.3.5 which resolve gcc
build errors and warnings
2025-11-28 07:52:38 -05:00
250e03f00a feat(composition): added az_to_species binding and added bindings for fourdst exceptions 2025-11-26 12:31:46 -05:00
26 changed files with 3735 additions and 100 deletions

8
.gitignore vendored
View File

@@ -75,7 +75,11 @@ subprojects/liblogging/
subprojects/eigen-*/ subprojects/eigen-*/
!subprojects/pybind11.wrap !subprojects/pybind11.wrap
subprojects/libplugin/ subprojects/libplugin/
subprojects/minizip-ng-*
subprojects/.wraplock subprojects/.wraplock
subprojects/openssl-*
subprojects/glaze/
subprojects/tomlplusplus-*/
*.csv *.csv
*.dot *.dot
@@ -83,6 +87,10 @@ subprojects/.wraplock
qhull.wrap qhull.wrap
quill.wrap quill.wrap
yaml-cpp.wrap yaml-cpp.wrap
minizip-ng.wrap
openssl.wrap
glaze.wrap
tomlplusplus.wrap
.vscode/ .vscode/

View File

@@ -1,4 +1,9 @@
composition_p = subproject('libcomposition', default_options: ['pkg-config=' + pkg_config_bool_str]) composition_p = subproject('libcomposition',
default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
comp_dep = composition_p.get_variable('composition_dep') comp_dep = composition_p.get_variable('composition_dep')
libcomposition = composition_p.get_variable('libcomposition') libcomposition = composition_p.get_variable('libcomposition')
spw_dep = composition_p.get_variable('species_weight_dep') spw_dep = composition_p.get_variable('species_weight_dep')
@@ -7,4 +12,4 @@ composition_dep = [
spw_dep, spw_dep,
] ]
alias_target('build-libcomposition', libcomposition) alias_target('build-libcomposition', libcomposition)

View File

@@ -1,5 +1,7 @@
config_p = subproject('libconfig', default_options:['pkg-config=false']) config_p = subproject('libconfig',
default_options:[
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
config_dep = config_p.get_variable('config_dep') config_dep = config_p.get_variable('config_dep')
libconfig = config_p.get_variable('libconfig')
alias_target('build-libconfig', libconfig)

View File

@@ -1,4 +1,8 @@
const_p = subproject('libconstants', default_options: ['pkg-config=' + pkg_config_bool_str]) const_p = subproject('libconstants', default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
const_dep = const_p.get_variable('const_dep') const_dep = const_p.get_variable('const_dep')
libconst = const_p.get_variable('libconst') libconst = const_p.get_variable('libconst')

View File

@@ -1,4 +1,8 @@
logging_p = subproject('liblogging', default_options: ['pkg-config=' + pkg_config_bool_str]) logging_p = subproject('liblogging', default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
liblogging = logging_p.get_variable('liblogging') liblogging = logging_p.get_variable('liblogging')
logging_dep = logging_p.get_variable('logging_dep') logging_dep = logging_p.get_variable('logging_dep')
@@ -6,4 +10,4 @@ quill_dep = logging_p.get_variable('quill_dep')
log_dep = [logging_dep, quill_dep] log_dep = [logging_dep, quill_dep]
alias_target('build-liblogging', liblogging) alias_target('build-liblogging', liblogging)

View File

@@ -1,6 +1,10 @@
plugin_p = subproject('libplugin', default_options: ['pkg-config=' + pkg_config_bool_str, 'tests=' + get_option('tests').to_string()]) plugin_p = subproject('libplugin', default_options: [
'pkg-config=' + get_option('pkg_config').to_string(),
'build-tests=' + get_option('build_tests').to_string(),
'python-wheel=' + get_option('build_python').to_string(),
])
libplugin = plugin_p.get_variable('libplugin') libplugin = plugin_p.get_variable('libplugin')
plugin_dep = plugin_p.get_variable('plugin_dep') plugin_dep = plugin_p.get_variable('plugin_dep')
alias_target('build-libplugin', libplugin) alias_target('build-libplugin', libplugin)

View File

@@ -1,6 +1,19 @@
subdir('libcomposition') if get_option('build_lib_comp') or get_option('build_lib_all') or get_option('build_python')
subdir('libconfig') subdir('libcomposition')
subdir('libconstants') endif
subdir('liblogging') if get_option('build_lib_config') or get_option('build_lib_all') or get_option('build_python')
subdir('libplugin') subdir('libconfig')
subdir('pybind') endif
if get_option('build_lib_const') or get_option('build_lib_all') or get_option('build_python')
subdir('libconstants')
endif
if get_option('build_lib_log') or get_option('build_lib_all')
subdir('liblogging')
endif
if get_option('build_lib_plugin') or get_option('build_lib_all')
subdir('libplugin')
endif
if get_option('build_python')
subdir('pybind')
endif

View File

@@ -1,8 +1,7 @@
# --- Python Extension Setup ---
py_installation = import('python').find_installation('python3', pure: false) py_installation = import('python').find_installation('python3', pure: false)
py_mod = py_installation.extension_module( py_mod = py_installation.extension_module(
'_phys', # Name of the generated .so/.pyd file (without extension) '_phys',
sources: [ sources: [
meson.project_source_root() + '/src-pybind/bindings.cpp', meson.project_source_root() + '/src-pybind/bindings.cpp',
meson.project_source_root() + '/src-pybind/composition/bindings.cpp', meson.project_source_root() + '/src-pybind/composition/bindings.cpp',
@@ -34,6 +33,7 @@ py_installation.install_sources(
meson.project_source_root() + '/src-pybind/fourdst/_phys/atomic.pyi', meson.project_source_root() + '/src-pybind/fourdst/_phys/atomic.pyi',
meson.project_source_root() + '/src-pybind/fourdst/_phys/config.pyi', meson.project_source_root() + '/src-pybind/fourdst/_phys/config.pyi',
meson.project_source_root() + '/src-pybind/fourdst/_phys/constants.pyi', meson.project_source_root() + '/src-pybind/fourdst/_phys/constants.pyi',
meson.project_source_root() + '/src-pybind/fourdst/_phys/exceptions.pyi',
), ),
subdir: 'fourdst/', subdir: 'fourdst/',
) )

View File

@@ -1,19 +1,13 @@
project('fourdst', 'cpp', version: 'v0.9.6', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') project('fourdst', 'cpp', version: 'v0.9.14', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
add_project_arguments('-fvisibility=default', language: 'cpp') add_project_arguments('-fvisibility=default', language: 'cpp')
pkg_config_bool_str = 'false'
if get_option('pkg-config')
pkg_config_bool_str = 'true'
endif
# Configure vendor libraries # Configure vendor libraries
subdir('build-config') subdir('build-config')
# Configure python bindings # Configure python bindings
subdir('build-python') if get_option('build_python')
subdir('build-python')
# Build python bindings endif
subdir('src-pybind')

View File

@@ -1,3 +1,10 @@
option('pkg-config', type: 'boolean', value: false, description: 'generate pkg-config file for all libraries and fourdst (defaults to false to allow easy pip building)') option('pkg_config', type: 'boolean', value: false, description: 'generate pkg-config file for all libraries and fourdst (defaults to false to allow easy pip building)')
option('electron-build-py-backend', type: 'boolean', value: false, description: 'use pyinstaller to build the python backend for the electron app') option('electron_build_py_backend', type: 'boolean', value: false, description: 'use pyinstaller to build the python backend for the electron app')
option('tests', type: 'boolean', value: false, description: 'compile subproject tests') option('build_tests', type: 'boolean', value: false, description: 'compile subproject tests')
option('build_lib_all', type: 'boolean', value: true, description: 'build the full fourdst library with all features enabled')
option('build_lib_comp', type: 'boolean', value: false, description: 'build the minimal fourdst library with only compression and decompression features enabled')
option('build_lib_config', type: 'boolean', value: false, description: 'build the fourdst library configuration tool only')
option('build_lib_const', type: 'boolean', value: false, description: 'build the fourdst library constants only')
option('build_python', type: 'boolean', value: true, description: 'build the python bindings so you can use fourdst from python. This will also build libcomposition, libconfig, and libconstants')
option('build_lib_log', type: 'boolean', value: false, description: 'build the fourdst library logging features only')
option('build_lib_plugin', type: 'boolean', value: false, description: 'build the fourdst plugin module only')

View File

@@ -8,7 +8,7 @@ build-backend = "mesonpy"
[project] [project]
name = "fourdst" # Choose your Python package name name = "fourdst" # Choose your Python package name
version = "0.8.5" # Your project's version version = "v0.9.11" # Your project's version
description = "Python interface to the utility fourdst modules from the 4D-STAR project" description = "Python interface to the utility fourdst modules from the 4D-STAR project"
readme = "readme.md" readme = "readme.md"
license = { file = "LICENSE.txt" } # Reference your license file [cite: 2] license = { file = "LICENSE.txt" } # Reference your license file [cite: 2]

View File

@@ -9,6 +9,9 @@
PYBIND11_MODULE(_phys, m) { PYBIND11_MODULE(_phys, m) {
m.doc() = "Python bindings for the fourdst utility modules which are a part of the 4D-STAR project."; m.doc() = "Python bindings for the fourdst utility modules which are a part of the 4D-STAR project.";
auto exceptionMod = m.def_submodule("exceptions", "Exception bindings");
register_comp_exceptions(exceptionMod);
auto atomicMod = m.def_submodule("atomic", "Species bindings"); auto atomicMod = m.def_submodule("atomic", "Species bindings");
register_species_bindings(atomicMod); register_species_bindings(atomicMod);
@@ -18,6 +21,6 @@ PYBIND11_MODULE(_phys, m) {
auto constMod = m.def_submodule("constants", "Constants-module bindings"); auto constMod = m.def_submodule("constants", "Constants-module bindings");
register_const_bindings(constMod); register_const_bindings(constMod);
auto configMod = m.def_submodule("config", "Configuration-module bindings"); const auto configMod = m.def_submodule("config", "Configuration-module bindings");
register_config_bindings(configMod); register_config_enums(configMod);
} }

View File

@@ -12,6 +12,7 @@
#include "fourdst/atomic/species.h" #include "fourdst/atomic/species.h"
#include "fourdst/composition/utils.h" #include "fourdst/composition/utils.h"
#include "fourdst/composition/utils/composition_hash.h" #include "fourdst/composition/utils/composition_hash.h"
#include "fourdst/composition/exceptions/exceptions_composition.h"
namespace py = pybind11; namespace py = pybind11;
@@ -335,7 +336,7 @@ void register_comp_bindings(pybind11::module &m) {
} }
void register_species_bindings(const pybind11::module &chem_submodule) { void register_species_bindings(pybind11::module &chem_submodule) {
// --- Bindings for species module --- // --- Bindings for species module ---
py::class_<fourdst::atomic::Species>(chem_submodule, "Species") py::class_<fourdst::atomic::Species>(chem_submodule, "Species")
.def("mass", &fourdst::atomic::Species::mass, "Get atomic mass (amu)") .def("mass", &fourdst::atomic::Species::mass, "Get atomic mass (amu)")
@@ -372,4 +373,35 @@ void register_species_bindings(const pybind11::module &chem_submodule) {
chem_submodule.attr("species") = py::cast(fourdst::atomic::species); // Expose the species map chem_submodule.attr("species") = py::cast(fourdst::atomic::species); // Expose the species map
auto replace_dash_with_underscore = [](const std::string& str) {
std::string result = str;
std::ranges::replace(result, '-', '_');
return result;
};
for (const auto& [name, species] : fourdst::atomic::species) {
chem_submodule.attr(replace_dash_with_underscore(name).c_str()) = py::cast(species);
}
chem_submodule.def("az_to_species",
[](const int a, const int z) {
const auto result = fourdst::atomic::az_to_species(a, z);
if (!result) {
throw fourdst::composition::exceptions::SpeciesError(std::format("Species with A={} and Z={} not found.", a, z));
}
return result.value();
},
py::arg("a"),
py::arg("z"),
"Get Species object from proton number (Z) and mass number (A)."
);
}
void register_comp_exceptions(pybind11::module &m) {
py::register_exception<fourdst::composition::exceptions::CompositionError>(m, "CompositionError");
py::register_exception<fourdst::composition::exceptions::InvalidCompositionError>(m, "InvalidCompositionError", m.attr("CompositionError"));
py::register_exception<fourdst::composition::exceptions::SpeciesError>(m, "SpeciesError");
py::register_exception<fourdst::composition::exceptions::UnknownSymbolError>(m, "UnknownSymbolError", m.attr("SpeciesError"));
py::register_exception<fourdst::composition::exceptions::UnregisteredSymbolError>(m, "UnregisteredSymbolError", m.attr("SpeciesError"));
} }

View File

@@ -2,5 +2,7 @@
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
void register_comp_exceptions(pybind11::module &m);
void register_species_bindings(pybind11::module &m);
void register_comp_bindings(pybind11::module &m); void register_comp_bindings(pybind11::module &m);
void register_species_bindings(const pybind11::module &m);

View File

@@ -1,55 +1,17 @@
#include <pybind11/pybind11.h>
#include <pybind11/stl.h> // Needed for vectors, maps, sets, strings
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc if needed directly
#include <string>
#include "bindings.h" #include "bindings.h"
#include <pybind11/pybind11.h>
#include "fourdst/config/config.h" #include "fourdst/config/config.h"
namespace py = pybind11; void register_config_enums(const pybind11::module_& m) {
using namespace fourdst::config;
pybind11::enum_<ConfigState>(m, "ConfigState")
.value("DEFAULT", ConfigState::DEFAULT)
.value("LOADED_FROM_FILE", ConfigState::LOADED_FROM_FILE)
.export_values();
// Helper function template for binding Config::get pybind11::enum_<RootNameLoadPolicy>(m, "RootNameLoadPolicy")
template <typename T> .value("FROM_FILE", RootNameLoadPolicy::FROM_FILE)
void def_config_get(py::module &m) { .value("KEEP_CURRENT", RootNameLoadPolicy::KEEP_CURRENT)
m.def("get", .export_values();
[](const std::string &key, T defaultValue) {
return fourdst::config::Config::getInstance().get<T>(key, defaultValue);
},
py::arg("key"), py::arg("defaultValue"),
"Get configuration value (type inferred from default)");
}
void register_config_bindings(pybind11::module &config_submodule) {
def_config_get<int>(config_submodule);
def_config_get<double>(config_submodule);
def_config_get<std::string>(config_submodule);
def_config_get<bool>(config_submodule);
config_submodule.def("loadConfig",
[](const std::string& configFilePath) {
return fourdst::config::Config::getInstance().loadConfig(configFilePath);
},
py::arg("configFilePath"),
"Load configuration from a YAML file.");
config_submodule.def("has",
[](const std::string &key) {
return fourdst::config::Config::getInstance().has(key);
},
py::arg("key"),
"Check if a key exists in the configuration.");
config_submodule.def("keys",
[]() {
return py::cast(fourdst::config::Config::getInstance().keys());
},
"Get a list of all configuration keys.");
config_submodule.def("__repr__",
[]() {
std::ostringstream oss;
oss << fourdst::config::Config::getInstance(); // Use the existing operator<<
return std::string("<fourdsse_bindings.config module accessing C++ Singleton>\n") + oss.str();
});
} }

View File

@@ -1,5 +1,26 @@
#pragma once #pragma once
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include "fourdst/config/config.h"
void register_config_bindings(pybind11::module &config_submodule); #include <string>
#include <format>
void register_config_enums(const pybind11::module_& m);
template <typename ConfigType>
pybind11::class_<ConfigType> bind_config_specialization(pybind11::module_& m , const std::string& name) {
return pybind11::class_<ConfigType>(m, name.c_str())
.def(pybind11::init<>())
.def("load", &ConfigType::load, pybind11::arg("file_path"), "Load configuration from a file.")
.def("save", &ConfigType::save, pybind11::arg("file_path") = "config_output.toml", "Save configuration to a file.")
.def("save_schema", &ConfigType::save_schema, pybind11::arg("directory") = ".", "Save the configuration schema to a directory.")
.def("get_state", &ConfigType::get_state, "Get the current state of the configuration.")
.def("describe_state", &ConfigType::describe_state, "Get the current state of the configuration.")
.def("__repr__",
[](const ConfigType &cfg) -> std::string {
return std::format("{}", cfg);
}
);
}

View File

@@ -11,4 +11,4 @@ sys.modules['fourdst.config'] = config
__all__ = ['atomic', 'composition', 'constants', 'config', 'core', 'cli'] __all__ = ['atomic', 'composition', 'constants', 'config', 'core', 'cli']
__version__ = 'v0.9.6' __version__ = 'v0.9.11'

View File

@@ -6,4 +6,5 @@ from . import atomic
from . import composition from . import composition
from . import config from . import config
from . import constants from . import constants
__all__: list[str] = ['atomic', 'composition', 'config', 'constants'] from . import exceptions
__all__: list[str] = ['atomic', 'composition', 'config', 'constants', 'exceptions']

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
"""
Exception bindings
"""
from __future__ import annotations
__all__: list[str] = ['CompositionError', 'InvalidCompositionError', 'SpeciesError', 'UnknownSymbolError', 'UnregisteredSymbolError']
class CompositionError(Exception):
pass
class InvalidCompositionError(CompositionError):
pass
class SpeciesError(Exception):
pass
class UnknownSymbolError(SpeciesError):
pass
class UnregisteredSymbolError(SpeciesError):
pass

View File

@@ -1,4 +0,0 @@
subdir('composition')
subdir('constants')
subdir('config')

View File

@@ -1,4 +1,4 @@
[wrap-git] [wrap-git]
url = https://github.com/4D-STAR/libcomposition.git url = https://github.com/4D-STAR/libcomposition.git
revision = v2.2.0 revision = v2.2.4
depth = 1 depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git] [wrap-git]
url = https://github.com/4D-STAR/libconfig.git url = https://github.com/4D-STAR/libconfig.git
revision = v1.1.3 revision = v2.0.2
depth = 1 depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git] [wrap-git]
url = https://github.com/4D-STAR/libconstants.git url = https://github.com/4D-STAR/libconstants.git
revision = v1.1.0 revision = v1.1.1
depth = 1 depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git] [wrap-git]
url = https://github.com/4D-STAR/liblogging.git url = https://github.com/4D-STAR/liblogging.git
revision = v1.1.0 revision = v1.1.1
depth = 1 depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git] [wrap-git]
url = https://github.com/4D-STAR/libplugin.git url = https://github.com/4D-STAR/libplugin.git
revision = v0.3.4 revision = v0.3.7
depth = 1 depth = 1