refactor(serif): fixed typos and updated names to reflect 4DSSE->SERiF

This commit is contained in:
2025-06-12 09:04:03 -04:00
parent 620f3d495c
commit 2eca802d01
9 changed files with 302 additions and 308 deletions

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# *********************************************************************** # # *********************************************************************** #
project('4DSSE', 'cpp', version: '0.0.1a', default_options: ['cpp_std=c++23'], meson_version: '>=1.6.0') project('SERiF', 'cpp', version: '0.0.1a', default_options: ['cpp_std=c++23'], meson_version: '>=1.6.0')
# Add default visibility for all C++ targets # Add default visibility for all C++ targets
add_project_arguments('-fvisibility=default', language: 'cpp') add_project_arguments('-fvisibility=default', language: 'cpp')
@@ -32,7 +32,7 @@ endif
if mode == 1 if mode == 1
data_dir = meson.project_source_root() + '/assets/dynamic' data_dir = meson.project_source_root() + '/assets/dynamic'
else else
data_dir = get_option('prefix') + '/' + get_option('datadir') + '/4DSSE' data_dir = get_option('prefix') + '/' + get_option('datadir') + '/SERiF'
endif endif
# Pass the DATA_DIR definition to the compiler # Pass the DATA_DIR definition to the compiler

64
mk
View File

@@ -26,7 +26,7 @@ Options:
You can use these flags in any order. Flags not passed will get default values. You can use these flags in any order. Flags not passed will get default values.
Examples: Examples:
For an end user who wants a seemless experience 4DSSE: For an end user who wants a seamless experience 4DSSE:
./mk --user ./mk --user
For developers who want to modify the source: For developers who want to modify the source:
./mk ./mk
@@ -83,7 +83,7 @@ if [[ ! -d "$LOGDIR" ]]; then
echo -e "${BLUE}[Info] Creating log directory...${NC}" echo -e "${BLUE}[Info] Creating log directory...${NC}"
mkdir "$LOGDIR" mkdir "$LOGDIR"
else else
echo -e "${MAGENTA}[Succsess] Log directory already exists. Skipping...${NC}" echo -e "${MAGENTA}[Success] Log directory already exists. Skipping...${NC}"
fi fi
LOGFILE="${LOGDIR}/4DSSE-install-log.txt" LOGFILE="${LOGDIR}/4DSSE-install-log.txt"
@@ -112,7 +112,7 @@ if ! command -v clang &> /dev/null && ! command -v gcc &> /dev/null; then
log "${YELLOW}[Info] Please install Clang or GCC and try again.${NC}" log "${YELLOW}[Info] Please install Clang or GCC and try again.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] Clang or GCC is installed. Continuing...${NC}" log "${MAGENTA}[Success] Clang or GCC is installed. Continuing...${NC}"
fi fi
# --- Check if MESON is installed --- # --- Check if MESON is installed ---
@@ -137,7 +137,7 @@ if ! command -v meson &> /dev/null; then
log "${YELLOW}[Info] Please install pip and try again.${NC}" log "${YELLOW}[Info] Please install pip and try again.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}" log "${MAGENTA}[Success] pip is installed. Continuing...${NC}"
fi fi
# check if python3 is installed # check if python3 is installed
@@ -147,7 +147,7 @@ if ! command -v meson &> /dev/null; then
log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}" log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}" log "${MAGENTA}[Success] python3 is installed. Continuing...${NC}"
fi fi
# Check if the venv ~/.4DSSE_env exists # Check if the venv ~/.4DSSE_env exists
@@ -155,9 +155,9 @@ if ! command -v meson &> /dev/null; then
log "${BLUE}[Info] Creating virtual environment...${NC}" log "${BLUE}[Info] Creating virtual environment...${NC}"
python3 -m venv "$HOME/.4DSSE_env" python3 -m venv "$HOME/.4DSSE_env"
source "$HOME/.4DSSE_env/bin/activate" source "$HOME/.4DSSE_env/bin/activate"
log "${GREEN}[Succsess] Virtual environment created.${NC}" log "${GREEN}[Success] Virtual environment created.${NC}"
else else
log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}" log "${MAGENTA}[Success] Virtual environment already exists. Skipping...${NC}"
fi fi
# install meson # install meson
@@ -170,14 +170,14 @@ if ! command -v meson &> /dev/null; then
log "${YELLOW}[Info] Please manually install Meson and try again.${NC}" log "${YELLOW}[Info] Please manually install Meson and try again.${NC}"
exit 1 exit 1
else else
log "${GREEN}[Succsess] Meson installed.${NC}" log "${GREEN}[Success] Meson installed.${NC}"
fi fi
else else
log "${YELLOW}[Info] Please install Meson and try again.${NC}" log "${YELLOW}[Info] Please install Meson and try again.${NC}"
exit 1 exit 1
fi fi
else else
log "${MAGENTA}[Succsess] Meson is installed. Continuing...${NC}" log "${MAGENTA}[Success] Meson is installed. Continuing...${NC}"
fi fi
# --- Check if NINJA is installed --- # --- Check if NINJA is installed ---
@@ -203,7 +203,7 @@ if ! command -v ninja &> /dev/null; then
log "${YELLOW}[Info] Please install pip and try again.${NC}" log "${YELLOW}[Info] Please install pip and try again.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}" log "${MAGENTA}[Success] pip is installed. Continuing...${NC}"
fi fi
# check if python3 is installed # check if python3 is installed
@@ -213,7 +213,7 @@ if ! command -v ninja &> /dev/null; then
log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}" log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}" log "${MAGENTA}[Success] python3 is installed. Continuing...${NC}"
fi fi
# Check if the venv ~/.4DSSE_env exists # Check if the venv ~/.4DSSE_env exists
@@ -221,9 +221,9 @@ if ! command -v ninja &> /dev/null; then
log "${BLUE}[Info] Creating virtual environment...${NC}" log "${BLUE}[Info] Creating virtual environment...${NC}"
python3 -m venv "$HOME/.4DSSE_env" python3 -m venv "$HOME/.4DSSE_env"
source "$HOME/.4DSSE_env/bin/activate" source "$HOME/.4DSSE_env/bin/activate"
log "${GREEN}[Succsess] Virtual environment created.${NC}" log "${GREEN}[Success] Virtual environment created.${NC}"
else else
log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}" log "${MAGENTA}[Success] Virtual environment already exists. Skipping...${NC}"
fi fi
# install ninja # install ninja
@@ -236,14 +236,14 @@ if ! command -v ninja &> /dev/null; then
log "${YELLOW}[Info] Please manually install Ninja and try again.${NC}" log "${YELLOW}[Info] Please manually install Ninja and try again.${NC}"
exit 1 exit 1
else else
log "${GREEN}[Succsess] Ninja installed.${NC}" log "${GREEN}[Success] Ninja installed.${NC}"
fi fi
else else
log "${YELLOW}[Info] Please install Ninja and try again.${NC}" log "${YELLOW}[Info] Please install Ninja and try again.${NC}"
exit 1 exit 1
fi fi
else else
log "${MAGENTA}[Succsess] Ninja is installed. Continuing...${NC}" log "${MAGENTA}[Success] Ninja is installed. Continuing...${NC}"
fi fi
# --- Check if CMake is installed --- # --- Check if CMake is installed ---
@@ -269,7 +269,7 @@ if ! command -v cmake &> /dev/null; then
log "${YELLOW}[Info] Please install pip and try again.${NC}" log "${YELLOW}[Info] Please install pip and try again.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] pip is installed. Continuing...${NC}" log "${MAGENTA}[Success] pip is installed. Continuing...${NC}"
fi fi
# check if python3 is installed # check if python3 is installed
@@ -279,7 +279,7 @@ if ! command -v cmake &> /dev/null; then
log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}" log "${YELLOW}[INFO] If you have python3 installed, please add it to your PATH.${NC}"
exit 1 exit 1
else else
log "${MAGENTA}[Succsess] python3 is installed. Continuing...${NC}" log "${MAGENTA}[Success] python3 is installed. Continuing...${NC}"
fi fi
# Check if the venv ~/.4DSSE_env exists # Check if the venv ~/.4DSSE_env exists
@@ -287,9 +287,9 @@ if ! command -v cmake &> /dev/null; then
log "${BLUE}[Info] Creating virtual environment...${NC}" log "${BLUE}[Info] Creating virtual environment...${NC}"
python3 -m venv "$HOME/.4DSSE_env" python3 -m venv "$HOME/.4DSSE_env"
source "$HOME/.4DSSE_env/bin/activate" source "$HOME/.4DSSE_env/bin/activate"
log "${GREEN}[Succsess] Virtual environment created.${NC}" log "${GREEN}[Success] Virtual environment created.${NC}"
else else
log "${MAGENTA}[Succsess] Virtual environment already exists. Skipping...${NC}" log "${MAGENTA}[Success] Virtual environment already exists. Skipping...${NC}"
fi fi
# install cmake # install cmake
@@ -302,11 +302,11 @@ if ! command -v cmake &> /dev/null; then
log "${YELLOW}[Info] Please manually install CMake and try again.${NC}" log "${YELLOW}[Info] Please manually install CMake and try again.${NC}"
exit 1 exit 1
else else
log "${GREEN}[Succsess] CMake installed.${NC}" log "${GREEN}[Success] CMake installed.${NC}"
fi fi
fi fi
else else
log "${MAGENTA}[Succsess] CMake is installed. Continuing...${NC}" log "${MAGENTA}[Success] CMake is installed. Continuing...${NC}"
fi fi
# --- Build 4DSSE --- # --- Build 4DSSE ---
@@ -327,7 +327,7 @@ fi
log "${BLUE}[Info] Checking Boost status...${NC}" log "${BLUE}[Info] Checking Boost status...${NC}"
# if the following script exists with anything other than a 0 status the script will exit # if the following script exists with anything other than a 0 status the script will exit
if [[ -f ./build-config/boost/.boost_installed ]]; then if [[ -f ./build-config/boost/.boost_installed ]]; then
log "${MAGENTA}[Succsess] Boost already installed. Skipping...${NC}" log "${MAGENTA}[Success] Boost already installed. Skipping...${NC}"
else else
log "${BLUE}[Info] Installing Boost...${NC}" log "${BLUE}[Info] Installing Boost...${NC}"
if ! ./build-config/boost/install.sh; then if ! ./build-config/boost/install.sh; then
@@ -335,7 +335,7 @@ else
exit 1 exit 1
else else
touch ./build-config/boost/.boost_installed touch ./build-config/boost/.boost_installed
log "${GREEN}[Succsess] Boost check passed.${NC}" log "${GREEN}[Success] Boost check passed.${NC}"
fi fi
fi fi
@@ -343,7 +343,7 @@ fi
log "${BLUE}[Info] Checking MPI status...${NC}" log "${BLUE}[Info] Checking MPI status...${NC}"
# if the following script exists with anything other than a 0 status the script will exit # if the following script exists with anything other than a 0 status the script will exit
if [[ -f ./build-config/mpi/.mpi_installed ]]; then if [[ -f ./build-config/mpi/.mpi_installed ]]; then
log "${MAGENTA}[Succsess] MPI already installed. Skipping...${NC}" log "${MAGENTA}[Success] MPI already installed. Skipping...${NC}"
else else
log "${BLUE}[Info] Installing MPI...${NC}" log "${BLUE}[Info] Installing MPI...${NC}"
if ! ./build-config/mpi/install.sh; then if ! ./build-config/mpi/install.sh; then
@@ -351,7 +351,7 @@ else
exit 1 exit 1
else else
touch ./build-config/mpi/.mpi_installed touch ./build-config/mpi/.mpi_installed
log "${GREEN}[Succsess] MPI check passed.${NC}" log "${GREEN}[Success] MPI check passed.${NC}"
fi fi
fi fi
@@ -369,7 +369,7 @@ if [[ -f $buildDir/.last_build_flags ]]; then
lastUserFlag=$(grep -Eo 'userFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2) lastUserFlag=$(grep -Eo 'userFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2)
lastTestsFlag=$(grep -Eo 'testsFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2) lastTestsFlag=$(grep -Eo 'testsFlag=[0-9]+' $buildDir/.last_build_flags | cut -d'=' -f2)
if [[ $lastUserFlag -eq $userFlag && $lastTestsFlag -eq $testsFlag ]]; then if [[ $lastUserFlag -eq $userFlag && $lastTestsFlag -eq $testsFlag ]]; then
log "${MAGENTA}[Succsess] Last build flags match current build flags. Skipping configuration...${NC}" log "${MAGENTA}[Success] Last build flags match current build flags. Skipping configuration...${NC}"
doReconfigure=0 doReconfigure=0
else else
log "${YELLOW}[Info] Last build flags do not match current build flags. Reconfiguring...${NC}" log "${YELLOW}[Info] Last build flags do not match current build flags. Reconfiguring...${NC}"
@@ -384,7 +384,7 @@ fi
if [[ $doReconfigure -eq 1 ]]; then if [[ $doReconfigure -eq 1 ]]; then
log "${BLUE}[Info] Configuring build directory...${NC}" log "${BLUE}[Info] Configuring build directory...${NC}"
if [ -f "$buildDir/build.ninja" ]; then if [ -f "$buildDir/build.ninja" ]; then
log "${MAGENTA}[Succsess] Build directory already configured. Skipping...${NC}" log "${MAGENTA}[Success] Build directory already configured. Skipping...${NC}"
else else
if [[ $userFlag -eq 1 ]]; then if [[ $userFlag -eq 1 ]]; then
meson setup "$buildDir" -Duser_mode=true --buildtype=release meson setup "$buildDir" -Duser_mode=true --buildtype=release
@@ -395,7 +395,7 @@ if [[ $doReconfigure -eq 1 ]]; then
meson setup "$buildDir" --buildtype=debug -Dbuild_tests=false meson setup "$buildDir" --buildtype=debug -Dbuild_tests=false
fi fi
fi fi
log "${GREEN}[Succsess] Build directory configured successfully.${NC}" log "${GREEN}[Success] Build directory configured successfully.${NC}"
fi fi
log "${BLUE}[Info] Caching last build flags...${NC}" log "${BLUE}[Info] Caching last build flags...${NC}"
@@ -411,7 +411,7 @@ if [[ $doReconfigure -eq 1 ]]; then
echo "testsFlag=0" >> $buildDir/.last_build_flags echo "testsFlag=0" >> $buildDir/.last_build_flags
fi fi
log "${GREEN}[Succsess] Last build flags cached.${NC}" log "${GREEN}[Success] Last build flags cached.${NC}"
fi fi
log "${BLUE}[Info] Building 4DSSE...${NC}" log "${BLUE}[Info] Building 4DSSE...${NC}"
@@ -429,10 +429,10 @@ if [[ $runTestsFlag -eq 1 ]]; then
fi fi
if [[ $userFlag -eq 1 ]]; then if [[ $userFlag -eq 1 ]]; then
log "${GREEN}[Succsess] 4DSSE built and installed successfully.${NC}" log "${GREEN}[Success] 4DSSE built and installed successfully.${NC}"
else else
log "${GREEN}[Succsess] 4DSSE built successfully.${NC}" log "${GREEN}[Success] 4DSSE built successfully.${NC}"
fi fi
log "${GREEN}[Succsess] 4DSSE mk script complete.${NC}" log "${GREEN}[Success] 4DSSE mk script complete.${NC}"

View File

@@ -29,83 +29,81 @@
#include "config.h" #include "config.h"
namespace serif { namespace serif::config {
namespace config {
Config::Config() {} Config::Config() {}
Config::~Config() {} Config::~Config() {}
Config& Config::getInstance() { Config& Config::getInstance() {
static Config instance; static Config instance;
return 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) { bool Config::loadConfig(const std::string& configFile) {
return configMap.find(key) != configMap.end(); configFilePath = configFile;
} try {
yamlRoot = YAML::LoadFile(configFile);
void Config::addToCache(const std::string &key, const YAML::Node &node) { } catch (YAML::BadFile& e) {
configMap[key] = node; std::cerr << "Error: " << e.what() << std::endl;
}
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; 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) {
std::string key = it.first.as<std::string>();
std::string new_path = path.empty() ? key : path + ":" + key;
recurse_keys(it.second, keyList, new_path);
} }
} else { m_loaded = true;
keyList.push_back(path); 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;
} }
} }
std::vector<std::string> Config::keys() const {
std::vector<std::string> keyList;
YAML::Node node = YAML::Clone(yamlRoot);
recurse_keys(node, keyList);
return keyList;
}
} // namespace config
} // namespace serif

View File

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

View File

@@ -41,12 +41,16 @@
#include "config.h" #include "config.h"
#include "quill/LogMacros.h" #include "quill/LogMacros.h"
namespace serif::constant {
class Constants;
}
using namespace std; using namespace std;
// interpolating polynomila function definitions // interpolating polynomila function definitions
namespace serif::eos::helmholtz { namespace serif::eos::helmholtz {
double** heap_allocate_contiguous_2D_memory(int rows, int cols) { double** heap_allocate_contiguous_2D_memory(int rows, int cols) {
double **array = new double*[rows]; auto array = new double*[rows];
array[0] = new double[rows * cols]; array[0] = new double[rows * cols];
for (int i = 1; i < rows; i++) { for (int i = 1; i < rows; i++) {
@@ -124,13 +128,13 @@ namespace serif::eos::helmholtz {
// this function reads in the HELM table and stores in the above arrays // this function reads in the HELM table and stores in the above arrays
std::unique_ptr<HELMTable> read_helm_table(const std::string filename) { std::unique_ptr<HELMTable> read_helm_table(const std::string filename) {
serif::config::Config& config = serif::config::Config::getInstance(); serif::config::Config& config = serif::config::Config::getInstance();
std::string logFile = config.get<std::string>("EOS:Helm:LogFile", "log"); auto logFile = config.get<std::string>("EOS:Helm:LogFile", "log");
serif::probe::LogManager& logManager = serif::probe::LogManager::getInstance(); serif::probe::LogManager& logManager = serif::probe::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger(logFile); quill::Logger* logger = logManager.getLogger(logFile);
LOG_INFO(logger, "read_helm_table : Reading HELM table from file {}", filename); LOG_INFO(logger, "read_helm_table : Reading HELM table from file {}", filename);
// Make a unique pointer to the HELMTable // Make a unique pointer to the HELMTable
std::unique_ptr<serif::eos::helmholtz::HELMTable> table = std::make_unique<serif::eos::helmholtz::HELMTable>(); auto table = std::make_unique<serif::eos::helmholtz::HELMTable>();
string data; string data;
int i, j; int i, j;
@@ -235,7 +239,7 @@ namespace serif::eos::helmholtz {
***/ ***/
serif::eos::helmholtz::EOS get_helm_EOS(serif::eos::helmholtz::EOSInput &q, const serif::eos::helmholtz::HELMTable &table) { serif::eos::helmholtz::EOS get_helm_EOS(serif::eos::helmholtz::EOSInput &q, const serif::eos::helmholtz::HELMTable &table) {
serif::config::Config& config = serif::config::Config::getInstance(); serif::config::Config& config = serif::config::Config::getInstance();
std::string logFile = config.get<std::string>("EOS:Helm:LogFile", "log"); auto logFile = config.get<std::string>("EOS:Helm:LogFile", "log");
serif::probe::LogManager& logManager = serif::probe::LogManager::getInstance(); serif::probe::LogManager& logManager = serif::probe::LogManager::getInstance();
quill::Logger* logger = logManager.getLogger(logFile); quill::Logger* logger = logManager.getLogger(logFile);

View File

@@ -25,9 +25,7 @@
#include "config.h" #include "config.h"
#include <string> #include <string>
namespace serif { namespace serif::polytrope::polyMFEMUtils {
namespace polytrope {
namespace polyMFEMUtils {
NonlinearPowerIntegrator::NonlinearPowerIntegrator(const double n) : NonlinearPowerIntegrator::NonlinearPowerIntegrator(const double n) :
m_polytropicIndex(n), m_polytropicIndex(n),
m_epsilon(serif::config::Config::getInstance().get<double>("Poly:Solver:Epsilon", 1.0e-8)) { m_epsilon(serif::config::Config::getInstance().get<double>("Poly:Solver:Epsilon", 1.0e-8)) {
@@ -48,99 +46,94 @@ namespace polyMFEMUtils {
mfem::ElementTransformation &Trans, mfem::ElementTransformation &Trans,
const mfem::Vector &elfun, const mfem::Vector &elfun,
mfem::Vector &elvect) { mfem::Vector &elvect) {
const mfem::IntegrationRule *ir = &mfem::IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 3);
int dof = el.GetDof();
elvect.SetSize(dof);
elvect = 0.0;
mfem::Vector shape(dof); const mfem::IntegrationRule *ir = &mfem::IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 3);
mfem::Vector physCoord; const int dof = el.GetDof();
for (int iqp = 0; iqp < ir->GetNPoints(); iqp++) { elvect.SetSize(dof);
mfem::IntegrationPoint ip = ir->IntPoint(iqp); elvect = 0.0;
Trans.SetIntPoint(&ip);
const double weight = ip.weight * Trans.Weight();
el.CalcShape(ip, shape);
double u_val = 0.0;
for (int j = 0; j < dof; j++) {
u_val += elfun(j) * shape(j);
}
double u_nl; mfem::Vector shape(dof);
Trans.Transform(ip, physCoord); mfem::Vector physCoord;
const double r = physCoord.Norml2(); for (int iqp = 0; iqp < ir->GetNPoints(); iqp++) {
std::ofstream outFile("r.dat", std::ios::app); mfem::IntegrationPoint ip = ir->IntPoint(iqp);
outFile << r << '\n'; Trans.SetIntPoint(&ip);
outFile.close(); const double weight = ip.weight * Trans.Weight();
if (r > m_regularizationRadius) {
if (u_val < m_epsilon) { el.CalcShape(ip, shape);
u_nl = fmod(u_val, m_polytropicIndex, m_epsilon);
} else { double u_val = 0.0;
u_nl = std::pow(u_val, m_polytropicIndex); for (int j = 0; j < dof; j++) {
} u_val += elfun(j) * shape(j);
}
double u_nl;
Trans.Transform(ip, physCoord);
const double r = physCoord.Norml2();
if (r > m_regularizationRadius) {
if (u_val < m_epsilon) {
u_nl = fmod(u_val, m_polytropicIndex, m_epsilon);
} else { } else {
u_nl = 1.0 - m_polytropicIndex * m_regularizationCoeff * std::pow(r, 2); u_nl = std::pow(u_val, m_polytropicIndex);
}
for (int i = 0; i < dof; i++){
elvect(i) += shape(i) * u_nl * weight;
} }
} else {
u_nl = 1.0 - m_polytropicIndex * m_regularizationCoeff * std::pow(r, 2);
}
for (int i = 0; i < dof; i++){
elvect(i) += shape(i) * u_nl * weight;
} }
} }
}
void NonlinearPowerIntegrator::AssembleElementGrad (
const mfem::FiniteElement &el,
mfem::ElementTransformation &Trans,
const mfem::Vector &elfun,
mfem::DenseMatrix &elmat) {
const mfem::IntegrationRule *ir = &mfem::IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 3);
const int dof = el.GetDof();
elmat.SetSize(dof);
elmat = 0.0;
mfem::Vector shape(dof);
mfem::DenseMatrix dshape(dof, 3);
mfem::DenseMatrix invJ(3, 3);
mfem::Vector physCoord;
for (int iqp = 0; iqp < ir->GetNPoints(); iqp++) { void NonlinearPowerIntegrator::AssembleElementGrad (
const mfem::IntegrationPoint &ip = ir->IntPoint(iqp); const mfem::FiniteElement &el,
Trans.SetIntPoint(&ip); mfem::ElementTransformation &Trans,
const double weight = ip.weight * Trans.Weight(); const mfem::Vector &elfun,
Trans.Transform(ip, physCoord); mfem::DenseMatrix &elmat) {
double r = physCoord.Norml2();
el.CalcShape(ip, shape);
double u_val = 0.0; const mfem::IntegrationRule *ir = &mfem::IntRules.Get(el.GetGeomType(), 2 * el.GetOrder() + 3);
const int dof = el.GetDof();
for (int j = 0; j < dof; j++) { elmat.SetSize(dof);
u_val += elfun(j) * shape(j); elmat = 0.0;
} mfem::Vector shape(dof);
mfem::DenseMatrix dshape(dof, 3);
mfem::DenseMatrix invJ(3, 3);
mfem::Vector physCoord;
double d_u_nl; for (int iqp = 0; iqp < ir->GetNPoints(); iqp++) {
if (r > m_regularizationRadius) { const mfem::IntegrationPoint &ip = ir->IntPoint(iqp);
if (u_val < m_epsilon) { Trans.SetIntPoint(&ip);
d_u_nl = dfmod(m_epsilon, m_polytropicIndex); const double weight = ip.weight * Trans.Weight();
} else { Trans.Transform(ip, physCoord);
d_u_nl = m_polytropicIndex * std::pow(u_val, m_polytropicIndex - 1.0); double r = physCoord.Norml2();
}
} else {
d_u_nl = 0.0;
}
for (int i = 0; i < dof; i++) { el.CalcShape(ip, shape);
for (int j = 0; j < dof; j++) {
elmat(i, j) += shape(i) * d_u_nl * shape(j) * weight; double u_val = 0.0;
}
} for (int j = 0; j < dof; j++) {
u_val += elfun(j) * shape(j);
}
double d_u_nl;
if (r > m_regularizationRadius) {
if (u_val < m_epsilon) {
d_u_nl = dfmod(m_epsilon, m_polytropicIndex);
} else {
d_u_nl = m_polytropicIndex * std::pow(u_val, m_polytropicIndex - 1.0);
}
} else {
d_u_nl = 0.0;
}
for (int i = 0; i < dof; i++) {
for (int j = 0; j < dof; j++) {
elmat(i, j) += shape(i) * d_u_nl * shape(j) * weight;
}
}
} }
} }
} // namespace polyMFEMUtils }
} // namespace polytrope
} // namespace serif

View File

@@ -38,7 +38,7 @@ namespace serif::resource {
ResourceManager::ResourceManager() { ResourceManager::ResourceManager() {
const std::string defaultDataDir = TOSTRING(DATA_DIR); const std::string defaultDataDir = TOSTRING(DATA_DIR);
m_dataDir = m_config.get<std::string>("Data:Dir", defaultDataDir); m_dataDir = m_config.get<std::string>("Data:Dir", defaultDataDir);
// -- Get the index file path using filesytem to make it a system safe path // -- Get the index file path using filesystem to make it a system safe path
const std::string indexFilePath = m_dataDir + "/index.yaml"; const std::string indexFilePath = m_dataDir + "/index.yaml";
// TODO Add checks to make sure data dir exists and index.yaml exists // TODO Add checks to make sure data dir exists and index.yaml exists
const std::filesystem::path indexFile(indexFilePath); const std::filesystem::path indexFile(indexFilePath);
@@ -50,7 +50,7 @@ namespace serif::resource {
} }
std::vector<std::string> ResourceManager::getAvaliableResources() const { std::vector<std::string> ResourceManager::getAvailableResources() const {
const std::vector<std::string> resources = m_resourceConfig.keys(); const std::vector<std::string> resources = m_resourceConfig.keys();
return resources; return resources;
} }

View File

@@ -87,10 +87,10 @@ namespace serif::resource {
* Example usage: * Example usage:
* @code * @code
* ResourceManager& manager = ResourceManager::getInstance(); * ResourceManager& manager = ResourceManager::getInstance();
* std::vector<std::string> resources = manager.getAvaliableResources(); * std::vector<std::string> resources = manager.getAvailableResources();
* @endcode * @endcode
*/ */
std::vector<std::string> getAvaliableResources() const; std::vector<std::string> getAvailableResources() const;
/** /**
* @brief Gets a resource by name. * @brief Gets a resource by name.

View File

@@ -35,7 +35,7 @@ TEST_F(resourceManagerTest, constructor) {
TEST_F(resourceManagerTest, getAvaliableResources) { TEST_F(resourceManagerTest, getAvaliableResources) {
serif::config::Config::getInstance().loadConfig(TEST_CONFIG); serif::config::Config::getInstance().loadConfig(TEST_CONFIG);
serif::resource::ResourceManager& rm = serif::resource::ResourceManager::getInstance(); serif::resource::ResourceManager& rm = serif::resource::ResourceManager::getInstance();
std::vector<std::string> resources = rm.getAvaliableResources(); std::vector<std::string> resources = rm.getAvailableResources();
std::set<std::string> expected = {"eos:helm", "mesh:sphere"}; std::set<std::string> expected = {"eos:helm", "mesh:sphere"};
std::set<std::string> actual(resources.begin(), resources.end()); std::set<std::string> actual(resources.begin(), resources.end());
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);