BmnRoot 26.10.0-210-gc52d34b0
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
histo.C
Go to the documentation of this file.
1/*
2 BM@N alignment routine
3 BM@N experiment at NICA complex, JINR, 2025
4
5 Department: Math & Soft Group of HEP lab
6 Author: Claude (Opus 4.8)
7 Supervisor: Igor Polev, polev@jinr.int
8
9 Histogramming method of planar-detector alignment (diagnostic macro).
10
11 For every alignable element the classic residual-histogram set is filled
12 and read to extract a first-order estimate of each of the 6 corrections.
13 The reading rules follow directly from the linearized measurement model
14 (see BmnMeasureModel::dXdA / dYdA), where the X-residual expands as
15
16 rx = dX - dZ*beta_x - psi*y_bar - phi*(beta_x*y_bar) + theta*(beta_x*x_bar)
17
18 so each correction is the coefficient of one covariate:
19
20 histogram / profile of rx read as gives
21 -------------------------- ---------- -----------------
22 rx mean dX
23 rx vs beta_x slope dZ = -slope
24 rx vs y_bar slope psi = -slope
25 rx vs beta_x * y_bar slope phi = -slope
26 rx vs beta_x * x_bar slope theta = +slope
27
28 (dY is read from the mean of ry; the symmetric ry expansion gives an
29 independent estimate of dZ, psi, phi, theta - reported as the alternative
30 readings and drawn as the X/Y pairs next to the X-residual ones.)
31
32 The single-covariate reading is deliberately approximate: the covariates
33 are mildly correlated, so the method is meant to be iterated - align the
34 reconstruction with the extracted corrections and re-run until every mean
35 sits at 0 and every profile is flat.
36
37 Run on a DST reconstructed with the current best alignment; the numbers
38 printed are the corrections still to be applied.
39*/
40
41// headers below are for IDE syntax to work and they will be
42// turned off during execution in ROOT macro mode
43#ifndef __CLING__
44#include "BmnAlignModels.h" // IWYU pragma: keep
45#include "BmnRootIterator.h"
47#include "BmnWeightedLine.h"
48
49#include <TCanvas.h>
50#include <TF1.h>
51#include <TH1D.h>
52#include <TH2D.h>
53#include <TLine.h>
54#include <TPad.h>
55#include <TPaveText.h>
56#include <TProfile.h>
57#include <TROOT.h>
58#include <TString.h>
59#include <TStyle.h>
60#include <TSystem.h>
61#include <array>
62#include <cmath>
63#include <iomanip>
64#include <iostream>
65#include <vector>
66#endif
67
68// POSIX terminal control for single-key (arrow) interactive detector switching.
69// Kept out of the CLING-skipped block: these are not autoloaded by ROOT.
70#include <termios.h>
71#include <unistd.h>
72
73// correction parameters, ordered as BmnParamLayout::ParamNames().
74// Local enum so the macro stays self-contained in interpreted ROOT mode
75#define PARAM_CNT 6
85constexpr static const char* PARAM_NAMES[PARAM_CNT]{"dX", "dY", "dZ", "phi", "theta", "psi"};
86// how each parameter is read from its diagnostic: mean of residual (shift)
87// or slope of residual vs covariate, and the sign that turns the reading
88// into the correction (matches the rx expansion in the header)
90// two independent readings per rotation/dZ: from the X-residual and from the
91// Y-residual. Only the sign of psi differs between them (see dXdA / dYdA).
92constexpr static const Double_t PARAM_SIGN_X[PARAM_CNT]{+1.0, +1.0, -1.0, -1.0, +1.0, -1.0};
93constexpr static const Double_t PARAM_SIGN_Y[PARAM_CNT]{+1.0, +1.0, -1.0, -1.0, +1.0, +1.0};
94constexpr static const char* PARAM_DIAG[PARAM_CNT]{// X-residual reading
95 "mean of X-residual",
96 "mean of Y-residual",
97 "slope of X-res vs track x-slope",
98 "slope of X-res vs (x-slope * y)",
99 "slope of X-res vs (x-slope * x)",
100 "slope of X-res vs y"};
101constexpr static const char* PARAM_DIAG_Y[PARAM_CNT]{// Y-residual reading
102 "mean of X-residual",
103 "mean of Y-residual",
104 "slope of Y-res vs track y-slope",
105 "slope of Y-res vs (y-slope * y)",
106 "slope of Y-res vs (y-slope * x)",
107 "slope of Y-res vs x"};
108constexpr static const char* COV_TITLE_X[PARAM_CNT]{"X residual, cm",
109 "Y residual, cm",
110 "track x-slope #beta_{x}",
111 "#beta_{x} #upoint y_{bar}, cm",
112 "#beta_{x} #upoint x_{bar}, cm",
113 "y_{bar}, cm"};
114constexpr static const char* COV_TITLE_Y[PARAM_CNT]{"X residual, cm",
115 "Y residual, cm",
116 "track y-slope #beta_{y}",
117 "#beta_{y} #upoint y_{bar}, cm",
118 "#beta_{y} #upoint x_{bar}, cm",
119 "x_{bar}, cm"};
120
121// slope-panel drawing mode (drawMode argument):
122// DM_PROFILE - both slope rows as 1D TProfile (X in middle, Y in bottom)
123// DM_SCATTER - both slope rows as 2D TH2D (X in middle, Y in bottom)
124// DM_MIX - X-residual slopes only: 1D TProfile in middle, 2D TH2D in
125// bottom (Y-residual readings are computed but not drawn)
132
133// canvas and pads configuration: top row = shifts, middle row = X-residual
134// slopes, bottom row = Y-residual (alternative) slopes; one param per column
135#define RES_X 3440
136#define RES_Y 1440
137#define PADS_X 4
138#define PADS_Y 3
139
140// residual histogram ranges for the drawn shift panels
141#define RESIDUAL_RANGE_X 0.02
142#define RESIDUAL_RANGE_Y 0.4
143#define RESIDUAL_BINS 201
144#define PROFILE_BINS 201
145#define PAVE_TEXT_SIZE 0.04 // ~half of the TPaveText auto-fit default
146
147// simple accumulator: mean of y and slope of a straight line y = a + b*x, unweighted
148struct LinAcc
149{
150 BmnWeightedLine line; // unit weights
151 void Add(Double_t x, Double_t y) { line.Add(x, y); }
152 Double_t MeanY() const { return line.N() > 0 ? line.Mean() : 0.0; }
153 Double_t RmsY() const { return line.N() < 2 ? 0.0 : line.Rms(); }
154 Double_t MeanYErr() const { return line.N() > 0 ? RmsY() / std::sqrt(line.N()) : 0.0; }
155 Double_t Slope() const { return std::abs(line.Det()) > 0.0 ? line.Slope() : 0.0; }
157 {
158 if (!(std::abs(line.Det()) > 0.0) || line.N() < 3)
159 return 0.0;
160 // unit weights: the variance scale comes from the scatter itself
161 Double_t s2{line.Chi2() / (line.N() - 2)};
162 return s2 > 0.0 ? std::sqrt(s2 * line.SlopeVar()) : 0.0;
163 }
164 // reading turned into a correction: sign array selects X- or Y-solution
165 Double_t Value(Int_t p, const Double_t* sign) const { return sign[p] * (PARAM_IS_SHIFT[p] ? MeanY() : Slope()); }
166 Double_t Error(Int_t p) const { return PARAM_IS_SHIFT[p] ? MeanYErr() : SlopeErr(); }
167};
168
169// two independent readings per detector: from X-residuals and from Y-residuals
170struct DetAcc
171{
172 std::array<LinAcc, PARAM_CNT> x, y;
173};
174
175// per-hit drawn quantities kept for every detector so the picture can be
176// redrawn instantly when the user browses to another detector (no re-read)
178{
179 VecDouble_t rx, ry, betaX, betaXY, betaXX, yBar, // X-residual covariates
180 betaY, betaYY, betaYX, xBar; // Y-residual covariates
181};
182
183// put the controlling terminal into non-canonical, no-echo mode (on == true)
184// so single keystrokes - including arrow escape sequences - are read at once
185static void histoSetRawMode(bool on, struct termios* saved)
186{
187 if (on) {
188 tcgetattr(STDIN_FILENO, saved);
189 struct termios raw{*saved};
190 raw.c_lflag &= ~(ICANON | ECHO);
191 raw.c_cc[VMIN] = 0; // non-blocking read
192 raw.c_cc[VTIME] = 0;
193 tcsetattr(STDIN_FILENO, TCSANOW, &raw);
194 } else {
195 tcsetattr(STDIN_FILENO, TCSANOW, saved);
196 }
197}
198
199// one drawn diagnostic panel (a shift histogram or a slope profile / 2D scatter)
200struct Panel
201{
203 Bool_t isShift, isY, as2D; // as2D: draw as TH2D instead of TProfile
204 const VecDouble_t* res; // residual values
205 const VecDouble_t* cov; // covariate values (nullptr for shift)
207 const char* diag;
208 const char* covTitle;
209 const LinAcc* a; // accumulator for the value/error box
211};
212
213/**
214 * @brief Per-element histogramming estimate of the alignment corrections.
215 *
216 * Diagnostic alternative to the global fit: for one alignable element at a time
217 * it fills the classic residual-histogram set and reads a first-order estimate
218 * of each of the 6 corrections off it, following the linearized measurement
219 * model derived in the file header. Navigate between elements interactively
220 * with the keyboard.
221 *
222 * @param fileListPath text file listing the .root files to read
223 * @param drawDetIdx index of the detector element to start on,
224 * 0 .. BmnDetectorModel::Alignables() - 1
225 * @param drawMode slope panel style: DM_PROFILE, DM_SCATTER or DM_MIX
226 * @param pdfPath .pdf file to save the canvas into, null to only display
227 *
228 * @return 0 on success, non-zero if the input data could not be read
229 */
230int histo(const char* fileListPath = "/home/igor/bmnroot/align_new/cfg/run8/7466.noa_rlerr.list",
231 Int_t drawDetIdx = 0, // detector index to visualize, 0 .. Alignables() - 1
232 Int_t drawMode = DM_MIX, // slope panels: DM_PROFILE / DM_SCATTER / DM_MIX
233 const char* pdfPath = nullptr)
234{
235 // init section
236 BmnRun8cgTopDM detModel;
237 detModel.Init();
238 const Int_t nDet{detModel.Alignables()};
239 if (drawDetIdx < 0 || drawDetIdx >= nDet) {
240 std::cerr << " <!> histo: drawDetIdx " << drawDetIdx << " out of range [0, " << nDet << ")" << std::endl;
241 return 1;
242 }
243 if (drawMode < DM_PROFILE || drawMode > DM_MIX) {
244 std::cerr << " <!> histo: drawMode " << drawMode << " out of range [" << DM_PROFILE << ", " << DM_MIX << "]"
245 << std::endl;
246 return 1;
247 }
248 BmnSimpleProgressBar progressBar;
249 BmnRootIterator itr(fileListPath, detModel, BmnDefaultTrackFilter(), BmnDefaultHitFilter(detModel), &progressBar);
250 if (!itr.Initialized()) {
251 std::cerr << " <!> histo: failed to initialize iterator on " << fileListPath << std::endl;
252 return 1;
253 }
254
255 std::cout << "\nInitializing ROOT reader for " << fileListPath << "\n";
256 itr.CountElements(); // count suitable tracks/hits, calibrate per-track progress
257
258 std::vector<DetAcc> acc(nDet); // per-detector X- and Y-residual accumulators
259 std::vector<DetDraw> draw(nDet); // per-detector per-hit records for drawing
260
261 // walk tracks; fit a straight line per track, then read residuals
262 std::cout << "Reading data...\n";
263 Long64_t usedTracks{0}, usedHits{0};
264 progressBar.Init();
265 for (itr.ResetAll(); !itr.EndOfTracks(); itr.NextTrack()) {
266 // weighted straight-line fit x = alpha_x + beta_x * z, y = alpha_y + beta_y * z
267 BmnWeightedLine lineX, lineY;
268 for (itr.ResetHits(); !itr.EndOfHits(); itr.NextHit()) {
269 lineX.Add(itr.HitZ(), itr.HitX(), itr.HitWx());
270 lineY.Add(itr.HitZ(), itr.HitY(), itr.HitWy());
271 }
272 if (!(lineX.Det() > 0.0) || !(lineY.Det() > 0.0)) // degenerate track (no z spread)
273 continue;
274
275 usedTracks++;
276 Double_t betaX{lineX.Slope()}, alphaX{lineX.At0()}, betaY{lineY.Slope()}, alphaY{lineY.At0()};
277 // residuals and covariates (bar = straight-line prediction)
278 for (itr.ResetHits(); !itr.EndOfHits(); itr.NextHit(), usedHits++) {
279 Int_t d{detModel.Idx(itr.HitDetectorID())};
280 Double_t z{itr.HitZ()}, xBar{alphaX + betaX * z}, yBar{alphaY + betaY * z}, rx{itr.HitX() - xBar},
281 ry{itr.HitY() - yBar};
282
283 // X-residual readings
284 acc[d].x[P_dX].Add(0.0, rx); // mean -> dX
285 acc[d].x[P_dZ].Add(betaX, rx); // slope -> -dZ
286 acc[d].x[P_phi].Add(betaX * yBar, rx); // slope -> -phi
287 acc[d].x[P_theta].Add(betaX * xBar, rx); // slope -> +theta
288 acc[d].x[P_psi].Add(yBar, rx); // slope -> -psi
289 // Y-residual readings (alternative solution)
290 acc[d].y[P_dY].Add(0.0, ry); // mean -> dY
291 acc[d].y[P_dZ].Add(betaY, ry); // slope -> -dZ
292 acc[d].y[P_phi].Add(betaY * yBar, ry); // slope -> -phi
293 acc[d].y[P_theta].Add(betaY * xBar, ry); // slope -> +theta
294 acc[d].y[P_psi].Add(xBar, ry); // slope -> +psi
295
296 DetDraw& dd{draw[d]};
297 dd.rx.push_back(rx);
298 dd.ry.push_back(ry);
299 dd.betaX.push_back(betaX);
300 dd.betaXY.push_back(betaX * yBar);
301 dd.betaXX.push_back(betaX * xBar);
302 dd.yBar.push_back(yBar);
303 dd.betaY.push_back(betaY);
304 dd.betaYY.push_back(betaY * yBar);
305 dd.betaYX.push_back(betaY * xBar);
306 dd.xBar.push_back(xBar);
307 } // loop over hits
308 } // loop over tracks
309 progressBar.Clear();
310
311 if (usedTracks == 0) {
312 std::cerr << " <!> histo: no usable tracks found" << std::endl;
313 return 1;
314 }
315
316 // numeric report: extracted correction per detector
317
318 using namespace std;
319 cout << "\nHistogramming method: first-order corrections read from residuals\n";
320 cout << usedTracks << " tracks, " << usedHits << " hits\n\n";
321
322 // primary table: shifts from residual means, dZ/phi/theta/psi from X-residual
323 cout << "Primary readings (shifts from means, dZ/phi/theta/psi from X-residual):\n";
324 cout << " " << left << setw(8) << "det_idx" << setw(10) << "det_id" << setw(22) << "element";
325 cout << right << setw(11) << "samples";
326 for (Int_t p = 0; p < PARAM_CNT; p++)
327 cout << setw(13) << PARAM_NAMES[p];
328 cout << setw(13) << "RMS(rx)" << setw(13) << "RMS(ry)" << "\n";
329 for (Int_t d = 0; d < nDet; d++) {
330 cout << " " << left << setw(8) << d << setw(10) << detModel.EncodedID(d) << setw(22)
331 << detModel.DecodeID(detModel.EncodedID(d));
332 cout << right << setw(11) << acc[d].x[P_dX].line.N();
333 cout << fixed << setprecision(6);
334 cout << setw(13) << acc[d].x[P_dX].Value(P_dX, PARAM_SIGN_X) << setw(13)
335 << acc[d].y[P_dY].Value(P_dY, PARAM_SIGN_Y);
336 for (Int_t p = P_dZ; p < PARAM_CNT; p++)
337 cout << setw(13) << acc[d].x[p].Value(p, PARAM_SIGN_X);
338 cout << setw(13) << acc[d].x[P_dX].RmsY() << setw(13) << acc[d].y[P_dY].RmsY() << "\n";
339 }
340
341 // alternative table: dZ/phi/theta/psi from the Y-residual slopes
342 cout << "\nAlternative readings (dZ/phi/theta/psi from Y-residual):\n";
343 cout << " " << left << setw(8) << "det_idx" << setw(10) << "det_id" << setw(22) << "element" << right;
344 for (Int_t p = P_dZ; p < PARAM_CNT; p++)
345 cout << setw(13) << PARAM_NAMES[p];
346 cout << "\n";
347 for (Int_t d = 0; d < nDet; d++) {
348 cout << " " << left << setw(8) << d << setw(10) << detModel.EncodedID(d) << setw(22)
349 << detModel.DecodeID(detModel.EncodedID(d));
350 cout << right << fixed << setprecision(6);
351 for (Int_t p = P_dZ; p < PARAM_CNT; p++)
352 cout << setw(13) << acc[d].y[p].Value(p, PARAM_SIGN_Y);
353 cout << "\n";
354 }
355
356 // drawn objects are detached from any TDirectory and marked kCanDelete so
357 // that a canvas Clear() on each redraw disposes of the previous picture
359 gStyle->SetOptFit(1);
360 gStyle->SetOptStat("emr");
361
362 TCanvas* pCnv = new TCanvas( // RAM not released - acceptable in macro mode
363 "canvas", "BM@N histogramming", RES_X, RES_Y);
364 pCnv->SetCanvasSize(RES_X - 20, RES_Y - 96);
365
366 // (re)draw all diagnostics for detector idx and print its detailed readout
367 auto show = [&](Int_t idx) {
368 const DetAcc& da{acc[idx]};
369 const DetDraw& dd{draw[idx]};
370
371 // detailed readout: X- and Y-solutions side by side
372 cout << "\nExtracted corrections for detector " << idx << " (id " << detModel.EncodedID(idx) << ", "
373 << detModel.DecodeID(detModel.EncodedID(idx)) << ", " << da.x[P_dX].line.N() << " samples):\n";
374 cout << fixed << setprecision(6);
375 cout << " " << left << setw(7) << "dX" << " = " << right << setw(11) << da.x[P_dX].Value(P_dX, PARAM_SIGN_X)
376 << " +/- " << setw(10) << da.x[P_dX].Error(P_dX) << " (" << PARAM_DIAG[P_dX] << ")\n";
377 cout << " " << left << setw(7) << "dY" << " = " << right << setw(11) << da.y[P_dY].Value(P_dY, PARAM_SIGN_Y)
378 << " +/- " << setw(10) << da.y[P_dY].Error(P_dY) << " (" << PARAM_DIAG[P_dY] << ")\n";
379 for (Int_t p = P_dZ; p < PARAM_CNT; p++)
380 cout << " " << left << setw(7) << PARAM_NAMES[p] << right << " X: " << setw(11)
381 << da.x[p].Value(p, PARAM_SIGN_X) << " +/- " << setw(9) << da.x[p].Error(p) << " Y: " << setw(11)
382 << da.y[p].Value(p, PARAM_SIGN_Y) << " +/- " << setw(9) << da.y[p].Error(p) << "\n";
383 cout << flush;
384
385 // fresh canvas: drop the previous picture and rebuild the pad grid
386 pCnv->SetTitle(Form("BM@N histogramming : detector %d (id %d)", idx, detModel.EncodedID(idx)));
387 pCnv->Clear();
388 pCnv->cd();
389 const Double_t padW{1.0 / PADS_X}, padH{1.0 / PADS_Y};
390 TPad* pPads[PADS_Y][PADS_X];
391 for (UInt_t i = 0; i < PADS_Y; i++)
392 for (UInt_t j = 0; j < PADS_X; j++) {
393 pPads[i][j] = new TPad(Form("pad%u%u", i, j), Form("pad%u%u", i, j), padW * j, padH * i, padW * (j + 1),
394 padH * (i + 1));
395 pPads[i][j]->Draw();
396 }
397
398 // build the panel list: top row = shifts, middle row = X-residual
399 // slopes, bottom row = Y-residual (alternative) slopes; one per column
400 const Int_t slopeP[4]{P_dZ, P_phi, P_theta, P_psi};
401 const VecDouble_t* covX[4]{&dd.betaX, &dd.betaXY, &dd.betaXX, &dd.yBar};
402 const VecDouble_t* covY[4]{&dd.betaY, &dd.betaYY, &dd.betaYX, &dd.xBar};
403 std::vector<Panel> panels;
404 panels.push_back({0, 0, P_dX, kTRUE, kFALSE, kFALSE, &dd.rx, nullptr, RESIDUAL_RANGE_X, PARAM_DIAG[P_dX],
406 panels.push_back({0, 1, P_dY, kTRUE, kTRUE, kFALSE, &dd.ry, nullptr, RESIDUAL_RANGE_Y, PARAM_DIAG[P_dY],
408 for (Int_t c = 0; c < 4; c++) {
409 Int_t p{slopeP[c]};
410 // middle row: X-residual slope, 2D only in pure-scatter mode
411 panels.push_back({1, c, p, kFALSE, kFALSE, drawMode == DM_SCATTER, &dd.rx, covX[c], RESIDUAL_RANGE_X,
412 PARAM_DIAG[p], COV_TITLE_X[p], &da.x[p], PARAM_SIGN_X});
413 // bottom row: Y-residual slope normally; in mix mode the same
414 // X-residual slope drawn as 2D (Y readings stay computed, not drawn)
415 if (drawMode == DM_MIX)
416 panels.push_back({2, c, p, kFALSE, kFALSE, kTRUE, &dd.rx, covX[c], RESIDUAL_RANGE_X, PARAM_DIAG[p],
417 COV_TITLE_X[p], &da.x[p], PARAM_SIGN_X});
418 else
419 panels.push_back({2, c, p, kFALSE, kTRUE, drawMode == DM_SCATTER, &dd.ry, covY[c], RESIDUAL_RANGE_Y,
420 PARAM_DIAG_Y[p], COV_TITLE_Y[p], &da.y[p], PARAM_SIGN_Y});
421 }
422
423 for (const Panel& pn : panels) {
424 pPads[PADS_Y - 1 - pn.row][pn.col]->cd();
425 const char* tag{pn.isShift ? "" : (pn.isY ? " (Y)" : " (X)")};
426 const char* suff{pn.isY ? "y" : "x"};
427 const char* axis{pn.isY ? "Y" : "X"};
428
429 // per-pad report box with the extracted value
430 TPaveText* pave = new TPaveText(0.70, 0.86, 0.99, 0.92, "BR NDC");
431 pave->SetBit(kCanDelete);
432 pave->SetFillColor(0);
434 pave->AddText(
435 Form("%s%s = %+.5f #pm %.5f", PARAM_NAMES[pn.p], tag, pn.a->Value(pn.p, pn.sign), pn.a->Error(pn.p)));
436
437 if (pn.isShift) {
438 // shift: 1D residual histogram, correction = mean (dashed line)
439 TH1D* h = new TH1D(Form("h_%s_%d", PARAM_NAMES[pn.p], idx), Form("%s;%s;hits", pn.diag, pn.covTitle),
440 RESIDUAL_BINS, -pn.resRange, pn.resRange);
441 h->SetBit(kCanDelete);
442 for (Double_t r : *pn.res)
443 h->Fill(r);
444 h->SetLineColor(kAzure + 2);
445 h->SetStats(0);
446 h->Draw();
447 TLine* mean = new TLine(h->GetMean(), 0.0, h->GetMean(), h->GetMaximum());
448 mean->SetBit(kCanDelete);
449 mean->SetLineColor(kRed);
450 mean->SetLineStyle(2);
451 mean->SetLineWidth(2);
452 mean->Draw();
453 } else {
454 // rotation / dZ: residual against its covariate, slope fit
455 const VecDouble_t& cov{*pn.cov};
456 const VecDouble_t& res{*pn.res};
457 Double_t lo{+1e30}, hi{-1e30};
458 for (Double_t c : cov) {
459 if (c < lo)
460 lo = c;
461 if (c > hi)
462 hi = c;
463 }
464 if (hi <= lo) {
465 lo -= 1e-3;
466 hi += 1e-3;
467 }
468
469 Double_t margin{0.05 * (hi - lo)};
470 if (pn.as2D) {
471 // 2D scatter of residual vs covariate; pol1 fit is the slope
472 // (TH2::Fit weights each column by content, like the profile)
473 TH2D* h2 = new TH2D(Form("h2_%s_%s_%d", PARAM_NAMES[pn.p], suff, idx),
474 Form("%s;%s;%s residual, cm", pn.diag, pn.covTitle, axis), PROFILE_BINS,
475 lo - margin, hi + margin, RESIDUAL_BINS, -pn.resRange, pn.resRange);
476 h2->SetBit(kCanDelete);
477 for (std::size_t i = 0; i < cov.size(); i++)
478 h2->Fill(cov[i], res[i]);
479 h2->Fit("pol1", "Q");
480 if (TF1* fit = h2->GetFunction("pol1")) {
481 fit->SetLineColor(kRed);
482 fit->SetLineWidth(2);
483 }
484 h2->SetStats(0);
485 h2->Draw("COLZ");
486 } else {
487 // residual profiled against its covariate, slope fit
488 TProfile* pr = new TProfile(Form("p_%s_%s_%d", PARAM_NAMES[pn.p], suff, idx),
489 Form("%s;%s;#LT %s residual #GT, cm", pn.diag, pn.covTitle, axis),
490 PROFILE_BINS, lo - margin, hi + margin);
491 pr->SetBit(kCanDelete);
492 for (std::size_t i = 0; i < cov.size(); i++)
493 pr->Fill(cov[i], res[i]);
495 pr->SetMarkerColor(kAzure + 2);
496 pr->SetLineColor(kAzure + 2);
497 pr->Fit("pol1", "Q");
498 pr->SetStats(0);
499 pr->Draw();
500 }
501 }
502 pave->Draw();
503 }
504 pCnv->Update();
505 };
506
507 show(drawDetIdx);
508
509 if (pdfPath && pdfPath[0])
510 pCnv->SaveAs(pdfPath);
511
512 // interactive browser: Right/Left arrows step to the next/previous detector
513 // (wrapping around), q or Esc quits. Skipped in batch mode or when stdin is
514 // not a terminal (e.g. piped input) - there the single detector is drawn once.
515 if (!gROOT->IsBatch() && isatty(STDIN_FILENO)) {
516 cout << "\n[ Right / Left arrows: next / previous detector | q: quit ]\n" << flush;
517 struct termios saved;
518 histoSetRawMode(true, &saved);
519 Bool_t running{kTRUE};
520 while (running) {
521 gSystem->ProcessEvents();
522 // leave if the user closed the canvas window
523 if (!gROOT->GetListOfCanvases()->FindObject(pCnv))
524 break;
525 unsigned char c{0};
526 if (read(STDIN_FILENO, &c, 1) <= 0) { // nothing pending
527 gSystem->Sleep(20);
528 continue;
529 }
530 if (c == 'q' || c == 'Q') {
531 running = kFALSE;
532 } else if (c == 27) { // ESC: arrow escape sequence or a bare Esc
533 unsigned char a{0}, b{0};
534 gSystem->Sleep(1); // let the rest of the sequence arrive
535 if (read(STDIN_FILENO, &a, 1) <= 0) {
536 running = kFALSE;
537 continue;
538 }
539 read(STDIN_FILENO, &b, 1);
540 if (a == '[' && b == 'C')
541 drawDetIdx = (drawDetIdx + 1) % nDet;
542 else if (a == '[' && b == 'D')
543 drawDetIdx = (drawDetIdx - 1 + nDet) % nDet;
544 else
545 continue;
546 show(drawDetIdx);
547 }
548 }
549 histoSetRawMode(false, &saved);
550 }
551
552 return 0;
553}
std::vector< Double_t > VecDouble_t
TrackFilter_t BmnDefaultTrackFilter(Bool_t wholeTrackOnly=kTRUE)
HitFilter_t BmnDefaultHitFilter(const BmnDetectorModel &model)
int i
Definition P4_F32vec4.h:22
bool Bool_t
int Int_t
unsigned int UInt_t
constexpr Bool_t kFALSE
double Double_t
long long Long64_t
constexpr Bool_t kTRUE
kRed
kAzure
kFullCircle
kCanDelete
#define gROOT
char * Form(const char *fmt,...)
R__EXTERN TStyle * gStyle
R__EXTERN TSystem * gSystem
Bool_t EndOfTracks() const noexcept
Bool_t EndOfHits() const noexcept
Bool_t Initialized() const noexcept
Int_t EncodedID(Int_t idx) const
Bool_t Init(const char *targetGeoFile=nullptr)
Int_t Idx(Int_t ID) const
virtual Double_t HitY() const override
virtual void ResetAll() override
virtual Double_t HitWy() const override
virtual Int_t HitDetectorID() const override
virtual Double_t HitZ() const override
virtual Double_t HitX() const override
virtual Double_t HitWx() const override
virtual void ResetHits() override
virtual void NextTrack() override
virtual void NextHit() override
virtual std::string DecodeID(Int_t id) const override
Definition BmnRun8DM.h:160
virtual Int_t Alignables() const noexcept override
Definition BmnRun8DM.h:139
Double_t Det() const noexcept
Double_t At0() const noexcept
void Add(Double_t z, Double_t v, Double_t w=1.0) noexcept
Double_t Slope() const noexcept
virtual void SetFillColor(Color_t fcolor)
virtual void SetLineStyle(Style_t lstyle)
virtual void SetLineWidth(Width_t lwidth)
virtual void SetLineColor(Color_t lcolor)
virtual void SetMarkerColor(Color_t mcolor=1)
virtual void SetMarkerStyle(Style_t mstyle=1)
virtual void SetTextSize(Float_t tsize=1)
void Clear(Option_t *option="") override
TVirtualPad * cd(Int_t subpadnumber=0) override
void SetCanvasSize(UInt_t ww, UInt_t wh) override
void SetTitle(const char *title="") override
void Update() override
virtual Double_t GetMean(Int_t axis=1) const
static void AddDirectory(Bool_t add=kTRUE)
virtual TFitResultPtr Fit(const char *formula, Option_t *option="", Option_t *goption="", Double_t xmin=0, Double_t xmax=0)
virtual Double_t GetMaximum(Double_t maxval=FLT_MAX) const
void Draw(Option_t *option="") override
virtual Int_t Fill(const char *name, Double_t w)
virtual TF1 * GetFunction(const char *name) const
virtual void SetStats(Bool_t stats=kTRUE)
virtual Int_t Fill(const char *namex, const char *namey, Double_t w)
void SetBit(UInt_t f)
virtual void Draw(Option_t *option="")
void SaveAs(const char *filename="", Option_t *option="") const override
TVirtualPad * cd(Int_t subpadnumber=0) override
void Draw(Option_t *option="") override
virtual TText * AddText(const char *label)
void Draw(Option_t *option="") override
Int_t Fill(const char *namex, Double_t y) override
#define PADS_Y
Definition histo.C:138
#define RES_Y
Definition histo.C:136
#define PADS_X
Definition histo.C:137
#define RES_X
Definition histo.C:135
static constexpr const char * PARAM_NAMES[PARAM_CNT]
Definition histo.C:85
#define PARAM_CNT
Definition histo.C:75
#define PAVE_TEXT_SIZE
Definition histo.C:145
static constexpr const char * PARAM_DIAG_Y[PARAM_CNT]
Definition histo.C:101
#define RESIDUAL_RANGE_X
Definition histo.C:141
eParam
Definition histo.C:77
@ P_psi
Definition histo.C:83
@ P_theta
Definition histo.C:82
@ P_dX
Definition histo.C:78
@ P_dZ
Definition histo.C:80
@ P_dY
Definition histo.C:79
@ P_phi
Definition histo.C:81
static constexpr const Double_t PARAM_SIGN_X[PARAM_CNT]
Definition histo.C:92
static constexpr const char * COV_TITLE_Y[PARAM_CNT]
Definition histo.C:114
static constexpr const char * PARAM_DIAG[PARAM_CNT]
Definition histo.C:94
static constexpr const char * COV_TITLE_X[PARAM_CNT]
Definition histo.C:108
eDrawMode
Definition histo.C:127
@ DM_MIX
Definition histo.C:130
@ DM_SCATTER
Definition histo.C:129
@ DM_PROFILE
Definition histo.C:128
#define RESIDUAL_RANGE_Y
Definition histo.C:142
#define PROFILE_BINS
Definition histo.C:144
int histo(const char *fileListPath="/home/igor/bmnroot/align_new/cfg/run8/7466.noa_rlerr.list", Int_t drawDetIdx=0, Int_t drawMode=DM_MIX, const char *pdfPath=nullptr)
Per-element histogramming estimate of the alignment corrections.
Definition histo.C:230
static constexpr const Double_t PARAM_SIGN_Y[PARAM_CNT]
Definition histo.C:93
#define RESIDUAL_BINS
Definition histo.C:143
static void histoSetRawMode(bool on, struct termios *saved)
Definition histo.C:185
static constexpr const Bool_t PARAM_IS_SHIFT[PARAM_CNT]
Definition histo.C:89
std::array< LinAcc, PARAM_CNT > y
Definition histo.C:172
std::array< LinAcc, PARAM_CNT > x
Definition histo.C:172
VecDouble_t ry
Definition histo.C:179
VecDouble_t yBar
Definition histo.C:179
VecDouble_t xBar
Definition histo.C:180
VecDouble_t betaYX
Definition histo.C:180
VecDouble_t betaX
Definition histo.C:179
VecDouble_t betaYY
Definition histo.C:180
VecDouble_t betaXX
Definition histo.C:179
VecDouble_t betaY
Definition histo.C:180
VecDouble_t rx
Definition histo.C:179
VecDouble_t betaXY
Definition histo.C:179
Double_t RmsY() const
Definition histo.C:153
Double_t SlopeErr() const
Definition histo.C:156
BmnWeightedLine line
Definition histo.C:150
Double_t Value(Int_t p, const Double_t *sign) const
Definition histo.C:165
Double_t Slope() const
Definition histo.C:155
Double_t MeanYErr() const
Definition histo.C:154
Double_t MeanY() const
Definition histo.C:152
Double_t Error(Int_t p) const
Definition histo.C:166
void Add(Double_t x, Double_t y)
Definition histo.C:151
Definition histo.C:201
const char * diag
Definition histo.C:207
Double_t resRange
Definition histo.C:206
const Double_t * sign
Definition histo.C:210
const char * covTitle
Definition histo.C:208
Bool_t as2D
Definition histo.C:203
Bool_t isY
Definition histo.C:203
Bool_t isShift
Definition histo.C:203
const VecDouble_t * res
Definition histo.C:204
Int_t p
Definition histo.C:202
Int_t col
Definition histo.C:202
const LinAcc * a
Definition histo.C:209
Int_t row
Definition histo.C:202
const VecDouble_t * cov
Definition histo.C:205