90 delete fpRootIterator;
98 for (
auto pItr : fpIterators)
103template<
typename HitType>
107 LOG(state) <<
" > BmnAligner : data preparation started";
109 LOG(error) <<
" <!> BmnAligner is not initialized";
112 LOG_IF(info, fpIteratorMain == fpRamIterator) <<
" loading data from ROOT files into RAM...";
113 LOG_IF(info, fpIteratorMain == fpRootIterator) <<
" parsing ROOT data files...";
116 std::vector<SVectLC> arrAlpha(fTotalTracks);
118 Int_t detID, iTrack{0}, iHit{0};
119 Double_t Dx{0.0}, Dy{0.0};
120 fpRootIterator->ResetAll();
121 while (!fpRootIterator->EndOfTracks()) {
123 if (fpIteratorMain == fpRamIterator)
124 fpFirstHits[iTrack] = iHit;
126 Double_t xSum{0.0}, ySum{0.0}, zSum{0.0}, z2Sum{0.0}, zxSum{0.0}, zySum{0.0};
129 while (!fpRootIterator->EndOfHits()) {
130 detID = fpRootIterator->HitDetectorID();
132 if (fpDetModel->UnknownID(detID)) {
134 LOG(error) <<
" <!> Unknown detector module encoding:"
135 <<
"\n iterator::HitDetectorID() = " << detID
136 <<
"\n FairHit::GetDetectorID() = " << hit->GetDetectorID()
137 <<
"\n CbmStsHit::GetSystemId() = " << hit->
GetSystemId()
138 <<
"\n CbmStsHit::GetStationNr() = " << hit->GetStationNr()
139 <<
"\n CbmStsHit::GetSectorNr() = " << hit->GetSectorNr()
140 <<
"\n CbmStsHit::GetSensorNr() = " << hit->GetSensorNr();
144 fHitsPerDetector[fpDetModel->Idx(detID)]++;
147 if (fpIteratorMain == fpRamIterator)
148 new (&fpHits[iHit])
HitType(fpRootIterator->GetHit(), *fpDetModel);
150 Double_t x{fpRootIterator->HitX()}, y{fpRootIterator->HitY()}, z{fpRootIterator->HitZ()};
162 Dx += fpRootIterator->GetHit()->GetDx();
163 Dy += fpRootIterator->GetHit()->GetDy();
166 fpRootIterator->NextHit();
170 Double_t hitCnt{
static_cast<Double_t
>(fpRootIterator->HitsInTrack())},
171 factor{1.0 / (hitCnt * z2Sum - zSum * zSum)};
172 arrAlpha[iTrack] =
SVectLC((xSum * z2Sum - zSum * zxSum) * factor, (hitCnt * zxSum - zSum * xSum) * factor,
173 (ySum * z2Sum - zSum * zySum) * factor, (hitCnt * zySum - zSum * ySum) * factor);
176 fpRootIterator->NextTrack();
178 if (fpIteratorMain == fpRamIterator)
179 fpFirstHits[iTrack] = iHit;
180 StoreZeroSolution(arrAlpha);
185 fOmegaScaleFactor = (Dx + Dy) * 0.5;
186 fOmegaScaleFactor *= fOmegaScaleFactor;
194 BMN_RND.RndmArray(BMN_GLPARAMS_TOTAL, point.Array());
195 timerMSE.Start(kFALSE);
203 fProgressBar.Clear();
204 if (fpIteratorMain == fpRamIterator) {
205 LOG(info) <<
" " << iTrack <<
" tracks loaded";
206 LOG(info) <<
" " << iHit <<
" hits loaded";
208 LOG(info) <<
" average hit position errors: Dx = " << Dx <<
", Dy = " << Dy;
209 DoneInTime(timer,
"data preparation");
210 return LoadConstraints();
213template<
typename HitType>
217 LOG(state) <<
" > BmnAligner : loading constraints...";
218 if (!fpConstraintsPath) {
219 LOG(warning) <<
" constraints file in not provided, proceeding without constraints";
222 std::ifstream ifs(fpConstraintsPath);
224 LOG(error) <<
" <!> LoadConstraints: failed to open JSON file " << *fpConstraintsPath;
230 }
catch (
const std::exception& e) {
231 LOG(error) <<
" <!> LoadConstraints: failed to parse JSON file " << *fpConstraintsPath;
232 LOG(error) << e.what();
236 LOG(error) <<
" <!> LoadConstraints: top-level JSON is not an array in " << *fpConstraintsPath;
239 fConstraintsCnt = jsonData.
size();
240 if (fConstraintsCnt <= 0) {
241 LOG(error) <<
" <!> LoadConstraints: empty constraints array in " << *fpConstraintsPath;
245 fConstraints.resize(fConstraintsCnt);
246 for (Int_t
i = 0;
i < fConstraintsCnt;
i++) {
247 const auto& jsonLine = jsonData[
i];
248 if (!jsonLine.is_array()) {
249 LOG(error) <<
" <!> LoadConstraints: constraint " <<
i <<
" is not an array in " << fpConstraintsPath;
252 Int_t lineSize = jsonLine.
size();
253 if (lineSize > BMN_GLPARAMS_TOTAL) {
254 LOG(warning) <<
" constraint " <<
i <<
" size exceeds global parameters count, truncating";
255 lineSize = BMN_GLPARAMS_TOTAL;
256 }
else if (lineSize < BMN_GLPARAMS_TOTAL)
257 LOG(warning) <<
" constraint " <<
i <<
" size is less then global parameters count, padding with zeroes";
258 fConstraints[
i].ResizeTo(BMN_GLPARAMS_TOTAL);
259 for (Int_t k = 0; k < lineSize; k++)
260 fConstraints[
i](k) = jsonLine[k].get<Double_t>();
263 LOG(info) <<
" constraints loaded: " << fConstraintsCnt;
264 DoneInTime(timer,
"loading constraints");
268template<
typename HitType>
274 LOG(state) <<
" > BmnAligner : loading solution from file " << jsonPath;
276 std::ifstream ifs(jsonPath);
278 LOG(error) <<
" <!> LoadSolution: failed to open JSON file";
283 Int_t elementsLoaded{0};
289 if (js.contains(
"CorrectionValues")) {
290 if (js[
"CorrectionValues"] != jsAlignmentType) {
291 LOG(error) <<
" <!> LoadSolution: wrong alignment type in JSON file\n"
292 <<
" expected: " << jsAlignmentType <<
", in file: " << js[
"CorrectionValues"];
296 LOG(warning) <<
" CorrectionValues key is missing: assuming alignment type is correct";
297 if (js.contains(
"DetectorElements")) {
299 LOG(error) <<
" <!> LoadSolution: wrong detector configuration in JSON file\n"
300 <<
" modules expected: " <<
BMN_MODULE_COUNT <<
", in file: " << js[
"DetectorElements"];
304 LOG(warning) <<
" DetectorElements key is missing: assuming detector configuration is correct";
305 if (!js.contains(
"CorrectionsPerDetector") || !js[
"CorrectionsPerDetector"].is_array()) {
306 LOG(error) <<
" LoadSolution: CorrectionsPerDetector key is missing or not an array";
311 Int_t elementsCount{
static_cast<Int_t
>(js[
"CorrectionsPerDetector"].size())};
312 for (Int_t
i = 0;
i < elementsCount;
i++) {
313 json& element = js[
"CorrectionsPerDetector"][
i];
314 if (!element.
contains(
"detector_id")) {
315 LOG(warning) <<
" ATTENTION! DetectorID is missing for some element, skipping.";
318 Int_t detID = element[
"detector_id"].
get<Int_t>();
319 if (fpDetModel->UnknownID(detID)) {
320 LOG(warning) <<
" ATTENTION! Unregistered detector element ID: " << detID <<
", skipping.";
326 LOG(warning) <<
" ATTENTION! Correction values for the element " << detID
327 <<
" are invalid, skipping.";
332 Int_t detIdx = fpDetModel->Idx(detID);
333 json& values = element[
"values"];
334 SVectGL& A = fpResultCurrent->A(detIdx);
336 A(j) = values[j].
get<Double_t>();
338 Bool_t isFixed = element[
"isFixed"].
get<Bool_t>();
339 if (fDetectorActive[detIdx] == isFixed) {
340 fDetectorActive[detIdx] = not isFixed;
349 fpResultCurrent->ConcatenateA();
350 LOG(info) <<
" alignment corrections loaded for " << elementsLoaded <<
" detector elements";
355 LOG(info) <<
" loading tracks approximation from last knownsolution";
356 fpResultCurrent->Alpha() = fpResultLast->Alpha();
358 LOG(warning) <<
" ATTENTION! Local parameters approximation not found.";
360 }
catch (std::exception& e) {
361 LOG(error) <<
" <!> LoadSolution: failed to parse JSON file " << jsonPath;
362 LOG(error) << e.what();
368 DoneInTime(timer,
"solution loaded");
372template<
typename HitType>
376 LOG(state) <<
" > BmnAligner : saving solution to file " << jsonPath;
377 std::ofstream ofs(jsonPath);
379 LOG(error) <<
" <!> SaveSolution: failed to open output file";
390 js[
"CorrectionsPerDetector"] = json::array();
393 element[
"detector_id"] = fpDetModel->EncodedID(
i);
394 element[
"values"] = json::array();
396 element[
"values"].push_back(solution.A(
i)(j));
397 js[
"CorrectionsPerDetector"].
push_back(element);
403 js[
"TracksCount"] = fTotalTracks;
404 js[
"TracksParameters"] = json::array();
405 for (Int_t
i = 0;
i < fTotalTracks;
i++) {
406 json element = json::array();
409 js[
"TracksParameters"].
push_back(element);
415 ofs << std::setw(4) << js << std::endl;
416 }
catch (std::exception& e) {
417 LOG(error) <<
" <!> SaveSolution: failed to write JSON data to file\n" << e.what();
421 DoneInTime(timer,
"solution save");
432template<
typename HitType>
436 LOG(state) <<
" > BmnAligner : iterative alignment started";
439 Int_t minHits{
static_cast<Int_t
>(
BMN_MIN_HITS_PORTION * fTotalTracks / fpDetModel->MaxModulesInStation())};
441 if (!fDetectorActive[
i])
443 if (fHitsPerDetector[
i] < minHits) {
444 LOG(warning) << Form(
" detector element %d has only %d hits of %d required, it will be fixed",
445 fpDetModel->EncodedID(
i), fHitsPerDetector[
i], minHits);
446 fDetectorActive[
i] = kFALSE;
453 LOG(info) <<
" " << fActiveDetCount <<
" detector elements active of " <<
BMN_MODULE_COUNT <<
" total";
461 if (progressAbs < 0.0) {
465 LOG(error) <<
" <!> BmnAligner::Align : algorithm is diverging";
472 if (!IterateAlignment()) {
473 LOG(error) <<
" <!> BmnAligner::Align : iteration failed";
476 progressAbs = fpResultLast->GetValueMSE() - fpResultCurrent->GetValueMSE();
477 progressRel = progressAbs / fpResultLast->GetValueMSE();
478 LOG(info) << Form(
" = %+.3f%% relative progress, MSE change : %.3e -> %.3e\n", progressRel * 100.0,
479 fpResultLast->GetValueMSE(), fpResultCurrent->GetValueMSE());
481 retriesLast = regularRetries;
488 if (!fRegularIters && regularRetries)
491 LOG_IF(info, retriesLast != regularRetries) <<
" " << regularRetries <<
" regularization retries left";
497 for (
const auto& [idx, mse] : MSElist)
498 if (fDetectorActive[idx]) {
499 fDetectorActive[idx] = kFALSE;
507 LOG(info) <<
" " << fIterationResults.size() - 1 <<
" iterations until algorithm convergence criteria reached";
508 DoneInTime(timer,
"iterative alignment");
536template<
typename HitType>
541 LOG(state) <<
" > #" << fIteration + 1 <<
" iteration started";
543 LOG(error) <<
" <!> BmnAligner is not initialized";
550 TVectorD vB_dash(ActiveParamsCnt);
551 TMatrixD mC_dash(ActiveParamsCnt, ActiveParamsCnt);
554 LOG(info) <<
" " << fThreadsCnt <<
" threads started to perform dimension reduction (Millepede)";
556 TStopwatch timerMille;
558 LOG(info) << Form(
" %.1fs (REAL) / %.1fs (CPU) took to complete dimension reduction", timerMille.RealTime(),
559 timerMille.CpuTime());
560 fProgressBar.Clear();
579 TStopwatch timerGlobal;
582 TVectorD vBL(vB_dash);
583 TMatrixD mCL(mC_dash);
584 if (fConstraintsCnt) {
586 vBL.ResizeTo(ActiveParamsCnt + fConstraintsCnt);
587 mCL.ResizeTo(ActiveParamsCnt + fConstraintsCnt, ActiveParamsCnt + fConstraintsCnt);
589 std::vector<Bool_t> constActive(fConstraintsCnt,
false);
590 for (Int_t
i = 0, k = 0;
i < BMN_GLPARAMS_TOTAL;
i++) {
593 for (Int_t j = 0; j < fConstraintsCnt; j++) {
594 weight = fConstraints[j](
i);
596 mCL(k, ActiveParamsCnt + j) = weight;
597 mCL(ActiveParamsCnt + j, k) = weight;
598 constActive[j] = kTRUE;
604 TMatrixD row(1, mCL.GetNcols());
605 Int_t dstIdx{ActiveParamsCnt - 1},
606 maxIdx{ActiveParamsCnt + fConstraintsCnt - 1};
607 for (Int_t srcIdx = ActiveParamsCnt,
i = 0; srcIdx <= maxIdx; srcIdx++,
i++) {
610 if (++dstIdx == srcIdx)
612 mCL.GetSub(srcIdx, srcIdx, 0, maxIdx, row);
613 mCL.SetSub(dstIdx, 0, row);
614 mCL.SetSub(0, dstIdx, row.T());
617 mCL.ResizeTo(dstIdx, dstIdx);
618 vBL.ResizeTo(dstIdx);
619 LOG(info) <<
" " << dstIdx - ActiveParamsCnt <<
" active parameter constraints applied";
623 if (!fRegularIters) {
624 LOG(info) <<
" solving non-regularized system for global parameters...";
625 if (!SolveGlobal(mCL, vBL)) {
626 LOG(warning) <<
" iteration failed to improve MSE";
627 *fpResultCurrent = *fpResultLast;
631 LOG(info) <<
" starting Levenberg-Marquardt regularization...";
633 Double_t valueMSEbest{fpResultLast->GetValueMSE()}, LMfactorBest{0.0}, LMfactor{1.0};
634 Int_t LMiterarion{0};
635 Bool_t LMworking{kTRUE};
639 for (Int_t
i = 0;
i < ActiveParamsCnt;
i++)
640 mCL(
i,
i) = mC_dash(
i,
i) * LMfactor;
642 if (SolveGlobal(mCL, vBL)) {
652 if (fpResultCurrent->GetValueMSE() < valueMSEbest) {
653 valueMSEbest = fpResultCurrent->GetValueMSE();
654 LMfactorBest = LMfactor;
658 LOG(warning) << Form(
" LM regularization failed (F=%.3e)", LMfactor);
665 ROOT::Math::Functor1D fnLM([&mCL, &mC_dash, &vBL,
this, ActiveParamsCnt](Double_t factor) {
666 TMatrixD mCLcopy{mCL};
667 for (Int_t
i = 0;
i < ActiveParamsCnt;
i++)
668 mCLcopy(
i,
i) = mC_dash(
i,
i) * factor;
669 if (!SolveGlobal(mCLcopy, vBL))
670 throw std::runtime_error(Form(
"Levenberg-Marquardt failed (F=%.3e)", factor));
671 return fpResultCurrent->GetValueMSE();
674 if (!fRegularIters) {
677 " regularization cancelled : sufficient %+.1f%% of progress achieved using non-regularized method",
678 100.0 * (fpResultCurrent->GetValueMSE() / fpResultLast->GetValueMSE() - 1.0));
680 }
else if (LMfactorBest < 1.0) {
681 LOG(warning) <<
" iteration failed to improve MSE";
682 *fpResultCurrent = *fpResultLast;
684 }
else if (LMfactorBest == 1.0 || LMworking) {
688 << Form(
" F = %.3e : LM regularization approached gradient descent", LMfactorBest);
691 <<
" F = 1.0 : LM regularization did not improve results";
698 ROOT::Math::BrentMinimizer1D brent;
704 LOG(info) << Form(
" F = %.3e : optimal LM factor value", brent.XMinimum());
706 LOG(warning) << Form(
" F = %.3e : rough LM factor value used, 1D optimization failed",
708 fnLM(success ? brent.XMinimum() : LMfactorBest);
713 LOG(info) << Form(
" %d MSE value calculations performed during iteration", fMSEclcCounter);
714 LOG(info) << Form(
" %.1fs (REAL) / %.1fs (CPU) took to complete parameters estimation", timerGlobal.RealTime(),
715 timerGlobal.CpuTime());
718 LOG(state) << Form(
" < #%d iteration took %.1fs (REAL) / %.1fs (CPU)", fIteration + 1, timer.RealTime(),
723template<
typename HitType>
740 auto oldErrorLevel{gErrorIgnoreLevel};
741 gErrorIgnoreLevel = kBreak;
743 Bool_t success{mLU.Decompose()};
744 TDecompSVD mSVD{mCL};
746 gErrorIgnoreLevel = oldErrorLevel;
747 fpResultCurrent->SVDSig().ResizeTo(mSVD.GetSig());
748 fpResultCurrent->SVDSig() = mSVD.GetSig();
750 TVectorD vAL{success ? mLU.Invert(success) * vBL : mSVD.Solve(vBL, success)};
752 LOG(warning) <<
" <!> global matrix inversion unsuccessful";
757 Int_t activeConstCnt{vAL.GetNrows() - ActiveParamsCnt};
758 if (activeConstCnt) {
759 fpResultCurrent->L().ResizeTo(activeConstCnt);
760 vAL.GetSub(ActiveParamsCnt, vAL.GetNrows() - 1, fpResultCurrent->L());
763 Double_t *dst{fpResultCurrent->A().begin()}, *src{vAL.GetMatrixArray()};
765 if (fDetectorActive[
i])
773 ROOT::Math::Functor1D fnMSE([
this](Double_t step) {
774 SVectGLT point{fpResultLast->A() + fpResultCurrent->A() * step};
775 return CalculateMSE(point);
778 Double_t valueMSE, stepMin{0.0}, stepMax{1.0};
779 valueMSE = fnMSE(stepMax);
780 while (valueMSE < fpResultLast->GetValueMSE()) {
783 valueMSE = fnMSE(stepMax);
787 fBrent.SetFunction(fnMSE, stepMin, stepMax);
790 LOG(warning) <<
" Brent method failed to calculate step size";
795 fpResultCurrent->A() *= fBrent.XMinimum();
798 fpResultCurrent->A() += fpResultLast->A();
799 fpResultCurrent->SeparateA();
800 CalculateMSE(kFALSE);
814template<
typename HitType>
818 constexpr static const Int_t SMatrMaxSize{
819 std::max(std::max(
static_cast<Int_t
>(SMatrGL::kSize),
static_cast<Int_t
>(SMatrLC::kSize)),
820 static_cast<Int_t
>(SMatrGP::kSize))};
821 static const std::vector<Double_t> zeroes(SMatrMaxSize, 0.0);
822 static const auto zStart = zeroes.begin();
839 TMatrixD mGfull(ActiveParamsCnt,
BMN_LOCAL_PARAMS_PT), mCfull(ActiveParamsCnt, ActiveParamsCnt),
840 mC_part(ActiveParamsCnt, ActiveParamsCnt);
841 TVectorD vBfull(ActiveParamsCnt), vB_part(ActiveParamsCnt);
847 Int_t iTrack{fFirstTracksIdx[threadNum]};
849 while (!pItr->EndOfTracks()) {
852 if (!fpTrackUsable->at(iTrack)) {
865 vBeta.SetElements(zStart, SVectLC::kSize);
866 mGamma.SetElements(zStart, SMatrLC::kSize);
869 SVectLC& lc{fpResultLast->Alpha(iTrack)};
872 while (!pItr->EndOfHits()) {
876 const SVectGL& gl{fpResultLast->A(fpDetModel->Idx(pItr->HitDetectorID()))};
881 omega = fOmegaScaleFactor * pItr->HitWx();
882 vGradL = fpMeasureModel->GradXlocal(z, gl, lc);
883 mGamma += omega * ROOT::Math::TensorProd(vGradL, vGradL);
884 vBeta += (omega * (pItr->HitX() - fpMeasureModel->X(z, gl, lc))) * vGradL;
886 omega = fOmegaScaleFactor * pItr->HitWy();
887 vGradL = fpMeasureModel->GradYlocal(z, gl, lc);
888 mGamma += omega * ROOT::Math::TensorProd(vGradL, vGradL);
889 vBeta += (omega * (pItr->HitY() - fpMeasureModel->Y(z, gl, lc))) * vGradL;
897 if (!mGamma.Invert())
898 throw std::runtime_error(
"matrix inversion failed while calculating local parameters");
899 vDelta = mGamma * vBeta;
901 fpResultCurrent->Alpha(iTrack) = fpResultLast->Alpha(iTrack) + vDelta;
913 if (!fDetectorActive[
i])
915 vB[
i].SetElements(zStart, SVectGL::kSize);
916 mC[
i].SetElements(zStart, SMatrGL::kSize);
917 mG[
i].SetElements(zStart, SMatrGP::kSize);
922 while (!pItr->EndOfHits()) {
923 const Int_t iDet{fpDetModel->Idx(pItr->HitDetectorID())};
924 if (!fDetectorActive[iDet]) {
933 const SVectGL& gl{fpResultLast->A(iDet)};
938 omega = fOmegaScaleFactor * pItr->HitWx();
939 vGradL = fpMeasureModel->GradXlocal(z, gl, lc);
940 vGradG = fpMeasureModel->GradXglobal(z, gl, lc);
941 mG[iDet] += omega * ROOT::Math::TensorProd(vGradG, vGradL);
942 mC[iDet] += omega * ROOT::Math::TensorProd(vGradG, vGradG);
943 vB[iDet] += (omega * (pItr->HitX() - fpMeasureModel->X(z, gl, lc))) * vGradG;
945 omega = fOmegaScaleFactor * pItr->HitWy();
946 vGradL = fpMeasureModel->GradYlocal(z, gl, lc);
947 vGradG = fpMeasureModel->GradYglobal(z, gl, lc);
948 mG[iDet] += omega * ROOT::Math::TensorProd(vGradG, vGradL);
949 mC[iDet] += omega * ROOT::Math::TensorProd(vGradG, vGradG);
950 vB[iDet] += (omega * (pItr->HitY() - fpMeasureModel->Y(z, gl, lc))) * vGradG;
959 if (!fDetectorActive[
i])
964 vBfull.SetSub(j, vaB);
965 mGfull.SetSub(j, 0, maG);
966 mCfull.SetSub(j, j, maC);
969 TMatrixD mGfullT(TMatrixD::kTransposed, mGfull);
970 mC_part += mCfull - mGfull * maGamma * mGfullT;
971 vB_part += vBfull - mGfull * vaDelta;
978 std::lock_guard<std::mutex> lock(fMutexGlobal);
979 *pmC_dash += mC_part;
980 *pvB_dash += vB_part;
983template<
typename HitType>
988 BmnAlignResult *pBackupSolution{fpResultCurrent}, tempSolution(*fpResultCurrent);
989 tempSolution.A() = solution;
990 tempSolution.SeparateA();
991 fpResultCurrent = &tempSolution;
992 Double_t valueMSE{CalculateMSE(kFALSE)};
993 fpResultCurrent = pBackupSolution;
997template<
typename HitType>
1001 fpResultCurrent->ResetValueMSE();
1002 if (withResiduals) {
1003 fpResultCurrent->ResidualsX().Reset();
1004 fpResultCurrent->ResidualsY().Reset();
1007 fProgressBar.Init();
1010 fProgressBar.Clear();
1011 else if (0 == fMSEclcCounter % fMSEclcTick)
1012 std::cout <<
" " << fMSEclcCounter <<
" MSE calculations\r" << std::flush;
1013 return fpResultCurrent->GetValueMSE();
1016template<
typename HitType>
1019 Double_t
delta, omega;
1020 std::array<Double_t, BMN_MODULE_COUNT> arrMSE;
1021 TH1D *pResX, *pResY;
1024 if (withResiduals) {
1025 pResX =
new TH1D(Form(
"residualsX_%lu", fpResultCurrent->GetHistCounter()),
"Partial residuals by X",
1027 pResY =
new TH1D(Form(
"residualsY_%lu", fpResultCurrent->GetHistCounter()),
"Partial residuals by Y",
1033 if (threadNum == -1) {
1035 pItr = fpIteratorMain;
1037 iTrack = fFirstTracksIdx[threadNum];
1038 pItr = fpIterators[threadNum];
1042 if (!fpTrackUsable->at(iTrack)) {
1048 const SVectLC& lc{fpResultCurrent->Alpha(iTrack)};
1051 const SVectGL& gl{fpResultCurrent->A(detectorIdx)};
1053 omega = fOmegaScaleFactor * pItr->
HitWx();
1054 delta = pItr->
HitX() - fpMeasureModel->X(pItr->
HitZ(), gl, lc);
1055 arrMSE[detectorIdx] += omega *
delta *
delta;
1061 omega = fOmegaScaleFactor * pItr->
HitWy();
1062 delta = pItr->
HitY() - fpMeasureModel->Y(pItr->
HitZ(), gl, lc);
1063 arrMSE[detectorIdx] += omega *
delta *
delta;
1076 std::lock_guard<std::mutex> lock(fMutexGlobal);
1078 fpResultCurrent->AddValueMSE(iDet, arrMSE[iDet]);
1079 if (withResiduals) {
1080 fpResultCurrent->ResidualsX().Add(pResX);
1081 fpResultCurrent->ResidualsY().Add(pResY);
1087template<
typename HitType>
1090 BmnAlignResult &before{*GetResult(kFALSE)}, &after{*GetResult(kTRUE)};
1091 Int_t idxLast{after.
SVDSig().GetNrows() - 1};
1092 static const char* drawLine{
"================================================================================"};
1094 LOG(info) << drawLine;
1095 LOG(info) << Form(
"%.2e -> %.2e (%+.1f%%) : MSE value change", before.GetValueMSE(), after.GetValueMSE(),
1096 100.0 * (after.GetValueMSE() - before.GetValueMSE()) / before.GetValueMSE());
1098 "%.2e -> %.2e (%+.1f%%) : mean error in X change", before.ResidualsX().GetMean(), after.ResidualsX().GetMean(),
1099 100.0 * (after.ResidualsX().GetMean() - before.ResidualsX().GetMean()) / before.ResidualsX().GetMean());
1101 "%.2e -> %.2e (%+.1f%%) : mean error in Y change", before.ResidualsY().GetMean(), after.ResidualsY().GetMean(),
1102 100.0 * (after.ResidualsY().GetMean() - before.ResidualsY().GetMean()) / before.ResidualsY().GetMean());
1103 LOG(info) << Form(
"%.2e -> %.2e (%+.1f%%) : error stddev in X change", before.ResidualsX().GetStdDev(),
1104 after.ResidualsX().GetStdDev(),
1105 100.0 * (after.ResidualsX().GetStdDev() - before.ResidualsX().GetStdDev())
1106 / before.ResidualsX().GetStdDev());
1107 LOG(info) << Form(
"%.2e -> %.2e (%+.1f%%) : error stddev in Y change", before.ResidualsY().GetStdDev(),
1108 after.ResidualsY().GetStdDev(),
1109 100.0 * (after.ResidualsY().GetStdDev() - before.ResidualsY().GetStdDev())
1110 / before.ResidualsY().GetStdDev());
1111 LOG(info) << Form(
"SVD minimum singular value : %.2e", after.SVDSig()(idxLast));
1112 LOG(info) << Form(
"SVD condition number : %.2e", after.SVDSig()(0) / after.SVDSig()(idxLast));
1113 LOG(info) << drawLine;
1114 Int_t cpuTime{
static_cast<Int_t
>(fTotalCpuTime)}, realTime{
static_cast<Int_t
>(fTotalRealTime)};
1115 LOG(info) << Form(
"total CPU time spent .......... %dh %02dm %02ds", cpuTime / 3600, (cpuTime / 60) % 60,
1117 LOG(info) << Form(
"total real time spent ......... %dh %02dm %02ds", realTime / 3600, (realTime / 60) % 60,
1119 LOG(info) << Form(
"multithreading boost factor ... x%.1f", fTotalCpuTime / fTotalRealTime);
1122template<
typename HitType>
1129 if (max_threads < fThreadsCnt) {
1130 LOG(warning) <<
" too many threads requested for the size of dataset, using " << max_threads
1131 <<
" threads instead of " << fThreadsCnt;
1132 fThreadsCnt = max_threads;
1134 if (fpIteratorMain == fpRootIterator && fThreadsCnt > 1) {
1135 LOG(warning) <<
" parallelization implemented for RAM mode only";
1139 if (fThreadsCnt > 1) {
1141 fFirstTracksIdx.resize(fThreadsCnt);
1142 fpIterators.resize(fThreadsCnt);
1143 Int_t tracksPerThread = fTotalTracks / fThreadsCnt;
1144 for (Int_t
i = 0, iTrack = 0;
i < fThreadsCnt;
i++, iTrack += tracksPerThread) {
1145 fFirstTracksIdx[
i] = iTrack;
1148 i == fThreadsCnt - 1
1149 ? fTotalTracks - tracksPerThread *
i
1150 : tracksPerThread));
1153 fFirstTracksIdx.resize(1);
1154 fpIterators.resize(1);
1155 fFirstTracksIdx[0] = 0;
1156 fpIterators[0] = fpIteratorMain;
1160template<
typename HitType>
1164 LOG(state) << Form(
" < BmnAligner : %s completed in %.1fs (REAL) / %.1fs (CPU)", stage, timer.RealTime(),