Belle II Software  release-08-01-10
TOPDoublePulseGeneratorModule.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 // Own header.
10 #include <top/modules/TOPDoublePulseGenerator/TOPDoublePulseGeneratorModule.h>
11 
12 // TOP headers.
13 #include <top/geometry/TOPGeometryPar.h>
14 
15 // framework - DataStore
16 #include <framework/datastore/StoreArray.h>
17 #include <framework/datastore/StoreObjPtr.h>
18 
19 // framework aux
20 #include <framework/logging/Logger.h>
21 
22 // datastore classes
23 #include <framework/dataobjects/EventMetaData.h>
24 #include <top/dataobjects/TOPDigit.h>
25 
26 // root
27 #include <TRandom.h>
28 #include <TFile.h>
29 #include <TH1F.h>
30 
31 
32 using namespace std;
33 
34 namespace Belle2 {
40  using namespace TOP;
41 
42  //-----------------------------------------------------------------
44  //-----------------------------------------------------------------
45 
46  REG_MODULE(TOPDoublePulseGenerator);
47 
48  //-----------------------------------------------------------------
49  // Implementation
50  //-----------------------------------------------------------------
51 
52  TOPDoublePulseGeneratorModule::TOPDoublePulseGeneratorModule() : Module()
53 
54  {
55  // set module description
56  setDescription("Generator of calibration double pulses");
58 
59  // Add parameters
60  addParam("moduleIDs", m_moduleIDs,
61  "list of slots for which to generate cal pulse, empty list means all slots.",
62  m_moduleIDs);
63  m_asicChannels.push_back(0);
64  addParam("asicChannels", m_asicChannels,
65  "ASIC calibration channels (0 - 7), empty list means all channels.",
67  addParam("timeDifference", m_timeDifference,
68  "time difference between first and second pulse [ns].", 21.87);
69  addParam("timeResolution", m_timeResolution,
70  "sigma of time difference [ns].", 40.0e-3);
71  addParam("sampleTimeIntervals", m_sampleTimeIntervals,
72  "vector of 256 sample time intervals to construct sample times. "
73  "If empty, equidistant intervals will be used.", m_sampleTimeIntervals);
74  addParam("useDatabase", m_useDatabase,
75  "if true, use sample times from database instead of sampleTimeIntervals.",
76  false);
77  addParam("storageWindows", m_storageWindows,
78  "number of storage windows (old FW used 64 out of 512)", (unsigned) 512);
79  addParam("outputFileName", m_outputFileName,
80  "if given, sample times will be saved as root histograms in this file",
81  std::string(""));
82 
83  }
84 
86  {
87  if (m_timebase) delete m_timebase;
88  }
89 
91  {
92  // Output
93 
94  StoreArray<TOPDigit> digits;
95  digits.registerInDataStore();
96 
97  // prepare vectors to loop on
98 
99  const auto* geo = TOPGeometryPar::Instance()->getGeometry();
100 
101  if (m_moduleIDs.empty()) {
102  for (const auto& module : geo->getModules()) {
103  m_moduleIDs.push_back(module.getModuleID());
104  }
105  } else {
106  for (auto moduleID : m_moduleIDs) {
107  if (!geo->isModuleIDValid(moduleID))
108  B2ERROR("Invalid module ID found in input list: " << moduleID);
109  }
110  }
111 
112  if (m_asicChannels.empty()) {
113  for (unsigned ch = 0; ch < 8; ch++) m_asicChannels.push_back(ch);
114  } else {
115  for (unsigned ch : m_asicChannels) {
116  if (ch > 7)
117  B2ERROR("Invalid ASIC channel found in input list: " << ch);
118  }
119  }
120 
121  // set sample times
122 
123  double syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
124  m_sampleTimes.setTimeAxis(syncTimeBase); // equidistant
125  m_sampleDivisions = (0x1 << geo->getNominalTDC().getSubBits());
126 
127  if (m_useDatabase) {
129  } else if (m_sampleTimeIntervals.empty()) {
130  B2INFO("TOPDoublePulseGenerator: using equidistant sample times");
131  } else if (m_sampleTimeIntervals.size() == 256) {
132  std::vector<double> timeAxis;
133  timeAxis.push_back(0);
134  for (auto dt : m_sampleTimeIntervals) timeAxis.push_back(dt + timeAxis.back());
135  double rescale = 2 * syncTimeBase / timeAxis.back();
136  for (auto& t : timeAxis) t *= rescale;
137  m_sampleTimes.setTimeAxis(timeAxis, syncTimeBase); // given by steering
138  B2INFO("TOPDoublePulseGenerator: using sample times from steering");
139  } else {
140  B2ERROR("sampleTimeIntervals: size must be 256 or empty");
141  }
142 
144 
145  }
146 
147 
149  {
150  StoreObjPtr<EventMetaData> evtMetaData;
151  if (m_useDatabase) {
152  if (!(*m_timebase).isValid()) {
153  B2FATAL("Sample time calibration requested but not available for run "
154  << evtMetaData->getRun()
155  << " of experiment " << evtMetaData->getExperiment());
156  }
157  }
158 
159  }
160 
161 
163  {
164 
165  StoreArray<TOPDigit> digits;
166 
167  const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
168  const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
169 
170  double timeError = m_timeResolution / sqrt(2.0); // for single pulse
171 
172  for (auto moduleID : m_moduleIDs) {
173  for (unsigned asic = 0; asic < 64; asic++) {
174  for (auto asicChannel : m_asicChannels) {
175  unsigned channel = asic * 8 + asicChannel;
176  auto pixelID = chMapper.getPixelID(channel);
177 
178  // sample times: from steering or database
179  const TOPSampleTimes* sampleTimes = &m_sampleTimes;
180  if (m_useDatabase) {
181  unsigned scrodID = 0;
182  int bs = asic / 16;
183  const auto* feMap = feMapper.getMap(moduleID, bs);
184  if (feMap) scrodID = feMap->getScrodID();
185  sampleTimes = (*m_timebase)->getSampleTimes(scrodID, channel % 128);
186  if (!sampleTimes->isCalibrated()) {
187  B2WARNING("No sample time calibration available for SCROD " << scrodID
188  << " channel " << channel % 128 << " - equidistant will be used");
189  }
190  }
191 
192  // first calpulse
193  double time = gRandom->Rndm() * sampleTimes->getTimeRange();
194  unsigned window = gRandom->Rndm() * m_storageWindows;
195  double sample = sampleTimes->getSample(window, time);
196  auto* digit = digits.appendNew(moduleID, pixelID, sample);
197  digit->setFirstWindow(window);
198  digit->setTime(time);
199  digit->setTimeError(timeError);
200  digit->setChannel(channel);
201  digit->setHitQuality(TOPDigit::c_CalPulse);
202 
203  // second calpulse
204  time += gRandom->Gaus(m_timeDifference, m_timeResolution);
205  sample = sampleTimes->getSample(window, time);
206  digit = digits.appendNew(moduleID, pixelID, sample);
207  digit->setFirstWindow(window);
208  digit->setTime(time);
209  digit->setTimeError(timeError);
210  digit->setChannel(channel);
211  digit->setHitQuality(TOPDigit::c_CalPulse);
212  }
213  }
214  }
215 
216  }
217 
218 
220  {
221  }
222 
224  {
225  }
226 
227 
229  {
230  if (fileName.empty()) return;
231 
232  TFile* fout = TFile::Open(fileName.c_str(), "recreate");
233  if (!fout) {
234  B2ERROR("Can't open the output file " << fileName);
235  return;
236  }
237 
238  const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
239 
240  TH1F scrods("scrodID", "scrod ID's mapped to slots/boardstacks", 64, -0.5, 63.5);
241  scrods.SetXTitle("(slot - 1) * 4 + boardstack");
242  scrods.SetYTitle("scrod ID");
243 
244  for (auto moduleID : m_moduleIDs) {
245  for (int bs = 0; bs < 4; bs++) {
246  const auto* feMap = feMapper.getMap(moduleID, bs);
247  if (!feMap) {
248  B2ERROR("No front-end mapping available for slot " << moduleID
249  << " boardstack " << bs);
250  continue;
251  }
252  unsigned scrodID = feMap->getScrodID();
253  std::string subdir = "scrod" + std::to_string(scrodID);
254  int i = (moduleID - 1) * 4 + bs;
255  scrods.SetBinContent(i + 1, scrodID);
256  fout->mkdir(subdir.c_str());
257  }
258  }
259  scrods.Write();
260 
261  for (auto moduleID : m_moduleIDs) {
262  for (unsigned asic = 0; asic < 64; asic++) {
263  int bs = asic / 16;
264  const auto* feMap = feMapper.getMap(moduleID, bs);
265  if (!feMap) continue;
266  unsigned scrodID = feMap->getScrodID();
267  std::string subdir = "scrod" + std::to_string(scrodID);
268  fout->cd(subdir.c_str());
269  for (auto asicChannel : m_asicChannels) {
270  unsigned channel = (asic * 8 + asicChannel) % 128;
271  const TOPSampleTimes* sampleTimes = &m_sampleTimes;
272  if (m_useDatabase) {
273  sampleTimes = (*m_timebase)->getSampleTimes(scrodID, channel);
274  }
275  string forWhat = "scrod " + to_string(scrodID) +
276  " channel " + to_string(channel) +
277  " (slot" + to_string(moduleID) + ", as" + to_string(asic) +
278  ", ch" + to_string(asicChannel) + ")";
279  auto timeAxis = sampleTimes->getTimeAxis();
280  saveAsHistogram(timeAxis, "sampleTimes_ch" + to_string(channel),
281  "Generator input: sample times for " + forWhat,
282  "sample number", "t [ns]");
283  std::vector<double> dt;
284  for (unsigned i = 1; i < timeAxis.size(); i++) {
285  dt.push_back(timeAxis[i] - timeAxis[i - 1]);
286  }
287  saveAsHistogram(dt, "dt_ch" + to_string(channel),
288  "Generator input: sample time bins for " + forWhat,
289  "sample number", "#Delta t [ns]");
290  }
291  }
292  }
293 
294  fout->Close();
295 
296  }
297 
298 
299  void TOPDoublePulseGeneratorModule::saveAsHistogram(const std::vector<double>& vec,
300  const std::string& name,
301  const std::string& title,
302  const std::string& xTitle,
303  const std::string& yTitle) const
304  {
305  if (vec.empty()) return;
306 
307  TH1F h(name.c_str(), title.c_str(), vec.size(), 0, vec.size());
308  h.SetXTitle(xTitle.c_str());
309  h.SetYTitle(yTitle.c_str());
310  if (name.find("Fit") != string::npos) h.SetLineColor(2);
311 
312  for (unsigned i = 0; i < vec.size(); i++) h.SetBinContent(i + 1, vec[i]);
313 
314  h.Write();
315  }
316 
318 } // end Belle2 namespace
319 
Class for accessing objects in the database.
Definition: DBObjPtr.h:21
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
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:96
double m_timeDifference
time difference between first and second pulse
std::vector< unsigned > m_asicChannels
ASIC calibration channels.
std::vector< double > m_sampleTimeIntervals
sample time intervals
DBObjPtr< TOPCalTimebase > * m_timebase
sample times from database
unsigned m_storageWindows
number of storage windows
std::vector< int > m_moduleIDs
slot ID's to generate for
bool m_useDatabase
if true, use sample times from database
int m_sampleDivisions
number of sample divisions (from NominalTDC)
std::string m_outputFileName
if given, store sample times as root histograms
TOPSampleTimes m_sampleTimes
sample times from steering input
Calibration constants of a singe ASIC channel: time axis (sample times)
double getTimeRange() const
Returns time axis range (time interval corresponding to 4 asic windows)
bool isCalibrated() const
Returns calibration status.
const TOPGeometry * getGeometry() const
Returns pointer to geometry object using basf2 units.
const FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
virtual void endRun() override
End-of-run action.
virtual void terminate() override
Termination action.
void storeSampleTimes(std::string fileName)
Optionally store sample times used by the generator as root histograms fileName root output file name...
virtual void beginRun() override
Called when entering a new run.
void saveAsHistogram(const std::vector< double > &vec, const std::string &name, const std::string &title, const std::string &xTitle="", const std::string &yTitle="") const
Save vector to histogram and write it out.
double getSample(int window, double time) const
Returns sample with respect to sample 0 of the specified ASIC window (inverse of getTime).
void setTimeAxis(double syncTimeBase)
Sets equidistant time axis (uncalibrated).
std::vector< double > getTimeAxis() const
Returns time axis (sample times)
Abstract base class for different kinds of events.
record to be used to store ASIC info