59 void ReweightMCMC(
const std::string& inputFile,
const std::string& configFile);
74 double& mean,
double& sigma);
77 void LoadReweightingSettings(std::vector<ReweightConfig>& reweightConfigs,
const YAML::Node& reweight_settings);
80 int main(
int argc,
char *argv[])
85 MACH3LOG_ERROR(
"How to use: {} <config.yaml> <input_file.root>", argv[0]);
89 std::string configFile = argv[1];
90 std::string inputFile = argv[2];
99 for (
const auto& reweight : reweight_settings) {
100 const std::string& reweightKey = reweight.first.as<std::string>();
101 const YAML::Node& reweightConfigNode = reweight.second;
104 if (!GetFromManager<bool>(reweightConfigNode[
"Enabled"],
true)) {
105 MACH3LOG_INFO(
"Skipping disabled reweight: {}", reweightKey);
110 reweightConfig.
key = reweightKey;
111 reweightConfig.
name = GetFromManager<std::string>(reweightConfigNode[
"ReweightName"], reweightKey);
112 reweightConfig.
type = GetFromManager<std::string>(reweightConfigNode[
"ReweightType"],
"Gaussian");
113 reweightConfig.
dimension = GetFromManager<int>(reweightConfigNode[
"ReweightDim"], 1);
120 if (reweightConfig.
type ==
"Gaussian") {
122 auto paramNames = GetFromManager<std::vector<std::string>>(reweightConfigNode[
"ReweightVar"], {});
125 auto priorNode = reweightConfigNode[
"ReweightPrior"];
126 std::vector<std::vector<double>> allPriorValues;
128 if (priorNode.IsSequence() && priorNode.size() > 0) {
130 if (priorNode[0].IsScalar()) {
132 auto priorValues = GetFromManager<std::vector<double>>(priorNode, {});
133 if (priorValues.size() == 2) {
134 allPriorValues.push_back(priorValues);
138 for (
const auto& priorPair : priorNode) {
139 auto priorValues = GetFromManager<std::vector<double>>(priorPair, {});
140 if (priorValues.size() == 2) {
141 allPriorValues.push_back(priorValues);
150 if (paramNames.empty() || allPriorValues.empty() || paramNames.size() != allPriorValues.size()) {
151 MACH3LOG_ERROR(
"Invalid Gaussian reweight configuration for {}: {} parameters, {} prior pairs",
152 reweightKey, paramNames.size(), allPriorValues.size());
155 }
else if (reweightConfig.
type ==
"TGraph") {
157 auto paramNames = GetFromManager<std::vector<std::string>>(reweightConfigNode[
"ReweightVar"], {});
158 std::string fileName = GetFromManager<std::string>(reweightConfigNode[
"ReweightPrior"][
"file"],
"");
159 std::string graphName = GetFromManager<std::string>(reweightConfigNode[
"ReweightPrior"][
"graph_name"],
"");
164 if (paramNames.empty() || paramNames.size() != 1 || fileName.empty() || graphName.empty()) {
165 MACH3LOG_ERROR(
"Invalid TGraph reweight configuration for {}", reweightKey);
171 auto constraintFile = std::unique_ptr<TFile>(
TFile::Open(reweightConfig.
fileName.c_str(),
"READ"));
172 if (!constraintFile || constraintFile->IsZombie()) {
177 std::unique_ptr<TGraph> graph(constraintFile->Get<TGraph>(reweightConfig.
graphName.c_str()));
180 auto cloned_graph =
static_cast<TGraph*
>(graph->Clone());
181 cloned_graph->SetBit(kCanDelete,
true);
182 reweightConfig.
graph_1D = std::unique_ptr<TGraph>(cloned_graph);
189 MACH3LOG_ERROR(
"Unknown 1D reweight type: {} for {}", reweightConfig.
type, reweightKey);
193 }
else if (reweightConfig.
dimension == 2) {
194 auto paramNames = GetFromManager<std::vector<std::string>>(reweightConfigNode[
"ReweightVar"], {});
197 if (paramNames.size() != 2) {
198 MACH3LOG_ERROR(
"2D reweighting requires exactly 2 parameter names for {}", reweightKey);
204 if (reweightConfig.
type ==
"TGraph2D") {
205 auto priorConfig = reweightConfigNode[
"ReweightPrior"];
206 reweightConfig.
fileName = GetFromManager<std::string>(priorConfig[
"file"],
"");
207 reweightConfig.
graphName = GetFromManager<std::string>(priorConfig[
"graph_name"],
"");
208 reweightConfig.
hierarchyType = GetFromManager<std::string>(priorConfig[
"hierarchy"],
"auto");
211 MACH3LOG_ERROR(
"Invalid TGraph2D configuration for {}", reweightKey);
217 auto constraintFile = std::unique_ptr<TFile>(
TFile::Open(reweightConfig.
fileName.c_str(),
"READ"));
218 if (!constraintFile || constraintFile->IsZombie()) {
225 std::string graphName_NO = reweightConfig.
graphName +
"_NO";
228 std::unique_ptr<TGraph2D> graph_NO(constraintFile->Get<TGraph2D>(graphName_NO.c_str()));
231 auto cloned_graph =
static_cast<TGraph2D*
>(graph_NO->Clone());
232 cloned_graph->SetDirectory(
nullptr);
233 cloned_graph->SetBit(kCanDelete,
true);
234 reweightConfig.
graph_NO = std::unique_ptr<TGraph2D>(cloned_graph);
242 std::string graphName_IO = reweightConfig.
graphName +
"_IO";
244 std::unique_ptr<TGraph2D> graph_IO(constraintFile->Get<TGraph2D>(graphName_IO.c_str()));
247 auto cloned_graph =
static_cast<TGraph2D*
>(graph_IO->Clone());
248 cloned_graph->SetDirectory(
nullptr);
249 cloned_graph->SetBit(kCanDelete,
true);
250 reweightConfig.
graph_IO = std::unique_ptr<TGraph2D>(cloned_graph);
257 constraintFile->Close();
259 MACH3LOG_ERROR(
"Unknown 2D reweight type: {} for {}", reweightConfig.
type, reweightKey);
267 reweightConfigs.push_back(std::move(reweightConfig));
268 MACH3LOG_INFO(
"Added reweight configuration: {} ({}D, type: {})", reweightConfigs.back().name, reweightConfigs.back().dimension, reweightConfigs.back().type);
271 if (reweightConfigs.empty()) {
272 MACH3LOG_ERROR(
"No valid reweight configurations found in config file");
274 }
else if (reweightConfigs.size() > 1) {
275 MACH3LOG_ERROR(
"Currently only one reweight configuration is supported at a time, found {}", reweight_settings.size());
280 void ReweightMCMC(
const std::string& configFile,
const std::string& inputFile)
282 MACH3LOG_INFO(
"File for reweighting: {} with config {}", inputFile, configFile);
285 YAML::Node reweight_settings = reweight_yaml[
"ReweightMCMC"];
288 std::vector<ReweightConfig> reweightConfigs;
293 auto processor = std::make_unique<MCMCProcessor>(inputFile);
294 processor->Initialise();
298 for (
const auto& rwConfig : reweightConfigs) {
299 for (
const auto& paramName : rwConfig.paramNames) {
300 int paramIndex = processor->GetParamIndexFromName(paramName);
302 MACH3LOG_ERROR(
"Parameter {} not found in MCMC chain", paramName);
311 auto TempFile = std::unique_ptr<TFile>(
TFile::Open(inputFile.c_str(),
"READ"));
312 if (!TempFile || TempFile->IsZombie()) {
316 std::unique_ptr<TMacro> Config(TempFile->Get<TMacro>(
"MaCh3_Config"));
318 MACH3LOG_ERROR(
"Didn't find MaCh3_Config tree in MCMC file! {}", inputFile.c_str());
324 bool asimovfit = GetFromManager<bool>(Settings[
"General"][
"Asimov"],
false);
327 MACH3LOG_WARN(
"ReweightMCMC does not currently handle Asimov shifting, results may be incorrect!");
329 MACH3LOG_INFO(
"Not an Asimov fit, proceeding with reweighting");
333 auto inFile = std::unique_ptr<TFile>(
TFile::Open(inputFile.c_str(),
"READ"));
334 if (!inFile || inFile->IsZombie()) {
339 std::unique_ptr<TTree> inTree(inFile->Get<TTree>(
"posteriors"));
346 std::string configString = configFile.substr(configFile.find_last_of(
'/') + 1, configFile.find_last_of(
'.') - configFile.find_last_of(
'/') - 1);
347 std::string outputFile = inputFile.substr(0, inputFile.find_last_of(
'.')) +
"_reweighted_" + configString +
".root";
348 auto outFile = std::unique_ptr<TFile>(
TFile::Open(outputFile.c_str(),
"RECREATE"));
349 if (!outFile || outFile->IsZombie()) {
357 TIter next(inFile->GetListOfKeys());
358 while (TKey* key =
dynamic_cast<TKey*
>(next())) {
360 std::unique_ptr<TObject> obj(key->ReadObj());
361 if (obj->IsA()->InheritsFrom(TDirectory::Class())) {
363 TDirectory* srcDir =
static_cast<TDirectory*
>(obj.get());
364 TDirectory* destDir = outFile->mkdir(srcDir->GetName());
365 TIter nextSubKey(srcDir->GetListOfKeys());
366 while (TKey* subKey =
dynamic_cast<TKey*
>(nextSubKey())) {
368 std::unique_ptr<TObject> subObj(subKey->ReadObj());
372 }
else if (std::string(key->GetName()) !=
"posteriors") {
381 std::unique_ptr<TTree> outTree(inTree->CloneTree(0));
384 std::map<std::string, double> paramValues;
385 for (
const auto& rwConfig : reweightConfigs) {
386 for (
const auto& paramName : rwConfig.paramNames) {
387 if (paramValues.find(paramName) == paramValues.end()) {
388 paramValues[paramName] = 0.0;
389 inTree->SetBranchAddress(paramName.c_str(), ¶mValues[paramName]);
395 std::map<std::string, double> weights;
396 std::map<std::string, TBranch*> weightBranches;
398 for (
const auto& rwConfig : reweightConfigs) {
399 weights[rwConfig.weightBranchName] = 1.0;
400 weightBranches[rwConfig.weightBranchName] = outTree->Branch(
401 rwConfig.weightBranchName.c_str(),
402 &weights[rwConfig.weightBranchName],
403 (rwConfig.weightBranchName +
"/D").c_str()
405 MACH3LOG_INFO(
"Added weight branch: {}", rwConfig.weightBranchName);
408 bool processMCMCreweighted=
false;
411 for (
const auto& rwConfig : reweightConfigs){
412 if (rwConfig.dimension == 1 && rwConfig.type ==
"Gaussian"){
414 const std::vector<std::string>& paramNames = rwConfig.paramNames;
415 std::vector<double> priorCentral;
416 std::vector<double> priorSigma;
419 for (
const auto& priorPair : rwConfig.priorValues) {
420 priorCentral.push_back(priorPair[0]);
421 priorSigma.push_back(priorPair[1]);
424 processor->ReweightPrior(paramNames, priorCentral, priorSigma);
425 MACH3LOG_INFO(
"Applied Gaussian reweighting for {} parameters", paramNames.size());
426 for (
size_t i = 0; i < paramNames.size(); ++i) {
427 MACH3LOG_INFO(
" {}: mean={}, sigma={}", paramNames[i], priorCentral[i], priorSigma[i]);
429 processMCMCreweighted=
true;
434 Long64_t nEntries = inTree->GetEntries();
440 if (processMCMCreweighted) {
441 MACH3LOG_INFO(
"MCMCProcessor has reweighted, skipping duplicate reweighting");
443 for (Long64_t i = 0; i < nEntries; ++i) {
449 for (
const auto& rwConfig : reweightConfigs) {
452 if (rwConfig.dimension == 1 && rwConfig.type !=
"Gaussian") {
453 if (rwConfig.type ==
"TGraph") {
454 double paramValue = paramValues[rwConfig.paramNames[0]];
457 MACH3LOG_ERROR(
"Unsupported 1D reweight type: {} for {}", rwConfig.type, rwConfig.key);
459 }
else if (rwConfig.dimension == 2) {
460 if (rwConfig.type ==
"TGraph2D") {
461 double dm32 = paramValues[rwConfig.paramNames[0]];
462 double theta13 = paramValues[rwConfig.paramNames[1]];
465 if (rwConfig.graph_NO) {
473 if (rwConfig.graph_IO) {
482 weights[rwConfig.weightBranchName] = weight;
495 TMacro reweightMacro;
496 reweightMacro.SetName(
"Reweight_Config");
497 reweightMacro.SetTitle(
"ReweightMCMC configuration");
498 std::stringstream ss;
499 ss << reweight_settings;
500 reweightMacro.AddLine(ss.str().c_str());
501 reweightMacro.Write();
503 if (processMCMCreweighted){
504 MACH3LOG_INFO(
"MCMCProcessor reweighting applied, Final reweighted file is: {}_reweighted.root", inputFile.substr(0, inputFile.find_last_of(
'.')));
510 if (std::remove(outputFile.c_str()) != 0) {
528 double xmax = graph->GetXmax();
529 double xmin = graph->GetXmin();
530 double ymin = graph->GetYmin();
531 double ymax = graph->GetYmax();
533 double chiSquared, prior;
535 if (theta13 < xmax && theta13 > xmin && dm32 < ymax && dm32 > ymin) {
536 chiSquared = graph->Interpolate(theta13, dm32);
537 prior = std::exp(-0.5 * chiSquared);
552 double xmax = graph->GetXmax();
553 double xmin = graph->GetXmin();
554 double ymax = graph->GetYmax();
555 double ymin = graph->GetYmin();
558 double mod_dm32 = std::abs(dm32);
559 double chiSquared, prior;
561 if (theta13 < xmax && theta13 > xmin && mod_dm32 < ymax && mod_dm32 > ymin) {
562 chiSquared = graph->Interpolate(theta13, mod_dm32);
563 prior = std::exp(-0.5 * chiSquared);
579 double xmax = -999999999;
580 double xmin = 999999999;
582 for (
int i = 0; i < graph->GetN(); i++) {
583 double x = graph->GetX()[i];
584 if (x > xmax) xmax = x;
585 if (x < xmin) xmin = x;
588 double chiSquared, prior;
590 if (theta13 < xmax && theta13 > xmin) {
591 chiSquared = graph->Eval(theta13);
592 prior = std::exp(-0.5 * chiSquared);
601 double& mean,
double& sigma)
#define _MaCh3_Safe_Include_Start_
KS: Avoiding warning checking for headers.
#define _MaCh3_Safe_Include_End_
KS: Restore warning checking after including external headers.
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
int main(int argc, char *argv[])
Main function.
double Graph_interpolateNO(TGraph2D *graph, double theta13, double dm32)
Function to interpolate 2D graph for Normal Ordering.
void LoadReweightingSettings(std::vector< ReweightConfig > &reweightConfigs, const YAML::Node &reweight_settings)
Load reweighting setting like 1D or 2D from YAML config.
bool GetParameterInfo(MCMCProcessor *processor, const std::string ¶mName, double &mean, double &sigma)
Get parameter information from MCMCProcessor.
double Graph_interpolateIO(TGraph2D *graph, double theta13, double dm32)
Function to interpolate 2D graph for Inverted Ordering
double Graph_interpolate1D(TGraph *graph, double theta13)
Function to interpolate 1D graph.
void ReweightMCMC(const std::string &inputFile, const std::string &configFile)
Main executable responsible for reweighting MCMC chains.
YAML::Node TMacroToYAML(const TMacro ¯o)
KS: Convert a ROOT TMacro object to a YAML node.
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
void GetNthParameter(const int param, double &Prior, double &PriorError, TString &Title) const
Get properties of parameter by passing it number.
int GetParamIndexFromName(const std::string &Name) const
Get parameter number based on name.
Custom exception class used throughout MaCh3.
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Structure to hold reweight configuration.
std::unique_ptr< TGraph2D > graph_NO
std::string weightBranchName
std::unique_ptr< TGraph > graph_1D
std::vector< std::string > paramNames
std::vector< std::vector< double > > priorValues
std::string hierarchyType
std::unique_ptr< TGraph2D > graph_IO