Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /acts/Plugins/DD4hep/src/DDG4/ActsMaterialTrackWriter.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include "ActsPlugins/Root/RootMaterialTrackIo.hpp"
0010 
0011 #include <algorithm>
0012 #include <cstddef>
0013 #include <memory>
0014 #include <mutex>
0015 #include <string>
0016 
0017 #include <DDG4/Factories.h>
0018 #include <DDG4/Geant4Context.h>
0019 #include <DDG4/Geant4EventAction.h>
0020 #include <DDG4/Geant4Kernel.h>
0021 #include <DDG4/Geant4RunAction.h>
0022 #include <G4Event.hh>
0023 #include <G4Run.hh>
0024 #include <TFile.h>
0025 #include <TTree.h>
0026 
0027 #include "detail/RecordedMaterialTracks.hpp"
0028 
0029 namespace ActsPlugins {
0030 
0031 /// @brief DDG4 event action that writes recorded material tracks
0032 ///
0033 /// At the end of each event, the tracks the `ActsMaterialRecorder` stepping
0034 /// action attached to the event are written to a ROOT tree, one entry per
0035 /// track, with @ref ActsPlugins::RootMaterialTrackIo. This is the format the
0036 /// ACTS material mapping reads.
0037 ///
0038 /// In multi-threaded running, a single writer is shared by all worker threads
0039 /// by creating it as a shared DDG4 action, which serialises the end-of-event
0040 /// calls. The output file is opened when the first thread starts its run, and
0041 /// closed once all threads have ended theirs.
0042 ///
0043 /// Properties:
0044 /// - `OutputFile`: output ROOT file, default `material_tracks.root`
0045 /// - `TreeName`: name of the output tree, default `material_tracks`
0046 class ActsMaterialTrackWriter final : public dd4hep::sim::Geant4EventAction {
0047  public:
0048   /// Standard constructor of a DDG4 action
0049   /// @param context the DDG4 context
0050   /// @param name the name of the action instance
0051   ActsMaterialTrackWriter(dd4hep::sim::Geant4Context* context,
0052                           const std::string& name);
0053 
0054   /// Closes the output file if a thread never ended its run
0055   ~ActsMaterialTrackWriter() override;
0056 
0057   /// Register the run callbacks with the run action of a thread
0058   /// @param threadContext the context of the thread
0059   void configureFiber(dd4hep::sim::Geant4Context* threadContext) override;
0060 
0061   /// Write the material tracks of the event
0062   /// @param event the Geant4 event
0063   void end(const G4Event* event) override;
0064 
0065  private:
0066   void beginRun(const G4Run* run);
0067   void endRun(const G4Run* run);
0068   /// Write and close the output file, to be called with the lock held
0069   void closeFile();
0070 
0071   /// Output ROOT file
0072   std::string m_outputFile = "material_tracks.root";
0073   /// Name of the output tree
0074   std::string m_treeName = "material_tracks";
0075 
0076   std::unique_ptr<TFile> m_file;
0077   TTree* m_tree = nullptr;
0078   std::unique_ptr<ActsPlugins::RootMaterialTrackIo> m_trackIo;
0079   /// Guards opening and closing the output file. Writing the events is
0080   /// serialised by the shared action wrapper in multi-threaded running.
0081   std::mutex m_fileMutex;
0082   /// Number of threads that ended their run, the last one closes the file
0083   int m_endedRuns = 0;
0084   bool m_written = false;
0085   std::size_t m_nTracks = 0;
0086 };
0087 
0088 ActsMaterialTrackWriter::ActsMaterialTrackWriter(
0089     dd4hep::sim::Geant4Context* context, const std::string& name)
0090     : dd4hep::sim::Geant4EventAction(context, name) {
0091   declareProperty("OutputFile", m_outputFile);
0092   declareProperty("TreeName", m_treeName);
0093   // The run action has to exist to configure the thread fibers
0094   context->runAction();
0095 }
0096 
0097 void ActsMaterialTrackWriter::configureFiber(
0098     dd4hep::sim::Geant4Context* threadContext) {
0099   dd4hep::sim::Geant4EventAction::configureFiber(threadContext);
0100   threadContext->runAction().callAtBegin(this,
0101                                          &ActsMaterialTrackWriter::beginRun);
0102   threadContext->runAction().callAtEnd(this, &ActsMaterialTrackWriter::endRun);
0103 }
0104 
0105 ActsMaterialTrackWriter::~ActsMaterialTrackWriter() {
0106   std::scoped_lock lock(m_fileMutex);
0107   if (m_file != nullptr) {
0108     warning("Not all threads ended their run, closing '%s' anyway.",
0109             m_outputFile.c_str());
0110     closeFile();
0111   }
0112 }
0113 
0114 void ActsMaterialTrackWriter::beginRun(const G4Run* /*run*/) {
0115   std::scoped_lock lock(m_fileMutex);
0116   if (m_file != nullptr) {
0117     // Already opened by another thread
0118     return;
0119   }
0120   if (m_written) {
0121     except("Only a single run is supported, '%s' has already been written.",
0122            m_outputFile.c_str());
0123   }
0124 
0125   m_file.reset(TFile::Open(m_outputFile.c_str(), "RECREATE"));
0126   if (m_file == nullptr || m_file->IsZombie()) {
0127     except("Could not open output file '%s'.", m_outputFile.c_str());
0128   }
0129   // Owned by the file, which deletes it when it is closed
0130   m_tree = new TTree(m_treeName.c_str(), "Recorded material tracks");
0131   m_tree->SetDirectory(m_file.get());
0132 
0133   ActsPlugins::RootMaterialTrackIo::Config ioCfg;
0134   ioCfg.prePostStepInfo = true;
0135   ioCfg.recalculateTotals = true;
0136   m_trackIo = std::make_unique<ActsPlugins::RootMaterialTrackIo>(ioCfg);
0137   m_trackIo->connectForWrite(*m_tree);
0138 
0139   info("Writing material tracks to tree '%s' in '%s'.", m_treeName.c_str(),
0140        m_outputFile.c_str());
0141 }
0142 
0143 void ActsMaterialTrackWriter::endRun(const G4Run* /*run*/) {
0144   std::scoped_lock lock(m_fileMutex);
0145   // Counting ended runs rather than running threads, since a thread may only
0146   // start its run once another one already ended its own
0147   ++m_endedRuns;
0148   if (const int nThreads = std::max(
0149           context()->kernel().master().property("NumberOfThreads").value<int>(),
0150           1);
0151       m_endedRuns < nThreads || m_file == nullptr) {
0152     return;
0153   }
0154   closeFile();
0155 }
0156 
0157 void ActsMaterialTrackWriter::closeFile() {
0158   m_file->cd();
0159   m_tree->Write();
0160   m_file->Close();
0161   m_tree = nullptr;
0162   m_trackIo.reset();
0163   m_file.reset();
0164   m_written = true;
0165   info("Wrote %zu material tracks to '%s'.", m_nTracks, m_outputFile.c_str());
0166 }
0167 
0168 void ActsMaterialTrackWriter::end(const G4Event* event) {
0169   // Serialised by the shared action wrapper in multi-threaded running
0170   const auto* recorded =
0171       context()->event().extension<detail::RecordedMaterialTracks>(false);
0172   if (recorded == nullptr) {
0173     warning(
0174         "No recorded material tracks in event %d, is the "
0175         "ActsMaterialRecorder stepping action configured?",
0176         event->GetEventID());
0177     return;
0178   }
0179 
0180   for (const auto& [trackId, track] : recorded->tracks) {
0181     m_trackIo->write(event->GetEventID(), track);
0182     m_tree->Fill();
0183   }
0184   m_nTracks += recorded->tracks.size();
0185 }
0186 
0187 }  // namespace ActsPlugins
0188 
0189 DECLARE_GEANT4ACTION_NS(ActsPlugins, ActsMaterialTrackWriter)