CbmRoot
Loading...
Searching...
No Matches
CbmDigitizationSource.cxx
Go to the documentation of this file.
1/* Copyright (C) 2018-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Volker Friese [committer], Florian Uhlig */
4
5/*
6 * CbmDigitizationSource.cxx
7 *
8 * Created on: 06.11.2018
9 * Author: vfriese
10 */
11
13
14#include "FairRootManager.h"
15
16#include "TChain.h"
17#include "TFolder.h"
18#include "TROOT.h"
19#include <TFile.h>
20
21#include <cassert>
22#include <iomanip>
23#include <utility>
24
25using cbm::sim::Mode;
27
28
29// ----- Constructor -----------------------------------------------------
31 : FairSource()
32 , fInputSets()
33 , fInputMap()
34 , fNextEvent()
35 , fMCEventHeader()
36 , fListOfFolders(new TObjArray())
37 , fBranches()
38 , fTimeStart(1000.)
39 , fCurrentTime(0.)
40 , fCurrentEntryId(0)
41 , fCurrentInputId(0)
42 , fCurrentRunId(0)
43 , fFirstCall(kTRUE)
44 , fMode(cbm::sim::Mode::Timebased)
45 , fCurrentInputSet(nullptr)
46 , fSwitchInputSet(kFALSE)
47{
48}
49// ---------------------------------------------------------------------------
50
51
52// ----- Destructor ------------------------------------------------------
54{
55 for (auto const& inputSet : fInputSets)
56 if (inputSet) delete inputSet;
57 fBranches.clear();
58}
59// ---------------------------------------------------------------------------
60
61
62// ----- Set the branch address of a branch -----------------------------
63Bool_t CbmDigitizationSource::ActivateObject(TObject** object, const char* branchName)
64{
65
66 // The branch address has to be set for each input chain of each input set
67 for (auto const& inputSet : fInputSets)
68 inputSet->ActivateObject(object, branchName);
69
70 return kTRUE;
71}
72// ---------------------------------------------------------------------------
73
74
75// ----- Add a transport input -------------------------------------------
76void CbmDigitizationSource::AddInput(UInt_t inputId, TChain* chain, TimeDist dist, Double_t rate, ECbmTreeAccess mode)
77{
78
79 // Catch input ID already being used
80 if (fInputMap.find(inputId) != fInputMap.end()) {
81 LOG(fatal) << "DigitizationSource: Input ID " << inputId << " is already defined!";
82 return;
83 } //? Input ID already in use
84
85 // Create a new inputSet and add the input to it
86 CbmMCInputSet* inputSet = new CbmMCInputSet(dist, rate);
87 inputSet->AddInput(inputId, chain, mode);
88
89 // If it is the first input set, it defines the reference branch list.
90 if (fInputSets.size() == 0) { fBranches = inputSet->GetBranchList(); } //? First input set
91
92 // If it is not the first set, check compatibility of branch list.
93 else {
94 if (!CheckBranchList(inputSet)) {
95 LOG(fatal) << "DigitizationSource: Incompatible branch list!";
96 return;
97 } //? Branch list in new input set not compatible
98 } //? Not the first input set
99
100 // Register the new input set and input
101 fInputSets.push_back(inputSet);
102 fInputMap[inputId] = inputSet;
103
104 LOG(info) << "DigitizationSource: Added input " << inputId << " with rate " << rate << " / s, mode: "
105 << (mode == ECbmTreeAccess::kRegular ? "regular" : (mode == ECbmTreeAccess::kRepeat ? "repeat" : "random"));
106}
107// ---------------------------------------------------------------------------
108
109
110// ----- Check the branch list of an input -------------------------------
112{
113
114 assert(inputSet);
115 Bool_t success = kTRUE;
116 for (auto const& entry : fBranches) {
117 auto it = inputSet->GetBranchList().find(entry);
118 if (it == inputSet->GetBranchList().end()) {
119 LOG(debug) << "DigitizationSource: required branch " << entry << " not present in input set!";
120 success = kFALSE;
121 break;
122 } //? Global branch not in input
123 } //# Global branches
124
125 if (!success) {
126 std::stringstream ss;
127 ss << "DigitizationSource: Global branch list is ";
128 for (auto const& entry : fBranches)
129 ss << entry << " ";
130 LOG(info) << ss.str();
131 std::stringstream ss1;
132 ss1 << "DigitizationSource: Input set branch list is ";
133 for (auto const& entry : inputSet->GetBranchList()) {
134 ss1 << entry << " ";
135 }
136 LOG(info) << ss1.str();
137 } //? Branches not compatible
138
139 return success;
140}
141// ---------------------------------------------------------------------------
142
143
144// ----- Check the maximal entry the source can run to -------------------
146{
147
148 // Catch the case when no input is connected
149 if (fInputSets.empty()) return 0;
150
151 Int_t maxEvents = (fInputSets.size() == 1 ? fInputSets.front()->GetMaxNofEvents() : -1);
152
153 // If the maximal number of events is not defined, the method returns a
154 // practically infinite number. The run will proceed until one of the
155 // inputs is exhausted or if terminated by CTRL+C.
156 // This is the case when there is more than one input set (mixing)
157 // or when the only input set has only unlimited inputs (all inputs
158 // are accessed with mode kRepeat or kRandom).
159 return (maxEvents >= 0 ? maxEvents : 1e6);
160}
161// ---------------------------------------------------------------------------
162
163
164// ----- Embed a transport input -----------------------------------------
165void CbmDigitizationSource::EmbedInput(UInt_t inputId, TChain* chain, UInt_t targetInputId, ECbmTreeAccess mode)
166{
167
168 // Catch input ID already being used
169 if (fInputMap.find(inputId) != fInputMap.end()) {
170 LOG(fatal) << "DigitizationSource: Input ID " << inputId << " is already defined!";
171 return;
172 } //? Input ID already in use
173
174 // Catch target input not existing
175 if (fInputMap.find(targetInputId) == fInputMap.end()) {
176 LOG(fatal) << "DigitizationSource: Target input ID " << targetInputId << " for input " << inputId
177 << " does not exist!";
178 return;
179 } //? Target input does not exist
180
181 // Add the new input to the respective input set
182 fInputMap[targetInputId]->AddInput(inputId, chain, mode);
183 fInputMap[inputId] = fInputMap[targetInputId];
184
185 LOG(info) << "DigitizationSource: Embedded input " << inputId << " into input " << targetInputId << ", mode: "
186 << (mode == ECbmTreeAccess::kRegular ? "regular" : (mode == ECbmTreeAccess::kRepeat ? "repeat" : "random"));
187}
188// ---------------------------------------------------------------------------
189
190
191// ----- Fill the event header -------------------------------------------
192void CbmDigitizationSource::FillEventHeader(FairEventHeader* event)
193{
194 assert(event);
195 event->SetEventTime(fCurrentTime);
196 event->SetMCEntryNumber(fCurrentEntryId);
197 event->SetInputFileId(fCurrentInputId);
198 event->SetRunId(fCurrentRunId);
199 LOG(debug) << "DigitizationSource: Event with RunId " << fCurrentRunId << ", input " << fCurrentInputId << ", entry "
200 << fCurrentEntryId << ", time " << fCurrentTime << " ns";
201}
202// ---------------------------------------------------------------------------
203
204
205// ----- Get an input ----------------------------------------------------
207{
208 assert(!fInputMap.empty());
209 return fInputMap.begin()->second->GetFirstInput().second;
210}
211// ---------------------------------------------------------------------------
212
213
214// ----- Initialisation --------------------------------------------------
216{
217
218 // Catch missing or too many input sets
219 if (fInputSets.empty()) {
220 LOG(fatal) << "DigitizationSource: No input sets defined!";
221 return kFALSE;
222 }
223 if (fMode == Mode::EventByEvent && fInputMap.size() != 1) {
224 LOG(fatal) << "DigitizationSource: More than one input defined "
225 << "in event-by-event mode!";
226 return kFALSE;
227 }
228
229 // Register all input chains to FairRootManager
230 for (auto const& inputSet : fInputSets)
231 inputSet->RegisterChains();
232
233 // Get folder from first input file and register it to FairRootManager
234 CbmMCInput* input = fInputSets.front()->GetFirstInput().second;
235 TFile* file = input->GetChain()->GetFile();
236 assert(file);
237 TFolder* folder = file->Get<TFolder>("cbmroot");
238 assert(folder);
239 gROOT->GetListOfBrowsables()->Add(folder);
240 fListOfFolders->Add(folder);
241 FairRootManager::Instance()->SetListOfFolders(fListOfFolders);
242
243 // Activate the MC event header to all respective input branches.
244 // This is necessary since it is used from this class.
245 // The other branches will be activated if needed by a task
246 // through the method ActivateObject called from FairRootManager
247 fMCEventHeader = new FairMCEventHeader();
248 TObject** object = reinterpret_cast<TObject**>(&fMCEventHeader);
249 ActivateObject(object, "MCEventHeader.");
250
251 // Set the time of the first event for each input set
252 if (fMode == Mode::Timebased) {
253 for (size_t iSet = 0; iSet < fInputSets.size(); iSet++) {
254 CbmMCInputSet* inputSet = fInputSets.at(iSet);
255 Double_t time = fTimeStart + inputSet->GetDeltaT();
256 LOG(info) << "First time for input set " << iSet << " is " << time << " ns.";
257 fNextEvent.insert(std::make_pair(time, inputSet));
258 } //# Input sets
259 }
260
261 // Select the input set with smallest event time
262 fCurrentTime = fNextEvent.begin()->first;
263 fCurrentInputSet = fNextEvent.begin()->second;
264
265 return kTRUE;
266}
267// ---------------------------------------------------------------------------
268
269
270// ----- Define one input event ------------------------------------------
272{
273
274 // Before the actual run, ReadEvent is once called from FairRunAna::Init().
275 // This is to get the run ID needed for setting the parameter containers.
276 // Since the input entries are read sequentially, this would mean
277 // always losing the first entry. We here protect against that by calling
278 // the first entry of the first input directly, without incrementing its
279 // current entry bookkeeper.
280 if (fFirstCall) {
281 ReadRunId();
282 fFirstCall = kFALSE;
283 return 0;
284 }
285
286 // In the event-by-event mode, get the respective event from the first
287 // input; the event time is fStartTime.
288 if (fMode == Mode::EventByEvent) return ReadEventByEvent(event);
289
290 // If the last used input set was exhausted, switch to a the next one
291 if (fSwitchInputSet) {
292
293 // Delete this entry from the list of next input sets
294 fNextEvent.erase(fNextEvent.begin());
295
296 // Generate a new event time for this input set and add it to the list
297 Double_t newTime = fCurrentTime + fCurrentInputSet->GetDeltaT();
298 fNextEvent.insert(std::make_pair(newTime, fCurrentInputSet));
299
300 // Store current time and input set
301 fCurrentTime = fNextEvent.begin()->first;
302 fCurrentInputSet = fNextEvent.begin()->second;
303
304 } //? Switch to next input set
305
306 // Get the next entry from the current input set
307 assert(fCurrentInputSet);
308 auto result = fCurrentInputSet->GetNextEntry();
309 fSwitchInputSet = std::get<0>(result);
310 fCurrentInputId = std::get<1>(result);
311 fCurrentEntryId = std::get<2>(result);
312 std::cout << std::endl;
313 LOG(info) << "DigitizationSource: Event " << event << " at t = " << std::fixed << std::setprecision(3) << fCurrentTime
314 << " ns"
315 << " from input " << fCurrentInputId << " (entry " << fCurrentEntryId << ")";
316
317 // Stop the run if the number of entries in this input is reached
318 if (fCurrentEntryId < 0) {
319 LOG(info) << "DigitizationSource: No more entries in input " << fCurrentInputId;
320 return 1;
321 }
322
323 return 0;
324}
325// ---------------------------------------------------------------------------
326
327
328// ----- Read event in the event-by-event mode ---------------------------
330{
331
332 // There should be only one input set with one input
333 auto result = fInputSets.front()->GetFirstInput();
334 fCurrentInputId = result.first;
335 CbmMCInput* input = result.second;
336 assert(input);
337
338 // In mode kRegular: Get requested entry number
339 if (input->GetMode() == ECbmTreeAccess::kRegular) {
340 if (event >= input->GetNofEntries()) {
341 LOG(info) << "DigitizationSource: Requested event " << event << " exceeds number of entries in input "
342 << fCurrentInputId << "( " << input->GetNofEntries() << " )";
343 return 1;
344 }
345 input->GetChain()->GetEntry(event);
346 fCurrentEntryId = event;
347 } //? kRegular
348
349 // In modes kRepeat or kRandom, get next entry
350 else
351 fCurrentEntryId = input->GetNextEntry();
352
353 // Set entry properties
355 LOG(info) << "DigitizationSource: Event " << event << " at t = " << fCurrentTime << " ns"
356 << " from input " << fCurrentInputId << " (entry " << fCurrentEntryId << ")";
357
358 return 0;
359}
360// ---------------------------------------------------------------------------
361
362
363// ----- Read run ID -----------------------------------------------------
365{
366
367 auto firstInput = fInputSets.front()->GetFirstInput();
368 fCurrentInputId = firstInput.first;
369 CbmMCInput* input = firstInput.second;
370 assert(input);
371 input->GetChain()->GetEntry(0);
372 fCurrentRunId = fMCEventHeader->GetRunID();
373 fCurrentEntryId = 0;
374 fFirstCall = kFALSE;
375 LOG(info) << "DigitizationSource: Run ID is " << fCurrentRunId;
376}
377// ---------------------------------------------------------------------------
378
379
ClassImp(CbmConverterManager)
ECbmTreeAccess
Mode to read entries from a ROOT TTree.
Definition CbmDefs.h:152
Source class for the input to digitization in CBM.
std::vector< CbmMCInputSet * > fInputSets
CbmMCInput * GetFirstInput()
First input from the first input set @value Pointer to first input.
FairMCEventHeader * fMCEventHeader
time -> inputSet
virtual Bool_t Init()
Abstract in base class. No implementation here.
Int_t ReadEventByEvent(UInt_t event)
Get next entry in event-by-event mode.
virtual Bool_t ActivateObject(TObject **object, const char *branchName)
Activate a branch and set its address.
Bool_t CheckBranchList(CbmMCInputSet *input)
Compare an input set branch list with the reference list.
void AddInput(UInt_t inputId, TChain *chain, cbm::sim::TimeDist dist, Double_t rate, ECbmTreeAccess mode=ECbmTreeAccess::kRegular)
Add a transport input.
virtual ~CbmDigitizationSource()
Destructor.
void EmbedInput(UInt_t inputId, TChain *chain, UInt_t targetInputId, ECbmTreeAccess mode=ECbmTreeAccess::kRegular)
Embed a transport input.
std::set< TString > fBranches
virtual Int_t CheckMaxEventNo(Int_t lastEntry=0)
Maximal entry number the source can run to.
void ReadRunId()
Read run ID from the first entry in the first input.
virtual void FillEventHeader(FairEventHeader *event)
Fill the output event header.
std::map< UInt_t, CbmMCInputSet * > fInputMap
std::multimap< Double_t, CbmMCInputSet * > fNextEvent
input ID -> inputSet
virtual Int_t ReadEvent(UInt_t event=0)
Provide one tree entry.
A MC transport input to digitisation in CBM.
Double_t GetDeltaT()
Time difference to next event @value Time difference to next event [ns].
void AddInput(UInt_t inputId, TChain *chain, ECbmTreeAccess mode=ECbmTreeAccess::kRegular)
Add an input to the set.
std::tuple< Bool_t, UInt_t, Int_t > GetNextEntry()
Get the next entry from the inputs @value Status tuple.
const std::set< TString > & GetBranchList() const
List of branches @value Reference to branch list.
An MC (transport) input to digitisation in CBM.
Definition CbmMCInput.h:33
ECbmTreeAccess GetMode() const
Tree access mode @value Access mode.
Definition CbmMCInput.h:80
TChain * GetChain() const
Pointer to chain @value Pointer to TChain object.
Definition CbmMCInput.h:60
Int_t GetNextEntry()
Get the next unused entry from the chain @value Id of tree entry.
Long64_t GetNofEntries() const
Number of entries @value Number of entries in this input chain.
Definition CbmMCInput.h:86
TimeDist
Definition Defs.h:29