ATLAS Offline Software
Loading...
Searching...
No Matches
LArCalorimeter/LArSamplesMon/src/Residual.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "TMath.h"
8#include <algorithm>
12
13#include "TRandom.h"
14#include "TH1D.h"
15
16#include <iostream>
17using std::cout;
18using std::endl;
19
20using namespace LArSamples;
21
22
23Residual::Residual(const TVectorD& deltas, int run, int event, double adcMax, double time)
26{
28}
29
30
35
36
37TVectorD Residual::scaledDeltas() const
38{
39 TVectorD vect = deltas();
40 vect *= 1/adcMax();
41 return vect;
42}
43
44
45double Residual::scaledDelta(short i) const
46{
47 if (!isInRange(i) || adcMax() <= 0) return 0;
48 return deltas()(i)/adcMax();
49}
50
51
53{
54 TVectorD vect(lwb(), upb() + 1);
55 vect.SetSub(lwb(), scaledDeltas());
56 vect(upb() + 1) = time();
57 return vect;
58}
59
60
61bool ResidualCompare::operator()(const Residual& r1, const Residual& r2) const
62{
63 if (!r1.hasSameRange(r2)) {
64 cout << "WARNING : residuals have different ranges, this may crash the sorting..." << endl;
65 return false;
66 }
67
68 // Very, very important! Since samples are integers, it *will* happen that some residuals will have *identical* deltas.
69 // It turns out that (at least in the way used here), operator<(double, double) is not a strict weak ordering: we will
70 // have cases where residual1[4] == residual2[4], and then we will have residual1[4] < residual2[4] and residual2[4] < residual1[4]
71 // both true, which will confuse std::sort and cause it to crash... so add this safety (lesson of 2 days of debugging)
72 // Note: if we write a<<b iff a < b - epsilon, then << is indeed a strict weak ordering so all is fine. It does mean there
73 // will be "sorting errors", i.e. residuals that differ by less than epsilon may be sorted the wrong way. But that's fine for our usage.
74 const double epsilon = 1E-5;
75// cout << "Comparing sample " << m_sampling << ", = "
76// << (m_sampling == r1.upb() + 1 ? r1.time() : r1.scaledDelta(m_sampling)) << " >/< "
77// << (m_sampling == r2.upb() + 1 ? r2.time() : r2.scaledDelta(m_sampling)) << " "
78// << ((m_sampling == r1.upb() + 1 ? r1.time() : r1.scaledDelta(m_sampling)) < (m_sampling == r2.upb() + 1 ? r2.time() : r2.scaledDelta(m_sampling))) << endl;
79
80 if (r1.isInRange(m_sampling)) return r1.scaledDelta(m_sampling) < r2.scaledDelta(m_sampling) - epsilon;
81 if (m_sampling == r1.upb() + 1) return r1.time() < r2.time() - epsilon;
82 cout << "WARNING : comparison on an unknown sample, this may crash the sorting..." << endl;
83 return false;
84}
85
86
87bool Residuals::medianVars(TVectorD& medians, TVectorD& widths) const
88{
89 if (size() == 0) return false;
90 medians.ResizeTo(lwb(), upb() + 1);
91 widths.ResizeTo (lwb(), upb() + 1);
92
93 double halfSigmaQuantile = TMath::Prob(1,1)/2;
94 double medianQuantile = 0.5;
95
96 std::vector<Residual> sortedResiduals = m_residuals;
97
98 for (short i = lwb(); i <= upb() + 1; i++) {
99// cout << "test-sorting sample " << i << " (n = " << m_residuals.size() << ")" << endl;
100// std::vector<const Residual*> testSort(m_residuals.size());
101// ResidualCompare comparer(i);
102// for (unsigned int i1 = 0; i1 < m_residuals.size(); i1++) {
103// const Residual& res1 = m_residuals[i1];
104// unsigned int nBefore = 0;
105// for (unsigned int i2 = 0; i2 < m_residuals.size(); i2++) {
106// if (i1 == i2) continue;
107// const Residual& res2 = m_residuals[i2];
108// //cout << "comparing " << i1 << " " << i2 << endl;
109// if (comparer(res2, res1)) nBefore++;
110// if ((i1 == 3617 || i1 == 3886) && comparer(res2, res1))
111// cout << i2 << " is bfore " << i1 << " " << res2.scaledDelta(i) << " < " << res1.scaledDelta(i)
112// << (res2.scaledDelta(i) < res1.scaledDelta(i)) << " " << (res2.scaledDelta(i) < res1.scaledDelta(i) - 1E-3) << endl;
113// }
114// cout << "index " << i1 << " : nBefore = " << nBefore << " " << res1.scaledDelta(i) << endl;
115// while (testSort[nBefore]) { nBefore++; if (nBefore == testSort.size()) cout << "ERROR!!! " << i1 << endl; }
116// testSort[nBefore] = &res1;
117// }
118// cout << "done sorting" << endl;
119// for (unsigned int i1 = 0; i1 < testSort.size(); i1++) {
120// const Residual* res1 = testSort[i1];
121// if (!res1) cout << "ERROR : null at index " << i1 << endl;
122// for (unsigned int i2 = 0; i2 < i1; i2++) {
123// const Residual* res2 = testSort[i2];
124// if (comparer(*res1, *res2)) cout << "Wrong order " << i1 << " " << i2 << endl;
125// }
126// }
127// cout << "done checking" << endl;
128 std::sort(sortedResiduals.begin(), sortedResiduals.end(), ResidualCompare(i));
129 Residual& medianRes = sortedResiduals[(unsigned int)(sortedResiduals.size()*medianQuantile)];
130 Residual& loHalfSigmaRes = sortedResiduals[(unsigned int)(sortedResiduals.size()*halfSigmaQuantile)];
131 Residual& hiHalfSigmaRes = sortedResiduals[(unsigned int)(sortedResiduals.size()*(1 - halfSigmaQuantile))];
132 double median = (i < upb() + 1 ? medianRes.scaledDelta(i) : medianRes.time()) ;
133 double loHalfSigma = (i < upb() + 1 ? loHalfSigmaRes.scaledDelta(i) : loHalfSigmaRes.time());
134 double hiHalfSigma = (i < upb() + 1 ? hiHalfSigmaRes.scaledDelta(i) : hiHalfSigmaRes.time());
135 //cout << loHalfSigma << " " << median << " " << hiHalfSigma << endl;
136 medians[i] = median;
137 widths[i] = (hiHalfSigma - median > median - loHalfSigma ? median - loHalfSigma : hiHalfSigma - median);
138 }
139 return true;
140}
141
142
143Residuals* Residuals::truncate(double nWidthsRes, double nWidthsTime, unsigned int nMax) const
144{
145 if (size() == 0) return new Residuals();
146 TVectorD medians, widths;
147
148 if (nMax > 0) {
149 Residuals* original = new Residuals();
150 for (unsigned int i = 0; i < nMax; i++) original->add(*residual(i));
151 if (!original->medianVars(medians, widths)) { delete original; return nullptr;}
152 delete original;
153 }
154 else {
155 if (!medianVars(medians, widths)) return nullptr;
156 }
157 Residuals* truncated = new Residuals();
158
159 for (const Residual& residual : m_residuals) {
160 bool pass = true;
161 if (nMax > 0 && truncated->size() == nMax) break;
162 for (short i = lwb(); i <= upb(); i++) {
163 if (nWidthsRes > 0 && TMath::Abs(residual.scaledDelta(i) - medians[i]) > nWidthsRes*widths[i]) {
164 pass = false;
165 break;
166 }
167 }
168 if (!pass) continue;
169 if (nWidthsTime > 0 && TMath::Abs(residual.time() - medians[upb() + 1]) > nWidthsTime*widths[upb() + 1]) continue;
170 truncated->add(residual);
171 }
172 return truncated;
173}
174
175
176TH1D* Residuals::histogram(short sample, const TString& name, int nBins, double xMin, double xMax) const
177{
178 TH1D* h = new TH1D(name, "", nBins, xMin, xMax);
179 for (const Residual& residual : m_residuals)
180 h->Fill(sample <= upb() ? residual.scaledDelta(sample) : residual.time());
181 return h;
182}
183
184
186{
187 if (size() == 0) return nullptr;
188
189 ResidualCalculator* calc = new ResidualCalculator(lwb(), upb(), weigh);
190 for (const Residual& residual : m_residuals)
191 calc->fill(residual);
192
193 return calc;
194}
195
196
197int ResidualCalculator::find(int r, int e) const
198{
199 for (unsigned int i = 0; i < size(); i++)
200 if (event(i) == e && run(i) == r) return i;
201 return -1;
202}
203
204
206{
207 m_runs.push_back(r);
208 m_events.push_back(e);
209 return true;
210}
211
212
214{
215 if (find(residual.run(), residual.event()) >= 0) return true;
216 add(residual.run(), residual.event());
217 return fill_with_weight(residual, +1);
218}
219
220
222{
223 //std::pair<int, int> ev(residual.run(), residual.event());
224 //std::map< std::pair<int, int>, bool>::iterator findEv = m_events.find(ev);
225 //if (findEv == m_events.end()) return true;
226 //cout << "Will remove run = " << ev.first << ", event = " << ev.second << endl;
227 //m_events.erase(findEv);
228 int index = find(residual.run(), residual.event());
229 if (index == -1) return true;
230 m_events[index] = -1;
231 m_runs[index] = -1;
232 return fill_with_weight(residual, -1);
233}
234
235
237{
238 TVectorD xi = regresser()->means().GetSub(lwb(), upb(), "I");
239 CovMatrix xiErr = regresser()->meanErrorMatrix().GetSub(lwb(), upb(), lwb(), upb(), "I");
240 double tbar = regresser()->mean(upb() + 1);
241
242 double denom = regresser()->covarianceMatrix()(upb() + 1, upb() + 1);
243 if (denom < 1E-6) {
244 TVectorD xip(lwb(), upb());
245 CovMatrix xipErr(lwb(), upb());
246 // happens for size==2 if we are removing one of the residuals.
247 if (size() > 2) cout << "WARNING: variance of t < 1E-6, returning correction without derivative term. (V = " << denom << ", N = " << size() << ")" << endl;
248 return new ShapeErrorData(xi, xip, xiErr, xipErr, tbar, regresser()->nEntries());
249 }
250
251 TVectorD xip = TVectorD(regresser()->covarianceMatrix()[upb() + 1]).GetSub(lwb(), upb(), "I");
252 xip *= -1/denom;
253
254 TVectorD xipErrVect = TVectorD(regresser()->covarianceMatrixErrors()[upb() + 1]).GetSub(lwb(), upb(), "I");
255 xipErrVect *= 1/denom;
256 CovMatrix xipErr(lwb(), upb());
257 for (int k1 = lwb(); k1 <= upb(); k1++) xipErr(k1, k1) = TMath::Power(xipErrVect(k1), 2);
258
259 return new ShapeErrorData(xi, xip, xiErr, xipErr, tbar, regresser()->nEntries());
260}
261
262
263double ResidualCalculator::weight(const Residual& residual) const
264{
265 if (!weigh()) return 1;
266 return TMath::Power(residual.adcMax(), 2);
267}
268
269
270bool ResidualCalculator::fill_with_weight(const Residual& residual, double w)
271{
272 w *= weight(residual);
273 return m_regresser.fill(residual.scaledDeltasAndTime(), w);
274}
275
276
278{
279 if (!m_regresser.append(*other.regresser())) return false;
280 //for (std::map< std::pair<int, int >, bool >::const_iterator event = other.events().begin();
281 // event != other.events().end(); event++)
282 // m_events[event->first] = event->second;
283 for (unsigned int i = 0; i < other.size(); i++) add(other.run(i), other.event(i));
284 return true;
285}
286
287
289{
290 TString str = "\n";
291 /*for (std::map< std::pair<int, int>, bool>::const_iterator ev = m_events.begin();
292 ev != m_events.end(); ev++)
293 str += Form("run %6d event %10d\n", ev->first.first, ev->first.second);
294 */
295 for (unsigned int i = 0; i < size(); i++)
296 str += Form("run %6d event %10d\n", run(i), event(i));
297
298 return str;
299}
300
301
303{
304 Residuals testVect;
305 TRandom r;
306 for (unsigned int i = 0; i < 100000; i++) {
307 TVectorD d(5);
308 //for (unsigned short j = 0; j < 5; j++) d(j) = 0.01*i;
309 for (unsigned short j = 0; j < 5; j++) d(j) = r.Gaus(0, 1);
310 testVect.add(Residual(d, i, i, i, i));
311 }
312
313// TVectorD m,w;
314// if (!getMedianVars(testVect, m, w)) return false;
315// m.Print();
316// w.Print();
317
318 Residuals* truncated = testVect.truncate(2);
319 if (!truncated) return false;
320
321 TH1D* h = truncated->histogram(0, "h", 100, -5, 5);
322 delete truncated;
323 h->Draw();
324 return true;
325}
326
double mean(unsigned int i) const
Definition Averager.cxx:191
CovMatrix meanErrorMatrix() const
Definition Averager.cxx:138
TVectorD means() const
Definition Averager.cxx:112
CovMatrix covarianceMatrix() const
Definition Averager.cxx:153
bool isInRange(int i) const
Definition IndexRange.h:27
bool fill_with_weight(const Residual &residual, double w)
bool operator()(const Residual &r1, const Residual &r2) const
Residual(const TVectorD &deltas=TVectorD(), int run=0, int event=0, double adcMax=-1, double time=0)
bool medianVars(TVectorD &medians, TVectorD &widths) const
Residuals * truncate(double nWidthsRes, double nWidthsTime=-1, unsigned int nMax=0) const
const Residual * residual(unsigned int i) const
TH1D * histogram(short sample, const TString &name, int nBins, double xMin, double xMax) const
ResidualCalculator * calculator(bool weigh=false) const
int r
Definition globals.cxx:22
Definition index.py:1
Definition run.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.