66int vertex(
const char* fileListPath =
"/home/igor/bmnroot/align_new/cfg/run9/9555.noa_rlerr.sample.list",
67 const char* outPath =
"vertex.root",
71 constexpr const char* TARGET_GEO{
"/home/igor/bmnroot/geometry/target_Sn.geo"};
72 constexpr Int_t SIBT_STATIONS{3}, SIBT_MIDDLE{1};
73 constexpr Double_t WINDOW_SIGMAS{5.0},
76 BEAM_LIKE_SLOPE{0.02};
78 fair::Logger::SetConsoleColor(
true);
79 fair::Logger::SetConsoleSeverity(
"info");
82 if (!detectorModel.
Init(TARGET_GEO))
85 halfT{0.5 * (zEnd - zStart)};
90 stsHits{reader,
"StsHit"};
92 TFile out{outPath,
"RECREATE"};
96 TTree* tree{
new TTree(
"vertex",
"SiBT beam line vs straight STS tracks at the target centre")};
97 Float_t beamX, beamY, beamErrX, beamErrY, beamSlopeX, beamSlopeY, beamPullX, beamPullY;
99 std::vector<Float_t> slopeX, slopeY, resX, resY, errX, errY;
100 tree->
Branch(
"beamX", &beamX);
101 tree->
Branch(
"beamY", &beamY);
102 tree->
Branch(
"beamErrX", &beamErrX);
103 tree->
Branch(
"beamErrY", &beamErrY);
104 tree->
Branch(
"beamSlopeX", &beamSlopeX);
105 tree->
Branch(
"beamSlopeY", &beamSlopeY);
106 tree->
Branch(
"beamPullX", &beamPullX);
107 tree->
Branch(
"beamPullY", &beamPullY);
108 tree->
Branch(
"tracksAll", &tracksAll);
109 tree->
Branch(
"slopeX", &slopeX);
110 tree->
Branch(
"slopeY", &slopeY);
111 tree->
Branch(
"resX", &resX);
112 tree->
Branch(
"resY", &resY);
113 tree->
Branch(
"errX", &errX);
114 tree->
Branch(
"errY", &errY);
116 Long64_t events{0}, eventsWithBeam{0}, tracksKept{0}, ndf{0};
118 while ((maxEvents <= 0 || events < maxEvents) && reader.
Next()) {
120 if (SIBT_STATIONS != sibtHits->GetEntriesFast())
125 Double_t midZ{0.0}, midX{0.0}, midY{0.0};
126 for (
Int_t i{0};
i < SIBT_STATIONS;
i++) {
138 if (stations != (1u << SIBT_STATIONS) - 1)
144 beamErrX = std::sqrt(bx.
Var(zc));
145 beamErrY = std::sqrt(by.
Var(zc));
146 beamSlopeX = bx.
Slope();
147 beamSlopeY = by.
Slope();
150 beamPullX = std::copysign(std::sqrt(std::max(bx.
Chi2(), 0.0)), midX - bx.
At(midZ));
151 beamPullY = std::copysign(std::sqrt(std::max(by.
Chi2(), 0.0)), midY - by.
At(midZ));
152 tracksAll = stsTracks->GetEntriesFast();
160 for (
Int_t i{0};
i < tracksAll;
i++) {
176 slopeX.push_back(tx.
Slope());
177 slopeY.push_back(ty.
Slope());
178 resX.push_back(bx.
At(zc) - tx.
At(zc));
179 resY.push_back(by.
At(zc) - ty.
At(zc));
180 errX.push_back(std::sqrt(tx.
Var(zc)));
181 errY.push_back(std::sqrt(ty.
Var(zc)));
183 tracksKept += slopeX.size();
187 std::cout <<
TString::Format(
"\n%lld events read, %lld (%.1f%%) with one hit in each SiBT station\n"
188 "target z from %.4f to %.4f cm, residuals taken at z_c = %.4f cm\n"
189 "%lld tracks accepted (%s), %.1f per event with a beam line\n",
190 events, eventsWithBeam, 100.0 * eventsWithBeam / std::max(events, 1LL), zStart, zEnd,
192 static_cast<Double_t>(tracksKept) / std::max(eventsWithBeam, 1LL));
196 tree->
SetEstimate(std::max(tracksKept, eventsWithBeam) + 1);
203 const TString vertexLike{
TString::Format(
"(abs(slopeX - beamSlopeX) >= %g || abs(slopeY - beamSlopeY) >= %g)",
204 BEAM_LIKE_SLOPE, BEAM_LIKE_SLOPE)};
205 const Long64_t tracksVertexLike{tree->
Draw(
"resX", vertexLike,
"goff")};
206 TString bothWindows{vertexLike};
208 for (
const TString p : {
"X",
"Y"}) {
209 const TString res{
"res" + p}, slope{
"(slope" + p +
" - beamSlope" + p +
")"}, err{
"err" + p},
210 beamErr{
"beamErr" + p}, beamPull{
"beamPull" + p};
211 const Double_t chi2ndf{(p ==
"X" ? chi2X : chi2Y) / ndf}, chi2Other{(p ==
"X" ? chi2Y : chi2X) / ndf};
215 const Double_t pullOffset{quantile(beamPull,
"", 0.5)},
216 beamScale{madToSigma * quantile(
TString::Format(
"abs(%s - (%g))", beamPull.Data(), pullOffset),
"", 0.5)};
223 depth{
TString::Format(
"abs%s * %g", slope.Data(), halfT)}, side[2]{slope +
" < 0", slope +
" >= 0"};
224 const Double_t slope99{quantile(
"abs" + slope, vertexLike, 0.99)};
227 new TProfile(
"vertexZ" + p +
"neg",
"slope < 0;track slope - beam slope;beam - track at z_c, cm", 20,
229 new TProfile(
"vertexZ" + p +
"pos",
"slope > 0;track slope - beam slope;beam - track at z_c, cm", 20, 0.0,
231 Double_t offset[2]{0.0, 0.0}, dz[2]{0.0, 0.0}, scale{1.0};
233 TString window{vertexLike}, fromLine;
235 for (
Int_t s{0}; s < 2; s++) {
237 window +
" && " + side[s],
"prof goff");
239 fitted[s] = profile[s]->
GetEntries() > 0 && 0 ==
static_cast<Int_t>(profile[s]->
Fit(
"pol1",
"Q0"));
245 fromLine =
TString::Format(
"(%s - (%s) * ((%g) + (%g) * %s) - (%s) * ((%g) + (%g) * %s))", res.
Data(),
246 side[0].Data(), offset[0], dz[0], slope.Data(), side[1].Data(), offset[1], dz[1],
250 TString::Format(
"abs%s / sqrt(%s^2 + (%s)^2 / 3)", fromLine.Data(), total.
Data(), depth.Data()),
253 WINDOW_SIGMAS * scale, total.
Data(), depth.Data());
255 bothWindows +=
" && " + window;
257 Long64_t sideTracks[2]{}, sideInWindow[2]{};
259 for (
Int_t s{0}; s < 2; s++) {
260 sideTracks[s] = tree->
Draw(res, vertexLike +
" && " + side[s],
"goff");
261 sideInWindow[s] = tree->
Draw(res, window +
" && " + side[s],
"goff");
262 sideWidth[s] = madToSigma * quantile(
"abs" + fromLine, window +
" && " + side[s], 0.5);
266 const Long64_t tracksInWindow{tree->
Draw(res, window,
"goff")};
267 const Double_t totalMedian{quantile(total, window, 0.5)}, slopeMedian{quantile(
"abs" + slope, window, 0.5)},
268 slope90{quantile(
"abs" + slope, window, 0.9)};
270 res, window +
TString::Format(
" && (%s)^2 / 3 > (%g * %s)^2", depth.Data(), beamScale, beamErr.Data()),
274 std::cout <<
TString::Format(
"straight line chi2/ndf over accepted tracks: %.2f\n", chi2ndf);
275 if (chi2ndf > 10.0 * chi2Other)
276 std::cout <<
" ! far above the other projection: check the field used in reco,\n"
277 " the hit errors and the misalignment before trusting the numbers below\n";
279 "beam at z_c: sigma %.4f cm predicted, pull scale %.2f (middle hit offset %.2f sigma)\n"
280 "beam - track at z_c = offset + dz * (track slope - beam slope), fitted per sign of the slope:\n"
281 " slope < 0 slope > 0\n"
282 " tracks %9lld %9lld\n"
283 " in the vertex window, %% %9.1f %9.1f\n"
284 " offset, cm %9.4f %9.4f\n"
285 " dz, cm %9.3f %9.3f\n"
286 " width around the line, cm %9.4f %9.4f\n"
287 "dz is the vertex z - z_c in the tracker frame: interaction depth plus the tracker z offset\n"
288 "vertex window: |r - line| < %g * %.2f * total error + |track slope - beam slope| * %.4f\n"
289 "total error median %.4f cm; |track slope - beam slope| in window: median %.3f, 90%% below %.3f\n"
290 "thickness term (t^2/12) above beam error: %.1f%% of tracks in window\n",
291 quantile(beamErr,
"", 0.5), beamScale, pullOffset, sideTracks[0], sideTracks[1],
292 100.0 * sideInWindow[0] / std::max(sideTracks[0], 1LL),
293 100.0 * sideInWindow[1] / std::max(sideTracks[1], 1LL), offset[0], offset[1], dz[0], dz[1], sideWidth[0],
294 sideWidth[1], WINDOW_SIGMAS, scale, halfT, totalMedian, slopeMedian, slope90,
295 100.0 * thicknessWins / std::max(tracksInWindow, 1LL));
299 const Long64_t tracksWithVertex{tree->
Draw(
"Sum$(" + bothWindows +
")", bothWindows,
"goff")};
301 "\n--- both projections\n"
302 "beam-like tracks (|track slope - beam slope| < %g in x and y), left out: %.1f%% of accepted\n"
303 "tracks in both vertex windows: %.1f%% of accepted, %.1f per event with a beam line\n"
304 "copies of the event's vertex hit, mean over the tracks that take it: %.1f\n",
305 BEAM_LIKE_SLOPE, 100.0 * (tracksKept - tracksVertexLike) / tracksKept, 100.0 * tracksWithVertex / tracksKept,
306 static_cast<Double_t>(tracksWithVertex) / eventsWithBeam,
311 std::cout <<
"\n" << outPath <<
" : ntuple 'vertex' and the vertex z profiles\n";