Skip to content

Commit

Permalink
feat: generalize config file handling for Algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
c-dilks committed Feb 11, 2024
1 parent 77bc601 commit 332906f
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 97 deletions.
2 changes: 1 addition & 1 deletion examples/iguana-example-02-YAMLReader.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include <iguana/services/ConfigFileManager.h>
#include <iguana/services/ConfigFileReader.h>
#include <iguana/services/YAMLReader.h>
#include <iostream>

Expand Down
21 changes: 9 additions & 12 deletions src/iguana/algorithms/Algorithm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,17 @@ namespace iguana {

void Algorithm::SetName(const std::string name) {
Object::SetName(name);
if(m_config_manager)
m_config_manager->SetName("config|"+name);
if(m_yaml_config)
m_yaml_config->SetName("config|"+m_name);
}

std::shared_ptr<ConfigFileManager>& Algorithm::GetConfigFileManager() {
if(!m_config_manager) // instantiate it, if it doesn't exist
m_config_manager = std::make_shared<ConfigFileManager>(m_name+ + "|config");
return m_config_manager;
}

void Algorithm::SetConfigFileManager(std::shared_ptr<ConfigFileManager> config_manager) {
if(m_config_manager)
m_log->Warn("config file manager already exists for this algorithm; overwriting...");
m_config_manager = config_manager;
void Algorithm::ParseYAMLConfig() {
if(m_yaml_config)
m_yaml_config.reset();
m_yaml_config = std::make_unique<YAMLReader>("config|"+m_name);
m_yaml_config->AddFile(m_default_config_file);
m_yaml_config->AddFile(m_user_config_file);
m_yaml_config->LoadFiles();
}

void Algorithm::CacheBankIndex(hipo::banklist& banks, const std::string bankName, hipo::banklist::size_type& idx) const {
Expand Down
37 changes: 21 additions & 16 deletions src/iguana/algorithms/Algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <hipo4/bank.h>

#include "iguana/services/Object.h"
#include "iguana/services/ConfigFileManager.h"
#include "iguana/services/YAMLReader.h"
#include "iguana/algorithms/AlgorithmBoilerplate.h"

namespace iguana {
Expand All @@ -37,7 +37,12 @@ namespace iguana {
public:

/// @param name the unique name for a derived class instance
Algorithm(const std::string name) : Object(name), m_rows_only(false) {}
Algorithm(const std::string name)
: Object(name)
, m_rows_only(false)
, m_default_config_file("")
, m_user_config_file("")
{}
virtual ~Algorithm() {}

/// Initialize an algorithm before any events are processed, with the intent to process _banks_;
Expand Down Expand Up @@ -84,18 +89,10 @@ namespace iguana {
/// @param name the new name
void SetName(const std::string name);

/// Get a reference to the configuration file manager for this algorithm.
/// If there is no configuration file manager owned by this algorithm,
/// calling this function will create one.
/// @return the configuration file manager reference
std::shared_ptr<ConfigFileManager>& GetConfigFileManager();
protected: // methods

/// Set the configuration file manager for this algorithm.
/// @param config_manager the configuration file manager
void SetConfigFileManager(std::shared_ptr<ConfigFileManager> config_manager);


protected:
/// Parse YAML configuration files. Sets `m_yaml_config`.
void ParseYAMLConfig();

/// Cache the index of a bank in a `hipo::banklist`; throws an exception if the bank is not found
/// @param[in] banks the list of banks this algorithm will use
Expand Down Expand Up @@ -171,16 +168,24 @@ namespace iguana {
/// @param level the log level
void ShowBank(hipo::bank& bank, const std::string message="", const Logger::Level level=Logger::trace) const;

protected: // members

/// Data structure to hold configuration options
std::unordered_map<std::string, option_t> m_opt;

/// If true, algorithm can only operate on bank _rows_; `Algorithm::GetBank`, and therefore `Algorithm::Run`, cannot be called
bool m_rows_only;

private:
/// Default configuration file name
std::string m_default_config_file;

/// Configuration file manager instance
std::shared_ptr<ConfigFileManager> m_config_manager;
/// User's configuration file name
std::string m_user_config_file;

/// YAML reader
std::unique_ptr<YAMLReader> m_yaml_config;

private:

};

Expand Down
14 changes: 10 additions & 4 deletions src/iguana/algorithms/AlgorithmBoilerplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

/// Generate an algorithm constructor
/// @param ALGO_NAME the name of the algorithm class
#define CONSTRUCT_IGUANA_ALGORITHM(ALGO_NAME) \
ALGO_NAME(std::string name="") : Algorithm(name=="" ? ClassName() : name) {}
#define CONSTRUCT_IGUANA_ALGORITHM(ALGO_NAME) \
ALGO_NAME(std::string name="") : Algorithm(name=="" ? GetClassName() : name) { \
m_default_config_file = GetDefaultConfigFile(); \
}

/// Generate an algorithm destructor
/// @param ALGO_NAME the name of the algorithm class
Expand All @@ -15,9 +17,13 @@
/// @param ALGO_NAME the name of the algorithm class
/// @param ALGO_FULL_NAME the full name of this algorithm, used by `iguana::AlgorithmFactory`
#define IGUANA_ALGORITHM_PUBLIC_MEMBERS(ALGO_NAME, ALGO_FULL_NAME) \
\
using Algorithm::Start; \
static algo_t Creator() { return std::make_unique<ALGO_NAME>(); } \
static std::string ClassName() { return #ALGO_FULL_NAME; }
static std::string GetClassName() { return #ALGO_FULL_NAME; } \
static std::string GetDefaultConfigFile() { \
return ConfigFileReader::ConvertAlgoNameToConfigName(#ALGO_FULL_NAME, "yaml"); \
}

/// Define the private members of an algorithm
#define IGUANA_ALGORITHM_PRIVATE_MEMBERS \
Expand All @@ -38,4 +44,4 @@
/// Register an algorithm for the `iguana::AlgorithmFactory`; this macro should be called in the algorithm's implementation
/// @param ALGO_NAME the name of the algorithm class
#define REGISTER_IGUANA_ALGORITHM(ALGO_NAME) \
bool ALGO_NAME::s_registered = AlgorithmFactory::Register(ALGO_NAME::ClassName(), ALGO_NAME::Creator);
bool ALGO_NAME::s_registered = AlgorithmFactory::Register(ALGO_NAME::GetClassName(), ALGO_NAME::Creator);
2 changes: 1 addition & 1 deletion src/iguana/algorithms/AlgorithmSequence.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace iguana {
// prepend sequence name to algorithm name
algo->SetName(m_name + "|" + algoName);
// use `this` config file manager in each of its algorithms (must be called AFTER `SetName`)
algo->SetConfigFileManager(GetConfigFileManager());
// algo->SetConfigFileManager(GetConfigFileManager()); // FIXME: implement some API to set one or all algorithms' config files
m_sequence.push_back(std::move(algo));
// check for duplicate algorithm name
if(m_algo_names.size() < m_sequence.size()) {
Expand Down
6 changes: 2 additions & 4 deletions src/iguana/algorithms/clas12/ZVertexFilter.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "ZVertexFilter.h"
#include "iguana/services/YAMLReader.h"

namespace iguana::clas12
{
Expand All @@ -12,11 +11,10 @@ namespace iguana::clas12
// FIXME: need a way of passing in run numbers and pid values
int runnb = 4768; //default to RG-A fall2018 inbending for now
int pid=0; //no PID needed for this filter
auto config_file = GetConfigFileManager()->FindFile("ZVertexFilter.yaml");
YAMLReader yamlr(config_file);

//Read YAML config file with cuts for a given run number.
std::vector<double> defaultValues = yamlr.findKeyAtRunAndPIDVector<double>("cuts","runs","pid", "vals", runnb,pid, {-20.0, 20.0});
ParseYAMLConfig();
std::vector<double> defaultValues = m_yaml_config->findKeyAtRunAndPIDVector<double>("cuts","runs","pid", "vals", runnb,pid, {-20.0, 20.0});

// define options, their default values, and cache them
CacheOption("low", defaultValues.at(0), o_zvertex_low);
Expand Down
14 changes: 7 additions & 7 deletions src/iguana/algorithms/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ algo_public_headers = [
'clas12/LorentzTransformer.h',
]

algo_config_dirs = [
'clas12/config',
algo_config_files = [
'clas12/ZVertexFilter.yaml',
]

algo_lib = shared_library(
Expand All @@ -40,10 +40,10 @@ install_headers(
preserve_path: true,
)

foreach algo_config_dir : algo_config_dirs
install_subdir(
algo_config_dir,
install_dir: project_etc,
strip_directory: true,
foreach algo_config_file : algo_config_files
install_data(
algo_config_file,
install_dir: project_etc,
preserve_path: true,
)
endforeach
Original file line number Diff line number Diff line change
@@ -1,41 +1,49 @@
#include "ConfigFileManager.h"
#include "ConfigFileReader.h"
#include <filesystem>

namespace iguana {

ConfigFileManager::ConfigFileManager(const std::string name) : Object(name) {
ConfigFileReader::ConfigFileReader(const std::string name) : Object(name) {
// add config files from installation prefix
AddDirectory(GetConfigPrefix());
}

std::string ConfigFileManager::GetConfigPrefix() {
std::string ConfigFileReader::GetConfigPrefix() {
return IGUANA_ETC;
}

void ConfigFileManager::AddDirectory(const std::string dir) {
void ConfigFileReader::AddDirectory(const std::string dir) {
m_log->Debug("Add directory {}", dir);
m_file_paths.push_front(dir);
m_directories.push_front(dir);
}

void ConfigFileManager::PrintDirectories(const Logger::Level level) {
void ConfigFileReader::AddFile(const std::string name) {
if(name=="") return; // handle unset filenames
auto full_name = FindFile(name);
m_log->Debug(" ===> Add file {}", full_name);
m_files.push_front(full_name);
}

void ConfigFileReader::PrintDirectories(const Logger::Level level) {
if(m_log->GetLevel() <= level) {
m_log->Print(level, "{:=^60}", " Configuration file search path order: ");
m_log->Print(level, " - ./");
for(const auto& dir : m_file_paths)
for(const auto& dir : m_directories)
m_log->Print(level, " - {}", dir);
m_log->Print(level, "{:=^60}", "");
}
}

std::string ConfigFileManager::FindFile(const std::string name) {
std::string ConfigFileReader::FindFile(const std::string name) {
if(name=="") return ""; // handle unset filenames
m_log->Debug("Searching for file '{}' in:", name);
// first try `./` or assume `name` is a relative or absolute path + filename
auto found_local = std::filesystem::exists(name);
m_log->Debug(" - ./{}", found_local ? " - FOUND" : "");
if(found_local)
return name;
// then search each entry of `m_file_paths`
for(const auto& dir : m_file_paths) {
// then search each entry of `m_directories`
for(const auto& dir : m_directories) {
std::string filename = dir + "/" + name;
auto found = std::filesystem::exists(filename);
m_log->Debug(" - {}{}", dir, found ? " - FOUND" : "");
Expand All @@ -48,11 +56,19 @@ namespace iguana {
throw std::runtime_error("configuration file not found");
}

std::string ConfigFileManager::DirName(const std::string name) {
std::string ConfigFileReader::DirName(const std::string name) {
auto result = std::filesystem::path{name}.parent_path().string();
if(result=="")
result = ".";
return result;
}

std::string ConfigFileReader::ConvertAlgoNameToConfigName(const std::string algo_name, const std::string ext) {
std::string result = algo_name;
std::string::size_type it = 0;
while((it = result.find("::", it)) != std::string::npos)
result.replace(it, 2, "/");
return result + "." + ext;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
namespace iguana {

/// @brief Configuration file manager
class ConfigFileManager : public Object {
class ConfigFileReader : public Object {

public:

/// @param name the name of this configuration file handler
ConfigFileManager(const std::string name="config");
ConfigFileReader(const std::string name="config");

/// Get the config files' _fixed_ installation prefix
/// @return the absolute path to the installed configuration file directory
Expand All @@ -21,14 +21,18 @@ namespace iguana {
/// @param dir the directory, which may be relative or absolute
void AddDirectory(const std::string dir);

/// Add a configuration file to be parsed
/// @param name the name of the file
void AddFile(const std::string name);

/// Print the list of directories (search path)
/// @param level the log level
void PrintDirectories(const Logger::Level level=Logger::info);

/// Find a configuration file by name. You may either give just a file name, or specify the full path and filename.
/// The following locations are searched, in order:
/// - current working directory `./`
/// - directories included by `ConfigFileManager::AddDirectory`, starting from the most recently added directory
/// - directories included by `ConfigFileReader::AddDirectory`, starting from the most recently added directory
/// - the common installation prefix
/// @param name the configuration file name (with or without a directory)
/// @return the found configuration file (with the directory)
Expand All @@ -40,10 +44,20 @@ namespace iguana {
/// @return the parent directory name
static std::string DirName(const std::string name);

private:
/// Convert a full algorithm name to a config file name, by replacing `::` with `/`
/// and ending with the given extension
/// @param algo_name the algorithm name
/// @param ext the file extension
/// @return the parent directory name
static std::string ConvertAlgoNameToConfigName(const std::string algo_name, const std::string ext);

protected:

/// Stack of directories to search for a file
std::deque<std::string> m_directories;

/// The sequence of algorithms
std::deque<std::string> m_file_paths;
/// Stack of file names to parse
std::deque<std::string> m_files;

};
}
Loading

0 comments on commit 332906f

Please sign in to comment.