#include #include #include #include #include #include "TROOT.h" #include "TFile.h" #include "TKey.h" #include "TH3.h" #include "TProfile.h" #include "TF3.h" #include "TString.h" #include "TRegexp.h" #include "JLang/JType.hh" #include "JLang/JTypeList.hh" #include "JLang/JToken.hh" #include "JTools/JRange.hh" #include "JGizmo/JRootObjectID.hh" #include "JGizmo/JGizmoToolkit.hh" #include "Jeep/JPrint.hh" #include "Jeep/JParser.hh" #include "Jeep/JMessage.hh" namespace { using namespace JPP; /** * Auxiliary class for ROOT fit. */ struct JFit { /** * Constructor. * * \param object object * \param fcn fcn * \param option option */ JFit(TObject& object, TF2* fcn, const std::string& option) : object(object), fcn (fcn), option(option) {} /** * Attempt fit for given data type. * * \param type data type */ template void operator()(const JType& type) { try { result = dynamic_cast(object).Fit(fcn, option.c_str(), "same"); } catch(const std::exception&) {} } TObject& object; TF2* fcn; std::string option; TFitResultPtr result; }; } /** * \file * General purpose fit program for 3D ROOT objects.\n * The option -f corresponds to \:\. * * The expressions for the fit function, start and fixed values should comply * with ROOT class TFormula. * * In the expressions of the start and fixed values, names of member methods * of corresponding class of the fit object may appear, * such as TH1::GetMaximum, TH1::GetRMS, etc., e.g: *
 *      -F "[0]*exp(-0.5*x*x/([1]*[1])*exp(-0.5*y*y/([2]*[2])*exp(-0.5*z*z/([3]*[3])"
 *      -@ "p0 = GetMaximum; p1 = 2*GetRMS(1); .."
 *      -= "p3 = 1"
 * 
* The result of the formulas for the start and fixed values will be evaluated * for each histogram separately. * \author mdejong */ int main(int argc, char **argv) { using namespace std; using namespace JPP; typedef JToken<';'> JToken_t; typedef JRange JRange_t; vector inputFile; string outputFile; string formula; vector startValues; vector fixedValues; vector limitValues; JRange_t X; JRange_t Y; JRange_t Z; string option; int debug; try { JParser<> zap("General purpose fit program for 2D ROOT objects."); zap['f'] = make_field(inputFile, ":"); zap['o'] = make_field(outputFile, "ROOT file with fit results") = "fit.root"; zap['F'] = make_field(formula, "fit formula, e.g: \"[0]+[1]*x\""); zap['@'] = make_field(startValues, "start values, e.g: \"p0 = GetMaximum;\""); zap['='] = make_field(fixedValues, "fixed values, e.g: \"p0 = GetMaximum;\"") = JPARSER::initialised(); zap['R'] = make_field(limitValues, "limit values, e.g: \"p0 = ;\"") = JPARSER::initialised(); zap['x'] = make_field(X, "abscissa range") = JRange_t(); zap['y'] = make_field(Y, "abscissa range") = JRange_t(); zap['z'] = make_field(Z, "abscissa range") = JRange_t(); zap['O'] = make_field(option, "Fit option") = ""; zap['d'] = make_field(debug) = 1; zap['='] = JPARSER::initialised(); zap(argc, argv); } catch(const exception &error) { FATAL(error.what() << endl); } if (option.find('O') == string::npos) { option += "O"; } //if (option.find('N') == string::npos) { option += "N"; } if (debug == 0 && option.find('Q') == string::npos) { option += "Q"; } TFile out(outputFile.c_str(), "recreate"); TF3* fcn = new TF3("user", formula.c_str()); fcn->SetNpx(10000); if (fcn->IsZombie()) { FATAL("Function: " << formula << " is zombie." << endl); } for (vector::const_iterator input = inputFile.begin(); input != inputFile.end(); ++input) { DEBUG("Input: " << *input << endl); TDirectory* dir = getDirectory(*input); if (dir == NULL) { ERROR("File: " << input->getFullFilename() << " not opened." << endl); continue; } const TRegexp regexp(input->getObjectName()); TIter iter(dir->GetListOfKeys()); for (TKey* key; (key = (TKey*) iter.Next()) != NULL; ) { const TString tag(key->GetName()); DEBUG("Key: " << tag << " match = " << tag.Contains(regexp) << endl); // option match if (tag.Contains(regexp) && isTObject(key)) { TObject* object = key->ReadObj(); // set fit parameters try { for (vector::const_iterator i = startValues.begin(); i != startValues.end(); ++i) { fcn->SetParameter(getParameter(*i), getValue(*i,object)); } for (vector::const_iterator i = fixedValues.begin(); i != fixedValues.end(); ++i) { fcn->FixParameter(getParameter(*i), getValue(*i,object)); } for (vector::const_iterator i = limitValues.begin(); i != limitValues.end(); ++i) { fcn->SetParLimits(getParameter(*i), getValue(*i,0), getValue(*i,1)); } } catch(JLANG::JParseError& error) { FATAL(error << endl); } DEBUG("Start values " << object->GetName() << endl); for (int i = 0; i != fcn->GetNpar(); ++i) { DEBUG(left << setw(12) << fcn->GetParName (i) << ' ' << SCIENTIFIC(12,5) << fcn->GetParameter(i) << endl); } Double_t xmin = numeric_limits::max(); Double_t xmax = numeric_limits::lowest(); Double_t ymin = numeric_limits::max(); Double_t ymax = numeric_limits::lowest(); Double_t zmin = numeric_limits::max(); Double_t zmax = numeric_limits::lowest(); { TH3* h3 = dynamic_cast(object); if (h3 != NULL) { xmin = min(xmin, h3->GetXaxis()->GetXmin()); xmax = max(xmax, h3->GetXaxis()->GetXmax()); ymin = min(ymin, h3->GetYaxis()->GetXmin()); ymax = max(ymax, h3->GetYaxis()->GetXmax()); zmin = min(zmin, h3->GetZaxis()->GetXmin()); zmax = max(zmax, h3->GetZaxis()->GetXmax()); } } if (X != JRange_t()) { xmin = X.getLowerLimit(); xmax = X.getUpperLimit(); } if (Y != JRange_t()) { ymin = Y.getLowerLimit(); ymax = Y.getUpperLimit(); } if (Z != JRange_t()) { zmin = Z.getLowerLimit(); zmax = Z.getUpperLimit(); } fcn->SetRange(xmin, ymin, zmin, xmax, ymax, zmax); if (option.find("R") == string::npos) { option += "R"; } // execute fit JFit fit(*object, fcn, option); for_each(fit, JType()); if (fit.result != -1) { // output fit results NOTICE("Fit values " << object->GetName() << endl); NOTICE("Fit formula " << formula << endl); for (int j = 0; j != fcn->GetNpar(); ++j) { NOTICE(left << setw(12) << fcn->GetParName (j) << ' ' << SCIENTIFIC(12,5) << fcn->GetParameter(j) << " +/- " << SCIENTIFIC(12,5) << fcn->GetParError (j) << endl); } } else { WARNING("Object: not compatible with ROOT Fit." << endl); } out.cd(); object->Write(); fcn ->Write(); } } dir->Close(); } out.Write(); out.Close(); }