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