18 std::vector<double>* fProp_Val) {
26 const double eigen_thresh,
const int _fNumPar) {
33 if (CovMatrix ==
nullptr) {
40 MACH3LOG_ERROR(
"FirstPCAdpar and LastPCAdpar are higher than the number of parameters");
45 MACH3LOG_ERROR(
"FirstPCAdpar and LastPCAdpar are less than 0 but not default -999");
58 TMatrixDSymEigen eigen(submat);
95 temp2.ResizeTo(CovMatrix->GetNrows(),
NumParPCA);
102 temp2(iRow, iRow) = 1.0;
110 for(
int iRow = 0;iRow < (CovMatrix->GetNrows()-1)-
LastPCAdpar; iRow++) {
113 temp2(OrigRow, PCARow) = 1.;
144 DebugPCA(sum, temp, submat, CovMatrix->GetNrows());
152 constexpr
double correlation_threshold = 1e-6;
154 bool found_significant_correlation =
false;
156 int N = CovMatrix->GetNrows();
158 for (
int j = 0; j < N; ++j) {
162 double corr_val = (*CovMatrix)(i, j);
163 if (std::fabs(corr_val) > correlation_threshold) {
164 found_significant_correlation =
true;
165 MACH3LOG_ERROR(
"Significant correlation detected between decomposed parameter '{}' "
166 "and undecomposed parameter '{}': {:.6e}", i, j, corr_val);
171 if (found_significant_correlation) {
172 MACH3LOG_ERROR(
"There are correlations between undecomposed and decomposed part of matrices, this will not work");
183 #pragma omp parallel for
195 const double GlobalStepScale,
201 #pragma omp parallel for
203 for (
int i = 0; i < NumParPCA; ++i)
205 if (_fErrorPCA[i] > 0.)
207 double IndStepScale = 1.;
209 if(isDecomposedPCA[i] >= 0)
211 IndStepScale *= IndivStepScale[isDecomposedPCA[i]];
212 IndStepScale *= corr_throw[isDecomposedPCA[i]];
217 IndStepScale *= randParams[i];
219 IndStepScale *= IndivStepScale[FirstPCAdpar];
221 _fParPropPCA(i) = _fParCurrPCA(i)+GlobalStepScale*IndStepScale*eigen_values_master[i];
233 TVectorD fParCurr_vec(
static_cast<Int_t
>(
_pCurrVal->size()));
234 TVectorD fParProp_vec(
static_cast<Int_t
>(
_pCurrVal->size()));
235 for(
int i = 0; i < static_cast<int>(
_pCurrVal->size()); ++i) {
236 fParCurr_vec(i) = (*_pCurrVal)[i];
237 fParProp_vec(i) = (*_pPropVal)[i];
261 #pragma omp parallel for
263 for(
int i = 0; i < static_cast<int>(
_pCurrVal->size()); ++i) {
264 (*_pPropVal)[i] = fParProp_vec(i);
265 (*_pCurrVal)[i] = fParCurr_vec(i);
282 tree.Branch(Form(
"%s_PCA", Names[i].c_str()), &
_fParCurrPCA.GetMatrixArray()[i], Form(
"%s_PCA/D", Names[i].c_str()));
288 tree.Branch(Form(
"%s_PCA_Prop", Names[i].c_str()), &
_fParPropPCA.GetMatrixArray()[i], Form(
"%s_PCA_Prop/D", Names[i].c_str()));
307 MACH3LOG_ERROR(
"Parameter {} is PCA decomposed can't fix this", Names[i]);
312 else MACH3LOG_INFO(
"Setting un-decomposed {}(parameter {}/{} in PCA base) free", Names[i], i, isDecom);
319 double** throwMatrixCholDecomp,
322 const std::vector<double>& fPreFitValue,
323 const std::vector<double>& fLowBound,
324 const std::vector<double>& fUpBound,
325 const int _fNumPar) {
334 (*_pPropVal)[i] = fPreFitValue[i] + corr_throw[i];
340 (*_pPropVal)[i] = fPreFitValue[i] + corr_throw_single;
345 MACH3LOG_WARN(
"Tried {} times to throw parameter {} but failed",
throws, i);
348 (*_pPropVal)[i] = fPreFitValue[i];
352 (*_pCurrVal)[i] = (*_pPropVal)[i];
362 for (
int i = 0; i < _fNumPar; ++i) {
363 (*_pPropVal)[i] = std::max(fLowBound[i], std::min((*
_pPropVal)[i], fUpBound[i]));
364 (*_pCurrVal)[i] = (*_pPropVal)[i];
369 #pragma GCC diagnostic ignored "-Wfloat-conversion"
372 void PCAHandler::DebugPCA(
const double sum, TMatrixD temp, TMatrixDSym submat,
int NumPar) {
374 int originalErrorWarning = gErrorIgnoreLevel;
375 gErrorIgnoreLevel = kFatal;
382 TFile *PCA_Debug =
new TFile(
"Debug_PCA.root",
"RECREATE");
385 bool PlotText =
true;
387 if(NumPar > 200) PlotText =
false;
389 auto heigen_values = std::make_unique<TH1D>(
"eigen_values",
"Eigen Values",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
390 heigen_values->SetDirectory(
nullptr);
391 auto heigen_cumulative = std::make_unique<TH1D>(
"heigen_cumulative",
"heigen_cumulative",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
392 heigen_cumulative->SetDirectory(
nullptr);
393 auto heigen_frac = std::make_unique<TH1D>(
"heigen_fractional",
"heigen_fractional",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
394 heigen_frac->SetDirectory(
nullptr);
395 heigen_values->GetXaxis()->SetTitle(
"Eigen Vector");
396 heigen_values->GetYaxis()->SetTitle(
"Eigen Value");
398 double Cumulative = 0;
402 heigen_cumulative->SetBinContent(i+1, (
eigen_values)(i)/sum + Cumulative);
406 heigen_values->Write(
"heigen_values");
408 heigen_cumulative->Write(
"heigen_values_cumulative");
409 heigen_frac->Write(
"heigen_values_frac");
412 heigen_vectors->GetXaxis()->SetTitle(
"Parameter in Normal Base");
413 heigen_vectors->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
414 heigen_vectors->Write(
"heigen_vectors");
417 TH2D* SubsetPCA =
new TH2D(temp);
418 SubsetPCA->GetXaxis()->SetTitle(
"Parameter in Normal Base");
419 SubsetPCA->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
421 SubsetPCA->Write(
"hSubsetPCA");
422 temp.Write(
"SubsetPCA");
424 hTransferMat->GetXaxis()->SetTitle(
"Parameter in Normal Base");
425 hTransferMat->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
428 hTransferMatT->GetXaxis()->SetTitle(
"Parameter in Decomposed Base");
429 hTransferMatT->GetYaxis()->SetTitle(
"Parameter in Normal Base");
431 hTransferMat->Write(
"hTransferMat");
433 hTransferMatT->Write(
"hTransferMatT");
436 auto c1 = std::make_unique<TCanvas>(
"c1",
" ", 0, 0, 1024, 1024);
437 c1->SetBottomMargin(0.1);
438 c1->SetTopMargin(0.05);
439 c1->SetRightMargin(0.05);
440 c1->SetLeftMargin(0.12);
443 gStyle->SetPaintTextFormat(
"4.1f");
444 gStyle->SetOptFit(0);
445 gStyle->SetOptStat(0);
447 constexpr
int NRGBs = 5;
448 TColor::InitializeColors();
449 Double_t stops[NRGBs] = { 0.00, 0.25, 0.50, 0.75, 1.00 };
450 Double_t red[NRGBs] = { 0.00, 0.25, 1.00, 1.00, 0.50 };
451 Double_t green[NRGBs] = { 0.00, 0.25, 1.00, 0.25, 0.00 };
452 Double_t blue[NRGBs] = { 0.50, 1.00, 1.00, 0.25, 0.00 };
453 TColor::CreateGradientColorTable(5, stops, red, green, blue, 255);
454 gStyle->SetNumberContours(255);
459 c1->Print(
"Debug_PCA.pdf[");
461 EigenLine->SetLineColor(kPink);
462 EigenLine->SetLineWidth(2);
463 EigenLine->SetLineStyle(kSolid);
465 auto text = std::make_unique<TText>(0.5, 0.5, Form(
"Threshold = %g",
eigen_threshold));
466 text->SetTextFont (43);
467 text->SetTextSize (40);
469 heigen_values->SetLineColor(kRed);
470 heigen_values->SetLineWidth(2);
471 heigen_cumulative->SetLineColor(kGreen);
472 heigen_cumulative->SetLineWidth(2);
473 heigen_frac->SetLineColor(kBlue);
474 heigen_frac->SetLineWidth(2);
477 heigen_values->SetMaximum(heigen_cumulative->GetMaximum()+heigen_cumulative->GetMaximum()*0.4);
478 heigen_values->Draw();
479 heigen_frac->Draw(
"SAME");
480 heigen_cumulative->Draw(
"SAME");
481 EigenLine->Draw(
"Same");
484 auto leg = std::make_unique<TLegend>(0.2, 0.2, 0.6, 0.5);
485 leg->SetTextSize(0.04);
486 leg->AddEntry(heigen_values.get(),
"Absolute",
"l");
487 leg->AddEntry(heigen_frac.get(),
"Fractional",
"l");
488 leg->AddEntry(heigen_cumulative.get(),
"Cumulative",
"l");
490 leg->SetLineColor(0);
491 leg->SetLineStyle(0);
492 leg->SetFillColor(0);
493 leg->SetFillStyle(0);
496 c1->Print(
"Debug_PCA.pdf");
497 c1->SetRightMargin(0.15);
500 heigen_vectors->SetMarkerSize(0.2);
501 minz = heigen_vectors->GetMinimum();
502 if (fabs(0-maxz)>fabs(0-minz)) heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
503 else heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
504 if(PlotText) heigen_vectors->Draw(
"COLZ TEXT");
505 else heigen_vectors->Draw(
"COLZ");
508 Eigen_Line->SetLineColor(kGreen);
509 Eigen_Line->SetLineWidth(2);
510 Eigen_Line->SetLineStyle(kDotted);
511 Eigen_Line->Draw(
"SAME");
512 c1->Print(
"Debug_PCA.pdf");
514 SubsetPCA->SetMarkerSize(0.2);
515 minz = SubsetPCA->GetMinimum();
516 if (fabs(0-maxz)>fabs(0-minz)) SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
517 else SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
518 if(PlotText) SubsetPCA->Draw(
"COLZ TEXT");
519 else SubsetPCA->Draw(
"COLZ");
520 c1->Print(
"Debug_PCA.pdf");
523 hTransferMat->SetMarkerSize(0.15);
524 minz = hTransferMat->GetMinimum();
525 if (fabs(0-maxz)>fabs(0-minz)) hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
526 else hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
527 if(PlotText) hTransferMat->Draw(
"COLZ TEXT");
528 else hTransferMat->Draw(
"COLZ");
529 c1->Print(
"Debug_PCA.pdf");
532 hTransferMatT->SetMarkerSize(0.15);
533 minz = hTransferMatT->GetMinimum();
534 if (fabs(0-maxz)>fabs(0-minz)) hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
535 else hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
536 if(PlotText) hTransferMatT->Draw(
"COLZ TEXT");
537 else hTransferMatT->Draw(
"COLZ");
538 c1->Print(
"Debug_PCA.pdf");
539 delete hTransferMatT;
544 Eigen::MatrixXd Submat_Eigen(submat.GetNrows(), submat.GetNcols());
547 #pragma omp parallel for
549 for(
int i = 0; i < submat.GetNrows(); i++)
551 for(
int j = 0; j < submat.GetNcols(); j++)
553 Submat_Eigen(i,j) = (submat)(i,j);
556 Eigen::EigenSolver<Eigen::MatrixXd> EigenSolver;
557 EigenSolver.compute(Submat_Eigen);
558 Eigen::VectorXd eigen_val = EigenSolver.eigenvalues().real();
559 Eigen::MatrixXd eigen_vect = EigenSolver.eigenvectors().real();
560 std::vector<std::tuple<double, Eigen::VectorXd>> eigen_vectors_and_values;
561 double Sum_Eigen = 0;
562 for(
int i = 0; i < eigen_val.size(); i++)
564 std::tuple<double, Eigen::VectorXd> vec_and_val(eigen_val[i], eigen_vect.row(i));
565 eigen_vectors_and_values.push_back(vec_and_val);
566 Sum_Eigen += eigen_val[i];
568 std::sort(eigen_vectors_and_values.begin(), eigen_vectors_and_values.end(),
569 [&](
const std::tuple<double, Eigen::VectorXd>& a,
const std::tuple<double, Eigen::VectorXd>& b) ->
bool
570 { return std::get<0>(a) > std::get<0>(b); } );
572 for(
auto const vect : eigen_vectors_and_values)
574 eigen_val(index) = std::get<0>(vect);
575 eigen_vect.row(index) = std::get<1>(vect);
578 TH1D* heigen_values_Eigen =
new TH1D(
"eig_values",
"Eigen Values", eigen_val.size(), 0.0, eigen_val.size());
579 TH1D* heigen_cumulative_Eigen =
new TH1D(
"eig_cumulative",
"heigen_cumulative", eigen_val.size(), 0.0, eigen_val.size());
580 TH1D* heigen_frac_Eigen =
new TH1D(
"eig_fractional",
"heigen_fractional", eigen_val.size(), 0.0, eigen_val.size());
581 heigen_values_Eigen->GetXaxis()->SetTitle(
"Eigen Vector");
582 heigen_values_Eigen->GetYaxis()->SetTitle(
"Eigen Value");
584 double Cumulative_Eigen = 0;
585 for(
int i = 0; i < eigen_val.size(); i++)
587 heigen_values_Eigen->SetBinContent(i+1, eigen_val(i));
588 heigen_cumulative_Eigen->SetBinContent(i+1, eigen_val(i)/sum + Cumulative_Eigen);
589 heigen_frac_Eigen->SetBinContent(i+1, eigen_val(i)/sum);
590 Cumulative_Eigen += eigen_val(i)/sum;
592 heigen_values_Eigen->SetLineColor(kRed);
593 heigen_values_Eigen->SetLineWidth(2);
594 heigen_cumulative_Eigen->SetLineColor(kGreen);
595 heigen_cumulative_Eigen->SetLineWidth(2);
596 heigen_frac_Eigen->SetLineColor(kBlue);
597 heigen_frac_Eigen->SetLineWidth(2);
600 heigen_values_Eigen->SetMaximum(heigen_cumulative_Eigen->GetMaximum()+heigen_cumulative_Eigen->GetMaximum()*0.4);
601 heigen_values_Eigen->Draw();
602 heigen_cumulative_Eigen->Draw(
"SAME");
603 heigen_frac_Eigen->Draw(
"SAME");
605 auto leg_Eigen = std::make_unique<TLegend>(0.2, 0.2, 0.6, 0.5);
606 leg_Eigen->SetTextSize(0.04);
607 leg_Eigen->AddEntry(heigen_values_Eigen,
"Absolute",
"l");
608 leg_Eigen->AddEntry(heigen_frac_Eigen,
"Fractional",
"l");
609 leg_Eigen->AddEntry(heigen_cumulative_Eigen,
"Cumulative",
"l");
611 leg_Eigen->SetLineColor(0);
612 leg_Eigen->SetLineStyle(0);
613 leg_Eigen->SetFillColor(0);
614 leg_Eigen->SetFillStyle(0);
615 leg_Eigen->Draw(
"Same");
617 c1->Print(
"Debug_PCA.pdf");
619 delete heigen_values_Eigen;
620 delete heigen_cumulative_Eigen;
621 delete heigen_frac_Eigen;
623 TH2D* heigen_vectors_Eigen =
new TH2D(
"Eigen_Vectors",
"Eigen_Vectors", eigen_val.size(), 0.0, eigen_val.size(), eigen_val.size(), 0.0, eigen_val.size());
625 for(
int i = 0; i < eigen_val.size(); i++)
627 for(
int j = 0; j < eigen_val.size(); j++)
630 heigen_vectors_Eigen->SetBinContent(i+1,j+1, eigen_vect(i,j));
633 heigen_vectors_Eigen->GetXaxis()->SetTitle(
"Parameter in Normal Base");
634 heigen_vectors_Eigen->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
635 heigen_vectors_Eigen->SetMarkerSize(0.15);
636 minz = heigen_vectors_Eigen->GetMinimum();
637 if (fabs(0-maxz)>fabs(0-minz)) heigen_vectors_Eigen->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
638 else heigen_vectors_Eigen->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
640 if(PlotText) heigen_vectors_Eigen->Draw(
"COLZ TEXT");
641 else heigen_vectors_Eigen->Draw(
"COLZ");
642 c1->Print(
"Debug_PCA.pdf");
644 heigen_vectors->SetTitle(
"ROOT minus Eigen");
645 heigen_vectors->Add(heigen_vectors_Eigen, -1.);
646 minz = heigen_vectors->GetMinimum();
647 if (fabs(0-maxz)>fabs(0-minz)) heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
648 else heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
649 if(PlotText) heigen_vectors->Draw(
"COLZ TEXT");
650 else heigen_vectors->Draw(
"COLZ");
651 c1->Print(
"Debug_PCA.pdf");
652 delete heigen_vectors_Eigen;
655 delete heigen_vectors;
657 c1->Print(
"Debug_PCA.pdf]");
660 gErrorIgnoreLevel = originalErrorWarning;
#define _noexcept_
KS: noexcept can help with performance but is terrible for debugging, this is meant to help easy way ...
#define _restrict_
KS: Using restrict limits the effects of pointer aliasing, aiding optimizations. While reading I foun...
Custom exception class used throughout MaCh3.
std::vector< int > isDecomposedPCA
If param is decomposed this will return -1, if not this will return enumerator to param in normal bas...
void ThrowParameters(const std::vector< std::unique_ptr< TRandom3 >> &random_number, double **throwMatrixCholDecomp, double *randParams, double *corr_throw, const std::vector< double > &fPreFitValue, const std::vector< double > &fLowBound, const std::vector< double > &fUpBound, int _fNumPar)
Throw the parameters according to the covariance matrix. This shouldn't be used in MCMC code ase it c...
void ToggleFixAllParameters(const std::vector< std::string > &Names)
fix parameters at prior values
TMatrixD TransferMat
Matrix used to converting from PCA base to normal base.
std::vector< double > eigen_values_master
Eigen values which have dimension equal to _fNumParPCA, and can be used in CorrelateSteps.
void SetBranches(TTree &tree, const bool SaveProposal, const std::vector< std::string > &Names)
set branches for output file
TMatrixD eigen_vectors
Eigen vectors only of params which are being decomposed.
TVectorD _fParPropPCA
CW: Current parameter value in PCA base.
bool IsParameterFixedPCA(const int i) const
Is parameter fixed in PCA base or not.
double GetParPropPCA(const int i) const
Get current parameter value using PCA.
int NumParPCA
Number of parameters in PCA base.
void SetInitialParameters()
KS: Transfer the starting parameters to the PCA basis, you don't want to start with zero....
std::vector< double > * _pCurrVal
Pointer to current value of the parameter.
TMatrixD TransferMatT
Matrix used to converting from normal base to PCA base.
void AcceptStep() _noexcept_
Accepted this step.
void CorrelateSteps(const std::vector< double > &IndivStepScale, const double GlobalStepScale, const double *_restrict_ randParams, const double *_restrict_ corr_throw) _noexcept_
Use Cholesky throw matrix for better step proposal.
void SetParPropPCA(const int i, const double value)
Set proposed value for parameter in PCA base.
void TransferToPCA()
Transfer param values from normal base to PCA base.
virtual ~PCAHandler()
Destructor.
void SetupPointers(std::vector< double > *fCurr_Val, std::vector< double > *fProp_Val)
KS: Setup pointers to current and proposed parameter value which we need to convert them to PCA base ...
double GetPreFitValuePCA(const int i) const
Get current parameter value using PCA.
std::vector< double > * _pPropVal
Pointer to proposed value of the parameter.
bool IsParameterDecomposed(const int i) const
Check if parameter in PCA base is decomposed or not.
TVectorD eigen_values
Eigen value only of particles which are being decomposed.
void TransferToParam()
Transfer param values from PCA base to normal base.
int LastPCAdpar
Index of the last param that is being decomposed.
int nKeptPCApars
Total number that remained after applying PCA Threshold.
std::vector< double > _fErrorPCA
Tells if parameter is fixed in PCA base or not.
std::vector< double > _fPreFitValuePCA
Prefit value for PCA params.
void ToggleFixParameter(const int i, const std::vector< std::string > &Names)
fix parameters at prior values
void SetParCurrPCA(const int i, const double value)
Set current value for parameter in PCA base.
void Print() const
KS: Print info about PCA parameters.
TVectorD _fParCurrPCA
CW: Proposed parameter value in PCA base.
void SanitisePCA(TMatrixDSym *CovMatrix)
KS: Make sure decomposed matrix isn't correlated with undecomposed.
void ConstructPCA(TMatrixDSym *CovMatrix, const int firstPCAd, const int lastPCAd, const double eigen_thresh, const int _fNumPar)
CW: Calculate eigen values, prepare transition matrices and remove param based on defined threshold.
int FirstPCAdpar
Index of the first param that is being decomposed.
double eigen_threshold
CW: Threshold based on which we remove parameters in eigen base.
int GetThreadIndex()
thread index inside parallel loop
double MatrixVectorMultiSingle(double **_restrict_ matrix, const double *_restrict_ vector, const int Length, const int i)
KS: Custom function to perform multiplication of matrix and single element which is thread safe.