Belle II Software development
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
32using namespace std;
33
34namespace Belle2 {
40 using namespace TOP;
41
42 //-----------------------------------------------------------------
44 //-----------------------------------------------------------------
45
46 REG_MODULE(TOPDoublePulseGenerator);
47
48 //-----------------------------------------------------------------
49 // Implementation
50 //-----------------------------------------------------------------
51
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.",
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
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
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 ChannelMapper & getChannelMapper() const
Returns default channel mapper (mapping of channels to pixels)
static TOPGeometryPar * Instance()
Static method to obtain the pointer to its instance.
const FrontEndMapper & getFrontEndMapper() const
Returns front-end mapper (mapping of SCROD's to positions within TOP modules)
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.
STL namespace.
record to be used to store ASIC info