<commit_before>/**
 * @file
 * @brief Implementation of geometry manager
 *
 * @copyright Copyright (c) 2017 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.
 */

#include <fstream>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <Math/RotationX.h>
#include <Math/RotationY.h>
#include <Math/RotationZ.h>
#include <Math/RotationZYX.h>
#include <Math/Vector3D.h>

#include "GeometryManager.hpp"
#include "core/config/ConfigReader.hpp"
#include "core/module/exceptions.h"
#include "core/utils/file.h"
#include "core/utils/log.h"
#include "exceptions.h"
#include "tools/ROOT.h"

#include "core/geometry/HybridPixelDetectorModel.hpp"
#include "core/geometry/MonolithicPixelDetectorModel.hpp"

using namespace allpix;
using namespace ROOT::Math;

GeometryManager::GeometryManager() : closed_{false} {}

/**
 * Loads the geometry by parsing the configuration file
 */
void GeometryManager::load(const Configuration& global_config, std::mt19937_64& seeder) {
    LOG(TRACE) << "Reading geometry";

    // Set up a random number generator and seed it with the global seed:
    std::mt19937_64 random_generator;
    random_generator.seed(seeder());

    std::string detector_file_name = global_config.getPath("detectors_file", true);
    std::fstream file(detector_file_name);
    ConfigReader reader(file, detector_file_name);

    // Loop over all defined detectors
    LOG(DEBUG) << "Loading all detectors:";
    for(auto& detector_section : reader.getConfigurations()) {
        LOG(DEBUG) << "Detector " << detector_section.getName() << "...";

        // Calculate possible detector misalignment to be added
        auto misalignment = [&](auto residuals) {
            double dx = std::normal_distribution<double>(0, residuals.x())(random_generator);
            double dy = std::normal_distribution<double>(0, residuals.y())(random_generator);
            double dz = std::normal_distribution<double>(0, residuals.z())(random_generator);
            return DisplacementVector3D<Cartesian3D<double>>(dx, dy, dz);
        };

        // Get the position and apply potenial misalignment
        auto position = detector_section.get<XYZPoint>("position", XYZPoint());
        LOG(DEBUG) << "Position:    " << display_vector(position, {"mm", "um"});
        position += misalignment(detector_section.get<XYZPoint>("alignment_precision_position", XYZPoint()));
        LOG(DEBUG) << " misaligned: " << display_vector(position, {"mm", "um"});

        // Get the orientation and apply misalignment to the individual angles before combining them
        auto orient_vec = detector_section.get<XYZVector>("orientation", XYZVector());
        LOG(DEBUG) << "Orientation: " << display_vector(orient_vec, {"deg"});
        orient_vec += misalignment(detector_section.get<XYZVector>("alignment_precision_orientation", XYZVector()));
        LOG(DEBUG) << " misaligned: " << display_vector(orient_vec, {"deg"});

        auto orientation_type = detector_section.get<std::string>("orientation_type", "zyx");
        Rotation3D orientation;

        if(orientation_type == "zyx") {
            orientation = ROOT::Math::RotationZYX(orient_vec.z(), orient_vec.y(), orient_vec.x());
        } else if(orientation_type == "xyz") {
            orientation = RotationZ(orient_vec.z()) * RotationY(orient_vec.y()) * RotationX(orient_vec.x());
        } else if(orientation_type == "zxz") {
            orientation = EulerAngles(orient_vec.x(), orient_vec.y(), orient_vec.z());
        } else {
            throw InvalidValueError(
                detector_section, "orientation_type", "orientation_mode should be either 'xyz' or 'zxz'");
        }

        // Create the detector and add it without model
        // NOTE: cannot use make_shared here due to the private constructor
        auto detector = std::shared_ptr<Detector>(new Detector(detector_section.getName(), position, orientation));
        addDetector(detector);

        // Add a link to the detector to add the model later
        nonresolved_models_[detector_section.get<std::string>("type")].emplace_back(detector_section, detector.get());
    }

    // Load the list of standard model paths
    if(global_config.has("model_paths")) {
        auto extra_paths = global_config.getPathArray("model_paths", true);<commit_msg>GeoManager: add some code comments to avoid confusion<commit_after>/**
 * @file
 * @brief Implementation of geometry manager
 *
 * @copyright Copyright (c) 2017 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.
 */

#include <fstream>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <Math/RotationX.h>
#include <Math/RotationY.h>
#include <Math/RotationZ.h>
#include <Math/RotationZYX.h>
#include <Math/Vector3D.h>

#include "GeometryManager.hpp"
#include "core/config/ConfigReader.hpp"
#include "core/module/exceptions.h"
#include "core/utils/file.h"
#include "core/utils/log.h"
#include "exceptions.h"
#include "tools/ROOT.h"

#include "core/geometry/HybridPixelDetectorModel.hpp"
#include "core/geometry/MonolithicPixelDetectorModel.hpp"

using namespace allpix;
using namespace ROOT::Math;

GeometryManager::GeometryManager() : closed_{false} {}

/**
 * Loads the geometry by parsing the configuration file
 */
void GeometryManager::load(const Configuration& global_config, std::mt19937_64& seeder) {
    LOG(TRACE) << "Reading geometry";

    // Set up a random number generator and seed it with the global seed:
    std::mt19937_64 random_generator;
    random_generator.seed(seeder());

    std::string detector_file_name = global_config.getPath("detectors_file", true);
    std::fstream file(detector_file_name);
    ConfigReader reader(file, detector_file_name);

    // Loop over all defined detectors
    LOG(DEBUG) << "Loading all detectors:";
    for(auto& detector_section : reader.getConfigurations()) {
        LOG(DEBUG) << "Detector " << detector_section.getName() << "...";

        // Calculate possible detector misalignment to be added
        auto misalignment = [&](auto residuals) {
            double dx = std::normal_distribution<double>(0, residuals.x())(random_generator);
            double dy = std::normal_distribution<double>(0, residuals.y())(random_generator);
            double dz = std::normal_distribution<double>(0, residuals.z())(random_generator);
            return DisplacementVector3D<Cartesian3D<double>>(dx, dy, dz);
        };

        // Get the position and apply potenial misalignment
        auto position = detector_section.get<XYZPoint>("position", XYZPoint());
        LOG(DEBUG) << "Position:    " << display_vector(position, {"mm", "um"});
        position += misalignment(detector_section.get<XYZPoint>("alignment_precision_position", XYZPoint()));
        LOG(DEBUG) << " misaligned: " << display_vector(position, {"mm", "um"});

        // Get the orientation and apply misalignment to the individual angles before combining them
        auto orient_vec = detector_section.get<XYZVector>("orientation", XYZVector());
        LOG(DEBUG) << "Orientation: " << display_vector(orient_vec, {"deg"});
        orient_vec += misalignment(detector_section.get<XYZVector>("alignment_precision_orientation", XYZVector()));
        LOG(DEBUG) << " misaligned: " << display_vector(orient_vec, {"deg"});

        auto orientation_type = detector_section.get<std::string>("orientation_type", "zyx");
        Rotation3D orientation;

        if(orientation_type == "zyx") {
            // First angle given in the configuration file is around z, second around y, last around x:
            orientation = ROOT::Math::RotationZYX(orient_vec.x(), orient_vec.y(), orient_vec.z());
        } else if(orientation_type == "xyz") {
            // First angle given in the configuration file is around x, second around y, last around z:
            orientation = RotationZ(orient_vec.z()) * RotationY(orient_vec.y()) * RotationX(orient_vec.x());
        } else if(orientation_type == "zxz") {
            // First angle given in the configuration file is around z, second around x, last around z:
            orientation = EulerAngles(orient_vec.x(), orient_vec.y(), orient_vec.z());
        } else {
            throw InvalidValueError(
                detector_section, "orientation_type", "orientation_mode should be either 'zyx', xyz' or 'zxz'");
        }

        // Create the detector and add it without model
        // NOTE: cannot use make_shared here due to the private constructor
        auto detector = std::shared_ptr<Detector>(new Detector(detector_section.getName(), position, orientation));
        addDetector(detector);

        // Add a link to the detector to add the model later
        nonresolved_models_[detector_section.get<std::string>("type")].emplace_back(detector_section, detector.get());
    }

    // Load the list of standard model paths
    if(global_config.has("model_paths")) {
        auto extra_paths = global_config.getPathArray("model_paths", true);
{'fraction_non_alphanumeric': 0.1243979057591623, 'fraction_numerical': 0.005235602094240838, 'mean_word_length': 3.92827657378741, 'pattern_counts': {'":': 0, '<': 99, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1994384', 'n_tokens_mistral': 2795, 'n_tokens_neox': 2644, 'n_words': 725}