MaCh3  2.4.2
Reference Guide
Classes | Functions
ReweightMCMC.cpp File Reference

This executable allow to reweight MCMC Chain, such technique is used to study impact of different priors without rerunning MCMC. More...

#include "Manager/Manager.h"
#include "Fitters/MCMCProcessor.h"
#include "TFile.h"
#include "TTree.h"
#include "TChain.h"
#include "TMath.h"
#include "TGraph2D.h"
#include "TGraph.h"
#include <memory>
#include <vector>
#include <string>
#include <cmath>
#include <fstream>
#include <map>
Include dependency graph for ReweightMCMC.cpp:

Go to the source code of this file.

Classes

struct  ReweightConfig
 Structure to hold reweight configuration. More...
 

Functions

void ReweightMCMC (const std::string &inputFile, const std::string &configFile)
 Main executable responsible for reweighting MCMC chains. More...
 
double Graph_interpolateNO (TGraph2D *graph, double theta13, double dm32)
 Function to interpolate 2D graph for Normal Ordering. More...
 
double Graph_interpolateIO (TGraph2D *graph, double theta13, double dm32)
 Function to interpolate 2D graph for Inverted Ordering
More...
 
double Graph_interpolate1D (TGraph *graph, double theta13)
 Function to interpolate 1D graph. More...
 
bool GetParameterInfo (MCMCProcessor *processor, const std::string &paramName, double &mean, double &sigma)
 Get parameter information from MCMCProcessor. More...
 
void LoadReweightingSettings (std::vector< ReweightConfig > &reweightConfigs, const YAML::Node &reweight_settings)
 Load reweighting setting like 1D or 2D from YAML config. More...
 
int main (int argc, char *argv[])
 Main function. More...
 

Detailed Description

This executable allow to reweight MCMC Chain, such technique is used to study impact of different priors without rerunning MCMC.

Author
David Riley
Evan Goodman

Definition in file ReweightMCMC.cpp.

Function Documentation

◆ GetParameterInfo()

bool GetParameterInfo ( MCMCProcessor processor,
const std::string &  paramName,
double &  mean,
double &  sigma 
)

Get parameter information from MCMCProcessor.

Definition at line 600 of file ReweightMCMC.cpp.

602 {
603  // Try to find the parameter index
604  int paramIndex = processor->GetParamIndexFromName(paramName);
605 
606  if (paramIndex == M3::_BAD_INT_) { // This indicate parameter not found
607  return false;
608  }
609 
610  // Get parameter information
611  TString title;
612  processor->GetNthParameter(paramIndex, mean, sigma, title);
613 
614  return true;
615 }
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.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:55

◆ Graph_interpolate1D()

double Graph_interpolate1D ( TGraph *  graph,
double  theta13 
)

Function to interpolate 1D graph.

Todo:
double check implementation of TGraph interpolation for 1D

Definition at line 571 of file ReweightMCMC.cpp.

572 {
574  if (!graph) {
575  MACH3LOG_ERROR("Graph pointer is null");
576  throw MaCh3Exception(__FILE__, __LINE__);
577  }
578 
579  double xmax = -999999999;
580  double xmin = 999999999;
581 
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;
586  }
587 
588  double chiSquared, prior;
589 
590  if (theta13 < xmax && theta13 > xmin) {
591  chiSquared = graph->Eval(theta13);
592  prior = std::exp(-0.5 * chiSquared);
593  } else {
594  prior = 0.0;
595  }
596 
597  return prior;
598 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
Custom exception class used throughout MaCh3.

◆ Graph_interpolateIO()

double Graph_interpolateIO ( TGraph2D *  graph,
double  theta13,
double  dm32 
)

Function to interpolate 2D graph for Inverted Ordering

Definition at line 545 of file ReweightMCMC.cpp.

546 {
547  if (!graph) {
548  MACH3LOG_ERROR("Graph pointer is null");
549  throw MaCh3Exception(__FILE__, __LINE__);
550  }
551 
552  double xmax = graph->GetXmax();
553  double xmin = graph->GetXmin();
554  double ymax = graph->GetYmax();
555  double ymin = graph->GetYmin();
556 
557  // The dm32 value is positive for in the TGraph2D so we should compare the abs value of the -delM32 values to get the chisq
558  double mod_dm32 = std::abs(dm32);
559  double chiSquared, prior;
560 
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);
564  } else {
565  prior = 0.0;
566  }
567 
568  return prior;
569 }

◆ Graph_interpolateNO()

double Graph_interpolateNO ( TGraph2D *  graph,
double  theta13,
double  dm32 
)

Function to interpolate 2D graph for Normal Ordering.

Todo:
add a generic 2D reweight that is not dm32 and theta13 specific DWR

Definition at line 521 of file ReweightMCMC.cpp.

522 {
523  if (!graph) {
524  MACH3LOG_ERROR("Graph pointer is null");
525  throw MaCh3Exception(__FILE__, __LINE__);
526  }
527 
528  double xmax = graph->GetXmax();
529  double xmin = graph->GetXmin();
530  double ymin = graph->GetYmin();
531  double ymax = graph->GetYmax();
532 
533  double chiSquared, prior;
534 
535  if (theta13 < xmax && theta13 > xmin && dm32 < ymax && dm32 > ymin) {
536  chiSquared = graph->Interpolate(theta13, dm32);
537  prior = std::exp(-0.5 * chiSquared);
538  } else {
539  prior = 0.0;
540  }
541 
542  return prior;
543 }

◆ LoadReweightingSettings()

void LoadReweightingSettings ( std::vector< ReweightConfig > &  reweightConfigs,
const YAML::Node &  reweight_settings 
)

Load reweighting setting like 1D or 2D from YAML config.

Definition at line 97 of file ReweightMCMC.cpp.

97  {
98  // iterate through the keys in the reweighting yaml creating and storing the ReweightConfig as we go
99  for (const auto& reweight : reweight_settings) {
100  const std::string& reweightKey = reweight.first.as<std::string>();
101  const YAML::Node& reweightConfigNode = reweight.second;
102 
103  // Check if this particular reweight is enabled !!! Currently only support one reweight at a time so this defaults to enabled
104  if (!GetFromManager<bool>(reweightConfigNode["Enabled"], true)) {
105  MACH3LOG_INFO("Skipping disabled reweight: {}", reweightKey);
106  continue;
107  }
108 
109  ReweightConfig reweightConfig;
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);
114  // reweightConfig.weightBranchName = "Weight_" + reweightKey; // for now all weights will be stored in branches called Weight until multi weight support
115  reweightConfig.weightBranchName = "Weight";
116  reweightConfig.enabled = true;
117 
118  // Handle different reweight types as they fill different members
119  if (reweightConfig.dimension == 1) {
120  if (reweightConfig.type == "Gaussian") {
121  // For Gaussian reweights, we need the parameter name(s) and prior values (mean, sigma pairs)
122  auto paramNames = GetFromManager<std::vector<std::string>>(reweightConfigNode["ReweightVar"], {});
123 
124  // Get prior values - handle both single [mean, sigma] pair and list of pairs for safety
125  auto priorNode = reweightConfigNode["ReweightPrior"];
126  std::vector<std::vector<double>> allPriorValues;
127 
128  if (priorNode.IsSequence() && priorNode.size() > 0) {
129  // Check if first element is a number (single [mean, sigma] pair) or sequence (list of pairs)
130  if (priorNode[0].IsScalar()) {
131  // Single [mean, sigma] pair - convert to list format
132  auto priorValues = GetFromManager<std::vector<double>>(priorNode, {});
133  if (priorValues.size() == 2) {
134  allPriorValues.push_back(priorValues);
135  }
136  } else {
137  // List of [mean, sigma] pairs
138  for (const auto& priorPair : priorNode) {
139  auto priorValues = GetFromManager<std::vector<double>>(priorPair, {});
140  if (priorValues.size() == 2) {
141  allPriorValues.push_back(priorValues);
142  }
143  }
144  }
145  }
146 
147  reweightConfig.paramNames = paramNames;
148  reweightConfig.priorValues = allPriorValues;
149 
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());
153  continue;
154  }
155  } else if (reweightConfig.type == "TGraph") {
156  // For TGraph reweights, we need the parameter name and the TGraph file and name
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"], "");
160  reweightConfig.paramNames = paramNames;
161  reweightConfig.fileName = fileName;
162  reweightConfig.graphName = graphName;
163 
164  if (paramNames.empty() || paramNames.size() != 1 || fileName.empty() || graphName.empty()) {
165  MACH3LOG_ERROR("Invalid TGraph reweight configuration for {}", reweightKey);
166  continue;
167  }
168 
169  // Load the 1D graph
170  MACH3LOG_INFO("Loading 1D constraint from file: {} (graph: {})", reweightConfig.fileName, reweightConfig.graphName);
171  auto constraintFile = std::unique_ptr<TFile>(TFile::Open(reweightConfig.fileName.c_str(), "READ"));
172  if (!constraintFile || constraintFile->IsZombie()) {
173  MACH3LOG_ERROR("Failed to open constraint file: {}", reweightConfig.fileName);
174  continue;
175  }
176 
177  std::unique_ptr<TGraph> graph(constraintFile->Get<TGraph>(reweightConfig.graphName.c_str()));
178  if (graph) {
179  // Create a completely independent copy
180  auto cloned_graph = static_cast<TGraph*>(graph->Clone());
181  cloned_graph->SetBit(kCanDelete, true); // Allow ROOT to delete it when we're done
182  reweightConfig.graph_1D = std::unique_ptr<TGraph>(cloned_graph);
183  MACH3LOG_INFO("Loaded 1D graph: {}", reweightConfig.graphName);
184  } else {
185  MACH3LOG_ERROR("Failed to load graph: {}", reweightConfig.graphName);
186  continue;
187  }
188  } else {
189  MACH3LOG_ERROR("Unknown 1D reweight type: {} for {}", reweightConfig.type, reweightKey);
190  throw MaCh3Exception(__FILE__, __LINE__);
191  }
192 
193  } else if (reweightConfig.dimension == 2) {
194  auto paramNames = GetFromManager<std::vector<std::string>>(reweightConfigNode["ReweightVar"], {});
195 
196  // 2D reweights need 2 parameter names
197  if (paramNames.size() != 2) {
198  MACH3LOG_ERROR("2D reweighting requires exactly 2 parameter names for {}", reweightKey);
199  continue;
200  }
201 
202  reweightConfig.paramNames = paramNames;
203 
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");
209 
210  if (reweightConfig.fileName.empty() || reweightConfig.graphName.empty()) {
211  MACH3LOG_ERROR("Invalid TGraph2D configuration for {}", reweightKey);
212  continue;
213  }
214 
215  // Load the 2D graphs
216  MACH3LOG_INFO("Loading 2D constraint from file: {} (graph: {})", reweightConfig.fileName, reweightConfig.graphName);
217  auto constraintFile = std::unique_ptr<TFile>(TFile::Open(reweightConfig.fileName.c_str(), "READ"));
218  if (!constraintFile || constraintFile->IsZombie()) {
219  MACH3LOG_ERROR("Failed to open constraint file: {}", reweightConfig.fileName);
220  continue;
221  }
222 
223  // Load both NO and IO graphs if hierarchy is auto
224  if (reweightConfig.hierarchyType == "auto" || reweightConfig.hierarchyType == "NO") {
225  std::string graphName_NO = reweightConfig.graphName + "_NO";
226  MACH3LOG_INFO("Loading NO graph: {}", graphName_NO);
227 
228  std::unique_ptr<TGraph2D> graph_NO(constraintFile->Get<TGraph2D>(graphName_NO.c_str()));
229  if (graph_NO) {
230  // Create a completely independent copy
231  auto cloned_graph = static_cast<TGraph2D*>(graph_NO->Clone());
232  cloned_graph->SetDirectory(nullptr); // Detach from file
233  cloned_graph->SetBit(kCanDelete, true); // Allow ROOT to delete it when we're done
234  reweightConfig.graph_NO = std::unique_ptr<TGraph2D>(cloned_graph);
235  MACH3LOG_INFO("Loaded NO graph: {}", graphName_NO);
236  } else {
237  MACH3LOG_ERROR("Failed to load NO graph: {}", graphName_NO);
238  }
239  }
240 
241  if (reweightConfig.hierarchyType == "auto" || reweightConfig.hierarchyType == "IO") {
242  std::string graphName_IO = reweightConfig.graphName + "_IO";
243  MACH3LOG_INFO("Loading IO graph: {}", graphName_IO);
244  std::unique_ptr<TGraph2D> graph_IO(constraintFile->Get<TGraph2D>(graphName_IO.c_str()));
245  if (graph_IO) {
246  // Create a completely independent copy
247  auto cloned_graph = static_cast<TGraph2D*>(graph_IO->Clone());
248  cloned_graph->SetDirectory(nullptr); // Detach from file
249  cloned_graph->SetBit(kCanDelete, true); // Allow ROOT to delete it when we're done
250  reweightConfig.graph_IO = std::unique_ptr<TGraph2D>(cloned_graph);
251  MACH3LOG_INFO("Loaded IO graph: {}", graphName_IO);
252  } else {
253  MACH3LOG_ERROR("Failed to load IO graph: {}", graphName_IO);
254  }
255  }
256 
257  constraintFile->Close();
258  } else {
259  MACH3LOG_ERROR("Unknown 2D reweight type: {} for {}", reweightConfig.type, reweightKey);
260  continue;
261  }
262  } else {
263  MACH3LOG_ERROR("Unsupported reweight dimension: {} for {}", reweightConfig.dimension, reweightKey);
264  continue;
265  }
266 
267  reweightConfigs.push_back(std::move(reweightConfig));
268  MACH3LOG_INFO("Added reweight configuration: {} ({}D, type: {})", reweightConfigs.back().name, reweightConfigs.back().dimension, reweightConfigs.back().type);
269  }
270 
271  if (reweightConfigs.empty()) {
272  MACH3LOG_ERROR("No valid reweight configurations found in config file");
273  throw MaCh3Exception(__FILE__, __LINE__);
274  } else if (reweightConfigs.size() > 1) { // check number of ReweightConfigs, currently maximum supported is 1 due to structure of ProcessMCMC
275  MACH3LOG_ERROR("Currently only one reweight configuration is supported at a time, found {}", reweight_settings.size());
276  throw MaCh3Exception(__FILE__, __LINE__);
277  }
278 }
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
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.
Structure to hold reweight configuration.
std::unique_ptr< TGraph2D > graph_NO
std::string key
std::string weightBranchName
std::string fileName
std::string graphName
std::unique_ptr< TGraph > graph_1D
std::string type
std::vector< std::string > paramNames
std::string name
std::vector< std::vector< double > > priorValues
std::string hierarchyType
std::unique_ptr< TGraph2D > graph_IO

◆ main()

int main ( int  argc,
char *  argv[] 
)

Main function.

Definition at line 80 of file ReweightMCMC.cpp.

81 {
83 
84  if (argc != 3) {
85  MACH3LOG_ERROR("How to use: {} <config.yaml> <input_file.root>", argv[0]);
86  throw MaCh3Exception(__FILE__, __LINE__);
87  }
88 
89  std::string configFile = argv[1];
90  std::string inputFile = argv[2];
91 
92  ReweightMCMC(configFile, inputFile);
93 
94  return 0;
95 }
void SetMaCh3LoggerFormat()
Set messaging format of the logger.
Definition: MaCh3Logger.h:61
void ReweightMCMC(const std::string &inputFile, const std::string &configFile)
Main executable responsible for reweighting MCMC chains.

◆ ReweightMCMC()

void ReweightMCMC ( const std::string &  inputFile,
const std::string &  configFile 
)

Main executable responsible for reweighting MCMC chains.

Parameters
inputFileMCMC Chain file path
configFileConfig file with reweighting settings
Author
David Riley
Evan Goodman
Todo:
Get list only of unique parameters, this is repeating unnecessarily when adding more than 1 weight DWR
Todo:
Finish Asimov shifting implementation, for now just warn that Asimovs are not being properly handled
Todo:
add tracking for how many events are outside the graph ranges for diagnostics DWR

Definition at line 280 of file ReweightMCMC.cpp.

281 {
282  MACH3LOG_INFO("File for reweighting: {} with config {}", inputFile, configFile);
283  // Load configuration
284  YAML::Node reweight_yaml = M3OpenConfig(configFile);
285  YAML::Node reweight_settings = reweight_yaml["ReweightMCMC"];
286 
287  // Parse all reweight configurations first
288  std::vector<ReweightConfig> reweightConfigs;
289 
290  LoadReweightingSettings(reweightConfigs, reweight_settings);
291 
292  // Create MCMCProcessor to get parameter information
293  auto processor = std::make_unique<MCMCProcessor>(inputFile);
294  processor->Initialise();
295 
296  // Validate that all required parameters exist in the chain
298  for (const auto& rwConfig : reweightConfigs) {
299  for (const auto& paramName : rwConfig.paramNames) {
300  int paramIndex = processor->GetParamIndexFromName(paramName);
301  if (paramIndex == M3::_BAD_INT_) {
302  MACH3LOG_ERROR("Parameter {} not found in MCMC chain", paramName);
303  throw MaCh3Exception(__FILE__, __LINE__);
304  }
305  MACH3LOG_INFO("Parameter {} found in chain", paramName);
306  }
307  }
308 
310  // Get the settings for the MCMC
311  auto TempFile = std::unique_ptr<TFile>(TFile::Open(inputFile.c_str(), "READ"));
312  if (!TempFile || TempFile->IsZombie()) {
313  MACH3LOG_ERROR("Cannot open MCMC file: {}", inputFile);
314  throw MaCh3Exception(__FILE__ , __LINE__ );
315  }
316  std::unique_ptr<TMacro> Config(TempFile->Get<TMacro>("MaCh3_Config"));
317  if (!Config) {
318  MACH3LOG_ERROR("Didn't find MaCh3_Config tree in MCMC file! {}", inputFile.c_str());
319  TempFile->ls();
320  throw MaCh3Exception(__FILE__ , __LINE__ );
321  }
322  MACH3LOG_INFO("Loading YAML config from MCMC chain");
323  YAML::Node Settings = TMacroToYAML(*Config);
324  bool asimovfit = GetFromManager<bool>(Settings["General"]["Asimov"], false);
325  if (asimovfit) {
326  MACH3LOG_WARN("MCMC chain was produced from an Asimov fit");
327  MACH3LOG_WARN("ReweightMCMC does not currently handle Asimov shifting, results may be incorrect!");
328  } else {
329  MACH3LOG_INFO("Not an Asimov fit, proceeding with reweighting");
330  }
331 
332  // Open input file and get tree
333  auto inFile = std::unique_ptr<TFile>(TFile::Open(inputFile.c_str(), "READ"));
334  if (!inFile || inFile->IsZombie()) {
335  MACH3LOG_ERROR("Cannot open input file: {}", inputFile);
336  throw MaCh3Exception(__FILE__, __LINE__);
337  }
338 
339  std::unique_ptr<TTree> inTree(inFile->Get<TTree>("posteriors"));
340  if (!inTree) {
341  MACH3LOG_ERROR("Cannot find 'posteriors' tree in input file");
342  throw MaCh3Exception(__FILE__, __LINE__);
343  }
344 
345  // Create output file
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()) {
350  MACH3LOG_ERROR("Cannot create output file: {}", outputFile);
351  throw MaCh3Exception(__FILE__, __LINE__);
352  }
353 
354  MACH3LOG_INFO("Output file will be: {}", outputFile);
355 
356  // Copy all the remaining objects into the out file (i.e. all but posteriors tree)
357  TIter next(inFile->GetListOfKeys());
358  while (TKey* key = dynamic_cast<TKey*>(next())) {
359  inFile->cd();
360  std::unique_ptr<TObject> obj(key->ReadObj());
361  if (obj->IsA()->InheritsFrom(TDirectory::Class())) {
362  // It's a folder, create and copy its contents
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())) {
367  srcDir->cd();
368  std::unique_ptr<TObject> subObj(subKey->ReadObj());
369  destDir->cd();
370  subObj->Write();
371  }
372  } else if (std::string(key->GetName()) != "posteriors") {
373  // Regular object, skip "posteriors" tree
374  outFile->cd();
375  obj->Write();
376  }
377  }
378 
379  // Clone the tree structure
380  outFile->cd();
381  std::unique_ptr<TTree> outTree(inTree->CloneTree(0));
382 
383  // Set up parameter reading
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(), &paramValues[paramName]);
390  }
391  }
392  }
393 
394  // Add weight branches
395  std::map<std::string, double> weights;
396  std::map<std::string, TBranch*> weightBranches;
397 
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()
404  );
405  MACH3LOG_INFO("Added weight branch: {}", rwConfig.weightBranchName);
406  }
407 
408  bool processMCMCreweighted=false;
409 
410  // If a given reweight is 1D Gaussian we can just let MCMCProcessor method do the reweight
411  for (const auto& rwConfig : reweightConfigs){
412  if (rwConfig.dimension == 1 && rwConfig.type == "Gaussian"){
413  // Extract the parameter names and convert priorValues to the format processor needs
414  const std::vector<std::string>& paramNames = rwConfig.paramNames;
415  std::vector<double> priorCentral;
416  std::vector<double> priorSigma;
417 
418  // Extract means and sigmas from the prior pairs
419  for (const auto& priorPair : rwConfig.priorValues) {
420  priorCentral.push_back(priorPair[0]); // mean
421  priorSigma.push_back(priorPair[1]); // sigma
422  }
423 
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]);
428  }
429  processMCMCreweighted=true;
430  }
431  }
432  // For 2D reweight and non-gaussian (ie TGraph) 1D reweight we need to do it ourselves
433  // Process all entries
434  Long64_t nEntries = inTree->GetEntries();
435  MACH3LOG_INFO("Processing {} entries", nEntries);
436 
437 
439 
440  if (processMCMCreweighted) {
441  MACH3LOG_INFO("MCMCProcessor has reweighted, skipping duplicate reweighting");
442  } else {
443  for (Long64_t i = 0; i < nEntries; ++i) {
444  if(i % (nEntries/20) == 0) MaCh3Utils::PrintProgressBar(i, nEntries);
445 
446  inTree->GetEntry(i);
447 
448  // Calculate weights for all configurations
449  for (const auto& rwConfig : reweightConfigs) {
450  double weight = 1.0;
451 
452  if (rwConfig.dimension == 1 && rwConfig.type != "Gaussian") {
453  if (rwConfig.type == "TGraph") {
454  double paramValue = paramValues[rwConfig.paramNames[0]];
455  weight = Graph_interpolate1D(rwConfig.graph_1D.get(), paramValue);
456  } else {
457  MACH3LOG_ERROR("Unsupported 1D reweight type: {} for {}", rwConfig.type, rwConfig.key);
458  }
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]];
463  if (dm32 > 0) {
464  // Normal Ordering
465  if (rwConfig.graph_NO) {
466  weight = Graph_interpolateNO(rwConfig.graph_NO.get(), theta13, dm32);
467  } else {
468  MACH3LOG_ERROR("NO graph not available for {}", rwConfig.key);
469  weight = 0.0;
470  }
471  } else {
472  // Inverted Ordering
473  if (rwConfig.graph_IO) {
474  weight = Graph_interpolateIO(rwConfig.graph_IO.get(), theta13, dm32);
475  } else {
476  MACH3LOG_ERROR("IO graph not available for {}", rwConfig.key);
477  weight = 0.0;
478  }
479  }
480  }
481  }
482  weights[rwConfig.weightBranchName] = weight;
483  }
484  // Fill the output tree
485  outTree->Fill();
486  } // end loop over entries
487  }
488 
489  // Write and close
490  outFile->cd();
491  outTree->Write();
492 
493  // once we have finished the reweight save its configuration (reweightConfigNode) to the root file as a macro
494 
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();
502 
503  if (processMCMCreweighted){
504  MACH3LOG_INFO("MCMCProcessor reweighting applied, Final reweighted file is: {}_reweighted.root", inputFile.substr(0, inputFile.find_last_of('.')));
505  // delete the file we just created since MCMCProcessor already did the reweighting and saved it to a file
506  outTree.reset(); // Release TTree before closing TFile
507  outFile->Close();
508  outFile.reset();
509 
510  if (std::remove(outputFile.c_str()) != 0) {
511  MACH3LOG_ERROR("Error deleting temporary file: {}", outputFile);
512  } else {
513  MACH3LOG_INFO("Deleted temporary file: {}", outputFile);
514  }
515  } else {
516  MACH3LOG_INFO("Reweighting completed successfully!");
517  MACH3LOG_INFO("Final reweighted file is: {}", outputFile);
518  }
519 }
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
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.
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.
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:152
#define M3OpenConfig(filename)
Macro to simplify calling LoadYaml with file and line info.
Definition: YamlHelper.h:589
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:228