src/core/module/Module.cpp

Implementation of module. More…

Detailed Description

Implementation of module.

Copyright: Copyright (c) 2017-2024 CERN and the Allpix Squared 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. SPDX-License-Identifier: MIT

Source code


#include "Module.hpp"

#include <filesystem>
#include <fstream>
#include <memory>
#include <stdexcept>
#include <utility>

#include "core/messenger/Messenger.hpp"
#include "core/module/exceptions.h"
#include "core/utils/log.h"

using namespace allpix;

Module::Module(Configuration& config) : Module(config, nullptr) {}
Module::Module(Configuration& config, std::shared_ptr<Detector> detector)
    : config_(config), detector_(std::move(detector)) {}
Module::~Module() {
    // Remove delegates
    try {
        for(auto& delegate : delegates_) {
            delegate.first->remove_delegate(delegate.second);
        }
    } catch(std::out_of_range&) {
        LOG(FATAL) << "Internal fault, cannot delete bound message (should never happen)";
        std::abort();
    }
}

std::string Module::getUniqueName() const {
    std::string unique_name = get_identifier().getUniqueName();
    if(unique_name.empty()) {
        throw InvalidModuleActionException("Cannot uniquely identify module in constructor");
    }
    return unique_name;
}

std::string
Module::createOutputFile(const std::string& pathname, const std::string& extension, bool global, bool delete_file) {
    std::filesystem::path file;
    if(global) {
        file = config_.get<std::string>("_global_dir", std::string());
    } else {
        file = config_.get<std::string>("_output_dir", std::string());
    }

    // The file name will only be empty if this method is executed from the constructor
    if(file.empty()) {
        throw InvalidModuleActionException("Cannot access local output path in constructor");
    }

    try {

        // Check if the requested path is an absolute path and issue a warning:
        std::filesystem::path path = pathname;
        if(path.is_absolute()) {
#ifdef __APPLE__ // Fix compiling error caused by Xcode iterator legacy
            auto path_it_v = std::vector<std::string>(path.begin(), path.end());
            auto file_it_v = std::vector<std::string>(file.begin(), file.end());
            const auto is_outside =
                std::search(path_it_v.begin(), path_it_v.end(), file_it_v.begin(), file_it_v.end()) == path_it_v.end();
#else
            const auto is_outside = std::search(path.begin(), path.end(), file.begin(), file.end()) == path.end();
#endif
            if(is_outside) {
                LOG(WARNING) << "Storing file at requested absolute location " << path
                             << " - this is outside the module output folder";
            }
        }
        // Add the file itself - this fully replaces the "file" path in case "path" is absolute:
        file /= (extension.empty() ? path : path.replace_extension(extension));

        // Create all the required main directories and possible subdirectories from the filename
        std::filesystem::create_directories(file.parent_path());

        if(std::filesystem::is_regular_file(file)) {
            auto global_overwrite = getConfigManager()->getGlobalConfiguration().get<bool>("deny_overwrite", false);
            if(config_.get<bool>("deny_overwrite", global_overwrite)) {
                throw ModuleError("Overwriting of existing file " + file.string() + " denied.");
            }
            LOG(WARNING) << "File " << file << " exists and will be overwritten.";
            try {
                std::filesystem::remove(file);
            } catch(std::filesystem::filesystem_error& e) {
                throw ModuleError("Deleting file " + file.string() + " failed: " + e.what());
            }
        } else if(std::filesystem::is_directory(file)) {
            throw ModuleError("Requested output file " + file.string() + " is an existing directory");
        }

        // Open the file to check if it can be accessed
        std::fstream file_stream(file, std::ios_base::out | std::ios_base::app);
        if(!file_stream.good()) {
            throw ModuleError("File " + file.string() + " not accessible");
        }

        // Convert the file to an absolute path
        file = std::filesystem::canonical(file);
    } catch(std::filesystem::filesystem_error& e) {
        throw ModuleError("Path " + file.string() + " cannot be created");
    }

    if(delete_file) {
        std::filesystem::remove(file);
    }
    return file;
}

TDirectory* Module::getROOTDirectory() const {
    // The directory will only be a null pointer if this method is executed from the constructor or destructor
    if(directory_ == nullptr) {
        throw InvalidModuleActionException("Cannot access ROOT directory in constructor or destructor");
    }

    return directory_;
}
void Module::set_ROOT_directory(TDirectory* directory) { directory_ = directory; }

ConfigManager* Module::getConfigManager() const {
    if(conf_manager_ == nullptr) {
        throw InvalidModuleActionException("Cannot access the config manager in constructor or destructor.");
    };
    return conf_manager_;
}
void Module::set_config_manager(ConfigManager* conf_manager) { conf_manager_ = conf_manager; }

void Module::add_delegate(Messenger* messenger, BaseDelegate* delegate) { delegates_.emplace_back(messenger, delegate); }
bool Module::check_delegates(Messenger* messenger, Event* event) {
    // Return false if any delegate is not satisfied
    return std::all_of(delegates_.cbegin(), delegates_.cend(), [messenger, event](auto& delegate) {
        return !delegate.second->isRequired() || messenger->isSatisfied(delegate.second, event);
    });
}

void SequentialModule::waive_sequence_requirement(bool waive) { sequence_required_ = !waive; }

Updated on 2024-12-13 at 08:31:37 +0000