1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
#include "DQM/SiStripCommissioningSources/interface/OptoScanTask.h"
#include "DataFormats/SiStripCommon/interface/SiStripConstants.h"
#include "DataFormats/SiStripCommon/interface/SiStripHistoTitle.h"
#include "DQMServices/Core/interface/DQMStore.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include <algorithm>
#include <cmath>
#include "DataFormats/SiStripCommon/interface/SiStripFedKey.h"
#include <iomanip>
using namespace sistrip;
// -----------------------------------------------------------------------------
//
OptoScanTask::OptoScanTask(DQMStore* dqm, const FedChannelConnection& conn)
: CommissioningTask(dqm, conn, "OptoScanTask"), opto_() {}
// -----------------------------------------------------------------------------
//
OptoScanTask::~OptoScanTask() {}
// -----------------------------------------------------------------------------
//
void OptoScanTask::book() {
uint16_t nbins = 50;
uint16_t gains = 4;
// Resize "histo sets"
opto_.resize(gains);
for (uint16_t igain = 0; igain < opto_.size(); igain++) {
opto_[igain].resize(3);
}
for (uint16_t igain = 0; igain < opto_.size(); igain++) {
for (uint16_t ihisto = 0; ihisto < 3; ihisto++) {
// Extra info
std::stringstream extra_info;
extra_info << sistrip::extrainfo::gain_ << igain;
if (ihisto == 0 || ihisto == 1) {
extra_info << sistrip::extrainfo::digital_ << ihisto;
} else {
extra_info << sistrip::extrainfo::baselineRms_;
}
// Title
std::string title = SiStripHistoTitle(sistrip::EXPERT_HISTO,
sistrip::OPTO_SCAN,
sistrip::FED_KEY,
fedKey(),
sistrip::LLD_CHAN,
connection().lldChannel(),
extra_info.str())
.title();
// Book histo
opto_[igain][ihisto].histo(dqm()->bookProfile(title,
title,
nbins,
0.5,
nbins * 1. + 0.5, // range is bias setting (1-50)
1024,
-0.5,
1023.5));
opto_[igain][ihisto].vNumOfEntries_.resize(nbins, 0);
opto_[igain][ihisto].vSumOfContents_.resize(nbins, 0);
opto_[igain][ihisto].vSumOfSquares_.resize(nbins, 0);
} // end loop on histos
} // end loop on gains
}
// -----------------------------------------------------------------------------
//
void OptoScanTask::fill(const SiStripEventSummary& summary, const edm::DetSet<SiStripRawDigi>& digis) {
//@@ if scope mode length is in trigger fed, then
//@@ can add check here on number of digis
if (digis.data.empty()) {
edm::LogWarning(mlDqmSource_) << "[OptoScanTask::" << __func__ << "]"
<< " Unexpected number of digis! " << digis.data.size();
} else {
// Retrieve opt bias and gain setting from SiStripEventSummary
uint16_t gain = summary.lldGain();
uint16_t bias = summary.lldBias();
if (gain >= opto_.size()) {
opto_.resize(gain);
for (uint16_t igain = 0; igain < opto_.size(); igain++) {
if (opto_[gain].size() != 3) {
opto_[gain].resize(3);
}
}
edm::LogWarning(mlDqmSource_) << "[OptoScanTask::" << __func__ << "]"
<< " Unexpected gain value! " << gain;
}
if (bias > 50) {
return;
} // only use bias settings 1-50
// Find digital "0" and digital "1" levels from tick marks within scope mode data
std::vector<float> baseline;
std::pair<float, float> digital_range;
digital_range.first = sistrip::invalid_;
digital_range.second = sistrip::invalid_;
float baseline_rms = sistrip::invalid_;
locateTicks(digis, digital_range, baseline, baseline_rms);
uint16_t bin = bias - 1; // fill "bins" (0-49), not bias (1-50)
// Digital "0"
if (digital_range.first < 1. * sistrip::valid_) {
updateHistoSet(opto_[gain][0], bin, digital_range.first);
}
// Digital "1"
if (digital_range.second < 1. * sistrip::valid_) {
updateHistoSet(opto_[gain][1], bin, digital_range.second);
}
// Baseline rms
if (baseline_rms < 1. * sistrip::valid_) {
updateHistoSet(opto_[gain][2], bin, baseline_rms);
}
}
}
// -----------------------------------------------------------------------------
//
void OptoScanTask::update() {
for (uint16_t igain = 0; igain < opto_.size(); igain++) {
for (uint16_t ihisto = 0; ihisto < opto_[igain].size(); ihisto++) {
updateHistoSet(opto_[igain][ihisto]);
}
}
}
// -----------------------------------------------------------------------------
//
void OptoScanTask::locateTicks(const edm::DetSet<SiStripRawDigi>& digis,
std::pair<float, float>& range,
std::vector<float>& baseline,
float& baseline_rms) {
// Copy ADC values and sort
std::vector<uint16_t> adc;
adc.reserve(digis.data.size());
for (uint16_t iadc = 0; iadc < digis.data.size(); iadc++) {
// only take the adc from the first APV (multiplexing alternates the digis)
// this was asked by Karl et al
if (iadc % 2 == 0) {
adc.push_back(digis.data[iadc].adc());
}
}
sort(adc.begin(), adc.end());
// To make sure we have a tickmark, which comes every 70 bxs,
// fully contained in the scope 'frame' we are analyzing
// standard length is 280, sufficient to contain a full apv frame
// in this run there is no frame though, just baseline and tickmarks
if (adc.size() > 70) {
// Define tick mark top" level as "max" ADC values
range.second = adc.back();
// Construct vector to hold "baseline samples" (exclude tick mark samples)
std::vector<uint16_t> truncated;
std::vector<uint16_t>::const_iterator ii = adc.begin();
// remove twice the expected number of tick samples, otherwise you bias the baseline mean and rms
std::vector<uint16_t>::const_iterator jj = adc.end() - 4 * ((adc.size() / 70) + 1);
truncated.resize(jj - ii);
std::copy(ii, jj, truncated.begin());
if (truncated.empty()) {
return;
}
// Calc mean baseline level
float b_mean = 0.;
std::vector<uint16_t>::const_iterator iii = truncated.begin();
std::vector<uint16_t>::const_iterator jjj = truncated.end();
for (; iii != jjj; ++iii) {
b_mean += *iii;
}
b_mean /= (1. * truncated.size());
range.first = b_mean;
// Calc baseline noise
float b_rms = 0.;
std::vector<uint16_t>::const_iterator iiii = truncated.begin();
std::vector<uint16_t>::const_iterator jjjj = truncated.end();
for (; iiii != jjjj; ++iiii) {
b_rms += fabs(*iiii - b_mean);
}
// Set baseline "noise" (requires any possible APV frames are filtered from the data!)
baseline_rms = sqrt(b_rms / (1. * truncated.size()));
} else {
edm::LogWarning(mlDqmSource_) << "[OptoScanTask::" << __func__ << "]"
<< " Insufficient ADC values: " << adc.size();
}
}
|