From db88e308de30d12c83d9e9df17c38eaf008df527 Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Sat, 21 Jun 2025 11:33:27 -0400 Subject: [PATCH] build(libcomposition): brought working build system into libcomposition --- .gitignore | 91 +++++++++++ assets/static/atomic/include/atomicSpecies.h | 8 +- assets/static/atomic/include/species.h | 2 +- assets/static/meson.build | 1 + build-config/fourdst/libconfig/meson.build | 2 + build-config/fourdst/libconstants/meson.build | 2 + build-config/fourdst/liblogging/meson.build | 6 + build-config/fourdst/meson.build | 3 + build-config/meson.build | 21 +-- meson.build | 42 +++++ readme.md | 23 +++ src/composition/meson.build | 6 +- src/composition/private/composition.cpp | 18 +-- src/composition/public/composition.h | 16 +- src/meson.build | 1 + subprojects/libconfig.wrap | 7 + subprojects/libconstants.wrap | 7 + subprojects/liblogging.wrap | 7 + subprojects/quill.wrap | 2 + subprojects/yaml-cpp.wrap | 2 + tests/composition/compositionTest.cpp | 62 +++---- tests/meson.build | 7 + utils/atomic/convertWeightsToHeader.py | 151 ++++++++++++++++++ utils/atomic/readme.md | 13 ++ 24 files changed, 424 insertions(+), 76 deletions(-) create mode 100644 .gitignore create mode 100644 assets/static/meson.build create mode 100644 build-config/fourdst/libconfig/meson.build create mode 100644 build-config/fourdst/libconstants/meson.build create mode 100644 build-config/fourdst/liblogging/meson.build create mode 100644 build-config/fourdst/meson.build create mode 100644 meson.build create mode 100644 readme.md create mode 100644 src/meson.build create mode 100644 subprojects/libconfig.wrap create mode 100644 subprojects/libconstants.wrap create mode 100644 subprojects/liblogging.wrap create mode 100644 subprojects/quill.wrap create mode 100644 subprojects/yaml-cpp.wrap create mode 100644 tests/meson.build create mode 100644 utils/atomic/convertWeightsToHeader.py create mode 100644 utils/atomic/readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a242571 --- /dev/null +++ b/.gitignore @@ -0,0 +1,91 @@ +# Python +__pycache__/ +*.py[cod] +*.pyo +*.pyd +*.env +*.venv +env/ +venv/ +ENV/ +ENV.bak/ +*.egg-info/ +dist/ +build/ +*.egg + +# C and C++ (using Meson) +build/ +*.o +*.a +*.so +*.d +*.dSYM/ +*.exe +*.out +*.obj +*.dll +*.lib +*.pdb +*.exp +*.log +*.stackdump + +# Fortran +*.mod +*.o +*.a +*.so +*.exe +*.out + +# Doxygen +html/ +latex/ +xml/ +man/ +rtf/ +tags + +## Misc +*.swp +*._DS_Store +*.DS_Store +*.bak +*.tmp +*.log +*.cache +*.private +*.private/ + +subprojects/mfem/ +subprojects/tetgen/ +subprojects/yaml-cpp/ +subprojects/quill/ +subprojects/googletest-*/ +subprojects/opat-core/ +subprojects/pybind11*/ +subprojects/packagecache/ +subprojects/hypre/ +subprojects/qhull/ +subprojects/cppad/ +subprojects/libconfig/ +subprojects/libconstants/ +subprojects/liblogging/ + +qhull.wrap + +.vscode/ + +*.log +mpi-install-log.txt + +output/ + +.boost_installed +4DSSE_logs/ +.last_build_flags + +.idea/ + +scratch/ diff --git a/assets/static/atomic/include/atomicSpecies.h b/assets/static/atomic/include/atomicSpecies.h index e6f5a8a..b126805 100644 --- a/assets/static/atomic/include/atomicSpecies.h +++ b/assets/static/atomic/include/atomicSpecies.h @@ -5,7 +5,7 @@ #include #include "atomicSpecies.h" -namespace serif::atomic { +namespace fourdst::atomic { struct Species { std::string m_name; //< Name of the species std::string m_el; //< Element symbol @@ -101,9 +101,9 @@ namespace serif::atomic { namespace std { template<> - struct hash { - size_t operator()(const serif::atomic::Species& s) const noexcept { + struct hash { + size_t operator()(const fourdst::atomic::Species& s) const noexcept { return std::hash()(s.m_name); } }; -} // namespace std \ No newline at end of file +} // namespace std diff --git a/assets/static/atomic/include/species.h b/assets/static/atomic/include/species.h index b7b7c71..66acdd8 100644 --- a/assets/static/atomic/include/species.h +++ b/assets/static/atomic/include/species.h @@ -4,7 +4,7 @@ #include #include "atomicSpecies.h" -namespace serif::atomic { +namespace fourdst::atomic { static const Species n_1("n-1", "n", 1, 1, 0, 1, 0.0, "B-", 782.347, 1.0086649159, 0.00047); static const Species H_1("H-1", "H", -1, 0, 1, 1, 0.0, "B-", std::numeric_limits::quiet_NaN(), 1.007825031898, 1.4e-05); static const Species H_2("H-2", "H", 0, 1, 1, 2, 1112.2831, "B-", std::numeric_limits::quiet_NaN(), 2.014101777844, 1.5e-05); diff --git a/assets/static/meson.build b/assets/static/meson.build new file mode 100644 index 0000000..aa735dc --- /dev/null +++ b/assets/static/meson.build @@ -0,0 +1 @@ +subdir('atomic') diff --git a/build-config/fourdst/libconfig/meson.build b/build-config/fourdst/libconfig/meson.build new file mode 100644 index 0000000..b7f6a5e --- /dev/null +++ b/build-config/fourdst/libconfig/meson.build @@ -0,0 +1,2 @@ +config_p = subproject('libconfig') +config_dep = config_p.get_variable('config_dep') \ No newline at end of file diff --git a/build-config/fourdst/libconstants/meson.build b/build-config/fourdst/libconstants/meson.build new file mode 100644 index 0000000..d578238 --- /dev/null +++ b/build-config/fourdst/libconstants/meson.build @@ -0,0 +1,2 @@ +const_p = subproject('libconstants') +const_dep = const_p.get_variable('const_dep') diff --git a/build-config/fourdst/liblogging/meson.build b/build-config/fourdst/liblogging/meson.build new file mode 100644 index 0000000..95b1800 --- /dev/null +++ b/build-config/fourdst/liblogging/meson.build @@ -0,0 +1,6 @@ +logging_p = subproject('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 new file mode 100644 index 0000000..c4385ff --- /dev/null +++ b/build-config/fourdst/meson.build @@ -0,0 +1,3 @@ +subdir('libconstants') +subdir('liblogging') +subdir('libconfig') diff --git a/build-config/meson.build b/build-config/meson.build index d3f262e..efdf5a1 100644 --- a/build-config/meson.build +++ b/build-config/meson.build @@ -1,24 +1,5 @@ cmake = import('cmake') -subdir('mfem') -subdir('yaml-cpp') -subdir('quill') -subdir('boost') -subdir('opatIO') -subdir('mpi') -subdir('hypre') -subdir('pybind') +subdir('fourdst') subdir('cppad') -# Set the config file error handling options -configErr = get_option('config_error_handling') - -# build up any -D flags we need -commonCppArgs = [] -if configErr == 'warn' - commonCppArgs += ['-DCONFIG_WARN'] -elif configErr == 'harsh' - commonCppArgs += ['-DCONFIG_HARSH'] -endif - -add_project_arguments(commonCppArgs, language: 'cpp') diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..88303a2 --- /dev/null +++ b/meson.build @@ -0,0 +1,42 @@ +# *********************************************************************** +# +# Copyright (C) 2025 -- The 4D-STAR Collaboration +# File Author: Emily Boudreaux +# Last Modified: June 21, 2025 +# +# libcomposition is free software; you can use it and/or modify +# it under the terms and restrictions the GNU General Library Public +# License version 3 (GPLv3) as published by the Free Software Foundation. +# +# libcomposition is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this software; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# *********************************************************************** # +project('libcomposition', 'cpp', version: 'v1.0.0', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0') + +# Add default visibility for all C++ targets +add_project_arguments('-fvisibility=default', language: 'cpp') + +cpp = meson.get_compiler('cpp') +subdir('build-config') +subdir('assets/static') +subdir('src') +subdir('tests') + +pkg = import('pkgconfig') +pkg.generate( + name: 'libcomposition', + description: 'Composition module for SERiF and related projects', + version: meson.project_version(), + libraries: [libcomposition], + subdirs: ['libcomposition'], + filebase: 'libcomposition', + install_dir: join_paths(get_option('libdir'), 'pkgconfig') +) + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b98d4c2 --- /dev/null +++ b/readme.md @@ -0,0 +1,23 @@ +# libcomposition + +libcomposition is the chemistry tracking tool used by SERiF and related products. + +This has been broken out of the main serif project to allow for more modularity + +## Building +In order to build libconstants you need `meson>=1.5.0`. This can be installed with `pip` + +```bash +pip install "meson>=1.5.0" +``` + +Then from the root libcomposition directory it is as simple as + +```bash +meson setup build --buildtype=release +meson compile -C build +meson test -C build +``` + +this will auto generate a pkg-config file for you so that linking other libraries to libcomposition is easy. + diff --git a/src/composition/meson.build b/src/composition/meson.build index a822e52..7262223 100644 --- a/src/composition/meson.build +++ b/src/composition/meson.build @@ -8,10 +8,10 @@ composition_headers = files( ) dependencies = [ - probe_dep, - quill_dep, species_weight_dep, const_dep, + config_dep, + log_dep ] # Define the libcomposition library so it can be linked against by other parts of the build system @@ -30,4 +30,4 @@ composition_dep = declare_dependency( ) # Make headers accessible -install_headers(composition_headers, subdir : 'SERiF/composition') \ No newline at end of file +install_headers(composition_headers, subdir : 'libcomposition/composition') diff --git a/src/composition/private/composition.cpp b/src/composition/private/composition.cpp index 7634d55..6c12184 100644 --- a/src/composition/private/composition.cpp +++ b/src/composition/private/composition.cpp @@ -33,13 +33,13 @@ #include "atomicSpecies.h" #include "species.h" -namespace serif::composition { +namespace fourdst::composition { - CompositionEntry::CompositionEntry() : m_symbol("H-1"), m_isotope(serif::atomic::species.at("H-1")), + CompositionEntry::CompositionEntry() : m_symbol("H-1"), m_isotope(fourdst::atomic::species.at("H-1")), m_initialized(false) { } - CompositionEntry::CompositionEntry(const std::string& symbol, const bool massFracMode) : m_symbol(symbol), m_isotope(serif::atomic::species.at(symbol)), m_massFracMode(massFracMode) { + CompositionEntry::CompositionEntry(const std::string& symbol, const bool massFracMode) : m_symbol(symbol), m_isotope(fourdst::atomic::species.at(symbol)), m_massFracMode(massFracMode) { setSpecies(symbol); } @@ -56,11 +56,11 @@ namespace serif::composition { if (m_initialized) { throw std::runtime_error("Composition entry is already initialized."); } - if (serif::atomic::species.count(symbol) == 0) { + if (fourdst::atomic::species.count(symbol) == 0) { throw std::runtime_error("Invalid symbol."); } m_symbol = symbol; - m_isotope = serif::atomic::species.at(symbol); + m_isotope = fourdst::atomic::species.at(symbol); m_initialized = true; } @@ -101,7 +101,7 @@ namespace serif::composition { return m_relAbundance; } - serif::atomic::Species CompositionEntry::isotope() const { + fourdst::atomic::Species CompositionEntry::isotope() const { return m_isotope; } @@ -258,7 +258,7 @@ namespace serif::composition { } bool Composition::isValidSymbol(const std::string& symbol) { - return serif::atomic::species.contains(symbol); + return fourdst::atomic::species.contains(symbol); } double Composition::setMassFraction(const std::string& symbol, const double& mass_fraction) { @@ -652,7 +652,7 @@ namespace serif::composition { return m_compositions.count(symbol) > 0; } - bool Composition::contains(const serif::atomic::Species &isotope) const { + bool Composition::contains(const fourdst::atomic::Species &isotope) const { // Check if the isotope's symbol is in the composition if (!m_finalized) { LOG_ERROR(m_logger, "Composition has not been finalized."); @@ -696,4 +696,4 @@ namespace serif::composition { return os; } -} // namespace serif::composition \ No newline at end of file +} // namespace fourdst::composition diff --git a/src/composition/public/composition.h b/src/composition/public/composition.h index 27c9911..d3671da 100644 --- a/src/composition/public/composition.h +++ b/src/composition/public/composition.h @@ -27,12 +27,12 @@ #include -#include "probe.h" #include "config.h" +#include "logging.h" #include "atomicSpecies.h" -namespace serif::composition { +namespace fourdst::composition { struct CanonicalComposition { double X = 0.0; ///< Mass fraction of Hydrogen. double Y = 0.0; ///< Mass fraction of Helium. @@ -63,7 +63,7 @@ namespace serif::composition { */ struct CompositionEntry { std::string m_symbol; ///< The chemical symbol of the species. - serif::atomic::Species m_isotope; ///< The isotope of the species. + fourdst::atomic::Species m_isotope; ///< The isotope of the species. bool m_massFracMode = true; ///< The mode of the composition entry. True if mass fraction, false if number fraction. double m_massFraction = 0.0; ///< The mass fraction of the species. @@ -142,7 +142,7 @@ namespace serif::composition { * @brief Gets the isotope of the species. * @return The isotope of the species. */ - serif::atomic::Species isotope() const; + fourdst::atomic::Species isotope() const; /** * @brief Gets the mode of the composition entry. @@ -215,8 +215,8 @@ namespace serif::composition { */ class Composition { private: - serif::config::Config& m_config = serif::config::Config::getInstance(); - serif::probe::LogManager& m_logManager = serif::probe::LogManager::getInstance(); + fourdst::config::Config& m_config = fourdst::config::Config::getInstance(); + fourdst::logging::LogManager& m_logManager = fourdst::logging::LogManager::getInstance(); quill::Logger* m_logger = m_logManager.getLogger("log"); bool m_finalized = false; ///< True if the composition is finalized. @@ -473,7 +473,7 @@ namespace serif::composition { */ bool hasSymbol(const std::string& symbol) const; - bool contains(const serif::atomic::Species& isotope) const; + bool contains(const fourdst::atomic::Species& isotope) const; /** * @brief Sets the composition mode. @@ -508,4 +508,4 @@ namespace serif::composition { Composition operator+(const Composition& other) const; }; -}; // namespace serif::composition \ No newline at end of file +}; // namespace fourdst::composition diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..8168d75 --- /dev/null +++ b/src/meson.build @@ -0,0 +1 @@ +subdir('composition') diff --git a/subprojects/libconfig.wrap b/subprojects/libconfig.wrap new file mode 100644 index 0000000..0ee2c0d --- /dev/null +++ b/subprojects/libconfig.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/4D-STAR/libconfig.git +revision = v1.0.0 +depth = 1 + +[provide] +libconfig = config_dep \ No newline at end of file diff --git a/subprojects/libconstants.wrap b/subprojects/libconstants.wrap new file mode 100644 index 0000000..1d42fa1 --- /dev/null +++ b/subprojects/libconstants.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/4D-STAR/libconstants.git +revision = v1.1 +depth = 1 + +[provide] +libconstants = const_dep diff --git a/subprojects/liblogging.wrap b/subprojects/liblogging.wrap new file mode 100644 index 0000000..5b37950 --- /dev/null +++ b/subprojects/liblogging.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/4D-STAR/liblogging.git +revision = v1.0.1 +depth = 1 + +[provide] +liblogging = logging_dep \ No newline at end of file diff --git a/subprojects/quill.wrap b/subprojects/quill.wrap new file mode 100644 index 0000000..e8d8184 --- /dev/null +++ b/subprojects/quill.wrap @@ -0,0 +1,2 @@ +[wrap-redirect] +filename = liblogging/subprojects/quill.wrap diff --git a/subprojects/yaml-cpp.wrap b/subprojects/yaml-cpp.wrap new file mode 100644 index 0000000..4a96321 --- /dev/null +++ b/subprojects/yaml-cpp.wrap @@ -0,0 +1,2 @@ +[wrap-redirect] +filename = libconfig/subprojects/yaml-cpp.wrap diff --git a/tests/composition/compositionTest.cpp b/tests/composition/compositionTest.cpp index c9dfd48..5fb7884 100644 --- a/tests/composition/compositionTest.cpp +++ b/tests/composition/compositionTest.cpp @@ -19,20 +19,20 @@ class compositionTest : public ::testing::Test {}; * @brief Test the constructor of the composition class. */ TEST_F(compositionTest, isotopeMasses) { - EXPECT_NO_THROW(serif::atomic::species.at("H-1")); - EXPECT_DOUBLE_EQ(serif::atomic::species.at("H-1").mass(), 1.007825031898); - EXPECT_DOUBLE_EQ(serif::atomic::species.at("He-3").mass(), 3.0160293219700001); - EXPECT_DOUBLE_EQ(serif::atomic::species.at("He-4").mass(),4.0026032541300003); + EXPECT_NO_THROW(fourdst::atomic::species.at("H-1")); + EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("H-1").mass(), 1.007825031898); + EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("He-3").mass(), 3.0160293219700001); + EXPECT_DOUBLE_EQ(fourdst::atomic::species.at("He-4").mass(),4.0026032541300003); } TEST_F(compositionTest, constructor) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - EXPECT_NO_THROW(serif::composition::Composition comp); + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + EXPECT_NO_THROW(fourdst::composition::Composition comp); } TEST_F(compositionTest, registerSymbol) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; EXPECT_NO_THROW(comp.registerSymbol("H-1")); EXPECT_NO_THROW(comp.registerSymbol("He-4")); EXPECT_THROW(comp.registerSymbol("H-19"), std::runtime_error); @@ -46,8 +46,8 @@ TEST_F(compositionTest, registerSymbol) { } TEST_F(compositionTest, setGetComposition) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); @@ -72,8 +72,8 @@ TEST_F(compositionTest, setGetComposition) { } TEST_F(compositionTest, setGetNumberFraction) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1", false); comp.registerSymbol("He-4", false); @@ -89,8 +89,8 @@ TEST_F(compositionTest, setGetNumberFraction) { } TEST_F(compositionTest, subset) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.6); @@ -98,14 +98,14 @@ TEST_F(compositionTest, subset) { EXPECT_NO_THROW(comp.finalize()); std::vector symbols = {"H-1"}; - serif::composition::Composition subsetComp = comp.subset(symbols, "norm"); + fourdst::composition::Composition subsetComp = comp.subset(symbols, "norm"); EXPECT_TRUE(subsetComp.finalize()); EXPECT_DOUBLE_EQ(subsetComp.getMassFraction("H-1"), 1.0); } TEST_F(compositionTest, finalizeWithNormalization) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.3); @@ -116,8 +116,8 @@ TEST_F(compositionTest, finalizeWithNormalization) { } TEST_F(compositionTest, finalizeWithoutNormalization) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.5); @@ -128,8 +128,8 @@ TEST_F(compositionTest, finalizeWithoutNormalization) { } TEST_F(compositionTest, getComposition) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.6); @@ -143,8 +143,8 @@ TEST_F(compositionTest, getComposition) { } TEST_F(compositionTest, setCompositionMode) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.6); @@ -165,8 +165,8 @@ TEST_F(compositionTest, setCompositionMode) { } TEST_F(compositionTest, hasSymbol) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp; comp.registerSymbol("H-1"); comp.registerSymbol("He-4"); comp.setMassFraction("H-1", 0.6); @@ -180,28 +180,28 @@ TEST_F(compositionTest, hasSymbol) { } TEST_F(compositionTest, mix) { - serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); - serif::composition::Composition comp1; + fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME); + fourdst::composition::Composition comp1; comp1.registerSymbol("H-1"); comp1.registerSymbol("He-4"); comp1.setMassFraction("H-1", 0.6); comp1.setMassFraction("He-4", 0.4); EXPECT_NO_THROW(comp1.finalize()); - serif::composition::Composition comp2; + fourdst::composition::Composition comp2; comp2.registerSymbol("H-1"); comp2.registerSymbol("He-4"); comp2.setMassFraction("H-1", 0.4); comp2.setMassFraction("He-4", 0.6); EXPECT_NO_THROW(comp2.finalize()); - serif::composition::Composition mixedComp = comp1 + comp2; + fourdst::composition::Composition mixedComp = comp1 + comp2; EXPECT_TRUE(mixedComp.finalize()); EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("H-1"), 0.5); EXPECT_DOUBLE_EQ(mixedComp.getMassFraction("He-4"), 0.5); - serif::composition::Composition mixedComp2 = comp1.mix(comp2, 0.25); + fourdst::composition::Composition mixedComp2 = comp1.mix(comp2, 0.25); EXPECT_TRUE(mixedComp2.finalize()); EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("H-1"), 0.45); EXPECT_DOUBLE_EQ(mixedComp2.getMassFraction("He-4"), 0.55); -} \ No newline at end of file +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..3db5282 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,7 @@ +# Google Test dependency +gtest_dep = dependency('gtest', main: true, required : true) +gtest_main = dependency('gtest_main', required: true) +gtest_nomain_dep = dependency('gtest', main: false, required : true) + +# Subdirectories for unit and integration tests +subdir('composition') diff --git a/utils/atomic/convertWeightsToHeader.py b/utils/atomic/convertWeightsToHeader.py new file mode 100644 index 0000000..a912013 --- /dev/null +++ b/utils/atomic/convertWeightsToHeader.py @@ -0,0 +1,151 @@ +import pandas as pd + +# Define fixed-width column specifications based on the format: +# a1 (width 1), i3 (width 3), i5 (width 5), i5 (width 5), i5 (width 5), +# 1x (skip 1), a3 (width 3), a4 (width 4), 1x (skip 1), +# f14.6 (width 14), f12.6 (width 12), f13.5 (width 13), +# 1x (skip 1), f10.5 (width 10), 1x (skip 1), +# a2 (width 2), f13.5 (width 13), f11.5 (width 11), +# 1x (skip 1), i3 (width 3), 1x (skip 1), +# f13.6 (width 13), f12.6 (width 12) +# Compute cumulative positions (0-indexed): +colSpecs = [ + (0, 1), # control + (1, 4), # NZ + (4, 9), # N + (9, 14), # Z + (14, 19), # A + # skip 1 char at position 19; next field starts at 20 + (20, 23), # el + (23, 27), # o + # skip 1 char at position 27; next field starts at 28 + (28, 42), # massExcess (f14.6) + (42, 54), # massExcessUnc (f12.6) + (54, 67), # bindingEnergy (f13.5) + # skip 1 char at position 67; next field starts at 68 + (68, 78), # bindingEnergyUnc (f10.5) + # skip 1 char at position 78; next field starts at 79 + (79, 81), # betaCode (a2) + (81, 94), # betaDecayEnergy (f13.5) + (94, 105), # betaDecayEnergyUnc (f11.5) + # skip 1 char at position 105; next field starts at 106 + (106, 109),# atomicMassInt (i3) + # skip 1 char at position 109; next field starts at 110 + (110, 123),# atomicMassFrac (f13.6) + (123, 135) # atomicMassUnc (f12.6) +] + +# Define column names (using camelCase for variables) +columnNames = [ + "control", + "nz", + "n", + "z", + "a", + "el", + "o", + "massExcess", + "massExcessUnc", + "bindingEnergy", + "bindingEnergyUnc", + "betaCode", + "betaDecayEnergy", + "betaDecayEnergyUnc", + "atomicMassInt", + "atomicMassFrac", + "atomicMassUnc" +] + +def combine_atomic_mass(row): + """ + Combine the integer and fractional parts of the atomic mass. + For example, if atomicMassInt is '1' and atomicMassFrac is '008664.91590', + this function returns float('1008664.91590'). + """ + intPart = str(row["atomicMassInt"]).strip() + fracPart = str(row["atomicMassFrac"]).strip() + try: + combined = int(intPart) + float(fracPart)/1e6 + return combined + except ValueError: + return None + +def mkInstanceName(row): + """ + Make a c++ instance name from the element and atomic number. + """ + speciesName = f"{row['el'].strip()}-{row['a']}" + return speciesName.replace("-", "_") + +def formatSpecies(row): + """ + Format c++ instantiation of Species struct from row data. + """ + name = f"{row['el'].strip()}-{row['a']}" + instanceName = name.replace("-", "_") + nz = int(row['nz']) + n = int(row['n']) + z = int(row['z']) + a = int(row['a']) + bindingEnergy = float(row['bindingEnergy']) + atomicMass = float(row['atomicMass']) + atomicMassUnc = float(row['atomicMassUnc']) + NaN = "std::numeric_limits::quiet_NaN()" + try: + betaDecayEnergy = float(row['betaDecayEnergy'].replace("#", "").replace("*", "")) + except ValueError: + betaDecayEnergy = NaN + instantiation = f"static const Species {instanceName}(\"{name}\", \"{row['el']}\", {nz}, {n}, {z}, {a}, {bindingEnergy}, \"{row['betaCode']}\", {betaDecayEnergy}, {atomicMass}, {atomicMassUnc});" + return instantiation, instanceName + +def formatSpeciesDefines(row): + instanceName = f"SERIF_SPECIES_{formatSpecies(row)[1]}" + define = f"""#ifndef {instanceName.upper()} + #define {instanceName.upper()} +#endif // {instanceName.upper()}""" + return define + +def formatHeader(dataFrame): + """ + Format c++ header file from DataFrame. + """ + header = f"""#pragma once +#include +#include +#include +#include "atomicSpecies.h" + +namespace fourdst::atomic {{ + {'\n '.join([formatSpecies(row)[0] for index, row in dataFrame.iterrows()])} + static const std::unordered_map species = {{ + {'\n '.join([f'{{"{row["el"].strip()}-{row["a"]}", {mkInstanceName(row)}}},' for index, row in dataFrame.iterrows()])} + }}; +}}; // namespace fourdst::atomic + +{'\n'.join([formatSpeciesDefines(row) for index, row in dataFrame.iterrows()])} +""" + return header + +if __name__ == "__main__": + import argparse + import os + parser = argparse.ArgumentParser(description="Convert mass data to c++ header file.") + parser.add_argument("input", help="Input file path.") + parser.add_argument("-o", "--output", help="Output file path.", default="../../assets/static/atomic/include/species.h") + args = parser.parse_args() + + + if not os.path.exists(args.input): + raise FileNotFoundError(f"File not found: {args.input}") + + # Read the file (adjust the skiprows value if your header differs) + dataFrame = pd.read_fwf(args.input, colspecs=colSpecs, names=columnNames, skiprows=36) + + # Combine the two atomic mass fields into one float column + dataFrame["atomicMass"] = dataFrame.apply(combine_atomic_mass, axis=1) + dataFrame.drop(columns=["atomicMassInt", "atomicMassFrac"], inplace=True) + + # Format the header + header = formatHeader(dataFrame) + with open(args.output, "w") as f: + f.write(header) diff --git a/utils/atomic/readme.md b/utils/atomic/readme.md new file mode 100644 index 0000000..b066b1d --- /dev/null +++ b/utils/atomic/readme.md @@ -0,0 +1,13 @@ +# Information +Simple python utility for turning the file assets/atomic/weights.dat into a c++ header which can be included to provide easy access to all atomic weights inside 4DSSE + +## Requirments +In order to use this utility you will need + +- Python +- Pandas + +## Usage +```bash +python convertWeightsToHeader.py -o atomicWeights.h +``` \ No newline at end of file