diff --git a/src/dd4pod/python/npsim.py b/src/dd4pod/python/npsim.py index 396f676..2496106 100755 --- a/src/dd4pod/python/npsim.py +++ b/src/dd4pod/python/npsim.py @@ -8,6 +8,7 @@ Modified with standard EIC EPIC requirements. """ from __future__ import absolute_import, unicode_literals +import argparse import logging import sys @@ -20,6 +21,17 @@ RUNNER = DD4hepSimulation() + # Parse our own options + parser = argparse.ArgumentParser("Running ePIC/EIC Simulations:", add_help=False) + parser.add_argument("--disableChecksum", action="store_true", default=False, + help="Disable the detector checksum calculations") + args, unknown = parser.parse_known_args() + sys.argv = [sys.argv[0]] + unknown + if "--help" in unknown: + parser.print_help() + print() + print() + # Parse remaining options (command line and steering file override above) # This is done before updating the settings to workaround issue reported in # https://github.com/AIDASoft/DD4hep/pull/1376 @@ -66,6 +78,17 @@ def setupCerenkov(kernel): RUNNER.action.mapActions['RICHEndcapN'] = 'Geant4OpticalTrackerAction' RUNNER.action.mapActions['DIRC'] = 'Geant4OpticalTrackerAction' + # Store detector checksum in run action + if not args.disableChecksum: + RUNNER.action.run += [ + { + "name": "DetectorChecksumRunAction", + "parameter": { + "ignoreDetectors": [] + } + } + ] + # Use the optical photon efficiency stacking action for hpDIRC RUNNER.action.stack = [ { diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 6216894..5900e2f 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -2,11 +2,12 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR) dd4hep_add_plugin(NPDetPlugins SOURCES + src/DetectorChecksumRunAction.cxx src/EICInteractionVertexBoost.cxx src/EICInteractionVertexSmear.cxx src/OpticalPhotonEfficiencyStackingAction.cxx INCLUDES $ - USES DD4hep::DDCore DD4hep::DDG4 + USES DD4hep::DDCore DD4hep::DDCorePlugins DD4hep::DDG4 ) install(TARGETS NPDetPlugins diff --git a/src/plugins/include/npdet/DetectorChecksumRunAction.h b/src/plugins/include/npdet/DetectorChecksumRunAction.h new file mode 100644 index 0000000..c20dd7c --- /dev/null +++ b/src/plugins/include/npdet/DetectorChecksumRunAction.h @@ -0,0 +1,107 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DETECTORCHECKSUMRUNACTION_H +#define DETECTORCHECKSUMRUNACTION_H + +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + +/// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit +namespace sim { + + using dd4hep::detail::DetectorChecksum; + using hashMap_t = std::map; + + template void RunParameters::ingestParameters(T const& hashMap) { + for (auto& [name, hash] : hashMap) { + // hashes are 64 bit, so we have to cast to string + m_strValues[name + "_hash"] = {std::format("{:x}",hash)}; + } + } + + class DetectorChecksumRunAction: public Geant4RunAction { + public: + /// Standard constructor with initializing arguments + DetectorChecksumRunAction(Geant4Context* c, const std::string& n) + : Geant4RunAction(c, n) { + declareProperty("ignoreDetectors", m_ignoreDetectors); + }; + /// Default destructor + virtual ~DetectorChecksumRunAction() {}; + + void begin(const G4Run* run); + private: + hashMap_t getHashMap(Detector& detector) const; + std::set m_ignoreDetectors; + }; + +void DetectorChecksumRunAction::begin(const G4Run* /* run */) { + try { + auto* parameters = context()->run().extension(false); + if (!parameters) { + parameters = new RunParameters(); + context()->run().addExtension(parameters); + } + parameters->ingestParameters(getHashMap(context()->detectorDescription())); + } catch(std::exception &e) { + printout(ERROR,"DetectorChecksumRunAction::begin","Failed to register run parameters: %s", e.what()); + } +} + +std::map +DetectorChecksumRunAction::getHashMap(Detector& detector) const { + std::map hashMap; +#if __has_include() + // Determine detector checksum + printout(INFO,"DetectorChecksumRunAction::getHashMap", "determining checksum... (disable with --disableChecksum)"); + // FIXME: ctor expects non-const detector + const auto start{std::chrono::steady_clock::now()}; + DetectorChecksum checksum(detector); + checksum.debug = 0; + checksum.max_level = -1; + checksum.precision = 3; + checksum.hash_meshes = true; + checksum.hash_readout = true; + bool checksum_det_element_recursive = true; + for (const auto& [name, det] : detector.world().children()) { + if (m_ignoreDetectors.contains(name)) { + continue; + } + checksum.analyzeDetector(det); + DetectorChecksum::hashes_t hash_vec{}; + checksum.checksumDetElement(0, det, hash_vec, checksum_det_element_recursive); + DetectorChecksum::hash_t hash = + dd4hep::detail::hash64(&hash_vec[0], hash_vec.size() * sizeof(DetectorChecksum::hash_t)); + hashMap[name] = hash; + } + const auto finish{std::chrono::steady_clock::now()}; + const std::chrono::duration elapsed_seconds{finish - start}; + printout(INFO,"DetectorChecksumRunAction::getHashMap", "duration: %f seconds", elapsed_seconds.count()); +#endif + return hashMap; +} + +} // End namespace sim +} // End namespace dd4hep + +#endif // DETECTORCHECKSUMRUNACTION_H diff --git a/src/plugins/src/DetectorChecksumRunAction.cxx b/src/plugins/src/DetectorChecksumRunAction.cxx new file mode 100644 index 0000000..55c744d --- /dev/null +++ b/src/plugins/src/DetectorChecksumRunAction.cxx @@ -0,0 +1,5 @@ +#include "DDG4/Factories.h" + +#include "npdet/DetectorChecksumRunAction.h" + +DECLARE_GEANT4ACTION(DetectorChecksumRunAction)