ATLAS Offline Software
RootFit.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
11 #include <dqm_algorithms/RootFit.h>
13 #include <TH1.h>
14 #include <TF1.h>
15 #include <TClass.h>
16 #include <ers/ers.h>
17 #include <TROOT.h>
18 
19 #include <dqm_core/AlgorithmManager.h>
20 #include <cmath>
21 
22 namespace
23 {
24  dqm_algorithms::RootFit gaussian_fit( "gaus" );
25  dqm_algorithms::RootFit linear_fit( "pol1" );
26  dqm_algorithms::RootFit landau_fit( "landau" );
27  dqm_algorithms::RootFit sinusoid_fit( "sinusoid" );
28  dqm_algorithms::RootFit gauspol1_fit( "gauspluspol1" );
29  dqm_algorithms::RootFit doublegaussian_fit( "doublegaus" );
30  dqm_algorithms::RootFit gausplusexpo_fit( "gausplusexpo" );
31  dqm_algorithms::RootFit fermi_fit( "fermi" );
32  dqm_algorithms::RootFit flat_fit( "flat" );
33 }
34 
35 dqm_algorithms::RootFit::RootFit( const std::string & name )
36  : m_name( name )
37 {
38 
39  if (m_name == "gaus"){
40  m_func.reset( new TF1("gaus1","gaus") );
41  }
42  if (m_name == "pol1"){
43  m_func.reset( new TF1("pol11","pol1") );
44  }
45  if (m_name == "landau"){
46  m_func.reset( new TF1("landau1","landau") );
47  }
48  if (m_name == "sinusoid"){
49  m_func.reset( new TF1("sinusoid","[0]*sin(x) + [1]*cos(x)") );
50  }
51  if (m_name == "gauspluspol1"){
52  m_func.reset( new TF1("gauspluspol1","gaus(0)+pol1(3)") );
53  }
54  if (m_name == "doublegaus"){
55  m_func.reset( new TF1("doublegaus","gaus(0)+gaus(3)",0,1) );
56  }
57  if (m_name == "gausplusexpo"){
58  m_func.reset( new TF1("gausplusexpo","gaus(0)+expo(3)",0,1) );
59  }
60  if (m_name == "fermi"){
61  m_func.reset( new TF1("fermi","[0]/(1+exp(([1]-x)/[2]))") );
62  }
63  if (m_name == "flat"){
64  m_func.reset( new TF1("flat","[0]") );
65  }
66  dqm_core::AlgorithmManager::instance().registerAlgorithm( "Simple_"+name +"_Fit", this );
67 }
68 
70 {
71  // totally defeats the purpose of unique_ptr, but fixes a segfault in 5.34 ...
72  (void)m_func.release();
73 }
74 
77 {
78  return new RootFit( m_name );
79 }
80 
81 
83 dqm_algorithms::RootFit::execute( const std::string & name,
84  const TObject & object,
85  const dqm_core::AlgorithmConfig & config )
86 {
87  //std::cout<<"ROOTFIT = calling rootfit with name "<<name<<std::endl;
88  const TH1 * histogram;
89  if(object.IsA()->InheritsFrom( "TH1" ))
90  {
91  histogram = static_cast<const TH1*>(&object);
92  if (histogram->GetDimension() > 1 ){
93  throw dqm_core::BadConfig( ERS_HERE, name, "dimension > 1 for Fit" );
94  }
95  //if (histogram->GetEffectiveEntries()==0 ){
96  //throw dqm_core::BadConfig( ERS_HERE, name, "Histogram is empty: No Fit performed" );
97  //}
98 
99  }
100  else {
101  throw dqm_core::BadConfig( ERS_HERE, name, "does not inherit from TH1" );
102  }
103 
104  //std::cout<<"ROOTFIT = Trying to get parameters"<<std::endl;
105  double xmin = dqm_algorithms::tools::GetFirstFromMap( "xmin", config.getParameters(), histogram->GetXaxis()->GetXmin());
106  double xmax = dqm_algorithms::tools::GetFirstFromMap( "xmax", config.getParameters(), histogram->GetXaxis()->GetXmax());
107  const bool ignoreFirstLastBin = dqm_algorithms::tools::GetFirstFromMap( "ignoreFirstLastBin", config.getParameters(), 0 );
108 
109  const double minstat = dqm_algorithms::tools::GetFirstFromMap( "MinStat", config.getParameters(), -1);
110  const bool verbose = static_cast<bool>(dqm_algorithms::tools::GetFirstFromMap( "Verbose", config.getParameters(), 0));
111 
112  const double minSig = dqm_algorithms::tools::GetFirstFromMap( "MinSignificance", config.getParameters(), 0);
113 
114  // const bool draw = static_cast<bool>(dqm_algorithms::tools::GetFirstFromMap( "DrawFitCurve", config.getParameters(), 0));
115  const double lf = dqm_algorithms::tools::GetFirstFromMap( "LikelihoodFit", config.getParameters(), 0);
116 
117  //std::cout << "verbose " << verbose
118  //<< " draw " << draw
119  //<< " lf " << lf << std::endl;
120 
121  if (histogram->GetEffectiveEntries() < minstat || histogram->GetEffectiveEntries()==0) {
123  result->tags_["InsufficientEffectiveEntries"] = histogram->GetEffectiveEntries();
124  return result;
125  }
126 
127  const TAxis *x = histogram->GetXaxis();
128  int nbins = x->GetNbins();
129  double high = x->GetBinUpEdge(nbins);
130  double low = x->GetBinUpEdge(0);
131 
132  if ( xmin>high || xmin<low || xmax>high || xmax<low) {
133  throw dqm_core::BadConfig( ERS_HERE, name, "xmin and/or xmax value not in histogram bin range" );
134  }
135 
136  std::string option;
137  //Always set option end to avoid making graphics object and drawing it.
138  //draw fit curve if DrawFitCurve == 1.0
139  if (verbose){
140  //if( draw ) option = "";
141  //else option="N";
142  option="N";
143  } else {
144  //if( draw ) option = "Q";
145  //else option = "QN";
146  option = "QN";
147  }
148 
149  // Likelihood fit
150  if( lf == 1.0 ) option += "L";
151  else if ( lf == 2.0 ) option += "LL";
152 
153  //Use Minos technique as recommended for better error calculation, if errors are important:
154  if ( minSig != 0 ) {
155  option += "E";
156  }
157  //show histo name and fit option for verbose mode
158  if( verbose ){
159  std::cout <<" histo name " << histogram->GetName() << std::endl;
160  std::cout <<" fit option " << option << std::endl;
161  }
162  //std::cout<<"ROOTFIT Trying to do fit"<<std::endl;
163  if (m_name == "gauspluspol1"){
164  m_func->SetParameters(histogram->GetBinContent(histogram->GetMaximumBin()),histogram->GetMean(),histogram->GetRMS());
165  m_func->SetParNames ("Constant","Mean","Sigma","pol1[0]","pol1[1]");
166  }
167  else if (m_name == "pol1"){
168  m_func->SetParNames ("pol1[0]","pol1[1]");
169  }
170  else if (m_name == "sinusoid") {
171  m_func->SetParameters(4.0,-1.0);
172  m_func->SetParNames("s1","s2");
173  }
174  else if (m_name == "doublegaus"){
175  TF1 f1("f1","gaus",xmin,xmax);
176  const_cast<TH1*>(histogram)->Fit(&f1,"q");
177  double par[6] ;
178 
179  f1.GetParameters(par);
180  m_func->SetParameters(par);
181  m_func->SetParameter(3,histogram->GetBinContent(histogram->GetMaximumBin()));
182  m_func->SetParameter(4,histogram->GetMean());
183  m_func->SetParameter(5,par[2]);
184  m_func->SetParNames("Constant","Mean","Sigma","Constant1","Mean1","Sigma1");
185  /*
186  const int numsig1 = m_func->GetParNumber("Sigma1");
187  const double sigmaup = dqm_algorithms::tools::GetFirstFromMap( "Sigma_upperLimit", config.getParameters(), 1000000);
188  m_func->SetParLimits(numsig1, 0., sigmaup);
189  */
190  }
191  else if (m_name == "gausplusexpo") {
192  m_func->SetParameters(histogram->GetBinContent(histogram->GetMaximumBin()),histogram->GetMean(),histogram->GetRMS());
193  m_func->SetParNames("Constant","Mean","Sigma","ConstantExpo","Slope");
194  }
195  else if (m_name == "fermi") {
196  m_func->SetParameter(0,0.99);
197  m_func->SetParameter(1,5);
198  m_func->SetParameter(2,1);
199  m_func->SetParNames("Plateau","Threshold","Resolution");
200  }
201  else if(m_name == "flat") {
202  if(verbose)std::cout << "set "<<name<< " parameters" << std::endl;
203  m_func->SetParNames("Height");
204  }
205 /*
206  const int numsig = m_func->GetParNumber("Sigma");
207 
208  if (numsig != -1 ){
209  double sigmaup = dqm_algorithms::tools::GetFirstFromMap( "Sigma_upperLimit", config.getParameters(), 1000000);
210  m_func->SetParLimits(numsig, 0., sigmaup);
211  }
212  */
213 
214 
215  if(ignoreFirstLastBin) {
216  int firstNonEmptyBin=0;
217  int lastNonEmptyBin=0;
218  for(int i=1 ; i<=nbins ; i++) {
219  if(histogram->GetBinContent(i)!=0.0) {
220  firstNonEmptyBin=i;
221  break;
222  }
223  }
224  for(int i=nbins ; i>=0 ; i--) {
225  if(histogram->GetBinContent(i)!=0.0) {
226  lastNonEmptyBin=i;
227  break;
228  }
229  }
230 
231  if( lastNonEmptyBin-firstNonEmptyBin>2) { //ensures at least two good non-empty bins
232  if ( x->GetBinLowEdge(firstNonEmptyBin+1) > xmin ) {
233  xmin=x->GetBinLowEdge(firstNonEmptyBin+1);
234  }
235  if ( x->GetBinUpEdge(lastNonEmptyBin-1) < xmax ) {
236  xmax=x->GetBinUpEdge(lastNonEmptyBin-1);
237  }
238  }
239 
240  }
241  const_cast<TH1*>(histogram)->Fit( m_func.get(), option.c_str(),"",xmin,xmax );
242  if (m_name == "doublegaus") {
243  double par[6];
244  m_func->GetParameters(par);
245  if (std::abs(par[2]) > std::abs(par[5])) {
246  m_func->SetParNames("Constant1","Mean1","Sigma1","Constant","Mean","Sigma");
247  double sigma=m_func->GetParameter(2);
248  m_func->SetParameter(2,std::abs(sigma));
249  }
250  else {
251  m_func->SetParNames("Constant","Mean","Sigma","Constant1","Mean1","Sigma1");
252  double sigma=m_func->GetParameter(5);
253  m_func->SetParameter(5,std::abs(sigma));
254  }
255  }
256 
257  const int numsig = m_func->GetParNumber("Sigma");
258  if (numsig != -1 ){
259  double sigma=m_func->GetParameter(numsig);
260  m_func->SetParameter(numsig,std::abs(sigma));
261  }
262 
263  try {
265  return result;
266  }
267  catch ( dqm_core::Exception & ex ) {
268  throw dqm_core::BadConfig( ERS_HERE, name, ex.what(), ex );
269  }
270 }
271 
272 void
274 {
275  out<<"Simple_"+m_name+"_Fit: Does simple "+m_name+" fit to histogram and checks fit parameters against thresholds\n"<<std::endl;
276  if ( m_name == "gaus"){
277  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
278  out<<"Green/Red Treshold: Mean : Mean fit value to give Green/Red Result"<<std::endl;
279  out<<"Green/Red Treshold: AbsMean : AbsMean fit value to give Green/Red Result"<<std::endl;
280  out<<"Green/Red Treshold: Simga : Sigma fit value to give Green/Red Result"<<std::endl;
281  out<<"Green/Red Treshold: Constant : Constant fit value to give Green/Red Result\n"<<std::endl;
282  } else if ( m_name == "sinusoid"){
283  out<<"The sinusoid fit has the following functional form: s1*sin(x) + s2*cos(x)."<<std::endl
284  <<"Checks can be configured on both parameters, s1 and s2, with green and red thresholds:"<<std::endl;
285  } else if ( m_name == "doublegaus"){
286  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
287  out<<"smaller width will be assigned to Sigma"<<std::endl;
288  out<<"Green/Red Treshold: Mean : Mean fit value to give Green/Red Result"<<std::endl;
289  out<<"Green/Red Treshold: AbsMean : AbsMean fit value to give Green/Red Result"<<std::endl;
290  out<<"Green/Red Treshold: Sigma : Sigma fit value to give Green/Red Result"<<std::endl;
291  out<<"Green/Red Treshold: Constant : Constant fit value to give Green/Red Result\n"<<std::endl;
292  out<<"Green/Red Treshold: Mean1 : Mean fit value to give Green/Red Result"<<std::endl;
293  out<<"Green/Red Treshold: AbsMean1 : AbsMean fit value to give Green/Red Result"<<std::endl;
294  out<<"Green/Red Treshold: Simga1 : Sigma fit value to give Green/Red Result"<<std::endl;
295  out<<"Green/Red Treshold: Constant1 : Constant fit value to give Green/Red Result\n"<<std::endl;
296  } else if (m_name == "pol1") {
297  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
298  out<<"Green/Red Treshold: pol1[0] : Constant linear fit value to give Green/Red Result"<<std::endl;
299  out<<"Green/Red Treshold: pol1[1] : Slope linear fit value to give Green/Red Result\n"<<std::endl;
300  } else if (m_name == "gauspluspol1"){
301  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
302  out<<"Green/Red Treshold: Mean : Mean fit value to give Green/Red Result"<<std::endl;
303  out<<"Green/Red Treshold: AbsMean : AbsMean fit value to give Green/Red Result"<<std::endl;
304  out<<"Green/Red Treshold: Sigma : Sigma fit value to give Green/Red Result"<<std::endl;
305  out<<"Green/Red Treshold: Constant : Constant fit value to give Green/Red Result"<<std::endl;
306  out<<"Green/Red Treshold: pol1[0] : Constant linear fit value to give Green/Red Result"<<std::endl;
307  out<<"Green/Red Treshold: pol1[1] : Slope linear fit value to give Green/Red Result\n"<<std::endl;
308  } else if (m_name == "gausplusexpo"){
309  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
310  out<<"Green/Red Treshold: Mean : Mean fit value to give Green/Red Result"<<std::endl;
311  out<<"Green/Red Treshold: AbsMean : AbsMean fit value to give Green/Red Result"<<std::endl;
312  out<<"Green/Red Treshold: Sigma : Sigma fit value to give Green/Red Result"<<std::endl;
313  out<<"Green/Red Treshold: Constant : Constant fit value to give Green/Red Result"<<std::endl;
314  out<<"Green/Red Treshold: ConstantExpo : ConstantExpo fit value to give Green/Red Result"<<std::endl;
315  out<<"Green/Red Treshold: Slope : Slope fit value to give Green/Red Result\n"<<std::endl;
316  } else if (m_name == "landau") {
317  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
318  out<<"Green/Red Treshold: MPV : MPV fit value to give Green/Red Result"<<std::endl;
319  out<<"Green/Red Treshold: Sigma : Sigma fit value to give Green/Red Result"<<std::endl;
320  out<<"Green/Red Treshold: Constant : Constant fit value to give Green/Red Result\n"<<std::endl;
321  } else if (m_name == "fermi" ) {
322  out<<"The following fit Parameters can be checked with Red and Green Thresholds; only one parameter is needed to get back real result"<<std::endl;
323  out<<"Green/Red Threshold: Plateau : Plateau fit value to give Green/Red Result"<<std::endl;
324  out<<"Green/Red Threshold: Threshold : Fermi energy fit value to give Green/Red Result"<<std::endl;
325  out<<"Green/Red Threshold: Resolution : Templature fit value to give Green/Red Result\n"<<std::endl;
326  }
327  out<<"Optional Parameter: Verbose: Write out fit results to log file (set to 1)"<<std::endl;
328  out<<"Optional Parameter: LikelihoodFit: Fit with L or LL option if 1 or 2"<<std::endl;
329  out<<"Optional Parameter: MinStat: Minimum histogram statistics needed to perform Algorithm"<<std::endl;
330  out<<"Optional Parameter: MinSignificance : Minimum multiple of the error in fit paramenter by which the parameter must exceed the thresholds"<<std::endl;
331  out<<"Optional Parameter: xmin: minimum x range"<<std::endl;
332  out<<"Optional Parameter: xmax: maximum x range"<<std::endl;
333  out<<"Optional Parameter: SubtractFromMean: value subtracted from XMean before test is applied: allows using AbsXMean for non-zero expected mean"<<std::endl;
334  out<<"Optional Parameter: ignoreFirstLastBin: ignores the first and last non-empty bin"<<std::endl;
335 // out<<"Optional Parameter: Sigma_upperLimit: Upper limit on Sigma- lower limit set to 0. and default upper value is 1e^6\n"<<std::endl;
336 
337 }
338 
Undefined
@ Undefined
Definition: MaterialTypes.h:8
pdg_comparison.sigma
sigma
Definition: pdg_comparison.py:324
get_generator_info.result
result
Definition: get_generator_info.py:21
IsA
#define IsA
Declare the TObject style functions.
Definition: xAODTEventBranch.h:59
dqm_algorithms::tools::GetFitResult
dqm_core::Result * GetFitResult(const TF1 *func, const dqm_core::AlgorithmConfig &config, double minSig=0)
Definition: AlgorithmHelper.cxx:308
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
dqm_algorithms::RootFit::m_name
std::string m_name
Definition: RootFit.h:34
x
#define x
dqm_algorithms::RootFit::clone
RootFit * clone()
Definition: RootFit.cxx:76
config
Definition: PhysicsAnalysis/AnalysisCommon/AssociationUtils/python/config.py:1
SCT_CalibAlgs::nbins
@ nbins
Definition: SCT_CalibNumbers.h:10
instance
std::map< std::string, double > instance
Definition: Run_To_Get_Tags.h:8
dqm_algorithms::RootFit::RootFit
RootFit(const std::string &name)
Definition: RootFit.cxx:35
dqm_algorithms::RootFit::~RootFit
~RootFit()
Definition: RootFit.cxx:69
lumiFormat.i
int i
Definition: lumiFormat.py:92
xmin
double xmin
Definition: listroot.cxx:60
Result
ICscStripFitter::Result Result
Definition: CalibCscStripFitter.cxx:13
dqm_algorithms::RootFit
Definition: RootFit.h:25
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
createCoolChannelIdFile.par
par
Definition: createCoolChannelIdFile.py:29
RootFit.h
TH1
Definition: rootspy.cxx:268
python.TriggerHandler.verbose
verbose
Definition: TriggerHandler.py:297
xmax
double xmax
Definition: listroot.cxx:61
dqm_algorithms::RootFit::printDescription
void printDescription(std::ostream &out)
Definition: RootFit.cxx:273
AlgorithmHelper.h
pickleTool.object
object
Definition: pickleTool.py:30
dqm_algorithms::RootFit::execute
dqm_core::Result * execute(const std::string &, const TObject &, const dqm_core::AlgorithmConfig &)
Definition: RootFit.cxx:83
dqm_algorithms::RootFit::m_func
std::unique_ptr< TF1 > m_func
Definition: RootFit.h:35
dqm_algorithms::tools::GetFirstFromMap
double GetFirstFromMap(const std::string &paramName, const std::map< std::string, double > &params)
Definition: AlgorithmHelper.cxx:339
histogram
std::string histogram
Definition: chains.cxx:52
read_hist_ntuple.f1
f1
Definition: read_hist_ntuple.py:4