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