Merge pull request #77 from tboudreaux/dependency/libconfig

SERiF now uses libconfig
This commit is contained in:
2025-06-21 08:59:50 -04:00
committed by GitHub
35 changed files with 51 additions and 880 deletions

1
.gitignore vendored
View File

@@ -70,6 +70,7 @@ subprojects/hypre/
subprojects/qhull/
subprojects/libconstants/
subprojects/liblogging/
subprojects/libconfig/
qhull.wrap

View File

@@ -0,0 +1,2 @@
config_p = subproject('libconfig')
config_dep = config_p.get_variable('config_dep')

View File

@@ -1,2 +1,3 @@
subdir('libconstants')
subdir('liblogging')
subdir('libconfig')

View File

@@ -216,7 +216,7 @@ namespace serif::composition {
*/
class Composition {
private:
serif::config::Config& m_config = serif::config::Config::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");

View File

@@ -1,26 +0,0 @@
# Define the library
config_sources = files(
'private/config.cpp',
)
config_headers = files(
'public/config.h'
)
# Define the libconfig library so it can be linked against by other parts of the build system
libconfig = library('config',
config_sources,
include_directories: include_directories('public'),
cpp_args: ['-fvisibility=default'],
dependencies: [yaml_cpp_dep],
install : true)
config_dep = declare_dependency(
include_directories: include_directories('public'),
link_with: libconfig,
sources: config_sources,
dependencies: [yaml_cpp_dep],
)
# Make headers accessible
install_headers(config_headers, subdir : '4DSSE/config')

View File

@@ -1,109 +0,0 @@
/* ***********************************************************************
//
// Copyright (C) 2025 -- The 4D-STAR Collaboration
// File Author: Emily Boudreaux
// Last Modified: March 20, 2025
//
// 4DSSE 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.
//
// 4DSSE 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
//
// *********************************************************************** */
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include "yaml-cpp/yaml.h"
#include "config.h"
namespace serif::config {
Config::Config() {}
Config::~Config() {}
Config& Config::getInstance() {
static Config instance;
return instance;
}
bool Config::loadConfig(const std::string& configFile) {
configFilePath = configFile;
try {
yamlRoot = YAML::LoadFile(configFile);
} catch (YAML::BadFile& e) {
std::cerr << "Error: " << e.what() << std::endl;
return false;
}
m_loaded = true;
return true;
}
bool Config::isKeyInCache(const std::string &key) {
return configMap.find(key) != configMap.end();
}
void Config::addToCache(const std::string &key, const YAML::Node &node) {
configMap[key] = node;
}
void Config::registerUnknownKey(const std::string &key) {
unknownKeys.push_back(key);
}
bool Config::has(const std::string &key) {
if (!m_loaded) {
throw std::runtime_error("Error! Config file not loaded");
}
if (isKeyInCache(key)) { return true; }
YAML::Node node = YAML::Clone(yamlRoot);
std::istringstream keyStream(key);
std::string subKey;
while (std::getline(keyStream, subKey, ':')) {
if (!node[subKey]) {
registerUnknownKey(key);
return false;
}
node = node[subKey]; // go deeper
}
// Key exists and is of the requested type
addToCache(key, node);
return true;
}
void recurse_keys(const YAML::Node& node, std::vector<std::string>& keyList, const std::string& path = "") {
if (node.IsMap()) {
for (const auto& it : node) {
auto key = it.first.as<std::string>();
auto new_path = path.empty() ? key : path + ":" + key;
recurse_keys(it.second, keyList, new_path);
}
} else {
keyList.push_back(path);
}
}
std::vector<std::string> Config::keys() const {
std::vector<std::string> keyList;
YAML::Node node = YAML::Clone(yamlRoot);
recurse_keys(node, keyList);
return keyList;
}
}

View File

@@ -1,245 +0,0 @@
/* ***********************************************************************
//
// Copyright (C) 2025 -- The 4D-STAR Collaboration
// File Author: Emily Boudreaux
// Last Modified: March 26, 2025
//
// 4DSSE 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.
//
// 4DSSE 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
//
// *********************************************************************** */
#pragma once
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <stdexcept>
// Required for YAML parsing
#include "yaml-cpp/yaml.h"
// -- Forward Def of Resource manager to let it act as a friend of Config --
namespace serif::resource { class ResourceManager; }
class configTestPrivateAccessor; // Forward declaration for test utility
namespace serif::config {
/**
* @class Config
* @brief Singleton class to manage configuration settings loaded from a YAML file.
*/
class Config {
private:
/**
* @brief Private constructor to prevent instantiation.
*/
Config();
/**
* @brief Destructor.
*/
~Config();
YAML::Node yamlRoot; ///< Root node of the YAML configuration.
std::string configFilePath; ///< Path to the configuration file.
bool debug = false; ///< Flag to enable debug output.
bool loaded = false; ///< Flag to indicate if the configuration has been loaded.
std::map<std::string, YAML::Node> configMap; ///< Cache for the location of configuration settings.
std::vector<std::string> unknownKeys; ///< Cache for the existence of configuration settings.
/**
* @brief Get a value from the configuration cache.
* @tparam T Type of the value to retrieve.
* @param key Key of the configuration value.
* @param defaultValue Default value to return if the key does not exist.
* @return Configuration value of type T.
*/
template <typename T>
T getFromCache(const std::string &key, T defaultValue) {
if (configMap.find(key) != configMap.end()) {
try {
return configMap[key].as<T>();
} catch (const YAML::Exception& e) {
return defaultValue;
}
}
return defaultValue;
}
/**
* @brief Check if a key exists in the configuration cache.
* @param key Key to check.
* @return True if the key exists in the cache, false otherwise.
*/
bool isKeyInCache(const std::string &key);
/**
* @brief Add a key-value pair to the configuration cache.
* @param key Key of the configuration value.
* @param node YAML node containing the configuration value.
*/
void addToCache(const std::string &key, const YAML::Node &node);
/**
* @brief Register a key as not found in the configuration.
* @param key Key that was not found.
*/
void registerUnknownKey(const std::string &key);
bool m_loaded = false;
// Only friends can access get without a default value
template <typename T>
T get(const std::string &key) {
if (!m_loaded) {
throw std::runtime_error("Error! Config file not loaded");
}
if (has(key)) {
return getFromCache<T>(key, T());
} else {
throw std::runtime_error("Error! Key not found in config file");
}
}
public:
/**
* @brief Get the singleton instance of the Config class.
* @return Reference to the Config instance.
*/
static Config& getInstance();
Config (const Config&) = delete;
Config& operator= (const Config&) = delete;
Config (Config&&) = delete;
Config& operator= (Config&&) = delete;
void setDebug(bool debug) { this->debug = debug; }
/**
* @brief Load configuration from a YAML file.
* @param configFilePath Path to the YAML configuration file.
* @return True if the configuration was loaded successfully, false otherwise.
*/
bool loadConfig(const std::string& configFilePath);
/**
* @brief Get the input table from the configuration.
* @return Input table as a string.
*/
std::string getInputTable() const;
/**
* @brief Get a configuration value by key.
* @tparam T Type of the value to retrieve.
* @param key Key of the configuration value.
* @param defaultValue Default value to return if the key does not exist.
* @return Configuration value of type T.
*
* @example
* @code
* Config& config = Config::getInstance();
* config.loadConfig("example.yaml");
* int maxIter = config.get<int>("opac:lowTemp:numeric:maxIter", 10);
*/
template <typename T>
T get(const std::string &key, T defaultValue) {
if (!m_loaded) {
// ONLY THROW ERROR IF HARSH OR WARN CONFIGURATION
#if defined(CONFIG_HARSH)
throw std::runtime_error("Error! Config file not loaded. To disable this error, recompile with CONFIG_HARSH=0");
#elif defined(CONFIG_WARN)
std::cerr << "Warning! Config file not loaded. This instance of 4DSSE was compiled with CONFIG_WARN so the code will continue using only default values" << std::endl;
#endif
}
// --- Check if the key has already been checked for existence
if (std::find(unknownKeys.begin(), unknownKeys.end(), key) != unknownKeys.end()) {
return defaultValue; // If the key has already been added to the unknown cache do not traverse the YAML tree or hit the cache
}
// --- Check if the key is already in the cache (avoid traversing YAML nodes)
if (isKeyInCache(key)) {
return getFromCache<T>(key, defaultValue);
}
// --- If the key is not in the cache, check the YAML file
else {
YAML::Node node = YAML::Clone(yamlRoot);
std::istringstream keyStream(key);
std::string subKey;
while (std::getline(keyStream, subKey, ':')) {
if (!node[subKey]) {
// Key does not exist
registerUnknownKey(key);
return defaultValue;
}
node = node[subKey]; // go deeper
}
try {
// Key exists and is of the requested type
addToCache(key, node);
return node.as<T>();
} catch (const YAML::Exception& e) {
// Key is not of the requested type
registerUnknownKey(key);
return defaultValue; // return default value if the key does not exist
}
}
}
/**
* @brief Check if the key exists in the given config file
* @param key Key to check;
* @return boolean true or false
*/
bool has(const std::string &key);
/**
* @brief Get all keys defined in the configuration file.
* @return Vector of all keys in the configuration file.
*/
std::vector<std::string> keys() const;
/**
* @brief Print the configuration file path and the YAML root node.
* @param os Output stream.
* @param config Config object to print.
* @return Output stream.
*/
friend std::ostream& operator<<(std::ostream& os, const Config& config) {
if (!config.m_loaded) {
os << "Config file not loaded" << std::endl;
return os;
}
if (!config.debug) {
os << "Config file: " << config.configFilePath << std::endl;
} else{
// Print entire YAML file from root
os << "Config file: " << config.configFilePath << std::endl;
os << config.yamlRoot << std::endl;
}
return os;
}
// Setup gTest class as a friend
friend class ::configTestPrivateAccessor; // Friend declaration for global test accessor
// -- Resource Manager is a friend of config so it can create a seperate instance
friend class serif::resource::ResourceManager; // Adjusted friend declaration
};
}

View File

@@ -1,24 +0,0 @@
# Define the library
const_sources = files(
'private/const.cpp',
)
const_headers = files(
'public/const.h'
)
# Define the libconst library so it can be linked against by other parts of the build system
libconst = library('const',
const_sources,
include_directories: include_directories('public'),
cpp_args: ['-fvisibility=default'],
dependencies: [const_data_dep],
install : true)
const_dep = declare_dependency(
include_directories: include_directories('public'),
link_with: libconst,
)
# Make headers accessible
install_headers(const_headers, subdir : '4DSSE/const')

View File

@@ -1,126 +0,0 @@
/* ***********************************************************************
//
// Copyright (C) 2025 -- The 4D-STAR Collaboration
// File Author: Emily Boudreaux
// Last Modified: March 17, 2025
//
// 4DSSE 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.
//
// 4DSSE 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
//
// *********************************************************************** */
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <set>
#include "const.h"
#include "embedded_constants.h" // Generated at build time by meson
namespace serif::constant {
Constants::Constants() {
loaded_ = initialize();
}
bool Constants::initialize() {
return load();
}
Constant Constants::get(const std::string& name) const {
auto it = constants_.find(name);
if (it != constants_.end()) {
return it->second;
} else {
throw std::out_of_range("Constant '" + name + "' not found.");
}
}
Constant Constants::operator[](const std::string& name) const {
return this->get(name);
}
bool Constants::has(const std::string& name) const {
return constants_.find(name) != constants_.end();
}
std::set<std::string> Constants::keys() const {
std::set<std::string> keys;
for (const auto& pair : constants_) {
keys.insert(pair.first);
}
return keys;
}
std::string Constants::trim(const std::string& str) {
size_t first = str.find_first_not_of(" \t");
if (first == std::string::npos) return "";
size_t last = str.find_last_not_of(" \t");
return str.substr(first, last - first + 1);
}
bool Constants::load() {
std::istringstream fileStream(embeddedConstants);
std::string line;
bool data_section = false;
int line_count = 0;
while (std::getline(fileStream, line)) {
line_count++;
// Detect start of data section (double divider line)
if (!data_section) {
if (line.find("Symbol") != std::string::npos) { // Find header row
std::getline(fileStream, line); // Skip dashed divider
std::getline(fileStream, line); // Skip second dashed divider
data_section = true;
}
continue;
}
// Ensure the line is long enough to contain all fields
if (line.length() < 125) continue;
// Define exact column widths from Python script
int start = 0;
const std::string symbol = trim(line.substr(start, col_widths_[0])); start += col_widths_[0];
const std::string name = trim(line.substr(start, col_widths_[1])); start += col_widths_[1];
const std::string valueStr = line.substr(start, col_widths_[2]); start += col_widths_[2];
const std::string unit = trim(line.substr(start, col_widths_[3])); start += col_widths_[3]; // Only trim the unit
const std::string uncertaintyStr = line.substr(start, col_widths_[4]); start += col_widths_[4];
const std::string reference = trim(line.substr(start, col_widths_[5])); // Only trim reference
// Convert numerical fields safely
double value = 0.0, uncertainty = 0.0;
try {
value = std::stod(valueStr);
} catch (...) {
std::cerr << "Warning: Invalid value in line " << line_count << ": " << valueStr << std::endl;
}
try {
uncertainty = std::stod(uncertaintyStr);
} catch (...) {
std::cerr << "Warning: Invalid uncertainty in line " << line_count << ": " << uncertaintyStr << std::endl;
}
// Store in map
constants_.emplace(symbol, Constant{name, value, uncertainty, unit, reference});
}
loaded_ = true;
return true;
}
}

View File

@@ -1,141 +0,0 @@
/* ***********************************************************************
//
// Copyright (C) 2025 -- The 4D-STAR Collaboration
// File Author: Emily Boudreaux
// Last Modified: March 17, 2025
//
// 4DSSE 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.
//
// 4DSSE 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
//
// *********************************************************************** */
#pragma once
#include <string>
#include <iostream>
#include <set>
#include <map>
namespace serif::constant {
/**
* @brief Structure to hold a constant's details.
*/
struct Constant {
const std::string name; ///< Name of the constant
const double value; ///< Value of the constant
const double uncertainty; ///< Uncertainty in the constant's value
const std::string unit; ///< Unit of the constant
const std::string reference; ///< Reference for the constant's value
/**
* @brief Parameterized constructor.
* @param name The name of the constant.
* @param value The value of the constant.
* @param uncertainty The uncertainty in the constant's value.
* @param unit The unit of the constant.
* @param reference The reference for the constant's value.
*/
Constant(const std::string& name, const double value, const double uncertainty, const std::string& unit, const std::string& reference)
: name(name), value(value), uncertainty(uncertainty), unit(unit), reference(reference) {}
/**
* @brief overload the << operator for pretty printing
*/
friend std::ostream& operator<<(std::ostream& os, const Constant& c) {
os << "<" << c.name << ": ";
os << c.value << "±" << c.uncertainty << " ";
os << c.unit << " (" << c.reference << ")>\n";
return os;
}
};
/**
* @brief Class to manage a collection of constants.
*/
class Constants {
private:
bool loaded_ = false; ///< Flag to indicate if constants are loaded
const int col_widths_[6] = {25, 52, 20, 20, 17, 45}; // From the python script used to generate the constants file
std::map<std::string, Constant> constants_; ///< Map to store constants by name
/**
* @brief Default constructor. Private to avoid direct instantiation
*/
Constants();
/**
* @brief Load constants from the embedded header file.
* @return True if loading was successful, false otherwise.
*/
bool load();
/**
* @brief Initialize constants.
* @return True if initialization was successful, false otherwise.
*/
bool initialize();
/**
* @brief Trim leading and trailing whitespace from a string.
* @param str The string to trim.
* @return The trimmed string.
*/
std::string trim(const std::string& str);
public:
/**
* @brief get instance of constants singleton
* @return instance of constants
*/
static Constants& getInstance() {
static Constants instance;
return instance;
}
/**
* @brief Check if constants are loaded.
* @return True if constants are loaded, false otherwise.
*/
bool isLoaded() const { return loaded_; }
/**
* @brief Get a constant by key.
* @param key The name of the constant to retrieve.
* @return The constant associated with the given key.
*/
Constant get(const std::string& key) const;
/**
* @brief Overloaded subscript operator to access constants by key.
* @param key The name of the constant to retrieve.
* @return The constant associated with the given key.
* @throws std::out_of_range if the key is not found.
*/
Constant operator[](const std::string& key) const;
/**
* @brief Check if a constant exists by key.
* @param key The name of the constant to check.
* @return True if the constant exists, false otherwise.
*/
bool has(const std::string& key) const;
/**
* @brief Get a list of all constant keys.
* @return A vector of all constant keys.
*/
std::set<std::string> keys() const;
};
} // namespace serif::const

View File

@@ -127,7 +127,7 @@ namespace serif::eos::helmholtz {
// this function reads in the HELM table and stores in the above arrays
std::unique_ptr<HELMTable> read_helm_table(const std::string &filename) {
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
auto logFile = config.get<std::string>("EOS:Helm:LogFile", "log");
fourdst::logging::LogManager& logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger(logFile);
@@ -238,7 +238,7 @@ namespace serif::eos::helmholtz {
and returns the calculated quantities in the input
***/
serif::eos::helmholtz::HELMEOSOutput get_helm_EOS(serif::eos::helmholtz::HELMEOSInput &q, const serif::eos::helmholtz::HELMTable &table) {
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
auto logFile = config.get<std::string>("EOS:Helm:LogFile", "log");
fourdst::logging::LogManager& logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger(logFile);

View File

@@ -5,11 +5,9 @@
# Utility Libraries
subdir('types')
subdir('misc')
subdir('config')
subdir('probe')
# Physically Informed Libraries
# subdir('constants')
subdir('composition')
# Asset Libraries

View File

@@ -19,6 +19,7 @@
//
// *********************************************************************** */
#include "network.h"
#include "config.h"
#include "approx8.h"
#include "logging.h"
@@ -26,7 +27,7 @@
namespace serif::network {
Network::Network(const NetworkFormat format) :
m_config(serif::config::Config::getInstance()),
m_config(fourdst::config::Config::getInstance()),
m_logManager(fourdst::logging::LogManager::getInstance()),
m_logger(m_logManager.getLogger("log")),
m_format(format) {

View File

@@ -117,7 +117,7 @@ namespace serif::network {
virtual NetOut evaluate(const NetIn &netIn);
protected:
serif::config::Config& m_config; ///< Configuration instance
fourdst::config::Config& m_config; ///< Configuration instance
fourdst::logging::LogManager& m_logManager; ///< Log manager instance
quill::Logger* m_logger; ///< Logger instance

View File

@@ -76,7 +76,7 @@ namespace laneEmden {
PolySolver::PolySolver(mfem::Mesh& mesh, const double n, const double order)
: m_config(serif::config::Config::getInstance()), // Updated
: m_config(fourdst::config::Config::getInstance()), // Updated
m_logManager(fourdst::logging::LogManager::getInstance()),
m_logger(m_logManager.getLogger("log")),
m_polytropicIndex(n),

View File

@@ -282,7 +282,7 @@ public: // Public methods
private: // Private Attributes
// --- Configuration and Logging ---
serif::config::Config& m_config; ///< Reference to the global configuration manager instance.
fourdst::config::Config& m_config; ///< Reference to the global configuration manager instance.
fourdst::logging::LogManager& m_logManager; ///< Reference to the global log manager instance.
quill::Logger* m_logger; ///< Pointer to the specific logger instance for this class.

View File

@@ -28,7 +28,7 @@
namespace serif::polytrope::polyMFEMUtils {
NonlinearPowerIntegrator::NonlinearPowerIntegrator(const double n) :
m_polytropicIndex(n),
m_epsilon(serif::config::Config::getInstance().get<double>("Poly:Solver:Epsilon", 1.0e-8)) {
m_epsilon(fourdst::config::Config::getInstance().get<double>("Poly:Solver:Epsilon", 1.0e-8)) {
if (m_polytropicIndex < 0.0) {
throw std::invalid_argument("Polytropic index must be non-negative.");

View File

@@ -71,7 +71,7 @@ namespace serif::polytrope {
*/
virtual void AssembleElementGrad (const mfem::FiniteElement &el, mfem::ElementTransformation &Trans, const mfem::Vector &elfun, mfem::DenseMatrix &elmat) override;
private:
serif::config::Config& m_config = serif::config::Config::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");
double m_polytropicIndex;

View File

@@ -57,7 +57,7 @@ void wait(int seconds) {
void glVisView(mfem::GridFunction& u, mfem::Mesh& mesh,
const std::string& windowTitle, const std::string& keyset) {
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
quill::Logger* logger = fourdst::logging::LogManager::getInstance().getLogger("log");
if (config.get<bool>("Probe:GLVis:Visualization", true)) {
std::string usedKeyset;
@@ -109,7 +109,7 @@ double getMeshRadius(mfem::Mesh& mesh) {
std::pair<std::vector<double>, std::vector<double>> getRaySolution(mfem::GridFunction& u, mfem::Mesh& mesh,
const std::vector<double>& rayDirection,
int numSamples, std::string filename) {
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
fourdst::logging::LogManager& logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger("log");
LOG_INFO(logger, "Getting ray solution...");

View File

@@ -28,7 +28,7 @@
#include "mfem.hpp"
/**
* @brief The Probe namespace contains utility functions for debugging and logging.
* @brief The Probe namespace contains utility functions for debugging.
*/
namespace serif::probe {
/**

View File

@@ -14,7 +14,7 @@ template <typename T>
void def_config_get(py::module &m) {
m.def("get",
[](const std::string &key, T defaultValue) {
return serif::config::Config::getInstance().get<T>(key, defaultValue);
return fourdst::config::Config::getInstance().get<T>(key, defaultValue);
},
py::arg("key"), py::arg("defaultValue"),
"Get configuration value (type inferred from default)");
@@ -28,28 +28,28 @@ void register_config_bindings(pybind11::module &config_submodule) {
config_submodule.def("loadConfig",
[](const std::string& configFilePath) {
return serif::config::Config::getInstance().loadConfig(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 serif::config::Config::getInstance().has(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(serif::config::Config::getInstance().keys());
return py::cast(fourdst::config::Config::getInstance().keys());
},
"Get a list of all configuration keys.");
config_submodule.def("__repr__",
[]() {
std::ostringstream oss;
oss << serif::config::Config::getInstance(); // Use the existing operator<<
oss << fourdst::config::Config::getInstance(); // Use the existing operator<<
return std::string("<fourdsse_bindings.config module accessing C++ Singleton>\n") + oss.str();
});
}

View File

@@ -54,11 +54,11 @@ namespace serif::resource {
*/
ResourceManager& operator=(const ResourceManager&) = delete;
serif::config::Config& m_config = serif::config::Config::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");
serif::config::Config m_resourceConfig;
fourdst::config::Config m_resourceConfig;
std::string m_dataDir;
std::unordered_map<std::string, types::Resource> m_resources;

View File

@@ -0,0 +1,7 @@
[wrap-git]
url = https://github.com/4D-STAR/libconfig.git
revision = v1.0.0
depth = 1
[provide]
libconfig = config_dep

View File

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

View File

@@ -25,12 +25,12 @@ TEST_F(compositionTest, isotopeMasses) {
}
TEST_F(compositionTest, constructor) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
EXPECT_NO_THROW(serif::composition::Composition comp);
}
TEST_F(compositionTest, registerSymbol) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
EXPECT_NO_THROW(comp.registerSymbol("H-1"));
EXPECT_NO_THROW(comp.registerSymbol("He-4"));
@@ -45,7 +45,7 @@ TEST_F(compositionTest, registerSymbol) {
}
TEST_F(compositionTest, setGetComposition) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -71,7 +71,7 @@ TEST_F(compositionTest, setGetComposition) {
}
TEST_F(compositionTest, setGetNumberFraction) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1", false);
comp.registerSymbol("He-4", false);
@@ -88,7 +88,7 @@ TEST_F(compositionTest, setGetNumberFraction) {
}
TEST_F(compositionTest, subset) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -103,7 +103,7 @@ TEST_F(compositionTest, subset) {
}
TEST_F(compositionTest, finalizeWithNormalization) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -115,7 +115,7 @@ TEST_F(compositionTest, finalizeWithNormalization) {
}
TEST_F(compositionTest, finalizeWithoutNormalization) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -127,7 +127,7 @@ TEST_F(compositionTest, finalizeWithoutNormalization) {
}
TEST_F(compositionTest, getComposition) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -142,7 +142,7 @@ TEST_F(compositionTest, getComposition) {
}
TEST_F(compositionTest, setCompositionMode) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -164,7 +164,7 @@ TEST_F(compositionTest, setCompositionMode) {
}
TEST_F(compositionTest, hasSymbol) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp;
comp.registerSymbol("H-1");
comp.registerSymbol("He-4");
@@ -179,7 +179,7 @@ TEST_F(compositionTest, hasSymbol) {
}
TEST_F(compositionTest, mix) {
serif::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
fourdst::config::Config::getInstance().loadConfig(EXAMPLE_FILENAME);
serif::composition::Composition comp1;
comp1.registerSymbol("H-1");
comp1.registerSymbol("He-4");

View File

@@ -9,7 +9,7 @@ int main(int argv, char* argc[]) {
} else {
pathToConfigFile = "config.json";
}
serif::config::Config::getInstance().loadConfig(pathToConfigFile);
fourdst::config::Config::getInstance().loadConfig(pathToConfigFile);
serif::composition::Composition comp;
std::vector<std::string> symbols = {"H-1", "He-4"};
comp.registerSymbol(symbols);

View File

@@ -1,111 +0,0 @@
#include <gtest/gtest.h>
#include "config.h"
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <sstream>
#include <algorithm>
std::string EXAMPLE_FILENAME = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/config/example.yaml";
/**
* @file configTest.cpp
* @brief Unit tests for the Config class.
*/
class configTestPrivateAccessor {
public:
static bool callIsKeyInCache(serif::config::Config& config, const std::string& key) {
return config.isKeyInCache(key);
}
static int callCacheSize(serif::config::Config& config) {
return config.configMap.size();
}
static void callAddToCache(serif::config::Config& config, const std::string& key, const YAML::Node& node) {
config.addToCache(key, node);
}
static void callRegisterKeyNotFound(serif::config::Config& config, const std::string& key) {
config.registerUnknownKey(key);
}
static bool CheckIfKeyUnknown(serif::config::Config& config, const std::string& key) {
if (std::find(config.unknownKeys.begin(), config.unknownKeys.end(), key) == config.unknownKeys.end()) {
return false;
}
return true;
}
};
/**
* @brief Test suite for the Config class.
*/
class configTest : public ::testing::Test {};
/**
* @brief Test the constructor of the Config class.
*/
TEST_F(configTest, constructor) {
EXPECT_NO_THROW(serif::config::Config::getInstance());
}
TEST_F(configTest, loadConfig) {
serif::config::Config& config = serif::config::Config::getInstance();
EXPECT_TRUE(config.loadConfig(EXAMPLE_FILENAME));
}
TEST_F(configTest, singletonTest) {
serif::config::Config& config1 = serif::config::Config::getInstance();
serif::config::Config& config2 = serif::config::Config::getInstance();
EXPECT_EQ(&config1, &config2);
}
TEST_F(configTest, getTest) {
serif::config::Config& config = serif::config::Config::getInstance();
config.loadConfig(EXAMPLE_FILENAME);
int maxIter = config.get<int>("opac:lowTemp:numeric:maxIter", 10);
EXPECT_EQ(maxIter, 100);
EXPECT_NE(maxIter, 10);
std::string logLevel = config.get<std::string>("logLevel", "DEBUG");
EXPECT_EQ(logLevel, "INFO");
EXPECT_NE(logLevel, "DEBUG");
float polytropicIndex = config.get<float>("poly:physics:index", 2);
EXPECT_EQ(polytropicIndex, 1.5);
EXPECT_NE(polytropicIndex, 2);
float polytropicIndex2 = config.get<float>("poly:physics:index2", 2.0);
EXPECT_EQ(polytropicIndex2, 2.0);
}
TEST_F(configTest, secondSingletonTest) {
serif::config::Config& config = serif::config::Config::getInstance();
EXPECT_EQ(config.get<int>("opac:lowTemp:numeric:maxIter", 10), 100);
}
TEST_F(configTest, isKeyInCacheTest) {
serif::config::Config& config = serif::config::Config::getInstance();
config.loadConfig(EXAMPLE_FILENAME);
EXPECT_TRUE(configTestPrivateAccessor::callIsKeyInCache(config, "opac:lowTemp:numeric:maxIter"));
EXPECT_FALSE(configTestPrivateAccessor::callIsKeyInCache(config, "opac:lowTemp:numeric:maxIter2"));
}
TEST_F(configTest, cacheSize) {
serif::config::Config& config = serif::config::Config::getInstance();
config.loadConfig(EXAMPLE_FILENAME);
EXPECT_EQ(configTestPrivateAccessor::callCacheSize(config), 3);
EXPECT_NE(configTestPrivateAccessor::callCacheSize(config), 4);
config.get<std::string>("outputDir", "DEBUG");
EXPECT_EQ(configTestPrivateAccessor::callCacheSize(config), 4);
}
TEST_F(configTest, unknownKeyTest) {
serif::config::Config& config = serif::config::Config::getInstance();
config.loadConfig(EXAMPLE_FILENAME);
config.get<int>("opac:lowTemp:numeric:random", 10);
EXPECT_FALSE(configTestPrivateAccessor::CheckIfKeyUnknown(config, "opac:lowTemp:numeric:maxIter"));
EXPECT_TRUE(configTestPrivateAccessor::CheckIfKeyUnknown(config, "opac:lowTemp:numeric:random"));
}

View File

@@ -1,32 +0,0 @@
# High level options
logLevel: "INFO"
outputDir: output
# Module options
poly:
numeric:
newtonTol: 1e-6
newtonMaxIter: 100
gmresTol: 1e-6
gmresMaxIter: 100
physics:
index: 1.5
# Module options
opac:
highTemp:
physics:
table: "/path/to/highTempTable.dat"
numeric:
tol: 1e-6
maxIter: 100
lowTemp:
physics:
table: "/path/to/lowTempTable.dat"
numeric:
tol: 1e-6
maxIter: 100
mesh:
structure:
refine: 2

View File

@@ -1,24 +0,0 @@
# Test files for const
test_sources = [
'configTest.cpp',
]
foreach test_file : test_sources
exe_name = test_file.split('.')[0]
message('Building test: ' + exe_name)
# Create an executable target for each test
test_exe = executable(
exe_name,
test_file,
dependencies: [gtest_dep, config_dep, gtest_main],
include_directories: include_directories('../../src/config/public'),
install_rpath: '@loader_path/../../src' # Ensure runtime library path resolves correctly
)
# Add the executable as a test
test(
exe_name,
test_exe,
env: ['MESON_SOURCE_ROOT=' + meson.project_source_root(), 'MESON_BUILD_ROOT=' + meson.project_build_root()])
endforeach

View File

@@ -26,7 +26,7 @@ std::string TEST_CONFIG = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/tes
*/
TEST_F(eosTest, read_helm_table) {
serif::config::Config::getInstance().loadConfig(TEST_CONFIG);
fourdst::config::Config::getInstance().loadConfig(TEST_CONFIG);
const serif::resource::ResourceManager& rm = serif::resource::ResourceManager::getInstance();
auto& eos = std::get<std::unique_ptr<serif::eos::EOSio>>(rm.getResource("eos:helm"));
const auto& table = eos->getTable();

View File

@@ -6,7 +6,6 @@ gtest_nomain_dep = dependency('gtest', main: false, required : true)
# Subdirectories for unit and integration tests
subdir('meshIO')
subdir('probe')
subdir('config')
subdir('eos')
subdir('resource')
subdir('network')

View File

@@ -15,7 +15,7 @@ class approx8Test : public ::testing::Test {};
* @brief Test the constructor of the Config class.
*/
TEST_F(approx8Test, constructor) {
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
config.loadConfig(TEST_CONFIG);
EXPECT_NO_THROW(serif::network::approx8::Approx8Network());
}

View File

@@ -35,7 +35,7 @@ class polyTest : public ::testing::Test {};
TEST_F(polyTest, Solve) {
using namespace serif::polytrope;
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
config.loadConfig(CONFIG_FILENAME);
fourdst::logging::LogManager& logManager = fourdst::logging::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger("log");

View File

@@ -28,12 +28,12 @@ class resourceManagerTest : public ::testing::Test {};
* @brief Test the constructor of the resourceManager class.
*/
TEST_F(resourceManagerTest, constructor) {
serif::config::Config::getInstance().loadConfig(TEST_CONFIG);
fourdst::config::Config::getInstance().loadConfig(TEST_CONFIG);
EXPECT_NO_THROW(serif::resource::ResourceManager::getInstance());
}
TEST_F(resourceManagerTest, getAvaliableResources) {
serif::config::Config::getInstance().loadConfig(TEST_CONFIG);
fourdst::config::Config::getInstance().loadConfig(TEST_CONFIG);
serif::resource::ResourceManager& rm = serif::resource::ResourceManager::getInstance();
std::vector<std::string> resources = rm.getAvailableResources();
std::set<std::string> expected = {"eos:helm", "mesh:polySphere"};
@@ -42,7 +42,7 @@ TEST_F(resourceManagerTest, getAvaliableResources) {
}
TEST_F(resourceManagerTest, getResource) {
serif::config::Config::getInstance().loadConfig(TEST_CONFIG);
fourdst::config::Config::getInstance().loadConfig(TEST_CONFIG);
serif::resource::ResourceManager& rm = serif::resource::ResourceManager::getInstance();
std::string name = "eos:helm";
const serif::resource::types::Resource &r = rm.getResource(name);

View File

@@ -9,7 +9,7 @@
int main(int argv, char **argc) {
std::string CONFIG_FILENAME = std::string(getenv("MESON_SOURCE_ROOT")) + "/tests/testsConfig.yaml";
serif::config::Config& config = serif::config::Config::getInstance();
fourdst::config::Config& config = fourdst::config::Config::getInstance();
config.loadConfig(CONFIG_FILENAME);
// Read the mesh from the given mesh file
std::string meshFile = argc[1];