Commit e6890155 authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Separate ModuleManager from central Corryvreckan class

parent 65aeac06
......@@ -3,6 +3,7 @@ INCLUDE_DIRECTORIES(SYSTEM ${CORRYVRECKAN_DEPS_INCLUDE_DIRS})
# Create core library
ADD_LIBRARY(CorryvreckanCore SHARED
Corryvreckan.cpp
detector/Detector.cpp
utils/log.cpp
utils/unit.cpp
......
/** @file
* @brief Implementation of interface to the core framework
* @copyright Copyright (c) 2017 CERN and the Corryvreckan authors.
* This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
#include "Corryvreckan.hpp"
#include <chrono>
#include <climits>
#include <fstream>
#include <memory>
#include <stdexcept>
#include <thread>
#include <utility>
#include <TROOT.h>
#include <TRandom.h>
#include <TStyle.h>
#include <TSystem.h>
#include "core/config/exceptions.h"
#include "core/utils/file.h"
#include "core/utils/log.h"
#include "core/utils/unit.h"
using namespace corryvreckan;
/**
* This class will own the managers for the lifetime of the simulation. Will do early initialization:
* - Configure the special header sections.
* - Set the log level and log format as requested.
* - Load the detector configuration and parse it
*/
Corryvreckan::Corryvreckan(std::string config_file_name,
const std::vector<std::string>& module_options,
const std::vector<std::string>& detector_options)
: terminate_(false), has_run_(false), mod_mgr_(std::make_unique<ModuleManager>()) {
// Load the global configuration
conf_mgr_ = std::make_unique<ConfigManager>(std::move(config_file_name),
std::initializer_list<std::string>({"Corryvreckan", ""}),
std::initializer_list<std::string>({"Ignore"}));
// Load and apply the provided module options
conf_mgr_->loadModuleOptions(module_options);
// Load and apply the provided detector options
conf_mgr_->loadDetectorOptions(detector_options);
// Fetch the global configuration
Configuration& global_config = conf_mgr_->getGlobalConfiguration();
// Set the log level from config if not specified earlier
std::string log_level_string;
if(Log::getReportingLevel() == LogLevel::NONE) {
log_level_string = global_config.get<std::string>("log_level", "INFO");
std::transform(log_level_string.begin(), log_level_string.end(), log_level_string.begin(), ::toupper);
try {
LogLevel log_level = Log::getLevelFromString(log_level_string);
Log::setReportingLevel(log_level);
} catch(std::invalid_argument& e) {
LOG(ERROR) << "Log level \"" << log_level_string
<< "\" specified in the configuration is invalid, defaulting to INFO instead";
Log::setReportingLevel(LogLevel::INFO);
}
} else {
log_level_string = Log::getStringFromLevel(Log::getReportingLevel());
}
// Set the log format from config
std::string log_format_string = global_config.get<std::string>("log_format", "DEFAULT");
std::transform(log_format_string.begin(), log_format_string.end(), log_format_string.begin(), ::toupper);
try {
LogFormat log_format = Log::getFormatFromString(log_format_string);
Log::setFormat(log_format);
} catch(std::invalid_argument& e) {
LOG(ERROR) << "Log format \"" << log_format_string
<< "\" specified in the configuration is invalid, using DEFAULT instead";
Log::setFormat(LogFormat::DEFAULT);
}
// Open log file to write output to
if(global_config.has("log_file")) {
// NOTE: this stream should be available for the duration of the logging
log_file_.open(global_config.getPath("log_file"), std::ios_base::out | std::ios_base::trunc);
LOG(TRACE) << "Added log stream to file " << global_config.getPath("log_file");
Log::addStream(log_file_);
}
// Wait for the first detailed messages until level and format are properly set
LOG(TRACE) << "Global log level is set to " << log_level_string;
LOG(TRACE) << "Global log format is set to " << log_format_string;
}
/**
* Performs the initialization, including:
* - Determine and create the output directory
* - Include all the defined units
* - Load the modules from the configuration
*/
void Corryvreckan::load() {
LOG(TRACE) << "Loading Corryvreckan";
// Fetch the global configuration
Configuration& global_config = conf_mgr_->getGlobalConfiguration();
// Put welcome message and set version
LOG(STATUS) << "Welcome to Corryvreckan " << CORRYVRECKAN_PROJECT_VERSION;
global_config.set<std::string>("version", CORRYVRECKAN_PROJECT_VERSION);
// Set the default units to use
add_units();
// Load the modules from the configuration
if(!terminate_) {
mod_mgr_->load(conf_mgr_.get());
} else {
LOG(INFO) << "Skip loading modules because termination is requested";
}
}
/**
* Runs the Module::init() method linearly for every module
*/
void Corryvreckan::init() {
if(!terminate_) {
LOG(TRACE) << "Initializing Corryvreckan";
mod_mgr_->initialiseAll();
} else {
LOG(INFO) << "Skip initializing modules because termination is requested";
}
}
/**
* Runs every modules Module::run() method linearly for the number of events
*/
void Corryvreckan::run() {
if(!terminate_) {
LOG(TRACE) << "Running Corryvreckan";
mod_mgr_->run();
// Set that we have run and want to finalize as well
has_run_ = true;
} else {
LOG(INFO) << "Skip running modules because termination is requested";
}
}
/**
* Runs all modules Module::finalize() method linearly for every module
*/
void Corryvreckan::finalize() {
if(has_run_) {
LOG(TRACE) << "Finalizing Corryvreckan";
mod_mgr_->finaliseAll();
} else {
LOG(INFO) << "Skip finalizing modules because no module did run";
}
}
/*
* This function can be called safely from any signal handler. Time between the request to terminate
* and the actual termination is not always negigible.
*/
void Corryvreckan::terminate() {
terminate_ = true;
mod_mgr_->terminate();
}
void Corryvreckan::add_units() {
LOG(TRACE) << "Adding physical units";
// LENGTH
Units::add("nm", 1e-6);
Units::add("um", 1e-3);
Units::add("mm", 1);
Units::add("cm", 1e1);
Units::add("dm", 1e2);
Units::add("m", 1e3);
Units::add("km", 1e6);
// TIME
Units::add("ps", 1e-3);
Units::add("ns", 1);
Units::add("us", 1e3);
Units::add("ms", 1e6);
Units::add("s", 1e9);
// TEMPERATURE
Units::add("K", 1);
// ENERGY
Units::add("eV", 1e-6);
Units::add("keV", 1e-3);
Units::add("MeV", 1);
Units::add("GeV", 1e3);
// CHARGE
Units::add("e", 1);
Units::add("ke", 1e3);
Units::add("fC", 1 / 1.6021766208e-4);
Units::add("C", 1 / 1.6021766208e-19);
// VOLTAGE
// NOTE: fixed by above
Units::add("V", 1e-6);
Units::add("kV", 1e-3);
// MAGNETIC FIELD
Units::add("T", 1e-3);
Units::add("mT", 1e-6);
// ANGLES
// NOTE: these are fake units
Units::add("deg", 0.01745329252);
Units::add("rad", 1);
Units::add("mrad", 1e-3);
}
/** @file
* @brief Interface to the core framework
* @copyright Copyright (c) 2017 CERN and the Corryvreckan authors.
* This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
/**
* @defgroup Managers Managers
* @brief The global set of managers used in framework
*/
#ifndef CORRYVRECKAN_CORRYVRECKAN_H
#define CORRYVRECKAN_CORRYVRECKAN_H
#include <atomic>
#include <fstream>
#include <memory>
#include <string>
#include "config/ConfigManager.hpp"
#include "module/ModuleManager.hpp"
namespace corryvreckan {
/**
* @brief Provides the link between the core framework and the executable.
*
* Supply the path location the main configuration which should be provided to the executable. Hereafter this class
* should be used to load, initialize, run and finalize all the modules.
*/
class Corryvreckan {
public:
/**
* @brief Constructs Corryvreckan and initialize all managers
* @param config_file_name Path of the main configuration file
* @param options List of extra configuration options
*/
explicit Corryvreckan(std::string config_file_name,
const std::vector<std::string>& module_options = std::vector<std::string>(),
const std::vector<std::string>& detector_options = std::vector<std::string>());
/**
* @brief Load modules from the main configuration and construct them
* @warning Should be called after the \ref Corryvreckan() "constructor"
*/
void load();
/**
* @brief Initialize all modules (pre-run)
* @warning Should be called after the \ref Corryvreckan::load "load function"
*/
void init();
/**
* @brief Run all modules for the number of events (run)
* @warning Should be called after the \ref Corryvreckan::init "init function"
*/
void run();
/**
* @brief Finalize all modules (post-run)
* @warning Should be called after the \ref Corryvreckan::run "run function"
*/
void finalize();
/**
* @brief Request termination as early as possible without changing the standard flow
*/
void terminate();
private:
/**
* @brief Sets the default unit conventions
*/
void add_units();
/**
* @brief Set the default ROOT plot style
*/
void set_style();
// Indicate the framework should terminate
std::atomic<bool> terminate_;
std::atomic<bool> has_run_;
// Log file if specified
std::ofstream log_file_;
// All managers in the framework
std::unique_ptr<ModuleManager> mod_mgr_;
std::unique_ptr<ConfigManager> conf_mgr_;
};
} // namespace corryvreckan
#endif /* CORRYVRECKAN_CORRYVRECKAN_H */
......@@ -32,77 +32,13 @@
using namespace corryvreckan;
// Default constructor
ModuleManager::ModuleManager(std::string config_file_name,
const std::vector<std::string>& module_options,
const std::vector<std::string>& detector_options)
: m_reference(nullptr), m_terminate(false) {
LOG(TRACE) << "Loading Corryvreckan";
// Put welcome message
LOG(STATUS) << "Welcome to Corryvreckan " << CORRYVRECKAN_PROJECT_VERSION;
// Load the global configuration
conf_manager_ = std::make_unique<corryvreckan::ConfigManager>(std::move(config_file_name),
std::initializer_list<std::string>({"Corryvreckan", ""}),
std::initializer_list<std::string>({"Ignore"}));
// Load and apply the provided module options
conf_manager_->loadModuleOptions(module_options);
// Load and apply the provided detector options
conf_manager_->loadDetectorOptions(detector_options);
// Fetch the global configuration
Configuration& global_config = conf_manager_->getGlobalConfiguration();
// Set the log level from config if not specified earlier
std::string log_level_string;
if(Log::getReportingLevel() == LogLevel::NONE) {
log_level_string = global_config.get<std::string>("log_level", "INFO");
std::transform(log_level_string.begin(), log_level_string.end(), log_level_string.begin(), ::toupper);
try {
LogLevel log_level = Log::getLevelFromString(log_level_string);
Log::setReportingLevel(log_level);
} catch(std::invalid_argument& e) {
LOG(ERROR) << "Log level \"" << log_level_string
<< "\" specified in the configuration is invalid, defaulting to INFO instead";
Log::setReportingLevel(LogLevel::INFO);
}
} else {
log_level_string = Log::getStringFromLevel(Log::getReportingLevel());
}
// Set the log format from config
std::string log_format_string = global_config.get<std::string>("log_format", "DEFAULT");
std::transform(log_format_string.begin(), log_format_string.end(), log_format_string.begin(), ::toupper);
try {
LogFormat log_format = Log::getFormatFromString(log_format_string);
Log::setFormat(log_format);
} catch(std::invalid_argument& e) {
LOG(ERROR) << "Log format \"" << log_format_string
<< "\" specified in the configuration is invalid, using DEFAULT instead";
Log::setFormat(LogFormat::DEFAULT);
}
// Open log file to write output to
if(global_config.has("log_file")) {
// NOTE: this stream should be available for the duration of the logging
log_file_.open(global_config.getPath("log_file"), std::ios_base::out | std::ios_base::trunc);
Log::addStream(log_file_);
}
// Wait for the first detailed messages until level and format are properly set
LOG(TRACE) << "Global log level is set to " << log_level_string;
LOG(TRACE) << "Global log format is set to " << log_format_string;
ModuleManager::ModuleManager() : m_reference(nullptr), m_terminate(false) {
// New clipboard for storage:
m_clipboard = std::make_shared<Clipboard>();
}
void ModuleManager::load() {
add_units();
void ModuleManager::load(ConfigManager* conf_mgr) {
conf_manager_ = conf_mgr;
load_detectors();
load_modules();
......@@ -824,49 +760,3 @@ void ModuleManager::set_module_after(std::tuple<LogLevel, LogFormat> prev) {
LOG(TRACE) << "Reset log format to global level of " << Log::getStringFromFormat(old_format);
}
}
void ModuleManager::add_units() {
LOG(TRACE) << "Adding physical units";
// LENGTH
Units::add("nm", 1e-6);
Units::add("um", 1e-3);
Units::add("mm", 1);
Units::add("cm", 1e1);
Units::add("dm", 1e2);
Units::add("m", 1e3);
Units::add("km", 1e6);
// TIME
Units::add("ps", 1e-3);
Units::add("ns", 1);
Units::add("us", 1e3);
Units::add("ms", 1e6);
Units::add("s", 1e9);
// TEMPERATURE
Units::add("K", 1);
// ENERGY
Units::add("eV", 1e-6);
Units::add("keV", 1e-3);
Units::add("MeV", 1);
Units::add("GeV", 1e3);
// CHARGE
Units::add("e", 1);
Units::add("ke", 1e3);
Units::add("C", 1.6021766208e-19);
// VOLTAGE
// NOTE: fixed by above
Units::add("V", 1e-6);
Units::add("kV", 1e-3);
// ANGLES
// NOTE: these are fake units
Units::add("deg", 0.01745329252);
Units::add("rad", 1);
Units::add("mrad", 1e-3);
}
......@@ -6,8 +6,8 @@
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
#ifndef CORRYVRECKAN_ANALYSIS_H
#define CORRYVRECKAN_ANALYSIS_H
#ifndef CORRYVRECKAN_MODULE_MANAGER_H
#define CORRYVRECKAN_MODULE_MANAGER_H
#include <fstream>
#include <map>
......@@ -25,9 +25,10 @@
namespace corryvreckan {
/**
* @brief Core class of the Corryvreckan analysis framework
* @ingroup Managers
* @brief Manager responsible for dynamically loading all modules and running their event sequence
*
* The analysis class is the core class which allows the event processing to run. It basically contains a vector of
* The module manager class is the core class which allows the event processing to run. It basically contains a vector of
* modules, each of which is initialised, run on each event and finalised. It does not define what an event is, merely
* runs each module sequentially and passes the clipboard between them (erasing it at the end of each run sequence). When
* an module returns a Failure code, the event processing will stop.
......@@ -36,22 +37,38 @@ namespace corryvreckan {
using ModuleList = std::list<std::shared_ptr<Module>>;
public:
// Constructors and destructors
explicit ModuleManager(std::string config_file_name,
const std::vector<std::string>& module_options = std::vector<std::string>(),
const std::vector<std::string>& detector_options = std::vector<std::string>());
virtual ~ModuleManager(){};
/**
* @brief Construct manager
*/
ModuleManager();
/**
* @brief Use default destructor
*/
~ModuleManager() = default;
/// @{
/**
* @brief Copying the manager is not allowed
*/
ModuleManager(const ModuleManager&) = delete;
ModuleManager& operator=(const ModuleManager&) = delete;
/// @}
/// @{
/**
* @brief Moving the manager is not allowed
*/
ModuleManager(ModuleManager&&) = delete;
ModuleManager& operator=(ModuleManager&&) = delete;
/// @}
// Member functions
void load();
void load(ConfigManager* conf_mgr);
void run();
void timing();
void initialiseAll();
void finaliseAll();
void terminate();
void reset(){};
TBrowser* browser;
......@@ -61,9 +78,10 @@ namespace corryvreckan {
std::vector<std::shared_ptr<Detector>> m_detectors;
private:
void timing();
void load_detectors();
void load_modules();
void add_units();
/**
* @brief Get a specific detector, identified by its name
......@@ -110,7 +128,7 @@ namespace corryvreckan {
std::map<std::string, void*> loaded_libraries_;
std::atomic<bool> m_terminate;
std::unique_ptr<corryvreckan::ConfigManager> conf_manager_;
ConfigManager* conf_manager_;
std::tuple<LogLevel, LogFormat> set_module_before(const std::string&, const Configuration& config);
void set_module_after(std::tuple<LogLevel, LogFormat> prev);
......@@ -119,4 +137,4 @@ namespace corryvreckan {
};
} // namespace corryvreckan
#endif // CORRYVRECKAN_ANALYSIS_H
#endif // CORRYVRECKAN_MODULE_MANAGER_H
......@@ -6,8 +6,7 @@
#include <string>
#include <utility>
#include "core/config/ConfigManager.hpp"
#include "core/module/ModuleManager.hpp"
#include "core/Corryvreckan.hpp"
#include "core/utils/exceptions.h"
/**
* @file
......@@ -22,7 +21,7 @@ void clean();
void abort_handler(int);
void interrupt_handler(int);
std::unique_ptr<ModuleManager> corry;
std::unique_ptr<Corryvreckan> corry;
std::atomic<bool> cv_ready{false};
/**
......@@ -169,20 +168,20 @@ int main(int argc, const char* argv[]) {
try {
// Construct main Corryvreckan object
corry = std::make_unique<ModuleManager>(config_file_name, module_options, detector_options);
corry = std::make_unique<Corryvreckan>(config_file_name, module_options, detector_options);
cv_ready = true;
// Load modules
corry->load();
// Initialize modules (pre-run)
corry->initialiseAll();
corry->init();
// Run modules and event-loop
corry->run();
// Finalize modules (post-run)
corry->finaliseAll();
corry->finalize();
} catch(ConfigurationError& e) {
LOG(FATAL) << "Error in the configuration file:" << std::endl
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment