28#include <fairlogger/Logger.h>
34constexpr Int_t DRAW_TRACKS_CNT{20};
43 auto factor{std::abs(after / before)};
45 return Form(
"%+.1f%%", 100.0 * (after / before - 1.0));
47 return Form(
"%+.1fom", std::log10(factor));
52 LOG(state) <<
" > BmnAlignReport : final report ===============================================";
53 if (aligner.
Results().empty()) {
54 LOG(error) <<
"<!> No results to report";
55 LOG(state) <<
" < BmnAlignReport : report canceled ============================================";
60 Int_t idxLast{after.SVDSig().GetNrows() - 1};
61 LOG(info) <<
Form(
" %.2e -> %.2e (%s) : MSE value change", before.
GetValueMSE(), after.GetValueMSE(),
63 LOG(info) <<
Form(
" %.2e -> %.2e (%s) : mean error in X change (abs)", std::abs(before.
ResidualsX().
GetMean()),
64 std::abs(after.ResidualsX().GetMean()),
66 LOG(info) <<
Form(
" %.2e -> %.2e (%s) : mean error in Y change (abs)", std::abs(before.
ResidualsY().
GetMean()),
67 std::abs(after.ResidualsY().GetMean()),
70 after.ResidualsX().GetStdDev(),
73 after.ResidualsY().GetStdDev(),
75 if (after.SVDSig().GetNrows() > 0) {
76 LOG(info) <<
Form(
" %.2e : latest SVD minimum singular value", after.SVDSig()(idxLast));
77 LOG(info) <<
Form(
" %.2e : latest SVD condition number", after.SVDSig()(0) / after.SVDSig()(idxLast));
88 for (
Int_t i = 0;
i < constCount;
i++) {
89 if (std::abs(violation[
i]) <= SOFT_ZERO) {
93 LOG(warning) <<
Form(
" %.2e : constraint row #%d violation", std::abs(violation[
i]),
i + 1);
95 LOG(info) <<
Form(
" %d of %d : constraints satisfied within %.0e", goodCount, constCount, SOFT_ZERO);
98 LOG(info) <<
" Composite node corrections (own share, cm and rad):";
104 if (!node.IsComposite())
106 TString line{
Form(
" %3d %-14s", node.level, node.name)};
107 for (
const ParamRef& p : node.params)
108 line +=
Form(
" %+11.4e", params(p.
full));
130 LOG(info) <<
" Execution timings:";
132 LOG(info) <<
Form(
" %dh %02dm %02ds : total CPU time spent", cpuTime / 3600, (cpuTime / 60) % 60,
134 LOG(info) <<
Form(
" %dh %02dm %02ds : total real time spent", realTime / 3600, (realTime / 60) % 60,
137 LOG(state) <<
" < BmnAlignReport : final report end ===========================================";
138 LOG(state) <<
" ---";
143 LOG(state) <<
" > BmnAlignReport : weak modes analysis";
146 if (aligner.
Results().empty()) {
147 LOG(error) <<
" <!> no iteration results available, aborting";
153 if (sig.
GetNrows() == 0 || V.GetNrows() == 0) {
154 LOG(error) <<
" <!> SVD data not found, aborting";
157 const Int_t nTotal{V.GetNrows()};
160 if (nTotal < nParams) {
161 LOG(error) <<
" <!> stored V matrix smaller than param count, aborting";
172 std::ofstream newCnstrFile;
174 Int_t newCnstrCount{0};
176 auto openNewCnstrFile = [&]() {
177 if (newCnstrFile.is_open() || newCnstrFailed)
189 newCnstrPath =
"cnstr_new";
191 newCnstrPath +=
"_from-" + srcBase;
192 newCnstrPath +=
"_" + stamp +
".json";
193 newCnstrFile.open(newCnstrPath.
Data(), std::ios::out);
194 if (!newCnstrFile.is_open()) {
195 LOG(error) <<
" <!> ReportModesBelow: failed to open " << newCnstrPath
196 <<
" for writing; further dumps suppressed";
197 newCnstrFailed =
kTRUE;
200 newCnstrFile <<
"[\n";
207 for (
Int_t j = 0; j < cnstrRows.GetNrows(); j++)
211 LOG(info) <<
Form(
" %.2e : eigenvalue threshold to consider", absThreshold);
214 if (sig(k) > absThreshold)
219 constexpr Double_t PARAM_ENERGY_MIN{0.10};
223 const Double_t paramFrac{paramNorm2 / std::max(paramNorm2 + multNorm2, SOFT_ZERO)};
224 LOG(info) <<
" --------------------------------------------------";
225 LOG(info) <<
Form(
" = weak mode #%d : eigenvalue = %.3e, param-subspace energy = %.1f%%", weakFound, sig(k),
227 if (paramFrac < PARAM_ENERGY_MIN) {
228 LOG(info) <<
" --> multiplier-dominated, likely linearization artifact - skipped";
232 const Double_t pNorm{std::sqrt(paramNorm2)};
236 constexpr Double_t OVERLAP_MIN{0.2};
239 std::vector<std::pair<Int_t, Double_t>> overlaps;
241 const TVectorD dots{cnstrRows * vParam};
242 for (
Int_t j = 0; j < aligner.
Priors().ConstCount(); j++) {
243 const Double_t cosine{std::fabs(dots[j]) / std::max(pNorm * cnstrNorms[j], SOFT_ZERO)};
244 overlaps.emplace_back(j, cosine);
245 if (cosine > OVERLAP_MIN)
248 LOG(info) <<
" overlap with existing constraints (|cos angle|):";
249 for (
const auto& ov : overlaps)
250 if (ov.second > OVERLAP_MIN)
251 LOG(info) <<
Form(
" constraint row #%d : %.1f%% overlap", ov.first + 1, 100.0 * ov.second);
252 LOG_IF(warning, !anyOverlap) <<
" ! no overlap with any constraint detected"
253 " -- likely new DoF to be fixed";
262 if (newCnstrFile.is_open()) {
263 if (newCnstrCount > 0)
264 newCnstrFile <<
",\n";
265 newCnstrFile <<
" {\n";
266 newCnstrFile <<
Form(
" \"Comment\": \"weak mode #%d, eigenvalue = %.3e, auto-dumped\",\n",
268 newCnstrFile <<
" \"Coefficients\": [\n";
269 constexpr Double_t VALUE_SKIP_BELOW{0.5e-10};
270 for (
Int_t r = 0; r < nParams; r++) {
272 if (std::fabs(
v) < VALUE_SKIP_BELOW)
279 ?
Form(
" { \"NodeName\": %11s, \"ParamName\": \"%s\", "
280 "\"Value\": %.10f },\n",
282 :
Form(
" { \"DetectorID\": %9d, \"ParamName\": \"%s\", "
283 "\"Value\": %.10f },\n",
286 newCnstrFile <<
" { \"RHS\": 0.0 }\n";
287 newCnstrFile <<
" ]\n";
288 newCnstrFile <<
" }";
290 LOG(info) <<
" new constraint snippet written to " << newCnstrPath;
293 LOG(info) <<
" full eigenvector (param-subspace, normalized):";
295 LOG(info) <<
Form(
" %-30s : %+.6f", p.Label().Data(), V(p.full, k) / pNorm);
298 if (anyOverlap || dumpNew) {
300 std::vector<std::pair<Double_t, Int_t>> ranked;
301 ranked.reserve(nParams);
302 for (
Int_t r = 0; r < nParams; r++)
303 ranked.emplace_back(std::fabs(V(r, k) / pNorm), r);
304 std::partial_sort(ranked.begin(), ranked.begin() + std::min<Int_t>(
BMN_GLOBAL_PARAMS_PD, ranked.size()),
306 [](
const std::pair<Double_t, Int_t>& a,
const std::pair<Double_t, Int_t>& b) {
307 return a.first > b.first;
309 LOG(info) <<
" top contributors (param-subspace, normalized):";
311 const Int_t row{ranked[t].second};
313 LOG(info) <<
Form(
" %-30s : %+.6f", p.
Label().
Data(), V(row, k) / pNorm);
318 if (newCnstrFile.is_open()) {
319 newCnstrFile <<
"\n]\n";
320 newCnstrFile.close();
321 LOG(info) <<
" " << newCnstrCount <<
" new constraint(s) saved into " << newCnstrPath;
323 LOG(info) <<
" ========================";
324 LOG(info) <<
" " << weakFound <<
" weak mode(s) detected below threshold";
325 LOG(state) <<
" < BmnAlignReport : weak modes analysis done";
326 LOG(state) <<
" ---";
331 LOG(state) <<
" > BmnAlignReport : parameter correlation analysis";
333 if (aligner.
Results().empty()) {
334 LOG(error) <<
" <!> no iteration results available, aborting";
341 LOG(error) <<
" <!> covariance matrix not available, aborting";
355 if (sigmaOf(p.full) > 0.0)
364 std::vector<Pair> pairs;
366 for (std::size_t
i = 0;
i < params.size();
i++) {
371 for (std::size_t j =
i + 1; j < params.size(); j++) {
376 if (skipIntraDet && r.
node == s.
node)
380 if (std::fabs(rho) >= absThreshold)
381 pairs.push_back({rho, &r, &s});
385 std::sort(pairs.begin(), pairs.end(),
386 [](
const Pair& a,
const Pair& b) { return std::fabs(a.rho) > std::fabs(b.rho); });
388 LOG(info) <<
Form(
" %d param(s) with valid sigma", validCnt);
397 std::vector<GlCorr> glAbove;
399 if (sigmaOf(p.full) == 0.0)
401 if (glCorr(p.full) >= absThreshold)
402 glAbove.push_back({glCorr(p.full), &p});
404 std::sort(glAbove.begin(), glAbove.end(), [](
const GlCorr& a,
const GlCorr& b) { return a.corr > b.corr; });
405 LOG(info) <<
" --------------------------------------------------";
406 LOG(info) <<
Form(
" %d param(s) with rho_gl >= %.2f out of %d valid", (
Int_t)glAbove.size(), absThreshold,
408 const Int_t glShown{std::min(topK, (
Int_t)glAbove.size())};
410 LOG(info) <<
" top params by global correlation:";
411 LOG(info) <<
Form(
" %-51s %-7s %-10s",
"param",
"rho_gl",
"sigma");
412 for (
Int_t k = 0; k < glShown; k++) {
418 LOG(info) <<
" --------------------------------------------------";
419 LOG(info) <<
Form(
" %d pair(s) with |rho| >= %.2f out of %d pair(s) considered", (
Int_t)pairs.size(),
420 absThreshold, totalPairs);
421 const Int_t shown{std::min(topK, (
Int_t)pairs.size())};
423 LOG(state) <<
" < BmnAlignReport : correlation analysis done";
424 LOG(state) <<
" ---";
427 LOG(info) <<
" top correlated pairs:";
428 LOG(info) <<
Form(
" %-51s %-51s %-7s %-10s %-10s",
"param i",
"param j",
"rho",
"sigma_i",
"sigma_j");
429 for (
Int_t k = 0; k < shown; k++) {
430 const ParamRef &r{*pairs[k].r}, &s{*pairs[k].s};
432 s.prmName, pairs[k].rho, sigmaOf(r.
full), sigmaOf(s.full));
435 LOG(state) <<
" < BmnAlignReport : correlation analysis done";
436 LOG(state) <<
" ---";
450 static const UInt_t ww{1600}, wh{1200};
452 "canvas",
"BM@N alignment", ww, wh);
465 pads.
resX =
new TPad(
"padG5",
"G5", 0.0, 0.67, 0.25, 1.0);
466 pads.
resY =
new TPad(
"padG6",
"G6", 0.25, 0.67, 0.5, 1.0);
468 pads.
svd =
new TPad(
"padG7",
"G7", 0.5, 0.67, 0.75, 1.0);
470 pads.
tracks =
new TPad(
"padG8",
"G8", 0.75, 0.67, 1.0, 1.0);
502 pHist =
ClonePlot(res[idx].ResidualsX());
505 pHist->
Draw(
"CSAME");
517 pHist =
ClonePlot(res[idx].ResidualsY());
520 pHist->
Draw(
"CSAME");
526 const TVectorD& vSig{res[idx].SVDSig()};
535 constexpr Int_t BMN_SVD_TAIL_MIN{75};
536 constexpr Int_t BMN_SVD_TAIL_MARGIN{3};
537 constexpr Int_t BMN_SVD_DROPS_KEEP{2};
538 constexpr Double_t LOG2{0.6931471805599453};
543 for (
Int_t i = 0;
i < nSig - 1;
i++) {
544 Double_t a{std::max(vSig(
i), SOFT_ZERO)}, b{std::max(vSig(
i + 1), SOFT_ZERO)};
545 drop[
i] = std::log(a) - std::log(b);
546 if (drop[
i] > dropMax)
549 const Double_t thr{std::max(0.5 * dropMax, LOG2)};
550 Int_t earliestKeptJump{-1}, kept{0};
551 for (
Int_t i = nSig - 2;
i >= 0 && kept < BMN_SVD_DROPS_KEEP;
i--)
552 if (drop[
i] >= thr) {
553 earliestKeptJump =
i;
556 startIdx = (earliestKeptJump >= 0) ? std::max(0, earliestKeptJump - BMN_SVD_TAIL_MARGIN + 1)
557 : std::max(0, nSig - BMN_SVD_TAIL_MIN);
559 if (nSig - startIdx < BMN_SVD_TAIL_MIN)
560 startIdx = std::max(0, nSig - BMN_SVD_TAIL_MIN);
561 const Int_t nTail{nSig - startIdx};
565 pGsig->
SetName(
Form(
"svdSig_%lu", res[idx].GetHistCounter()));
566 pGsig->
SetTitle(
"MNE SVD overview (tail);eigenvalue index;eigenvalue");
574 const Double_t sigMin{vSig(nSig - 1)};
582 Form(
"#lambda_{min} = %.3g", sigMin));
594 pHist =
ClonePlot(res[idx].ResidualsSY());
608 pHist =
ClonePlot(res[idx].ResidualsSX());
618 LOG(state) <<
" > BmnAlignReport : drawing started";
621 std::size_t resultsCnt{results.size()}, resultIdx{number < 0 ? number + resultsCnt : number - 1};
622 LOG(info) <<
" " << resultsCnt <<
" results available to draw";
623 if (resultIdx < 0 || resultIdx >= resultsCnt) {
624 LOG(error) <<
"<!> result with number " << number <<
" not found";
625 LOG(state) <<
" < BmnAlignReport : drawing terminated";
628 LOG(info) <<
" drawing " << std::abs(number) <<
" saved results counting from "
629 << (number < 0 ?
"the end" :
"the beginning");
646 Int_t iTrack{0}, iTrackDrawn{0};
648 for (pIterator->
ResetAll(); iTrackDrawn < DRAW_TRACKS_CNT && !pIterator->EndOfTracks();
659 pTrackLines[iTrackDrawn].
SetPoint(iHit, pIterator->
HitZ(), pIterator->
HitY(), pIterator->
HitX());
662 pTrackLines[iTrackDrawn].
Draw();
666 pApproxLines[iTrackDrawn].
SetPoint(0, 0.0, Alpha(
iY0), Alpha(
iX0));
667 pApproxLines[iTrackDrawn].
SetPoint(1, maxZdraw, Alpha(
iY0) + maxZdraw * Alpha(
iY1),
668 Alpha(
iX0) + maxZdraw * Alpha(
iX1));
671 pApproxLines[iTrackDrawn].
Draw();
678 LOG(state) <<
" < BmnAlignReport : drawing finished";
679 LOG(state) <<
" ---";
std::vector< Double_t > VecDouble_t
RM::SVector< Double_t, BMN_LOCAL_PARAMS_PT > SVectLC
#define BMN_GLOBAL_PARAMS_PD
TMatrixTSym< Double_t > TMatrixDSym
TMatrixTColumn_const< Double_t > TMatrixDColumn_const
TMatrixTRow_const< Double_t > TMatrixDRow_const
TMatrixT< Double_t > TMatrixD
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
TVectorT< Double_t > TVectorD
Int_t CompositeCount() const noexcept
Int_t AllParams() const noexcept
TMatrixD PromoteConstraints(const TMatrixD &constraints) const
Int_t ConstCount() const noexcept
static Pads PrepareCanvas()
static void DrawResiduals(const BmnAligner &aligner, const Pads &pads, std::size_t idx)
static void Correlations(const BmnAligner &aligner, Double_t absThreshold=0.9, Int_t topK=20, Bool_t skipIntraDet=kFALSE)
static void ModesBelow(const BmnAligner &aligner, Double_t absThreshold, Bool_t dumpNew=kTRUE)
static TH1 * ClonePlot(const TH1 &source)
static char * Change(Double_t before, Double_t after)
static void Draw(const BmnAligner &aligner, Int_t number=-1)
static void Results(const BmnAligner &aligner)
TVectorD & SVDSig() noexcept
TMatrixD & SVDv() noexcept
TH1D & ResidualsX() noexcept
TH1D & ResidualsY() noexcept
TVectorD & AErr() noexcept
Double_t GetValueMSE() const noexcept
VecSVectLC_t & Alpha() noexcept
TMatrixDSym & Cov() noexcept
TVectorD & AglCorr() noexcept
BmnSimpleProgressBar * ProgressBar() const noexcept
std::deque< BmnAlignResult > Results_t
Double_t TotalCpuTime() const noexcept
Double_t MaxZvalue() const noexcept
const BmnDetectorModel * DetectorModel() const noexcept
Bool_t Initialized() const noexcept
Int_t TracksUsable() const noexcept
const BmnAlignResult & ResultLast() const
const VecBool_t * TrackUsable() const noexcept
const char * ConstraintsPath() const noexcept
BmnRamIterator * RamIterator() const noexcept
Results_t & Results() noexcept
const BmnParamLayout & Layout() const noexcept
const BmnAlignResult & ResultZero() const
const BmnAlignPriors & Priors() const noexcept
const BmnAlignHierarchy & Hierarchy() const noexcept
Double_t TotalRealTime() const noexcept
Bool_t EndOfHits() const noexcept
Int_t EncodedID(Int_t idx) const
const Nodes_t & ByNode() const noexcept
static const char * ParamName(Int_t p)
std::vector< ParamRef > Range_t
const Range_t & All() const noexcept
virtual void NextHit() override
virtual void ResetAll() override
virtual Double_t HitY() const override
virtual Double_t HitX() const override
virtual void NextTrack() override
virtual Double_t HitZ() const override
virtual void SetLabelSize(Float_t size=0.04)
virtual void SetFillColor(Color_t fcolor)
virtual void SetLineStyle(Style_t lstyle)
virtual void SetLineColor(Color_t lcolor)
virtual void SetTextAlign(Short_t align=11)
virtual void SetTextColor(Color_t tcolor=1)
virtual void SetTextFont(Font_t tfont=62)
virtual void SetTextSize(Float_t tsize=1)
virtual void SetRangeUser(Double_t ufirst, Double_t ulast)
void SetCanvasSize(UInt_t ww, UInt_t wh) override
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
void SetName(const char *name="") override
void Draw(Option_t *chopt="") override
void SetTitle(const char *title="") override
virtual void SetDirectory(TDirectory *dir)
void SetTitle(const char *title) override
virtual Double_t GetStdDev(Int_t axis=1) const
virtual Double_t GetMean(Int_t axis=1) const
void Draw(Option_t *option="") override
TObject * Clone(const char *newname="") const override
virtual void SetStats(Bool_t stats=kTRUE)
TLatex * DrawLatex(Double_t x, Double_t y, const char *text)
virtual void SetTitle(const char *title="")
const char * GetTitle() const override
void SetLogy(Int_t value=1) override
TVirtualPad * cd(Int_t subpadnumber=0) override
void Draw(Option_t *option="") override
virtual void SetPoint(Int_t point, Double_t x, Double_t y, Double_t z)
void Draw(Option_t *option="") override
virtual Double_t Uniform(Double_t x1, Double_t x2)
const char * Data() const
Ssiz_t Last(char c) const
TString & Remove(EStripType s, char c)
TVectorT< Element > GetSub(Int_t row_lwb, Int_t row_upb, Option_t *option="S") const
Bool_t IsComposite() const noexcept