30 std::vector<M3::float_t>* fProp_Val) {
38 const double eigen_thresh,
const int _fNumPar) {
45 if (CovMatrix ==
nullptr) {
52 MACH3LOG_ERROR(
"FirstPCAdpar and LastPCAdpar are higher than the number of parameters");
57 MACH3LOG_ERROR(
"FirstPCAdpar and LastPCAdpar are less than 0 but not default -999");
70 TMatrixDSymEigen eigen(submat);
107 temp2.ResizeTo(CovMatrix->GetNrows(),
NumParPCA);
114 temp2(iRow, iRow) = 1.0;
122 for(
int iRow = 0;iRow < (CovMatrix->GetNrows()-1)-
LastPCAdpar; iRow++) {
125 temp2(OrigRow, PCARow) = 1.;
154 #ifdef MACH3_DEBUG_PCA
156 DebugPCA(sum, temp, CovMatrix->GetNrows());
164 constexpr
double correlation_threshold = 1e-6;
166 bool found_significant_correlation =
false;
168 int N = CovMatrix->GetNrows();
170 for (
int j = 0; j < N; ++j) {
174 double corr_val = (*CovMatrix)(i, j);
175 if (std::fabs(corr_val) > correlation_threshold) {
176 found_significant_correlation =
true;
177 MACH3LOG_ERROR(
"Significant correlation detected between decomposed parameter '{}' "
178 "and undecomposed parameter '{}': {:.6e}", i, j, corr_val);
183 if (found_significant_correlation) {
184 MACH3LOG_ERROR(
"There are correlations between undecomposed and decomposed part of matrices, this will not work");
195 #pragma omp parallel for
207 const double GlobalStepScale,
213 #pragma omp parallel for
215 for (
int i = 0; i < NumParPCA; ++i)
217 if (_fErrorPCA[i] > 0.)
219 double IndStepScale = 1.;
221 if(isDecomposedPCA[i] >= 0)
223 IndStepScale *= IndivStepScale[isDecomposedPCA[i]];
224 IndStepScale *= corr_throw[isDecomposedPCA[i]];
229 IndStepScale *= randParams[i];
231 IndStepScale *= IndivStepScale[FirstPCAdpar];
233 _fParPropPCA(i) = _fParCurrPCA(i)+GlobalStepScale*IndStepScale*eigen_values_master[i];
245 TVectorD fParCurr_vec(
static_cast<Int_t
>(
_pCurrVal->size()));
246 TVectorD fParProp_vec(
static_cast<Int_t
>(
_pCurrVal->size()));
247 for(
int i = 0; i < static_cast<int>(
_pCurrVal->size()); ++i) {
248 fParCurr_vec(i) = (*_pCurrVal)[i];
249 fParProp_vec(i) = (*_pPropVal)[i];
269 #pragma GCC diagnostic push
270 #pragma GCC diagnostic ignored "-Wuseless-cast"
275 #pragma omp parallel for
277 for(
int i = 0; i < static_cast<int>(
_pCurrVal->size()); ++i) {
278 (*_pPropVal)[i] =
static_cast<M3::float_t>(fParProp_vec(i));
279 (*_pCurrVal)[i] = fParCurr_vec(i);
281 #pragma GCC diagnostic pop
297 tree.Branch(Form(
"%s_PCA", Names[i].c_str()), &
_fParCurrPCA.GetMatrixArray()[i], Form(
"%s_PCA/D", Names[i].c_str()));
303 tree.Branch(Form(
"%s_PCA_Prop", Names[i].c_str()), &
_fParPropPCA.GetMatrixArray()[i], Form(
"%s_PCA_Prop/D", Names[i].c_str()));
322 MACH3LOG_ERROR(
"Parameter {} is PCA decomposed can't fix this", Names[i]);
327 else MACH3LOG_INFO(
"Setting un-decomposed {}(parameter {}/{} in PCA base) free", Names[i], i, isDecom);
334 double** throwMatrixCholDecomp,
337 const std::vector<double>& fPreFitValue,
338 const std::vector<double>& fLowBound,
339 const std::vector<double>& fUpBound,
340 const int _fNumPar) {
342 #pragma GCC diagnostic push
343 #pragma GCC diagnostic ignored "-Wuseless-cast"
351 (*_pPropVal)[i] =
static_cast<M3::float_t>(fPreFitValue[i] + corr_throw[i]);
354 while ((*
_pPropVal)[i] > fUpBound[i] || (*_pPropVal)[i] < fLowBound[i]) {
357 (*_pPropVal)[i] =
static_cast<M3::float_t>(fPreFitValue[i] + corr_throw_single);
362 MACH3LOG_WARN(
"Tried {} times to throw parameter {} but failed",
throws, i);
365 (*_pPropVal)[i] =
static_cast<M3::float_t>(fPreFitValue[i]);
369 (*_pCurrVal)[i] = (*_pPropVal)[i];
379 for (
int i = 0; i < _fNumPar; ++i) {
382 (*_pPropVal)[i] = std::max(up, std::min((*
_pPropVal)[i], low));
383 (*_pCurrVal)[i] = (*_pPropVal)[i];
385 #pragma GCC diagnostic pop
389 #pragma GCC diagnostic ignored "-Wfloat-conversion"
392 void PCAHandler::DebugPCA(
const double sum, TMatrixD temp,
int NumPar) {
394 int originalErrorWarning = gErrorIgnoreLevel;
395 gErrorIgnoreLevel = kFatal;
401 TFile *PCA_Debug =
new TFile(
"Debug_PCA.root",
"RECREATE");
404 bool PlotText =
true;
406 if(NumPar > 200) PlotText =
false;
408 auto heigen_values = std::make_unique<TH1D>(
"eigen_values",
"Eigen Values",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
409 heigen_values->SetDirectory(
nullptr);
410 auto heigen_cumulative = std::make_unique<TH1D>(
"heigen_cumulative",
"heigen_cumulative",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
411 heigen_cumulative->SetDirectory(
nullptr);
412 auto heigen_frac = std::make_unique<TH1D>(
"heigen_fractional",
"heigen_fractional",
eigen_values.GetNrows(), 0.0,
eigen_values.GetNrows());
413 heigen_frac->SetDirectory(
nullptr);
414 heigen_values->GetXaxis()->SetTitle(
"Eigen Vector");
415 heigen_values->GetYaxis()->SetTitle(
"Eigen Value");
417 double Cumulative = 0;
421 heigen_cumulative->SetBinContent(i+1, (
eigen_values)(i)/sum + Cumulative);
425 heigen_values->Write(
"heigen_values");
427 heigen_cumulative->Write(
"heigen_values_cumulative");
428 heigen_frac->Write(
"heigen_values_frac");
431 heigen_vectors->GetXaxis()->SetTitle(
"Parameter in Normal Base");
432 heigen_vectors->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
433 heigen_vectors->Write(
"heigen_vectors");
436 TH2D* SubsetPCA =
new TH2D(temp);
437 SubsetPCA->GetXaxis()->SetTitle(
"Parameter in Normal Base");
438 SubsetPCA->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
440 SubsetPCA->Write(
"hSubsetPCA");
441 temp.Write(
"SubsetPCA");
443 hTransferMat->GetXaxis()->SetTitle(
"Parameter in Normal Base");
444 hTransferMat->GetYaxis()->SetTitle(
"Parameter in Decomposed Base");
447 hTransferMatT->GetXaxis()->SetTitle(
"Parameter in Decomposed Base");
448 hTransferMatT->GetYaxis()->SetTitle(
"Parameter in Normal Base");
450 hTransferMat->Write(
"hTransferMat");
452 hTransferMatT->Write(
"hTransferMatT");
455 auto c1 = std::make_unique<TCanvas>(
"c1",
" ", 0, 0, 1024, 1024);
456 c1->SetBottomMargin(0.1);
457 c1->SetTopMargin(0.05);
458 c1->SetRightMargin(0.05);
459 c1->SetLeftMargin(0.12);
462 gStyle->SetPaintTextFormat(
"4.1f");
463 gStyle->SetOptFit(0);
464 gStyle->SetOptStat(0);
466 constexpr
int NRGBs = 5;
467 TColor::InitializeColors();
468 Double_t stops[NRGBs] = { 0.00, 0.25, 0.50, 0.75, 1.00 };
469 Double_t red[NRGBs] = { 0.00, 0.25, 1.00, 1.00, 0.50 };
470 Double_t green[NRGBs] = { 0.00, 0.25, 1.00, 0.25, 0.00 };
471 Double_t blue[NRGBs] = { 0.50, 1.00, 1.00, 0.25, 0.00 };
472 TColor::CreateGradientColorTable(5, stops, red, green, blue, 255);
473 gStyle->SetNumberContours(255);
478 c1->Print(
"Debug_PCA.pdf[");
480 EigenLine->SetLineColor(kPink);
481 EigenLine->SetLineWidth(2);
482 EigenLine->SetLineStyle(kSolid);
484 auto text = std::make_unique<TText>(0.5, 0.5, Form(
"Threshold = %g",
eigen_threshold));
485 text->SetTextFont (43);
486 text->SetTextSize (40);
488 heigen_values->SetLineColor(kRed);
489 heigen_values->SetLineWidth(2);
490 heigen_cumulative->SetLineColor(kGreen);
491 heigen_cumulative->SetLineWidth(2);
492 heigen_frac->SetLineColor(kBlue);
493 heigen_frac->SetLineWidth(2);
496 heigen_values->SetMaximum(heigen_cumulative->GetMaximum()+heigen_cumulative->GetMaximum()*0.4);
497 heigen_values->Draw();
498 heigen_frac->Draw(
"SAME");
499 heigen_cumulative->Draw(
"SAME");
500 EigenLine->Draw(
"Same");
503 auto leg = std::make_unique<TLegend>(0.2, 0.2, 0.6, 0.5);
504 leg->SetTextSize(0.04);
505 leg->AddEntry(heigen_values.get(),
"Absolute",
"l");
506 leg->AddEntry(heigen_frac.get(),
"Fractional",
"l");
507 leg->AddEntry(heigen_cumulative.get(),
"Cumulative",
"l");
509 leg->SetLineColor(0);
510 leg->SetLineStyle(0);
511 leg->SetFillColor(0);
512 leg->SetFillStyle(0);
515 c1->Print(
"Debug_PCA.pdf");
516 c1->SetRightMargin(0.15);
519 heigen_vectors->SetMarkerSize(0.2);
520 minz = heigen_vectors->GetMinimum();
521 if (fabs(0-maxz)>fabs(0-minz)) heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
522 else heigen_vectors->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
523 if(PlotText) heigen_vectors->Draw(
"COLZ TEXT");
524 else heigen_vectors->Draw(
"COLZ");
527 Eigen_Line->SetLineColor(kGreen);
528 Eigen_Line->SetLineWidth(2);
529 Eigen_Line->SetLineStyle(kDotted);
530 Eigen_Line->Draw(
"SAME");
531 c1->Print(
"Debug_PCA.pdf");
533 SubsetPCA->SetMarkerSize(0.2);
534 minz = SubsetPCA->GetMinimum();
535 if (fabs(0-maxz)>fabs(0-minz)) SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
536 else SubsetPCA->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
537 if(PlotText) SubsetPCA->Draw(
"COLZ TEXT");
538 else SubsetPCA->Draw(
"COLZ");
539 c1->Print(
"Debug_PCA.pdf");
542 hTransferMat->SetMarkerSize(0.15);
543 minz = hTransferMat->GetMinimum();
544 if (fabs(0-maxz)>fabs(0-minz)) hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
545 else hTransferMat->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
546 if(PlotText) hTransferMat->Draw(
"COLZ TEXT");
547 else hTransferMat->Draw(
"COLZ");
548 c1->Print(
"Debug_PCA.pdf");
551 hTransferMatT->SetMarkerSize(0.15);
552 minz = hTransferMatT->GetMinimum();
553 if (fabs(0-maxz)>fabs(0-minz)) hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-maxz),0+fabs(0-maxz));
554 else hTransferMatT->GetZaxis()->SetRangeUser(0-fabs(0-minz),0+fabs(0-minz));
555 if(PlotText) hTransferMatT->Draw(
"COLZ TEXT");
556 else hTransferMatT->Draw(
"COLZ");
557 c1->Print(
"Debug_PCA.pdf");
558 delete hTransferMatT;
560 delete heigen_vectors;
562 c1->Print(
"Debug_PCA.pdf]");
565 gErrorIgnoreLevel = originalErrorWarning;
#define _noexcept_
KS: noexcept can help with performance but is terrible for debugging, this is meant to help easy way ...
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
#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.
void SetupPointers(std::vector< double > *fCurr_Val, std::vector< M3::float_t > *fProp_Val)
KS: Setup pointers to current and proposed parameter value which we need to convert them to PCA base ...
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< M3::float_t > * _pPropVal
Pointer to proposed value of the parameter.
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.
double GetPreFitValuePCA(const int i) const
Get current parameter value using PCA.
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.