diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8d9b7daa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# ignore all files generated from an in-repo build +build/ diff --git a/src/classes/PFitter.cpp b/src/classes/PFitter.cpp index 41d2ac26..ac1c0a3f 100644 --- a/src/classes/PFitter.cpp +++ b/src/classes/PFitter.cpp @@ -39,9 +39,10 @@ #include #include #include - #include +#include + #include #include "Minuit2/FunctionMinimum.h" @@ -2473,6 +2474,121 @@ Bool_t PFitter::ExecuteSave(Bool_t firstSave) ccorr->Write("ccorr", TObject::kOverwrite, sizeof(ccorr)); hcorr->Write("hcorr", TObject::kOverwrite, sizeof(hcorr)); 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 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 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 } else { diff --git a/src/musrFT.cpp b/src/musrFT.cpp index a2d50364..a9bf6ca1 100644 --- a/src/musrFT.cpp +++ b/src/musrFT.cpp @@ -1437,19 +1437,18 @@ Int_t main(Int_t argc, Char_t *argv[]) musrFT_dumpData(startupParam.dumpFln, fourier, startupParam.fourierRange[0], startupParam.fourierRange[1]); } else { // do Canvas - // if Fourier graphical export is whished, switch to batch mode + // if Fourier graphical export is wished, switch to batch mode Bool_t batch = false; - int cc=0; - char **arg; + // create list of essential arguments to pass to the ROOT application + std::vector args; + args.push_back(argv[0]); // program name if (startupParam.graphicFormat.Length() != 0) { batch = true; - arg[cc] = (Char_t*)malloc(16*sizeof(Char_t)); - strcpy(arg[cc], "-b"); - cc++; + args.push_back((char*)"-b"); // batch mode flag } - + int cc = args.size(); // plot the Fourier transform - TApplication app("App", &cc, arg); + TApplication app("App", &cc, args.data()); if (startupHandler) { fourierCanvas = std::unique_ptr(new PFourierCanvas(fourier, dataSetTag, startupParam.title.Data(), diff --git a/src/musrview.cpp b/src/musrview.cpp index b76383e0..69ba93d7 100644 --- a/src/musrview.cpp +++ b/src/musrview.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -301,15 +302,15 @@ int main(int argc, char *argv[]) } if (result == PMUSR_SUCCESS) { - // generate Root application needed for PMusrCanvas - int cc=0; - char **arg; + // create the ROOT application needed for PMusrCanvas + // and pass it only essential arguments + std::vector args; + args.push_back(argv[0]); // program name if (graphicsOutput || asciiOutput) { - arg[cc] = (char*)malloc(16*sizeof(char)); - strcpy(arg[cc], "-b"); - cc++; + args.push_back((char*)"-b"); // batch mode flag } - TApplication app("App", &cc, arg); + int cc = args.size(); + TApplication app("App", &cc, args.data()); std::vector canvasVector; PMusrCanvas *musrCanvas;