Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-07-03 07:05:27

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022, 2023 Whitney Armstrong, Wouter Deconinck, David Lawrence
0003 //
0004 
0005 #include <JANA/JException.h>
0006 #include <Parsers/Printout.h>
0007 #include <TGeoManager.h>
0008 #include <fmt/color.h>
0009 #include <fmt/core.h>
0010 #include <fmt/format.h>
0011 #include <algorithm>
0012 #include <cstdlib>
0013 #include <exception>
0014 #include <filesystem>
0015 #include <iostream>
0016 #include <stdexcept>
0017 #include <utility>
0018 #include <vector>
0019 
0020 #include "DD4hep_service.h"
0021 #include "services/log/Log_service.h"
0022 
0023 //----------------------------------------------------------------
0024 // Services
0025 //----------------------------------------------------------------
0026 void DD4hep_service::acquire_services(JServiceLocator *srv_locator) {
0027     // logging service
0028     auto log_service = srv_locator->get<Log_service>();
0029     m_log = log_service->logger("dd4hep");
0030 
0031     // Set the DD4hep print level to be quieter by default, but let user adjust it
0032     std::string print_level_str{"WARNING"};
0033     m_app->SetDefaultParameter("dd4hep:print_level", print_level_str, "Set DD4hep print level (see DD4hep/Printout.h)");
0034     dd4hep::setPrintLevel(dd4hep::decodePrintLevel(print_level_str));
0035 
0036     // Set the TGeoManager verbose level (lower dd4hep level is more verbose)
0037     TGeoManager::SetVerboseLevel(dd4hep::printLevel() <= dd4hep::PrintLevel::INFO ? 1 : 0);
0038 }
0039 
0040 //----------------------------------------------------------------
0041 // destructor
0042 //----------------------------------------------------------------
0043 DD4hep_service::~DD4hep_service(){
0044     try {
0045         if(m_dd4hepGeo) m_dd4hepGeo->destroyInstance();
0046         m_dd4hepGeo = nullptr;
0047     } catch (...) {}
0048 }
0049 
0050 //----------------------------------------------------------------
0051 // detector
0052 //
0053 /// Return pointer to the dd4hep::Detector object.
0054 /// Call Initialize if needed.
0055 //----------------------------------------------------------------
0056 gsl::not_null<const dd4hep::Detector*>
0057 DD4hep_service::detector() {
0058     std::call_once(init_flag, &DD4hep_service::Initialize, this);
0059     return m_dd4hepGeo.get();
0060 }
0061 
0062 //----------------------------------------------------------------
0063 // converter
0064 //
0065 /// Return pointer to the cellIDPositionConverter object.
0066 /// Call Initialize if needed.
0067 //----------------------------------------------------------------
0068 gsl::not_null<const dd4hep::rec::CellIDPositionConverter*>
0069 DD4hep_service::converter() {
0070     std::call_once(init_flag, &DD4hep_service::Initialize, this);
0071     return m_cellid_converter.get();
0072 }
0073 
0074 //----------------------------------------------------------------
0075 // Initialize
0076 //
0077 /// Initialize the dd4hep geometry by reading in from the XML.
0078 /// Note that this is called automatically the first time detector()
0079 /// is called. Which XML file(s) are read is determined by the
0080 /// dd4hep:xml_files configuration parameter.
0081 //----------------------------------------------------------------
0082 void DD4hep_service::Initialize() {
0083 
0084     if (m_dd4hepGeo) {
0085         m_log->warn("DD4hep_service already initialized!");
0086     }
0087 
0088     // The current recommended way of getting the XML file is to use the environment variables
0089     // DETECTOR_PATH and DETECTOR_CONFIG.
0090     // Look for those first, so we can use it for the default
0091     // config parameter.
0092     auto *detector_config_env = std::getenv("DETECTOR_CONFIG");
0093     auto *detector_path_env = std::getenv("DETECTOR_PATH");
0094 
0095     std::string detector_config;
0096     // Check if detector_config_env is set
0097     if(detector_config_env != nullptr) {
0098         detector_config = detector_config_env;
0099     }
0100 
0101     // do we have default file name
0102     if(!detector_config.empty()) {
0103         m_xml_files.push_back(std::string(detector_path_env ? detector_path_env : ".") + "/" + detector_config + ".xml");
0104     }
0105 
0106     // User may specify multiple geometry files via the config. parameter. Normally, this
0107     // will be a single file which itself has includes for other files.
0108     m_app->SetDefaultParameter("dd4hep:xml_files", m_xml_files, "Comma separated list of XML files describing the DD4hep geometry. (Defaults to ${DETECTOR_PATH}/${DETECTOR_CONFIG}.xml using envars.)");
0109 
0110     if( m_xml_files.empty() ){
0111         m_log->error("No dd4hep XML file specified for the geometry!");
0112         m_log->error("Set your DETECTOR_PATH and DETECTOR_CONFIG environment variables");
0113         m_log->error("(the latter is typically done by sourcing the thisepic.sh");
0114         m_log->error("script the epic directory.)");
0115         throw std::runtime_error("No dd4hep XML file specified.");
0116     }
0117 
0118     // Reading the geometry may take a long time and if the JANA ticker is enabled, it will keep printing
0119     // while no other output is coming which makes it look like something is wrong. Disable the ticker
0120     // while parsing and loading the geometry
0121     auto tickerEnabled = m_app->IsTickerEnabled();
0122     m_app->SetTicker( false );
0123 
0124     // load geometry
0125     auto detector = dd4hep::Detector::make_unique("");
0126     try {
0127         m_log->info("Loading DD4hep geometry from {} files", m_xml_files.size());
0128         for (auto &filename : m_xml_files) {
0129 
0130             auto resolved_filename = resolveFileName(filename, detector_path_env);
0131 
0132             m_log->info("  - loading geometry file:  '{}' (patience ....)", resolved_filename);
0133             try {
0134                 detector->fromCompact(resolved_filename);
0135             } catch(std::runtime_error &e) {        // dd4hep throws std::runtime_error, no way to detail further
0136                 throw JException(e.what());
0137             }
0138         }
0139         detector->volumeManager();
0140         detector->apply("DD4hepVolumeManager", 0, nullptr);
0141         m_cellid_converter = std::make_unique<const dd4hep::rec::CellIDPositionConverter>(*detector);
0142         m_dd4hepGeo = std::move(detector); // const
0143 
0144         m_log->info("Geometry successfully loaded.");
0145     } catch(std::exception &e) {
0146         m_log->error("Problem loading geometry: {}", e.what());
0147         throw std::runtime_error(fmt::format("Problem loading geometry: {}", e.what()));
0148     }
0149 
0150     // Restore the ticker setting
0151     m_app->SetTicker( tickerEnabled );
0152 }
0153 
0154 std::string DD4hep_service::resolveFileName(const std::string &filename, char *detector_path_env) {
0155 
0156     std::string result(filename);
0157 
0158     // Check that this XML file actually exists.
0159     if( ! std::filesystem::exists(result) ){
0160 
0161         // filename does not exist, maybe DETECTOR_PATH/filename is meant?
0162         if(detector_path_env) {
0163 
0164             // Try looking filename in DETECTOR_PATH
0165             result = std::string(detector_path_env) + "/" + filename;
0166 
0167             if( ! std::filesystem::exists(result) ) {
0168                 // Here we go against the standard practice of throwing an error and print
0169                 // the message and exit immediately. This is because we want the last message
0170                 // on the screen to be that this file doesn't exist.
0171                 auto mess = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), "ERROR: ");
0172                 mess += fmt::format(fmt::emphasis::bold, "file: {} does not exist!", filename);
0173                 mess += "\nCheck that your DETECTOR_PATH and DETECTOR_CONFIG environment variables are set correctly.";
0174                 std::cerr << std::endl << std::endl << mess << std::endl << std::endl; // TODO standard log here!
0175                 std::_Exit(EXIT_FAILURE);
0176             }
0177         }
0178     }
0179     return result;
0180 }