10 #include <top/modules/TOPDoublePulseGenerator/TOPDoublePulseGeneratorModule.h>
11 #include <top/geometry/TOPGeometryPar.h>
14 #include <framework/datastore/StoreArray.h>
15 #include <framework/datastore/StoreObjPtr.h>
18 #include <framework/logging/Logger.h>
21 #include <framework/dataobjects/EventMetaData.h>
22 #include <top/dataobjects/TOPDigit.h>
54 setDescription(
"Generator of calibration double pulses");
55 setPropertyFlags(c_ParallelProcessingCertified);
58 addParam(
"moduleIDs", m_moduleIDs,
59 "list of slots for which to generate cal pulse, empty list means all slots.",
61 m_asicChannels.push_back(0);
62 addParam(
"asicChannels", m_asicChannels,
63 "ASIC calibration channels (0 - 7), empty list means all channels.",
65 addParam(
"timeDifference", m_timeDifference,
66 "time difference between first and second pulse [ns].", 21.87);
67 addParam(
"timeResolution", m_timeResolution,
68 "sigma of time difference [ns].", 40.0e-3);
69 addParam(
"sampleTimeIntervals", m_sampleTimeIntervals,
70 "vector of 256 sample time intervals to construct sample times. "
71 "If empty, equidistant intervals will be used.", m_sampleTimeIntervals);
72 addParam(
"useDatabase", m_useDatabase,
73 "if true, use sample times from database instead of sampleTimeIntervals.",
75 addParam(
"storageWindows", m_storageWindows,
76 "number of storage windows (old FW used 64 out of 512)", (
unsigned) 512);
77 addParam(
"outputFileName", m_outputFileName,
78 "if given, sample times will be saved as root histograms in this file",
83 TOPDoublePulseGeneratorModule::~TOPDoublePulseGeneratorModule()
85 if (m_timebase)
delete m_timebase;
88 void TOPDoublePulseGeneratorModule::initialize()
93 digits.registerInDataStore();
97 const auto* geo = TOPGeometryPar::Instance()->getGeometry();
99 if (m_moduleIDs.empty()) {
100 for (
const auto& module : geo->getModules()) {
101 m_moduleIDs.push_back(module.getModuleID());
104 for (
auto moduleID : m_moduleIDs) {
105 if (!geo->isModuleIDValid(moduleID))
106 B2ERROR(
"Invalid module ID found in input list: " << moduleID);
110 if (m_asicChannels.empty()) {
111 for (
unsigned ch = 0; ch < 8; ch++) m_asicChannels.push_back(ch);
113 for (
unsigned ch : m_asicChannels) {
115 B2ERROR(
"Invalid ASIC channel found in input list: " << ch);
121 double syncTimeBase = geo->getNominalTDC().getSyncTimeBase();
122 m_sampleTimes.setTimeAxis(syncTimeBase);
123 m_sampleDivisions = (0x1 << geo->getNominalTDC().getSubBits());
127 }
else if (m_sampleTimeIntervals.empty()) {
128 B2INFO(
"TOPDoublePulseGenerator: using equidistant sample times");
129 }
else if (m_sampleTimeIntervals.size() == 256) {
130 std::vector<double> timeAxis;
131 timeAxis.push_back(0);
132 for (
auto dt : m_sampleTimeIntervals) timeAxis.push_back(dt + timeAxis.back());
133 double rescale = 2 * syncTimeBase / timeAxis.back();
134 for (
auto& t : timeAxis) t *= rescale;
135 m_sampleTimes.setTimeAxis(timeAxis, syncTimeBase);
136 B2INFO(
"TOPDoublePulseGenerator: using sample times from steering");
138 B2ERROR(
"sampleTimeIntervals: size must be 256 or empty");
141 if (!m_outputFileName.empty()) storeSampleTimes(m_outputFileName);
146 void TOPDoublePulseGeneratorModule::beginRun()
150 if (!(*m_timebase).isValid()) {
151 B2FATAL(
"Sample time calibration requested but not available for run "
152 << evtMetaData->getRun()
153 <<
" of experiment " << evtMetaData->getExperiment());
160 void TOPDoublePulseGeneratorModule::event()
165 const auto& chMapper = TOPGeometryPar::Instance()->getChannelMapper();
166 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
168 double timeError = m_timeResolution / sqrt(2.0);
170 for (
auto moduleID : m_moduleIDs) {
171 for (
unsigned asic = 0; asic < 64; asic++) {
174 auto pixelID = chMapper.getPixelID(channel);
179 unsigned scrodID = 0;
181 const auto* feMap = feMapper.getMap(moduleID, bs);
183 sampleTimes = (*m_timebase)->getSampleTimes(scrodID, channel % 128);
185 B2WARNING(
"No sample time calibration available for SCROD " << scrodID
186 <<
" channel " << channel % 128 <<
" - equidistant will be used");
191 double time = gRandom->Rndm() * sampleTimes->
getTimeRange();
192 unsigned window = gRandom->Rndm() * m_storageWindows;
193 double sample = sampleTimes->
getSample(window, time);
194 auto* digit = digits.appendNew(moduleID, pixelID, sample);
195 digit->setFirstWindow(window);
196 digit->setTime(time);
197 digit->setTimeError(timeError);
198 digit->setChannel(channel);
199 digit->setHitQuality(TOPDigit::c_CalPulse);
202 time += gRandom->Gaus(m_timeDifference, m_timeResolution);
203 sample = sampleTimes->
getSample(window, time);
204 digit = digits.appendNew(moduleID, pixelID, sample);
205 digit->setFirstWindow(window);
206 digit->setTime(time);
207 digit->setTimeError(timeError);
208 digit->setChannel(channel);
209 digit->setHitQuality(TOPDigit::c_CalPulse);
217 void TOPDoublePulseGeneratorModule::endRun()
221 void TOPDoublePulseGeneratorModule::terminate()
226 void TOPDoublePulseGeneratorModule::storeSampleTimes(std::string fileName)
228 if (fileName.empty())
return;
230 TFile* fout = TFile::Open(fileName.c_str(),
"recreate");
232 B2ERROR(
"Can't open the output file " << fileName);
236 const auto& feMapper = TOPGeometryPar::Instance()->getFrontEndMapper();
238 TH1F scrods(
"scrodID",
"scrod ID's mapped to slots/boardstacks", 64, -0.5, 63.5);
239 scrods.SetXTitle(
"(slot - 1) * 4 + boardstack");
240 scrods.SetYTitle(
"scrod ID");
242 for (
auto moduleID : m_moduleIDs) {
243 for (
int bs = 0; bs < 4; bs++) {
244 const auto* feMap = feMapper.getMap(moduleID, bs);
246 B2ERROR(
"No front-end mapping available for slot " << moduleID
247 <<
" boardstack " << bs);
250 unsigned scrodID = feMap->getScrodID();
251 std::string subdir =
"scrod" + std::to_string(scrodID);
252 int i = (moduleID - 1) * 4 + bs;
253 scrods.SetBinContent(i + 1, scrodID);
254 fout->mkdir(subdir.c_str());
259 for (
auto moduleID : m_moduleIDs) {
260 for (
unsigned asic = 0; asic < 64; asic++) {
262 const auto* feMap = feMapper.getMap(moduleID, bs);
263 if (!feMap)
continue;
264 unsigned scrodID = feMap->getScrodID();
265 std::string subdir =
"scrod" + std::to_string(scrodID);
266 fout->cd(subdir.c_str());
271 sampleTimes = (*m_timebase)->getSampleTimes(scrodID, channel);
273 string forWhat =
"scrod " + to_string(scrodID) +
274 " channel " + to_string(channel) +
275 " (slot" + to_string(moduleID) +
", as" + to_string(asic) +
278 saveAsHistogram(timeAxis,
"sampleTimes_ch" + to_string(channel),
279 "Generator input: sample times for " + forWhat,
280 "sample number",
"t [ns]");
281 std::vector<double> dt;
282 for (
unsigned i = 1; i < timeAxis.size(); i++) {
283 dt.push_back(timeAxis[i] - timeAxis[i - 1]);
285 saveAsHistogram(dt,
"dt_ch" + to_string(channel),
286 "Generator input: sample time bins for " + forWhat,
287 "sample number",
"#Delta t [ns]");
297 void TOPDoublePulseGeneratorModule::saveAsHistogram(
const std::vector<double>& vec,
298 const std::string& name,
299 const std::string& title,
300 const std::string& xTitle,
301 const std::string& yTitle)
const
303 if (vec.empty())
return;
305 TH1F h(name.c_str(), title.c_str(), vec.size(), 0, vec.size());
306 h.SetXTitle(xTitle.c_str());
307 h.SetYTitle(yTitle.c_str());
308 if (name.find(
"Fit") != string::npos) h.SetLineColor(2);
310 for (
unsigned i = 0; i < vec.size(); i++) h.SetBinContent(i + 1, vec[i]);
Class for accessing objects in the database.
Accessor to arrays stored in the data store.
Type-safe access to single objects in the data store.
Generator of double calibration pulses Output to TOPDigits.
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)
unsigned getScrodID() const
Returns scrod ID.
bool isCalibrated() const
Returns calibration status.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
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.
record to be used to store ASIC info