write the fit results to an easy-to-read/parse yaml file
This patch adds routines for writing a comprehensive set of fit results (i.e., parameter values, parabolic errors, asymmetric errors, covariances, correlation coefficients, etc.) for an individual `.msr` file to an easy-to-read/parse `.yaml` file. The main motivation for the code addition is to provide users with easy access to the fit's covariance matrix without the need for "extra" manual effort (e.g., parsing the contents of `MINUIT2.OUTPUT` or `MINUIT2.root`). The other fit quantities are also included for completeness. Reading/accessing the output is trivial using, for example, the PyYAML Python library (https://github.com/yaml/pyyaml): ```python import yaml with open("2125_tf_histo.yaml", "r") as fh: results = yaml.load(fh, Loader=yaml.SafeLoader) cov = results["covariance"]["Field_1"]["Sigma_1"] ``` Note: the naming conventions chosen for the blocks in the `.yaml` output closely follow those used by the iminuit Python library (https://github.com/scikit-hep/iminuit).
This commit is contained in:
parent
b71dce9291
commit
833171c712
@ -39,9 +39,10 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <boost/variant/variant.hpp>
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include "Minuit2/FunctionMinimum.h"
|
#include "Minuit2/FunctionMinimum.h"
|
||||||
@ -2473,6 +2474,121 @@ Bool_t PFitter::ExecuteSave(Bool_t firstSave)
|
|||||||
ccorr->Write("ccorr", TObject::kOverwrite, sizeof(ccorr));
|
ccorr->Write("ccorr", TObject::kOverwrite, sizeof(ccorr));
|
||||||
hcorr->Write("hcorr", TObject::kOverwrite, sizeof(hcorr));
|
hcorr->Write("hcorr", TObject::kOverwrite, sizeof(hcorr));
|
||||||
ff.Close();
|
ff.Close();
|
||||||
|
|
||||||
|
// write the fit results to an easy-to-read/parse yaml file
|
||||||
|
// note: the block names follow those used by Python library iminuit
|
||||||
|
// https://github.com/scikit-hep/iminuit
|
||||||
|
|
||||||
|
// dynamically name the yaml output file
|
||||||
|
// https://stackoverflow.com/a/25389052
|
||||||
|
std::string yaml_filename(fRunInfo->GetFileName().Data());
|
||||||
|
const std::string msr_ext(".msr");
|
||||||
|
yaml_filename.replace(yaml_filename.find(msr_ext), msr_ext.length(),
|
||||||
|
".yaml");
|
||||||
|
|
||||||
|
// define yaml's 2-space indentation
|
||||||
|
const std::string yaml_indent(" ");
|
||||||
|
|
||||||
|
// open the yaml file for writing
|
||||||
|
std::ofstream yaml_file(yaml_filename);
|
||||||
|
|
||||||
|
// number formatting of the output
|
||||||
|
yaml_file << std::scientific << std::setprecision(16);
|
||||||
|
|
||||||
|
// write the parameter values
|
||||||
|
yaml_file << "values:\n";
|
||||||
|
for (unsigned int i = 0; i < fParams.size(); ++i) {
|
||||||
|
yaml_file << yaml_indent << fParams[i].fName.Data() << ": "
|
||||||
|
<< fParams[i].fValue << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the parabolic errors
|
||||||
|
yaml_file << "errors:\n";
|
||||||
|
for (unsigned int i = 0; i < fParams.size(); ++i) {
|
||||||
|
yaml_file << yaml_indent << fParams[i].fName.Data() << ": "
|
||||||
|
<< fMnUserParams.Error(i) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the minos errors
|
||||||
|
yaml_file << "mnerrors:\n";
|
||||||
|
for (unsigned int i = 0; i < fParams.size(); ++i) {
|
||||||
|
// use boost's implementation of a variant, which can be streamed by
|
||||||
|
// default - see: https://stackoverflow.com/q/47168477
|
||||||
|
boost::variant<double, std::string> positive_error, negative_error;
|
||||||
|
if (fParams[i].fPosErrorPresent) {
|
||||||
|
positive_error = fParams[i].fPosError;
|
||||||
|
negative_error = fParams[i].fStep;
|
||||||
|
} else {
|
||||||
|
positive_error = "null";
|
||||||
|
negative_error = "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_file << yaml_indent << fParams[i].fName.Data() << ":\n";
|
||||||
|
yaml_file << yaml_indent << yaml_indent
|
||||||
|
<< "positive: " << positive_error << "\n";
|
||||||
|
yaml_file << yaml_indent << yaml_indent
|
||||||
|
<< "negative: " << negative_error << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the parameter limits
|
||||||
|
yaml_file << "limits:\n";
|
||||||
|
for (unsigned int i = 0; i < fParams.size(); ++i) {
|
||||||
|
// use boost's implementation of a variant, which can be streamed by
|
||||||
|
// default - see: https://stackoverflow.com/q/47168477
|
||||||
|
boost::variant<double, std::string> upper_limit, lower_limit;
|
||||||
|
if (fParams[i].fLowerBoundaryPresent) {
|
||||||
|
lower_limit = fParams[i].fLowerBoundary;
|
||||||
|
} else {
|
||||||
|
lower_limit = "null";
|
||||||
|
}
|
||||||
|
if (fParams[i].fUpperBoundaryPresent) {
|
||||||
|
upper_limit = fParams[i].fUpperBoundary;
|
||||||
|
} else {
|
||||||
|
upper_limit = "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_file << yaml_indent << fParams[i].fName.Data() << ":\n";
|
||||||
|
yaml_file << yaml_indent << yaml_indent << "lower: " << lower_limit
|
||||||
|
<< "\n";
|
||||||
|
yaml_file << yaml_indent << yaml_indent << "upper: " << upper_limit
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// write if the parameter is fixed
|
||||||
|
yaml_file << "fixed:\n";
|
||||||
|
for (unsigned int i = 0; i < fParams.size(); ++i) {
|
||||||
|
std::string is_fixed = fParams[i].fStep == 0.0 ? "true" : "false";
|
||||||
|
yaml_file << yaml_indent << fParams[i].fName.Data() << ": " << is_fixed
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the covariance matrix (omitting fixed parameters)
|
||||||
|
yaml_file << "covariance:\n";
|
||||||
|
for (unsigned int i = 0; i < cov.Nrow(); ++i) {
|
||||||
|
yaml_file << yaml_indent << mnState.Name(parNo[i]) << ":\n";
|
||||||
|
for (unsigned int j = 0; j < cov.Nrow(); ++j) {
|
||||||
|
yaml_file << yaml_indent << yaml_indent << mnState.Name(parNo[j])
|
||||||
|
<< ": " << cov(i, j) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the correlation matrix (omitting fixed parameters)
|
||||||
|
yaml_file << "correlation:\n";
|
||||||
|
for (unsigned int i = 0; i < cov.Nrow(); ++i) {
|
||||||
|
yaml_file << yaml_indent << mnState.Name(parNo[i]) << ":\n";
|
||||||
|
for (unsigned int j = 0; j < cov.Nrow(); ++j) {
|
||||||
|
double correlation =
|
||||||
|
i == j ? 1.0
|
||||||
|
: cov(i, j) / (fMnUserParams.Error(parNo[i]) *
|
||||||
|
fMnUserParams.Error(parNo[j]));
|
||||||
|
yaml_file << yaml_indent << yaml_indent << mnState.Name(parNo[j])
|
||||||
|
<< ": " << correlation << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the yaml file
|
||||||
|
yaml_file.close();
|
||||||
|
|
||||||
}
|
}
|
||||||
parNo.clear(); // clean up
|
parNo.clear(); // clean up
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user