ATTPCROOT  0.3.0-alpha
A ROOT-based framework for analyzing data from active target detectors
AtLinkDAQTask.cxx
Go to the documentation of this file.
1 #include "AtLinkDAQTask.h"
2 
3 #include "AtBaseEvent.h"
4 #include "AtRunAna.h"
5 
6 #include <FairLogger.h>
7 #include <FairRootFileSink.h>
8 #include <FairRootManager.h>
9 #include <FairRunAna.h>
10 #include <FairSink.h> // for FairSink
11 #include <FairTask.h>
12 
13 #include <TChain.h>
14 #include <TClonesArray.h>
15 #include <TFile.h>
16 #include <TGraph.h>
17 #include <TMathBase.h>
18 #include <TObject.h>
19 
20 #include "HTTimestamp.h"
21 
22 #include <algorithm>
23 #include <iostream>
24 #include <memory>
25 
26 bool AtLinkDAQTask::SetInputTree(TString fileName, TString treeName)
27 {
28  if (evtTree != nullptr) {
29  LOG(error) << "HiRAEVT Tree was already set! Add more trees using the "
30  << "function AddInputTree.";
31  return false;
32  }
33  // Add the tree to the input
34  evtTree = std::make_unique<TChain>(treeName);
35 
36  // If there is a tree with the correct name in the file
37  return AddInputTree(fileName);
38 }
39 
40 bool AtLinkDAQTask::AddInputTree(TString fileName)
41 {
42  if (evtTree == nullptr) {
43  LOG(fatal) << "HiRAEVT TChain was not initialized using the "
44  << "function SetInputTree.";
45  return false;
46  }
47 
48  return (evtTree->Add(fileName, -1) == 1);
49 }
50 
51 InitStatus AtLinkDAQTask::Init()
52 {
53  auto *run = dynamic_cast<AtRunAna *>(FairRunAna::Instance());
54  if (run == nullptr)
55  LOG(fatal) << "Run must be of type AtRunAna or a derived type!";
56 
57  // Register the input and output branches with the IO manager
58  FairRootManager *ioMan = FairRootManager::Instance();
59  if (ioMan == nullptr) {
60  LOG(fatal) << "Cannot find RootManager!";
61  return kFATAL;
62  }
63 
64  fInputEventArray = dynamic_cast<TClonesArray *>(ioMan->GetObject(fInputBranchName));
65  if (fInputEventArray == nullptr) {
66  LOG(fatal) << "Cannot find AtRawEvent array in branch " << fInputBranchName << "!";
67  return kFATAL;
68  }
69 
70  // Set the branch addresses for the HiRAEVT detectors
71  if (evtTree == nullptr) {
72  LOG(fatal) << "HiRAEVT tree was never initialized!";
73  return kFATAL;
74  }
75  std::cout << "EVT address: " << evtTree.get() << std::endl;
76  evtTree->SetBranchAddress(fEvtTimestampName, &fEvtTS);
77 
78  // Create the clone of the HiRA tree in the new file
79  fEvtOutputFile = new TFile(fEvtOutputFileName, "RECREATE"); // NOLINT (owned by ROOT)
80  if (fEvtOutputFile->IsZombie()) {
81  LOG(fatal) << "Failed to open output file: " << fEvtOutputFileName;
82  return kERROR;
83  }
84  fEvtOutputFile->cd();
85  fEvtOutputTree = evtTree->CloneTree(0);
86  LOG(info) << "Initialized output EVT tree in " << fEvtOutputFileName;
87 
88  return kSUCCESS;
89 }
90 
91 void AtLinkDAQTask::DoFirstEvent()
92 {
93  evtTree->GetEntry(0);
94  fEvtTimestamp = fEvtTS->GetTimestamp();
95  fTpcTimestamp = fEvent->GetTimestamps();
96 
97  LOG(info) << "Initial timestamps: " << fTpcTimestamp.at(fTpcTimestampIndex) << " " << fEvtTimestamp;
98  kFirstEvent = false;
99  AtRunAna::Instance()->MarkFill(false);
100  fEvtTreeIndex = 1;
101  fTpcTreeIndex = 1;
102 
103  // Get the number of timestamps in the the AtRawEvent
104  // And create the graphs to plot
105  auto numTimestamps = fEvent->GetTimestamps().size();
106  for (int i = 0; i < numTimestamps; ++i) {
107  fGrDataRatio.emplace_back();
108  fGrDataAbs.emplace_back();
109  }
110 }
111 
112 bool AtLinkDAQTask::UpdateTimestamps()
113 {
114  if (evtTree->GetEntry(fEvtTreeIndex) <= 0)
115  return false;
116 
117  fEvtTreeIndex++;
118  fTpcTreeIndex++;
119  fOldEvtTimestamp = fEvtTimestamp;
120  fOldTpcTimestamp = fTpcTimestamp;
121  fEvtTimestamp = fEvtTS->GetTimestamp();
122  fTpcTimestamp = fEvent->GetTimestamps();
123  if (fTpcTimestamp.size() < fTpcTimestampIndex)
124  return false;
125 
126  return true;
127 }
128 
129 void AtLinkDAQTask::ResetFlags()
130 {
131  auto *run = dynamic_cast<AtRunAna *>(FairRunAna::Instance());
132  kFillEvt = run->GetMarkFill();
133  kCorruptedTimestamp = false;
134 }
135 
136 // return < 0 -> Extra evt event
137 // return == 0 -> match
138 // return > 0 -> extra TPC
139 Int_t AtLinkDAQTask::CheckMatch()
140 {
141  if (kCorruptedTimestamp) {
142  // Get the difference in the TPC and EVT timestamps
143  // diff = evt - tpc;
144  Double_t diff = static_cast<double>(fEvtTimestamp) - static_cast<double>(fTpcTimestamp[fTpcTimestampIndex]);
145  diff -= fDifferenceOffset;
146 
147  if (TMath::Abs(diff) < fCorruptedSearchRadius)
148  return 0;
149 
150  LOG(info) << "TPC Timestamp: " << fTpcTimestamp.at(fTpcTimestampIndex) << std::endl
151  << "EVT Timestamp: " << fEvtTimestamp << std::endl
152  << "diff: " << diff << std::endl;
153 
154  return diff;
155  } else {
156  fIntervalEvt = fEvtTimestamp - fOldEvtTimestamp;
157  fIntervalTpc = fTpcTimestamp.at(fTpcTimestampIndex) - fOldTpcTimestamp.at(fTpcTimestampIndex);
158 
159  //|intervalTPC-intervalNSCL|/freqRatio
160  double scaledInterval = GetScaledInterval(fIntervalEvt, fIntervalTpc);
161 
162  if (scaledInterval < fSearchRadius)
163  return 0;
164 
165  LOG(info) << "TPC Timestamp: " << fTpcTimestamp.at(fTpcTimestampIndex) << std::endl
166  << "EVT Timestamp: " << fEvtTimestamp << std::endl
167  << "TPC Interval: " << fIntervalTpc << std::endl
168  << "EVT Interval: " << fIntervalEvt << std::endl
169  << "Scaled Interval: " << scaledInterval << std::endl;
170 
171  if (fIntervalTpc > fIntervalEvt * fSearchMean)
172  return -1;
173  else
174  return 1;
175  }
176 }
177 
178 void AtLinkDAQTask::Exec(Option_t *opt)
179 {
180  ResetFlags();
181  // Should already have loaded the event from iomanager. If this is the
182  // first event then set the old timestamp and continue without filling
183  if (fInputEventArray->GetEntriesFast() == 0)
184  return;
185  fEvent = dynamic_cast<AtBaseEvent *>(fInputEventArray->At(0));
186 
187  if (kFirstEvent) {
188  DoFirstEvent();
189  return;
190  }
191 
192  // Grab both timestamps for this event, set old timestamp and update counter
193  if (!UpdateTimestamps()) {
194  LOG(warn) << "Failed to update timestamps. Skipping event";
195  AtRunAna::Instance()->MarkFill(false);
196  kFillEvt = false;
197 
198  return;
199  }
200 
201  // Check for corrupted timestamp data (All FFFFs in a word)
202  ULong64_t upperInt = fTpcTimestamp.at(fTpcTimestampIndex) & 0xFFFFFFFF00000000;
203  kCorruptedTimestamp = (upperInt == 0xFFFFFFFF00000000);
204  if (kCorruptedTimestamp) {
205  LOG(warn) << "Corrupted timestamp " << std::hex << fTpcTimestamp.at(fTpcTimestampIndex) << " correcting to "
206  << (fTpcTimestamp.at(fTpcTimestampIndex) & 0x00000000FFFFFFFF) << " EVT: " << fEvtTimestamp << std::dec;
207 
208  fTpcTimestamp.at(fTpcTimestampIndex) &= 0x00000000FFFFFFFF;
209  }
210 
211  // Compare both timestamps with their old ones. If it is negative, we must
212  // have taken an event before the clocks cleared so reset the old TS
213  // and continue without filling
214  if (fEvtTimestamp < fOldEvtTimestamp ||
215  fTpcTimestamp.at(fTpcTimestampIndex) < fOldTpcTimestamp.at(fTpcTimestampIndex)) {
216  LOG(warn) << "Timestamp was reset between EVT event " << fEvtTreeIndex - 2 << " and " << fEvtTreeIndex - 1
217  << " reseting old timestamps and "
218  << " continuing.";
219  LOG(warn) << "EVT TS old: " << fOldEvtTimestamp << " EVT TS new: " << fEvtTimestamp;
220  LOG(warn) << "TPC TS old: " << fOldTpcTimestamp.at(fTpcTimestampIndex)
221  << " TPC TS new: " << fTpcTimestamp.at(fTpcTimestampIndex);
222  AtRunAna::Instance()->MarkFill(false);
223  kFillEvt = false;
224  return;
225  }
226 
227  // Compare intervalTPC/intervalNSCL to the search mean and radius
228  // If it lies within, then fill the HiRAET tree, upadate the old timestamps,
229  // and return
230  auto match = CheckMatch();
231  // LOG(info) << match;
232  if (match == 0) {
233  // Record timestamps
234  if (fDifferenceOffset == 0)
235  fDifferenceOffset = (double)fEvtTimestamp - (double)fTpcTimestamp[fTpcTimestampIndex];
236  Fill();
237  return;
238  }
239 
240  /***** If we have an extra EVT event *****/
241  LOG(warn) << "Extra event, match number: " << match;
242  if (match < 0) {
243 
244  LOG(info) << "Extra EVT event found, searching for matching event";
245 
246  // Loop through until we hit the last entry of the tree, or until
247  // we can match the event interval,
248  auto currentIndex = fEvtTreeIndex;
249  auto maxIndex = currentIndex + 3;
250  // auto currentTS = fEvtTimestamp;
251  if (maxIndex > evtTree->GetEntries())
252  maxIndex = evtTree->GetEntries();
253 
254  // Change to a loop until EVT timestamp is further along
255  while (currentIndex < maxIndex) {
256  // Get the next NSCL event and associated interval
257  evtTree->GetEntry(currentIndex++);
258  fEvtTimestamp = fEvtTS->GetTimestamp();
259 
260  // Check for a match
261  if (CheckMatch() == 0) {
262  LOG(info) << "Found match!" << std::endl;
263  fEvtTreeIndex = currentIndex;
264  Fill();
265  return;
266  }
267  } // while(currentIndex < maxIndex)
268 
269  LOG(error) << "Did not find match in next three events" << std::endl;
270  AtRunAna::Instance()->MarkFill(false);
271  kFillEvt = false;
272 
273  } // if we had an extra EVT event
274 
275  /**** We have an extra TPC event *******/
276  else {
277  LOG(info) << "Extra TPC event found, searching for matching event!";
278 
279  AtRunAna::Instance()->MarkFill(false);
280  kFillEvt = false;
281  // Reset the evtIndex so we're still looking at the same event
282  fEvtTreeIndex--;
283  return;
284  }
285 }
286 
287 void AtLinkDAQTask::Fill()
288 {
289  // Checkl to see if we should actually fill
290  if (!kFillEvt)
291  return;
292 
293  // Get the EVt timestamp interval
294  double evtInterval = fEvtTimestamp - fOldEvtTimestamp;
295  for (int i = 0; i < fGrDataRatio.size(); ++i) {
296  // Get signed scaled interval for this timestamp
297  double intDiff = evtInterval;
298 
299  if (i < fTpcTimestamp.size() && i < fOldTpcTimestamp.size())
300  intDiff -= static_cast<double>(fTpcTimestamp.at(i) - fOldTpcTimestamp.at(i));
301 
302  fGrDataAbs.at(i).push_back(intDiff);
303 
304  intDiff /= evtInterval;
305  fGrDataRatio.at(i).push_back(intDiff);
306  }
307  fEvtOutputTree->Fill();
308 }
309 
311 {
312  auto run = dynamic_cast<AtRunAna *>(FairRunAna::Instance());
313  auto outFile = dynamic_cast<FairRootFileSink *>(run->GetSink());
314  if (outFile) {
315  LOG(info) << "Adding TTree " << fEvtOutputTree->GetName() << " as friend to output tree "
316  << outFile->GetOutTree()->GetName();
317  outFile->GetOutTree()->AddFriend(fEvtOutputTree);
318  }
319 
320  LOG(info) << "Writing graph and tree";
321 
322  // Create Graphs and fill
323  for (int index = 0; index < fGrDataRatio.size(); ++index) {
324  fEvtOutputFile->cd();
325  auto gr = std::make_unique<TGraph>(fGrDataRatio[index].size());
326  auto gr2 = std::make_unique<TGraph>(fGrDataAbs[index].size());
327  gr->SetTitle(TString::Format("Relative intercal difference. TS_%d", index));
328  gr2->SetTitle(TString::Format("Abs interval difference. TS_%d", index));
329 
330  for (int i = 0; i < fGrDataRatio[index].size(); ++i) {
331  gr->SetPoint(i, i, fGrDataRatio[index].at(i));
332  gr2->SetPoint(i, i, fGrDataAbs[index].at(i));
333  }
334  gr->Write(TString::Format("Ratio_%d", index));
335  gr2->Write(TString::Format("Abs_%d", index));
336  }
337 
338  fEvtOutputFile->cd();
339  fEvtOutputTree->Write();
340  fEvtOutputFile->Close();
341 }
342 
343 Double_t AtLinkDAQTask::GetScaledInterval(ULong64_t intervalEvt, ULong64_t fIntercalTPC)
344 {
345  if (kUseRatio)
346  return TMath::Abs(static_cast<double>(fIntercalTPC) / static_cast<double>(intervalEvt)) / fSearchMean;
347  return TMath::Abs(static_cast<double>(intervalEvt) - static_cast<double>(fIntercalTPC)) / fSearchMean;
348 }
AtRunAna
Definition: AtRunAna.h:12
AtBaseEvent.h
AtLinkDAQTask::Init
virtual InitStatus Init() override
Definition: AtLinkDAQTask.cxx:51
AtLinkDAQTask::Finish
virtual void Finish() override
Definition: AtLinkDAQTask.cxx:310
AtLinkDAQTask::SetInputTree
bool SetInputTree(TString fileName, TString treeName)
Definition: AtLinkDAQTask.cxx:26
AtBaseEvent::GetTimestamps
const std::vector< ULong64_t > & GetTimestamps() const
Definition: AtBaseEvent.h:69
AtRunAna.h
AtLinkDAQTask.h
AtLinkDAQTask::Exec
virtual void Exec(Option_t *opt) override
Definition: AtLinkDAQTask.cxx:178
AtBaseEvent
Base class for all event types in ATTPCROOT.
Definition: AtBaseEvent.h:20
AtLinkDAQTask::AddInputTree
bool AddInputTree(TString fileName)
Definition: AtLinkDAQTask.cxx:40