Belle II Software  release-05-02-19
TOPInterimFENtupleModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2017 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Maeda Yosuke *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <top/modules/TOPInterimFENtuple/TOPInterimFENtupleModule.h>
12 
13 #include <framework/datastore/StoreObjPtr.h>
14 #include <framework/datastore/StoreArray.h>
15 
16 #include <framework/dataobjects/EventMetaData.h>
17 #include <top/dataobjects/TOPDigit.h>
18 #include <top/dataobjects/TOPRawDigit.h>
19 #include <top/dataobjects/TOPRawWaveform.h>
20 #include <top/dataobjects/TOPInterimFEInfo.h>
21 #include <top/dataobjects/TOPProductionEventDebug.h>
22 #include <rawdata/dataobjects/RawTOP.h>
23 
24 #include <iostream>
25 #include <sstream>
26 
27 #include <set>
28 #include <map>
29 #include <TMath.h>
30 
31 using namespace std;
32 
33 namespace Belle2 {
39  REG_MODULE(TOPInterimFENtuple)
40 
41 
43  {
44  setDescription("Create ntuple mainly from TOPDigit with double pulse identification. "
45  "Data taken with both InterimFE FW and production FW are available. (since Jan, 2017)");
46 
47  addParam("calibrationChannel", m_calibrationChannel, "asic channel # where calibration pulses routed",
48  (unsigned)0);
49  addParam("saveWaveform", m_saveWaveform, "whether to save waveform data or not",
50  (bool)false);
51  addParam("useDoublePulse", m_useDoublePulse,
52  "set true when you require both of double calibration pulses for reference timing. You need to enable offline feature extraction.",
53  (bool)true);
54  // addParam("averageSamplingRate", m_averageSamplingRate, "sampling rate with assumption of uniform interval in a unit of GHz",
55  // (float)2.71394);
56  addParam("minHeightFirstCalPulse", m_calibrationPulseThreshold1, "pulse height threshold for the first cal. pulse",
57  (float)600.);
58  addParam("minHeightSecondCalPulse", m_calibrationPulseThreshold2, "pulse height threshold for the second cal. pulse",
59  (float)450.);
60  addParam("nominalDeltaT", m_calibrationPulseInterval, "nominal DeltaT (time interval of the double calibration pulses) [ns]",
61  (float)21.85);
62  addParam("nominalDeltaTRange", m_calibrationPulseIntervalRange,
63  "acceptable DeltaT shift from the noinal value before calibration [ns]",
64  (float)2.);
65  addParam("globalRefSlotNum", m_globalRefSlotNum,
66  "slot number where a global reference asic exists. slot01-asic0 (pixelId=1-8) is default.", 1);
67  addParam("globalRefAsicNum", m_globalRefAsicNum,
68  "asic number defined as int((pixelId-1)/8) of a global reference asic", 0);
69 
70  addParam("timePerWin", m_timePerWin, "time interval of a single window (=64 samples) [ns]", (float)23.581939);
71  }
72 
73  TOPInterimFENtupleModule::~TOPInterimFENtupleModule() {}
74 
75  void TOPInterimFENtupleModule::initialize()
76  {
77  REG_HISTOGRAM;
78 
79  StoreArray<RawTOP> rawTOPs;
80  rawTOPs.isRequired();
81  StoreArray<TOPRawDigit> rawDigits;
82  rawDigits.isRequired();
83  StoreArray<TOPDigit> digits;
84  digits.isRequired();
86  infos.isRequired();
88  prodDebugs.isRequired();
90  waveforms.isRequired();
91  }
92 
93  void TOPInterimFENtupleModule::defineHisto()
94  {
95 
96  m_tree = new TTree("tree", "TTree for generator output");
97 
98  std::ostringstream nModuleStr;
99  nModuleStr << "[" << c_NModule << "]";
100 
101  m_tree->Branch("nHit", &m_nHit, "nHit/I");
102  m_tree->Branch("eventNum", &m_eventNum, "eventNum/i");
103  m_tree->Branch("eventNumCopper", m_eventNumCopper,
104  std::string(std::string("eventNumCopper") + nModuleStr.str() + "/i").c_str());
105  m_tree->Branch("ttuTime", m_ttuTime,
106  std::string(std::string("ttuTime") + nModuleStr.str() + "/i").c_str());
107  m_tree->Branch("ttcTime", m_ttcTime,
108  std::string(std::string("ttcTime") + nModuleStr.str() + "/i").c_str());
109  m_tree->Branch("slotNum", m_slotNum, "slotNum[nHit]/S");
110  m_tree->Branch("pixelId", m_pixelId, "pixelId[nHit]/S");
111  m_tree->Branch("channelId", m_channelId, "channel[nHit]/S");
112  m_tree->Branch("isCalCh", m_isCalCh, "isCalCh[nHit]/O");
113  m_tree->Branch("winNum", m_winNum, "winNum[nHit]/S");
114  m_tree->Branch("eventWinNum", m_eventWinNum, "eventWinNum[nHit]/S");
115  m_tree->Branch("trigWinNum", m_trigWinNum, "trigWinNum[nHit]/S");
116  m_tree->Branch("revo9Counter", m_revo9Counter, "revo9Counter[nHit]/S");
117  m_tree->Branch("windowsInOrder", m_windowsInOrder, "windowsInOrder[nHit]/O");
118  m_tree->Branch("hitQuality", m_hitQuality, "hitQuality[nHit]/b");
119  m_tree->Branch("time", m_time, "time[nHit]/F");
120  m_tree->Branch("rawTime", m_rawTime, "rawTime[nHit]/F");
121  m_tree->Branch("refTime", m_refTime, "refTime[nHit]/F");
122  m_tree->Branch("globalRefTime", &m_globalRefTime, "globalRefTime/F");
123  m_tree->Branch("sample", m_sample, "sample[nHit]/s");
124  m_tree->Branch("height", m_height, "height[nHit]/F");
125  m_tree->Branch("integral", m_integral, "integral[nHit]/F");
126  m_tree->Branch("width", m_width, "width[nHit]/F");
127  m_tree->Branch("peakSample", m_peakSample, "peakSampe[nHit]/s");
128  m_tree->Branch("offlineFlag", m_offlineFlag, "offlineFlag[nHit]/B");
129  m_tree->Branch("nHitOfflineFE", m_nHitOfflineFE, "nHitOfflineFE[nHit]/S");
130  std::ostringstream brstr[2];
131  brstr[0] << "winNumList[nHit][" << c_NWindow << "]/S";
132  m_tree->Branch("winNumList", m_winNumList, brstr[0].str().c_str());
133  if (m_saveWaveform) {
134  brstr[1] << "waveform[nHit][" << c_NWaveformSample << "]/S";
135  m_tree->Branch("waveform", m_waveform, brstr[1].str().c_str());
136  }
137  m_tree->Branch("waveformStartSample", m_waveformStartSample, "waveformStartSample[nHit]/S");
138  m_tree->Branch("nWaveformSample", m_nWaveformSample, "nWaveformSample[nHit]/s");
139 
140  m_tree->Branch("nFEHeader", &m_nFEHeader, "nFEHeader/S");
141  m_tree->Branch("nEmptyFEHeader", &m_nEmptyFEHeader, "nEmptyFEHeader/S");
142  m_tree->Branch("nWaveform", &m_nWaveform, "nWaveform/S");
143  m_tree->Branch("errorFlag", &m_errorFlag, "errorFlag/i");
144  m_tree->Branch("eventErrorFlag", &m_eventErrorFlag, "eventErrorFlag/i");
145 
146  m_tree->Branch("nDebugInfo", &m_nDebugInfo, "nDebugInfo/I");
147  m_tree->Branch("scordCtime", m_scrodCtime, "scrodCtime[nDebugInfo]/s");
148  m_tree->Branch("phase", m_phase, "phase[nDebugInfo]/s");
149  m_tree->Branch("asicMask", m_asicMask, "asicMask[nDebugInfo]/s");
150  m_tree->Branch("eventQueuDepth", m_eventQueuDepth, "eventQueuDepth[nDebugInfo]/s");
151  m_tree->Branch("eventNumberByte", m_eventNumberByte, "eventNumberByte[nDebugInfo]/s");
152  }
153 
154  void TOPInterimFENtupleModule::beginRun()
155  {
156  }
157 
158  void TOPInterimFENtupleModule::event()
159  {
160 
161  m_nHit = 0;
162  m_nFEHeader = 0;
163  m_nEmptyFEHeader = 0;
164  m_nWaveform = 0;
165  m_errorFlag = 0;
166 
167  StoreObjPtr<EventMetaData> EventMetaDataPtr;
168  StoreArray<RawTOP> rawTOPs;
169  StoreArray<TOPDigit> digits;
170 
171  for (int iSlot = 0 ; iSlot < c_NModule ; iSlot++) {
172  m_eventNumCopper[iSlot] = -1;
173  m_ttuTime[iSlot] = -1;
174  m_ttcTime[iSlot] = -1;
175  }
176  int iSlotTTC = 0;
177  short trigCtime = -1;
178  for (auto& rawTOP : rawTOPs) {
179  if (iSlotTTC >= c_NModule) {
180  B2WARNING("too many TTC information");
181  break;
182  }
183  m_eventNumCopper[iSlotTTC] = rawTOP.GetEveNo(0);
184  m_ttuTime[iSlotTTC] = rawTOP.GetTTUtime(0);
185  m_ttcTime[iSlotTTC] = rawTOP.GetTTCtime(0);
186 
187  if (trigCtime < 0)
188  trigCtime = ((((long)m_ttcTime[iSlotTTC] + (long)(m_ttuTime[iSlotTTC] - 1524741300) * 127216000) % 11520) % 3840) % 1284;
189  iSlotTTC++;
190  }
191 
192  std::map<short, short> nHitOfflineFEMap;
193  static std::set<short> noisyChannelBlackListSet;
194  UInt_t EventNum = EventMetaDataPtr->getEvent();
195  m_eventNum = EventNum;
196  m_eventErrorFlag = EventMetaDataPtr->getErrorFlag();
197  for (const auto& digit : digits) {
198 
199  if (m_nHit >= c_NMaxHitEvent) {
200  B2WARNING("TOPInterimFENtuple : too many hits found (>=" << c_NMaxHitEvent
201  << "), EventNo = " << EventNum << ", no more hits are recorded.");
202  break;
203  }
204 
205  m_slotNum[m_nHit] = digit.getModuleID();
206  m_pixelId[m_nHit] = (short)digit.getPixelID();
207  m_channelId[m_nHit] = (short)digit.getChannel();
208  m_isCalCh[m_nHit] = (digit.getASICChannel() == m_calibrationChannel);
209  m_winNum[m_nHit] = -1;
210  m_eventWinNum[m_nHit] = (short)digit.getFirstWindow();
211  m_trigWinNum[m_nHit] = trigCtime;
212  m_revo9Counter[m_nHit] = -1;
213  m_hitQuality[m_nHit] = (unsigned char)digit.getHitQuality();
214  m_isReallyJunk[m_nHit] = false;
215  m_windowsInOrder[m_nHit] = true;
216  m_rawTime[m_nHit] = digit.getRawTime();
217  m_time[m_nHit] = digit.getTime() + m_winNum[m_nHit] * m_timePerWin;
218  m_sample[m_nHit] = TMath::FloorNint(m_rawTime[m_nHit] + m_winNum[m_nHit] * c_NSamplePerWindow) % c_NSampleTBC;
219  m_height[m_nHit] = digit.getPulseHeight();
220  m_integral[m_nHit] = digit.getIntegral();
221  m_width[m_nHit] = digit.getPulseWidth();
222  m_peakSample[m_nHit] = -1;
223  for (int iWindow = 0 ; iWindow < c_NWindow ; iWindow++)
224  m_winNumList[m_nHit][iWindow] = -32767;
225  for (int iSample = 0 ; iSample < c_NWaveformSample ; iSample++)
226  m_waveform[m_nHit][iSample] = -32767;
227  m_waveformStartSample[m_nHit] = -1;
228 
229  short globalChannelId = m_pixelId[m_nHit] - 1 + (m_slotNum[m_nHit] - 1) * c_NPixelPerModule;
230  if (nHitOfflineFEMap.count(globalChannelId) == 0) nHitOfflineFEMap[globalChannelId] = 0;
231  else if (nHitOfflineFEMap[globalChannelId] > c_NMaxHitPerChannel) {
232  if (noisyChannelBlackListSet.count(globalChannelId) == 0) { // cppcheck-suppress stlFindInsert
233  noisyChannelBlackListSet.insert(globalChannelId);
234  B2WARNING("TOPInterimFENtuple : noisy channel with too many hits (slotNum="
235  << (globalChannelId / c_NPixelPerModule + 1) << ", pixelId = "
236  << (globalChannelId / c_NPixelPerModule + 1) << ") ");
237  }
238  continue;
239  }
240 
241  const auto* rawDigit = digit.getRelated<TOPRawDigit>();
242  if (rawDigit) {
243  m_winNum[m_nHit] = rawDigit->getASICWindow();
244  m_revo9Counter[m_nHit] = rawDigit->getRevo9Counter();
245  m_peakSample[m_nHit] = rawDigit->getSamplePeak();
246  m_windowsInOrder[m_nHit] = rawDigit->areWindowsInOrder();
247  if (rawDigit->getDataType() == TOPRawDigit::c_Interim)
248  m_trigWinNum[m_nHit] = (short)rawDigit->getLastWriteAddr();
249  if (rawDigit->isPedestalJump()) m_isReallyJunk[m_nHit] = true;
250  const auto* waveform = rawDigit->getRelated<TOPRawWaveform>();
251  if (waveform) {
252  if (rawDigit->isMadeOffline()) {
253 
254  //fill hit flags ; =1 : first hit from offline FE, =2 : second ... , =0 : online FE, -1 : no waveform
255  nHitOfflineFEMap[globalChannelId]++;
256  m_offlineFlag[m_nHit] = nHitOfflineFEMap[globalChannelId];
257  } else { //hit from online feature extraction
258  m_offlineFlag[m_nHit] = 0;
259 
260  //store waveform data
261  unsigned nSampleWfm = waveform->getSize();
262  unsigned nSample = TMath::Min((UShort_t)nSampleWfm, (UShort_t)c_NWaveformSample);
263  if (nSample > c_NWaveformSample)
264  B2WARNING("TOPInterimFENtuple: too many waveform samples in TOPRawWaveform : " << nSampleWfm << ", only first " << nSample <<
265  " are considered.");
266  for (unsigned iSample = 0 ; iSample < nSample ; iSample++)
267  m_waveform[m_nHit][iSample] = waveform->getWaveform()[iSample];
268  m_waveformStartSample[m_nHit] = (short)waveform->getStartSample();
269  m_nWaveformSample[m_nHit] = nSampleWfm;
270  //store window number
271  int iWin = 0;
272  for (const auto& window : waveform->getStorageWindows()) {
273  if (iWin < c_NWindow)
274  m_winNumList[m_nHit][iWin] = window;
275  else
276  B2WARNING("TOPInterimFENtuple: too many windows were found");
277 
278  iWin++;
279  }
280 
281  }
282  }//if( waveform )
283  else m_offlineFlag[m_nHit] = -1;
284  } else {
285  B2WARNING("TOPInterimFENtuple : no TOPRawDigit object found!");
286  m_offlineFlag[m_nHit] = -100;
287  }//if( rawDigit )
288 
289 
290  m_nHit++;
291  }//for( const auto& digit : digits )
292 
293  for (int iHit = 0 ; iHit < m_nHit ; iHit++) {
294 
295  short globalChannelId = m_pixelId[iHit] - 1 + (m_slotNum[iHit] - 1) * c_NPixelPerModule;
296  m_nHitOfflineFE[iHit] = nHitOfflineFEMap[globalChannelId];
297 
298  }//for(int iHit)
299 
301  for (const auto& info : infos) {
302  m_nFEHeader += info.getFEHeadersCount();
303  m_nEmptyFEHeader += info.getEmptyFEHeadersCount();
304  m_nWaveform += info.getWaveformsCount();
305  m_errorFlag |= info.getErrorFlags();
306  }
307 
309  m_nDebugInfo = 0;
310  for (const auto& prodDebug : prodDebugs) {
311  m_scrodCtime[m_nDebugInfo] = prodDebug.getCtime();
312  m_phase[m_nDebugInfo] = prodDebug.getPhase();
313  m_asicMask[m_nDebugInfo] = prodDebug.getAsicMask();
314  m_eventQueuDepth[m_nDebugInfo] = prodDebug.getEventQueueDepth();
315  m_eventNumberByte[m_nDebugInfo] = prodDebug.getEventNumberByte();
316  m_nDebugInfo++;
317  }
318 
319  //identify cal. pulse timing
320  getReferenceTiming();
321 
322  m_tree->Fill();
323  }
324 
325  void TOPInterimFENtupleModule::endRun()
326  {
327  }
328 
329  void TOPInterimFENtupleModule::terminate()
330  {
331  }
332 
333  void TOPInterimFENtupleModule::getReferenceTiming()
334  {
335  static short globalRefAsic = m_globalRefAsicNum + 100 * m_globalRefSlotNum;
336  m_globalRefTime = -99999;
337  std::map<short, short> iRefHitMap;
338  for (int iHit = 0 ; iHit < m_nHit ; iHit++) {
339  if (!m_isCalCh[iHit]) continue;
340  short reducedPixelId = (m_pixelId[iHit] - 1) / 8 + 100 * m_slotNum[iHit];
341  if (iRefHitMap.count(reducedPixelId) > 0) continue;
342 
343  if (!m_useDoublePulse) {
344  iRefHitMap[reducedPixelId] = iHit;
345  continue;
346  }
347 
348  std::vector<short> iHitVec;
349  iHitVec.push_back(iHit);
350  for (int jHit = iHit + 1 ; jHit < m_nHit ; jHit++) {
351  short jReducedPixelId = (m_pixelId[jHit] - 1) / 8 + 100 * m_slotNum[jHit];
352  if (m_isCalCh[jHit] && jReducedPixelId == reducedPixelId) iHitVec.push_back(jHit);
353  }
354 
355  int nCands = 0;
356  for (unsigned int iVec = 0 ; iVec < iHitVec.size() ; iVec++) {
357  int jHit = iHitVec[iVec];
358  for (unsigned int jVec = iVec + 1 ; jVec < iHitVec.size() ; jVec++) {
359  int kHit = iHitVec[jVec];
360  float timediff = m_time[kHit] - m_time[jHit];
361  if (m_height[jHit] > m_calibrationPulseThreshold1
362  && m_height[kHit] > m_calibrationPulseThreshold2
363  && TMath::Abs(timediff - m_calibrationPulseInterval) < m_calibrationPulseIntervalRange) {
364  if (nCands == 0) {
365  iRefHitMap[reducedPixelId] = jHit;
366  m_hitQuality[jHit] += 100;
367  m_hitQuality[kHit] += 200;
368  }
369  nCands++;
370  }
371  //in case jHit and kHit are not in time order (added at 28th Nov)
372  else if (timediff < 0 && m_height[kHit] > m_calibrationPulseThreshold1
373  && m_height[jHit] > m_calibrationPulseThreshold2
374  && TMath::Abs(timediff + m_calibrationPulseInterval) < m_calibrationPulseIntervalRange) {
375  if (nCands == 0) {
376  iRefHitMap[reducedPixelId] = kHit;
377  m_hitQuality[kHit] += 100;
378  m_hitQuality[jHit] += 200;
379  }
380  nCands++;
381  }//satisfy selection criteria for calibration signal
382  }
383  }//iVec (finish selecting a calibration signal candidate)
384  }
385 
386 
387  //loop all hits again to fill the array "refTime"
388  for (int iHit = 0 ; iHit < m_nHit ; iHit++) {
389  short reducedPixelId = (m_pixelId[iHit] - 1) / 8 + 100 * m_slotNum[iHit];
390  if (iRefHitMap.count(reducedPixelId) > 0) {
391  int iRef = iRefHitMap[reducedPixelId];
392  m_refTime[iHit] = m_time[iRef];
393  if (reducedPixelId == globalRefAsic) m_globalRefTime = m_time[iRef];
394  if (!m_isReallyJunk[iHit] && m_hitQuality[iRef] >= 100) {
395  m_hitQuality[iHit] += 10;
396  }
397  } else m_refTime[iHit] = -99999;
398  }
399 
400  return;
401  }
402 
404 } // end Belle2 namespace
405 
Belle2::TOPInterimFENtupleModule
Module to produce ntuple from TOPDigits and TOPRawDigits.
Definition: TOPInterimFENtupleModule.h:37
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::TOPRawWaveform
Class to store raw data waveforms.
Definition: TOPRawWaveform.h:34
Belle2::TOPRawDigit
Class to store unpacked raw data (hits in feature-extraction format) It provides also calculation of ...
Definition: TOPRawDigit.h:34
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
Belle2::StoreArray
Accessor to arrays stored in the data store.
Definition: ECLMatchingPerformanceExpertModule.h:33
Belle2::TOPRawDigit::getASICWindow
unsigned getASICWindow() const
Returns ASIC storage window number.
Definition: TOPRawDigit.h:253
Belle2::HistoModule
HistoModule.h is supposed to be used instead of Module.h for the modules with histogram definitions t...
Definition: HistoModule.h:29