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 {
39
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 // Output
88
90 digits.registerInDataStore();
91
92 // prepare vectors to loop on
93
94 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
95
96 if (m_moduleIDs.empty()) {
97 for (const auto& module : geo->getModules()) {
98 m_moduleIDs.push_back(module.getModuleID());
99 }
100 } else {
101 for (auto moduleID : m_moduleIDs) {
102 if (!geo->isModuleIDValid(moduleID))
103 B2ERROR("Invalid module ID found in input list: " << moduleID);
104 }
105 }
106
107 if (m_asicChannels.empty()) {
108 for (unsigned ch = 0; ch < 8; ch++) m_asicChannels.push_back(ch);
109 } else {
110 for (unsigned ch : m_asicChannels) {
111 if (ch > 7)
112 B2ERROR("Invalid ASIC channel found in input list: " << ch);
113 }
114 }
115
116 // set sample times
117
118 double syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
119 m_sampleTimes.setTimeAxis(syncTimeBase); // equidistant
120 m_sampleDivisions = (0x1 << geo->getNominalTDC().getSubBits());
121
122 if (m_useDatabase) {
123 B2INFO("TOPDoublePulseGenerator: using sample times from database");
124 } else if (m_sampleTimeIntervals.empty()) {
125 B2INFO("TOPDoublePulseGenerator: using equidistant sample times");
126 } else if (m_sampleTimeIntervals.size() == 256) {
127 std::vector<double> timeAxis;
128 timeAxis.push_back(0);
129 for (auto dt : m_sampleTimeIntervals) timeAxis.push_back(dt + timeAxis.back());
130 double rescale = 2 * syncTimeBase / timeAxis.back();
131 for (auto& t : timeAxis) t *= rescale;
132 m_sampleTimes.setTimeAxis(timeAxis, syncTimeBase); // given by steering
133 B2INFO("TOPDoublePulseGenerator: using sample times from steering");
134 } else {
135 B2ERROR("sampleTimeIntervals: size must be 256 or empty");
136 }
137
139
140 }
141
142
144 {
145 StoreObjPtr<EventMetaData> evtMetaData;
146 if (m_useDatabase) {
147 if (!m_timebase.isValid()) {
148 B2FATAL("Sample time calibration requested but not available for run "
149 << evtMetaData->getRun()
150 << " of experiment " << evtMetaData->getExperiment());
151 }
152 }
153
154 }
155
156
158 {
159
161
162 const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
163 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
164
165 double timeError = m_timeResolution / sqrt(2.0); // for single pulse
166
167 for (auto moduleID : m_moduleIDs) {
168 for (unsigned asic = 0; asic < 64; asic++) {
169 for (auto asicChannel : m_asicChannels) {
170 unsigned channel = asic * 8 + asicChannel;
171 auto pixelID = chMapper.getPixelID(channel);
172
173 // sample times: from steering or database
174 const TOPSampleTimes* sampleTimes = &m_sampleTimes;
175 if (m_useDatabase) {
176 unsigned scrodID = 0;
177 int bs = asic / 16;
178 const auto* feMap = feMapper.getMap(moduleID, bs);
179 if (feMap) scrodID = feMap->getScrodID();
180 sampleTimes = m_timebase->getSampleTimes(scrodID, channel % 128);
181 if (!sampleTimes->isCalibrated()) {
182 B2WARNING("No sample time calibration available for SCROD " << scrodID
183 << " channel " << channel % 128 << " - equidistant will be used");
184 }
185 }
186
187 // first calpulse
188 double time = gRandom->Rndm() * sampleTimes->getTimeRange();
189 unsigned window = gRandom->Rndm() * m_storageWindows;
190 double sample = sampleTimes->getSample(window, time);
191 auto* digit = digits.appendNew(moduleID, pixelID, sample);
192 digit->setFirstWindow(window);
193 digit->setTime(time);
194 digit->setTimeError(timeError);
195 digit->setChannel(channel);
196 digit->setHitQuality(TOPDigit::c_CalPulse);
197
198 // second calpulse
199 time += gRandom->Gaus(m_timeDifference, m_timeResolution);
200 sample = sampleTimes->getSample(window, time);
201 digit = digits.appendNew(moduleID, pixelID, sample);
202 digit->setFirstWindow(window);
203 digit->setTime(time);
204 digit->setTimeError(timeError);
205 digit->setChannel(channel);
206 digit->setHitQuality(TOPDigit::c_CalPulse);
207 }
208 }
209 }
210
211 }
212
213
214 void TOPDoublePulseGeneratorModule::storeSampleTimes(const std::string& fileName)
215 {
216 if (fileName.empty()) return;
217
218 TFile* fout = TFile::Open(fileName.c_str(), "recreate");
219 if (!fout) {
220 B2ERROR("Can't open the output file " << fileName);
221 return;
222 }
223
224 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
225
226 TH1F scrods("scrodID", "scrod ID's mapped to slots/boardstacks", 64, -0.5, 63.5);
227 scrods.SetXTitle("(slot - 1) * 4 + boardstack");
228 scrods.SetYTitle("scrod ID");
229
230 for (auto moduleID : m_moduleIDs) {
231 for (int bs = 0; bs < 4; bs++) {
232 const auto* feMap = feMapper.getMap(moduleID, bs);
233 if (!feMap) {
234 B2ERROR("No front-end mapping available for slot " << moduleID
235 << " boardstack " << bs);
236 continue;
237 }
238 unsigned scrodID = feMap->getScrodID();
239 std::string subdir = "scrod" + std::to_string(scrodID);
240 int i = (moduleID - 1) * 4 + bs;
241 scrods.SetBinContent(i + 1, scrodID);
242 fout->mkdir(subdir.c_str());
243 }
244 }
245 scrods.Write();
246
247 for (auto moduleID : m_moduleIDs) {
248 for (unsigned asic = 0; asic < 64; asic++) {
249 int bs = asic / 16;
250 const auto* feMap = feMapper.getMap(moduleID, bs);
251 if (!feMap) continue;
252 unsigned scrodID = feMap->getScrodID();
253 std::string subdir = "scrod" + std::to_string(scrodID);
254 fout->cd(subdir.c_str());
255 for (auto asicChannel : m_asicChannels) {
256 unsigned channel = (asic * 8 + asicChannel) % 128;
257 const TOPSampleTimes* sampleTimes = &m_sampleTimes;
258 if (m_useDatabase) {
259 sampleTimes = m_timebase->getSampleTimes(scrodID, channel);
260 }
261 string forWhat = "scrod " + to_string(scrodID) +
262 " channel " + to_string(channel) +
263 " (slot" + to_string(moduleID) + ", as" + to_string(asic) +
264 ", ch" + to_string(asicChannel) + ")";
265 auto timeAxis = sampleTimes->getTimeAxis();
266 saveAsHistogram(timeAxis, "sampleTimes_ch" + to_string(channel),
267 "Generator input: sample times for " + forWhat,
268 "sample number", "t [ns]");
269 std::vector<double> dt;
270 for (unsigned i = 1; i < timeAxis.size(); i++) {
271 dt.push_back(timeAxis[i] - timeAxis[i - 1]);
272 }
273 saveAsHistogram(dt, "dt_ch" + to_string(channel),
274 "Generator input: sample time bins for " + forWhat,
275 "sample number", "#Delta t [ns]");
276 }
277 }
278 }
279
280 fout->Close();
281
282 }
283
284
285 void TOPDoublePulseGeneratorModule::saveAsHistogram(const std::vector<double>& vec,
286 const std::string& name,
287 const std::string& title,
288 const std::string& xTitle,
289 const std::string& yTitle)
290 {
291 if (vec.empty()) return;
292
293 TH1F h(name.c_str(), title.c_str(), vec.size(), 0, vec.size());
294 h.SetXTitle(xTitle.c_str());
295 h.SetYTitle(yTitle.c_str());
296 if (name.find("Fit") != string::npos) h.SetLineColor(2);
297
298 for (unsigned i = 0; i < vec.size(); i++) h.SetBinContent(i + 1, vec[i]);
299
300 h.Write();
301 }
302
304} // end Belle2 namespace
305
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
Module()
Constructor.
Definition Module.cc:30
@ 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.
DBObjPtr< TOPCalTimebase > m_timebase
sample times from database
std::vector< double > m_sampleTimeIntervals
sample time intervals
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
const TOPNominalTDC & getNominalTDC() const
Returns nominal time-to-digit conversion parameters.
double getSyncTimeBase() const
Returns synchronization time base (time width of c_syncWindows)
Calibration constants of a single 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:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
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 beginRun() override
Called when entering a new run.
void storeSampleTimes(const std::string &fileName)
Optionally store sample times used by the generator as root histograms fileName root output file name...
static void saveAsHistogram(const std::vector< double > &vec, const std::string &name, const std::string &title, const std::string &xTitle="", const std::string &yTitle="")
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).
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