Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TFitEditor.cxx
Go to the documentation of this file.
1 // @(#)root/fitpanel:$Id: ed8d59036b6a51c67cd739c2c75aa7780b847bf8 $
2 // Author: Ilka Antcheva, Lorenzo Moneta 10/08/2006
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 
13 //////////////////////////////////////////////////////////////////////////
14 // //
15 // TFitEditor //
16 // //
17 // Allows to perform, explore and compare various fits. //
18 // //
19 // To display the new Fit panel interface right click on a histogram //
20 // or a graph to pop up the context menu and then select the menu //
21 // entry 'Fit Panel'. //
22 // //
23 // "General" Tab //
24 // //
25 // The first set of GUI elements is related to the function choice //
26 // and settings. The status bar on the bottom provides information //
27 // about the current minimization settings using the following //
28 // abbreviations: //
29 // LIB - shows the current choice between Minuit/Minuit2/Fumili //
30 // MIGRAD or FUMILI points to the current minimization method in use. //
31 // Itr: - shows the maximum number of iterations nnnn set for the fit. //
32 // Prn: - can be DEF/VER/QT and shows the current print option in use. //
33 // //
34 // "Predefined" combo box - contains a list of predefined functions //
35 // in ROOT. The default one is Gaussian. //
36 // //
37 // "Operation" radio button group defines selected operational mode //
38 // between functions: NOP - no operation (default); ADD - addition //
39 // CONV - convolution (will be implemented in the future). //
40 // //
41 // Users can enter the function expression in a text entry field. //
42 // The entered string is checked after Enter key was pressed. An //
43 // error message shows up if the string is not accepted. The current //
44 // prototype is limited and users have no freedom to enter file/user //
45 // function names in this field. //
46 // //
47 // "Set Parameters" button opens a dialog for parameters settings. //
48 // //
49 // "Fit Settings" provides user interface elements related to the //
50 // fitter. Currently there are two method choices: Chi-square and //
51 // Binned Likelihood. //
52 // //
53 // "Linear Fit" check button sets the use of Linear fitter is it is //
54 // selected. Otherwise the option 'F' is applied if polN is selected. //
55 // "Robust" number entry sets the robust value when fitting graphs. //
56 // "No Chi-square" check button sets ON/OFF option 'C' - do not //
57 // calculate Chi-square (for Linear fitter). //
58 // //
59 // Fit options: //
60 // "Integral" check button switch ON/OFF option 'I' - use integral //
61 // of function instead of value in bin center. //
62 // "Best Errors" sets ON/OFF option 'E' - better errors estimation //
63 // using Minos technique. //
64 // "All weights = 1" sets ON/OFF option 'W' - all weights set to 1, //
65 // excluding empty bins and ignoring error bars. //
66 // "Empty bins, weights=1" sets ON/OFF option 'WW' - all weights //
67 // equal to 1, including empty bins, error bars ignored. //
68 // "Use range" sets ON/OFF option 'R' - fit only data within the //
69 // specified function range with the slider. //
70 // "Improve fit results" sets ON/OFF option 'M' - after minimum is //
71 // found, search for a new one. //
72 // "Add to list" sets On/Off option '+'- add function to the list //
73 // without deleting the previous. //
74 // //
75 // Draw options: //
76 // "SAME" sets On/Off function drawing on the same pad. //
77 // "No drawing" sets On/Off option '0'- do not draw function graphics. //
78 // "Do not store/draw" sets On/Off option 'N'- do not store the //
79 // function, do not draw it. //
80 // //
81 // Sliders settings are used if option 'R' - use range is active. //
82 // Users can change min/max values by pressing the left mouse button //
83 // near to the left/right slider edges. It is possible o change both //
84 // values simultaneously by pressing the left mouse button near to its //
85 // center and moving it to a new desire position. //
86 // //
87 // "Minimization" Tab //
88 // //
89 // "Library" group allows you to use Minuit, Minuit2 or Fumili //
90 // minimization packages for your fit. //
91 // "Minuit" - the popular Minuit minimization package. //
92 // "Minuit2" - a new object-oriented implementation of Minuit in C++. //
93 // "Fumili" - the popular Fumili minimization package. //
94 // //
95 // "Method" group has currently restricted functionality. //
96 // "MIGRAD" method is available for Minuit and Minuit2 //
97 // "FUMILI" method is available for Fumili and Minuit2 //
98 // "SIMPLEX" method is disabled (will come with the new fitter design) //
99 // //
100 // "Minimization Settings' group allows users to set values for: //
101 // "Error definition" - between 0.0 and 100.0 (default is 1.0). //
102 // "Maximum tolerance" - the fit relative precision in use. //
103 // "Maximum number of iterations" - default is 5000. //
104 // //
105 // Print options: //
106 // "Default" - between Verbose and Quiet. //
107 // "Verbose" - prints results after each iteration. //
108 // "Quiet" - no fit information is printed. //
109 // //
110 // Fit button - performs a fit. //
111 // Reset - resets all GUI elements and related fit settings to the //
112 // default ones. //
113 // Close - closes this window. //
114 // //
115 // Begin_Html //
116 /*
117 <img src="gif/TFitEditor.gif">
118 */
119 //End_Html
120 //////////////////////////////////////////////////////////////////////////
121 
122 #include "TFitEditor.h"
123 #include "TROOT.h"
124 #include "TClass.h"
125 #include "TCanvas.h"
126 #include "TGTab.h"
127 #include "TGLabel.h"
128 #include "TG3DLine.h"
129 #include "TGComboBox.h"
130 #include "TGTextEntry.h"
131 #include "TGFont.h"
132 #include "TGGC.h"
133 #include "TGButtonGroup.h"
134 #include "TGNumberEntry.h"
135 #include "TGDoubleSlider.h"
136 #include "TGStatusBar.h"
137 #include "TFitParametersDialog.h"
138 #include "TGMsgBox.h"
139 #include "TAxis.h"
140 #include "TGraph.h"
141 #include "TGraph2D.h"
142 #include "TH1.h"
143 #include "TH2.h"
144 #include "HFitInterface.h"
145 #include "TF1.h"
146 #include "TF1NormSum.h"
147 #include "TF1Convolution.h"
148 #include "TF2.h"
149 #include "TF3.h"
150 #include "TTimer.h"
151 #include "THStack.h"
152 #include "TMath.h"
153 #include "Fit/UnBinData.h"
154 #include "Fit/BinData.h"
155 #include "Fit/BinData.h"
156 #include "TMultiGraph.h"
157 #include "TTree.h"
158 #include "TTreePlayer.h"
159 #include "TTreeInput.h"
160 #include "TAdvancedGraphicsDialog.h"
161 
162 #include "RConfigure.h"
163 #include "TPluginManager.h"
164 
165 #include <vector>
166 #include <queue>
167 using std::vector;
168 using std::pair;
169 
170 #include "CommonDefs.h"
171 
172 // #include <iostream>
173 // using std::cout;
174 // using std::endl;
175 
176 void SearchCanvases(TSeqCollection* canvases, std::vector<TObject*>& objects);
177 
178 typedef std::multimap<TObject*, TF1*> FitFuncMap_t;
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// This method looks among the functions stored by the fitpanel, the
182 /// one that is currently selected in the fFuncList
183 
184 TF1* TFitEditor::FindFunction()
185 {
186  // Get the title/name of the function from fFuncList
187  TGTextLBEntry *te = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
188  if ( !te ) return 0;
189  TString name(te->GetTitle());
190 
191  // Look for a system function if it's USER DEFINED function
192  if ( fTypeFit->GetSelected() == kFP_UFUNC ) {
193  for (auto f : fSystemFuncs) {
194  if ( strcmp( f->GetName(), name ) == 0 )
195  // If found, return it.
196  return f;
197  }
198  // If we are looking for previously fitted functions, look in the
199  // fPrevFit data structure.
200  } else if ( fTypeFit->GetSelected() == kFP_PREVFIT ) {
201  std::pair<fPrevFitIter, fPrevFitIter> look = fPrevFit.equal_range(fFitObject);
202  for ( fPrevFitIter it = look.first; it != look.second; ++it ) {
203  TF1* f = it->second;
204  if ( strcmp( f->GetName(), name ) == 0 )
205  // If found, return it
206  return f;
207  }
208  }
209 
210  // Return a pointer to null if the function does not exist. This
211  // will eventually create a segmentation fault, but the line should
212  // never be executed.
213  return 0;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 ///Copies f into a new TF1 to be stored in the fitpanel with it's
218 ///own ownership. This is taken from Fit::StoreAndDrawFitFunction in
219 ///HFitImpl.cxx
220 
221 TF1* copyTF1(TF1 *f)
222 {
223  double xmin = 0, xmax = 0, ymin = 0, ymax = 0, zmin = 0, zmax = 0;
224 
225  // no need to use kNotGlobal bit. TF1::Copy does not add in the list by default
226  if ( dynamic_cast<TF3 *>(f) != 0 ) {
227  TF3* fnew = (TF3 *)f->IsA()->New();
228  f->Copy(*fnew);
229  f->GetRange(xmin,ymin,zmin,xmax,ymax,zmax);
230  fnew->SetRange(xmin,ymin,zmin,xmax,ymax,zmax);
231  fnew->SetParent( nullptr );
232  fnew->AddToGlobalList(false);
233  return fnew;
234  } else if ( dynamic_cast<TF2 *>(f) != 0 ) {
235  TF2* fnew = (TF2 *)f->IsA()->New();
236  f->Copy(*fnew);
237  f->GetRange(xmin,ymin,xmax,ymax);
238  fnew->SetRange(xmin,ymin,xmax,ymax);
239  fnew->Save(xmin,xmax,ymin,ymax,0,0);
240  fnew->SetParent( nullptr );
241  fnew->AddToGlobalList(false);
242  return fnew;
243  } else {
244  TF1* fnew = (TF1 *)f->IsA()->New();
245  f->Copy(*fnew);
246  f->GetRange(xmin,xmax);
247  fnew->SetRange(xmin,xmax);
248  // This next line is added, as fnew-Save fails with gausND! As
249  // the number of dimensions is unknown...
250  if ( '\0' != fnew->GetExpFormula()[0] )
251  fnew->Save(xmin,xmax,0,0,0,0);
252  fnew->SetParent( nullptr );
253  fnew->AddToGlobalList(false);
254  return fnew;
255  }
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 /// Stores the parameters of the given function into pars
260 
261 void GetParameters(TFitEditor::FuncParams_t & pars, TF1* func)
262 {
263  int npar = func->GetNpar();
264  if (npar != (int) pars.size() ) pars.resize(npar);
265  for ( Int_t i = 0; i < npar; ++i )
266  {
267  Double_t par_min, par_max;
268  pars[i][PAR_VAL] = func->GetParameter(i);
269  func->GetParLimits(i, par_min, par_max);
270  pars[i][PAR_MIN] = par_min;
271  pars[i][PAR_MAX] = par_max;
272  }
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// Restore the parameters from pars into the function
277 
278 void SetParameters(TFitEditor::FuncParams_t & pars, TF1* func)
279 {
280  int npar = func->GetNpar();
281  if (npar > (int) pars.size() ) pars.resize(npar);
282  for ( Int_t i = 0; i < npar; ++i )
283  {
284  func->SetParameter(i, pars[i][PAR_VAL]);
285  func->SetParLimits(i, pars[i][PAR_MIN], pars[i][PAR_MAX]);
286  }
287 }
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// Parameter initialization for the function
291 
292 template<class FitObject>
293 void InitParameters(TF1* func, FitObject * fitobj)
294 {
295  const int special = func->GetNumber();
296  if (100 == special || 400 == special) {
297  ROOT::Fit::BinData data;
298  ROOT::Fit::FillData(data,fitobj,func);
299  ROOT::Fit::InitGaus(data, func);
300  // case gaussian or Landau
301  } else if ( 110 == special || 410 == special ) {
302  ROOT::Fit::BinData data;
303  ROOT::Fit::FillData(data,fitobj,func);
304  ROOT::Fit::Init2DGaus(data,func);
305  }
306 }
307 
308 ////////////////////////////////////////////////////////////////////////////////
309 /// Splits the entry in fDataSet to get the selected variables and cuts
310 /// from the text.
311 
312 void GetTreeVarsAndCuts(TGComboBox* dataSet, TString& variablesStr, TString& cutsStr)
313 {
314  // Get the entry
315  TGTextLBEntry* textEntry =
316  static_cast<TGTextLBEntry*>( dataSet->GetListBox()->GetEntry( dataSet->GetSelected() ) );
317  if (!textEntry) return;
318  // Get the name of the tree
319  TString nameStr ( textEntry->GetText()->GetString() );
320  // Get the variables selected
321  variablesStr = nameStr(nameStr.First('(') + 2, nameStr.First(',') - nameStr.First('(') - 3);
322  // Get the cuts selected
323  cutsStr = nameStr( nameStr.First(',') + 3, nameStr.First(')') - nameStr.First(',') - 4 );
324 }
325 
326 
327 ClassImp(TFitEditor);
328 
329 TFitEditor *TFitEditor::fgFitDialog = 0;
330 
331 ////////////////////////////////////////////////////////////////////////////////
332 /// Static method - opens the fit panel.
333 
334 TFitEditor * TFitEditor::GetInstance(TVirtualPad* pad, TObject *obj)
335 {
336  // Get the default pad if not provided.
337  if (!pad)
338  {
339  if (!gPad)
340  gROOT->MakeDefCanvas();
341  pad = gPad;
342  }
343 
344  if (!fgFitDialog) {
345  fgFitDialog = new TFitEditor(pad, obj);
346  } else {
347  fgFitDialog->Show(pad, obj);
348  }
349  return fgFitDialog;
350 }
351 
352 ////////////////////////////////////////////////////////////////////////////////
353 /// Constructor of fit editor. 'obj' is the object to be fitted and
354 /// 'pad' where it is drawn.
355 
356 TFitEditor::TFitEditor(TVirtualPad* pad, TObject *obj) :
357  TGMainFrame(gClient->GetRoot(), 20, 20),
358  fParentPad (0),
359  fFitObject (0),
360  fDim (0),
361  fXaxis (0),
362  fYaxis (0),
363  fZaxis (0),
364  fSumFunc (0),
365  fConvFunc (0),
366  fFuncPars (0),
367  fChangedParams (kFALSE)
368 {
369  fType = kObjectHisto;
370  SetCleanup(kDeepCleanup);
371 
372  TGCompositeFrame *tf = new TGCompositeFrame(this, 350, 26,
373  kHorizontalFrame);
374  TGLabel *label = new TGLabel(tf,"Data Set: ");
375  tf->AddFrame(label, new TGLayoutHints(kLHintsNormal, 15, 0, 5, 0));
376 
377  fDataSet = new TGComboBox(tf, kFP_DATAS);
378  FillDataSetList();
379  fDataSet->Resize(264, 20);
380 
381  tf->AddFrame(fDataSet, new TGLayoutHints(kLHintsNormal, 13, 0, 5, 0));
382  fDataSet->Associate(this);
383 
384  this->AddFrame(tf, new TGLayoutHints(kLHintsNormal | kLHintsExpandX,0,0,5,5));
385 
386  CreateFunctionGroup();
387 
388  fTab = new TGTab(this, 10, 10);
389  AddFrame(fTab, new TGLayoutHints(kLHintsExpandY | kLHintsExpandX));
390  fTab->SetCleanup(kDeepCleanup);
391  fTab->Associate(this);
392 
393  TGHorizontalFrame *cf1 = new TGHorizontalFrame(this, 350, 20, kFixedWidth);
394  cf1->SetCleanup(kDeepCleanup);
395  fUpdateButton = new TGTextButton(cf1, "&Update", kFP_UPDATE);
396  fUpdateButton->Associate(this);
397  cf1->AddFrame(fUpdateButton, new TGLayoutHints(kLHintsTop |
398  kLHintsExpandX, 0, 20, 2, 2));
399 
400 
401  fFitButton = new TGTextButton(cf1, "&Fit", kFP_FIT);
402  fFitButton->Associate(this);
403  cf1->AddFrame(fFitButton, new TGLayoutHints(kLHintsTop |
404  kLHintsExpandX, 15, -6, 2, 2));
405 
406  fResetButton = new TGTextButton(cf1, "&Reset", kFP_RESET);
407  fResetButton->Associate(this);
408  cf1->AddFrame(fResetButton, new TGLayoutHints(kLHintsTop |
409  kLHintsExpandX, 11, -2, 2, 2));
410 
411  fCloseButton = new TGTextButton(cf1, "&Close", kFP_CLOSE);
412  fCloseButton->Associate(this);
413  cf1->AddFrame(fCloseButton, new TGLayoutHints(kLHintsTop |
414  kLHintsExpandX, 7, 2, 2, 2));
415  AddFrame(cf1, new TGLayoutHints(kLHintsNormal |
416  kLHintsRight, 0, 5, 5, 5));
417 
418  // Create status bar
419  int parts[] = { 20, 20, 20, 20, 20 };
420  fStatusBar = new TGStatusBar(this, 10, 10);
421  fStatusBar->SetParts(parts, 5);
422  AddFrame(fStatusBar, new TGLayoutHints(kLHintsBottom |
423  kLHintsLeft |
424  kLHintsExpandX));
425 
426  CreateGeneralTab();
427  CreateMinimizationTab();
428 
429  gROOT->GetListOfCleanups()->Add(this);
430 
431  MapSubwindows();
432  fGeneral->HideFrame(fSliderZParent);
433 
434  // do not allow resizing
435  TGDimension size = GetDefaultSize();
436  SetWindowName("Fit Panel");
437  SetIconName("Fit Panel");
438  SetClassHints("ROOT", "Fit Panel");
439 
440  SetMWMHints(kMWMDecorAll | kMWMDecorResizeH | kMWMDecorMaximize |
441  kMWMDecorMinimize | kMWMDecorMenu,
442  kMWMFuncAll | kMWMFuncResize | kMWMFuncMaximize |
443  kMWMFuncMinimize,
444  kMWMInputModeless);
445 
446  ConnectSlots();
447 
448  GetFunctionsFromSystem();
449 
450  if (!obj) {
451  TList* l = new TList();
452  l->Add(pad);
453  std::vector<TObject*> v;
454  SearchCanvases(l, v);
455  if ( v.size() )
456  obj = v[0];
457  delete l;
458  }
459 
460  SetFitObject(pad, obj, kButton1Down);
461 
462  // In case we want to make it without a default canvas. This will
463  // be implemented after the 5.21/06 Release. Remember to take out
464  // any reference to the pad/canvas when the fitpanel is shown
465  // and/or built.
466 
467  //SetCanvas(0 /*pad->GetCanvas()*/);
468 
469  if ( pad ) {
470  SetCanvas(pad->GetCanvas());
471  if ( obj )
472  pad->GetCanvas()->Selected(pad, obj, kButton1Down);
473  }
474 
475  UInt_t dw = fClient->GetDisplayWidth();
476  UInt_t cw = 0;
477  UInt_t cx = 0;
478  UInt_t cy = 0;
479  if (pad && pad->GetCanvas() ) {
480  cw = pad->GetCanvas()->GetWindowWidth();
481  cx = (UInt_t)pad->GetCanvas()->GetWindowTopX();
482  cy = (UInt_t)pad->GetCanvas()->GetWindowTopY();
483  }
484 
485  Resize(size);
486  MapWindow();
487 
488  if (cw + size.fWidth < dw) {
489  Int_t gedx = 0, gedy = 0;
490  gedx = cx+cw+4;
491  gedy = (cy > 20) ? cy-20 : 0;
492  MoveResize(gedx, gedy, size.fWidth, size.fHeight);
493  SetWMPosition(gedx, gedy);
494  }
495 
496  gVirtualX->RaiseWindow(GetId());
497 
498  ChangeOptions(GetOptions() | kFixedSize);
499  SetWMSize(size.fWidth, size.fHeight);
500  SetWMSizeHints(size.fWidth, size.fHeight, size.fWidth, size.fHeight, 0, 0);
501 }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 /// Fit editor destructor.
505 
506 TFitEditor::~TFitEditor()
507 {
508  DisconnectSlots();
509 
510  // Disconnect all the slot that were no disconnected in DisconnecSlots
511  fCloseButton ->Disconnect("Clicked()");
512  fDataSet ->Disconnect("Selected(Int_t)");
513  fUpdateButton->Disconnect("Clicked()");
514  TQObject::Disconnect("TCanvas", "Selected(TVirtualPad *, TObject *, Int_t)",
515  this, "SetFitObject(TVirtualPad *, TObject *, Int_t)");
516  gROOT->GetListOfCleanups()->Remove(this);
517 
518  //Clean up the members that are not automatically cleaned.
519  Cleanup();
520  delete fLayoutNone;
521  delete fLayoutAdd;
522  delete fLayoutConv;
523 
524  if (fConvFunc) delete fConvFunc;
525  if (fSumFunc) delete fSumFunc;
526 
527  // release memory used by stored functions of previous fits
528  for (auto &entry : fPrevFit)
529  delete entry.second;
530  fPrevFit.clear();
531 
532  // release memory used by copies of system functions
533  for (auto func : fSystemFuncs)
534  delete func;
535  fSystemFuncs.clear();
536 
537  // Set the singleton reference to null
538  fgFitDialog = 0;
539 }
540 
541 ////////////////////////////////////////////////////////////////////////////////
542 /// Creates the Frame that contains oll the information about the
543 /// function.
544 
545 void TFitEditor::CreateFunctionGroup()
546 {
547  TGGroupFrame *gf1 = new TGGroupFrame(this, "Fit Function", kFitWidth);
548  TGCompositeFrame *tf0 = new TGCompositeFrame(gf1, 350, 26, kHorizontalFrame);
549  TGLabel *label1 = new TGLabel(tf0,"Type:");
550  tf0 -> AddFrame(label1, new TGLayoutHints(kLHintsNormal, 0, 0, 5, 0));
551 
552  fTypeFit = new TGComboBox(tf0, kFP_TLIST);
553  fTypeFit -> AddEntry("User Func", kFP_UFUNC);
554  fTypeFit -> AddEntry("Predef-1D", kFP_PRED1D);
555  fTypeFit -> Resize(90, 20);
556  fTypeFit -> Select(kFP_PRED1D, kFALSE);
557 
558  TGListBox *lb = fTypeFit->GetListBox();
559  lb->Resize(lb->GetWidth(), 200);
560  tf0->AddFrame(fTypeFit, new TGLayoutHints(kLHintsNormal, 5, 0, 5, 0));
561  fTypeFit->Associate(this);
562 
563  fFuncList = new TGComboBox(tf0, kFP_FLIST);
564  FillFunctionList();
565  fFuncList->Resize(194, 20);
566  fFuncList->Select(kFP_GAUS, kFALSE);
567 
568  lb = fFuncList->GetListBox();
569  lb -> Resize(lb->GetWidth(), 500);
570  tf0 -> AddFrame(fFuncList, new TGLayoutHints(kLHintsNormal, 5, 0, 5, 0));
571  fFuncList->Associate(this);
572 
573  gf1->AddFrame(tf0, new TGLayoutHints(kLHintsNormal | kLHintsExpandX));
574 
575  TGCompositeFrame *tf1 = new TGCompositeFrame(gf1, 350, 26, kHorizontalFrame);
576  TGHButtonGroup *bgr = new TGHButtonGroup(tf1, "Operation");
577 
578  bgr -> SetRadioButtonExclusive();
579  fNone = new TGRadioButton(bgr, "Nop", kFP_NONE);
580  fAdd = new TGRadioButton(bgr, "Add", kFP_ADD);
581  fNormAdd = new TGRadioButton(bgr, "NormAdd", kFP_NORMADD);
582  fConv = new TGRadioButton(bgr, "Conv", kFP_CONV);
583 
584  fNone -> SetToolTipText("No operation defined");
585  fNone -> SetState(kButtonDown, kFALSE);
586  fAdd -> SetToolTipText("Addition");
587  // fAdd -> SetState(kButtonDown, kFALSE);
588  fNormAdd -> SetToolTipText("NormAddition");
589  //fNormAdd -> SetState(kButtonDown, kFALSE);
590  fConv -> SetToolTipText("Convolution");
591  //fConv -> SetState(kButtonDown, kTRUE);
592 
593  fLayoutNone = new TGLayoutHints(kLHintsLeft,0 ,5,3,-10);
594  fLayoutAdd = new TGLayoutHints(kLHintsLeft,10,5,3,-10);
595  fLayoutNormAdd = new TGLayoutHints(kLHintsLeft,10,5,3,-10);
596  fLayoutConv = new TGLayoutHints(kLHintsLeft,10,5,3,-10);
597 
598  bgr -> SetLayoutHints(fLayoutNone, fNone);
599  bgr -> SetLayoutHints(fLayoutAdd, fAdd);
600  bgr -> SetLayoutHints(fLayoutNormAdd,fNormAdd);
601  bgr -> SetLayoutHints(fLayoutConv, fConv);
602  bgr -> Show();
603  bgr -> ChangeOptions(kFitWidth | kHorizontalFrame);
604 
605  tf1 -> AddFrame(bgr, new TGLayoutHints(kLHintsExpandX, 0, 0, 3, 0));
606  gf1 -> AddFrame(tf1, new TGLayoutHints(kLHintsExpandX));
607 
608  TGCompositeFrame *tf2 = new TGCompositeFrame(gf1, 350, 26,
609  kHorizontalFrame);
610  fEnteredFunc = new TGTextEntry(tf2, new TGTextBuffer(0), kFP_FILE);
611  //fEnteredFunc->SetMaxLength(4000); // use default value (~4000)
612  fEnteredFunc->SetAlignment(kTextLeft);
613  TGTextLBEntry *te = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
614  assert(te);
615  fEnteredFunc->SetText(te->GetTitle());
616  fEnteredFunc->SetToolTipText("Enter file_name/function_name or a function expression");
617  fEnteredFunc->Resize(250,fEnteredFunc->GetDefaultHeight());
618  tf2->AddFrame(fEnteredFunc, new TGLayoutHints(kLHintsLeft |
619  kLHintsCenterY |
620  kLHintsExpandX, 2, 2, 2, 2));
621  gf1->AddFrame(tf2, new TGLayoutHints(kLHintsNormal |
622  kLHintsExpandX, 0, 0, 2, 0));
623 
624  TGHorizontalFrame *s1 = new TGHorizontalFrame(gf1);
625  TGLabel *label21 = new TGLabel(s1, "Selected: ");
626  s1->AddFrame(label21, new TGLayoutHints(kLHintsNormal |
627  kLHintsCenterY, 2, 2, 2, 0));
628  TGHorizontal3DLine *hlines = new TGHorizontal3DLine(s1);
629  s1->AddFrame(hlines, new TGLayoutHints(kLHintsCenterY | kLHintsExpandX));
630  gf1->AddFrame(s1, new TGLayoutHints(kLHintsExpandX));
631 
632  TGCompositeFrame *tf4 = new TGCompositeFrame(gf1, 350, 26,
633  kHorizontalFrame);
634  TGTextLBEntry *txt = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
635  TString s = txt->GetTitle();
636  fSelLabel = new TGLabel(tf4, s.Sizeof()>30?s(0,30)+"...":s);
637  tf4->AddFrame(fSelLabel, new TGLayoutHints(kLHintsNormal |
638  kLHintsCenterY, 0, 6, 2, 0));
639  Pixel_t color;
640  gClient->GetColorByName("#336666", color);
641  fSelLabel->SetTextColor(color, kFALSE);
642  TGCompositeFrame *tf5 = new TGCompositeFrame(tf4, 120, 20,
643  kHorizontalFrame | kFixedWidth);
644  fSetParam = new TGTextButton(tf5, "Set Parameters...", kFP_PARS);
645  tf5->AddFrame(fSetParam, new TGLayoutHints(kLHintsRight |
646  kLHintsCenterY |
647  kLHintsExpandX));
648  fSetParam->SetToolTipText("Open a dialog for parameter(s) settings");
649  tf4->AddFrame(tf5, new TGLayoutHints(kLHintsRight |
650  kLHintsTop, 5, 0, 2, 2));
651  gf1->AddFrame(tf4, new TGLayoutHints(kLHintsNormal |
652  kLHintsExpandX, 5, 0, 0, 0));
653 
654  this->AddFrame(gf1, new TGLayoutHints(kLHintsExpandX, 5, 5, 0, 0));
655 
656 }
657 
658 ////////////////////////////////////////////////////////////////////////////////
659 /// Create 'General' tab.
660 
661 void TFitEditor::CreateGeneralTab()
662 {
663  fTabContainer = fTab->AddTab("General");
664  fGeneral = new TGCompositeFrame(fTabContainer, 10, 10, kVerticalFrame);
665  fTabContainer->AddFrame(fGeneral, new TGLayoutHints(kLHintsTop |
666  kLHintsExpandX,
667  5, 5, 2, 2));
668 
669  // 'options' group frame
670  TGGroupFrame *gf = new TGGroupFrame(fGeneral, "Fit Settings", kFitWidth);
671 
672  // 'method' sub-group
673  TGHorizontalFrame *h1 = new TGHorizontalFrame(gf);
674  TGLabel *label4 = new TGLabel(h1, "Method");
675  h1->AddFrame(label4, new TGLayoutHints(kLHintsNormal |
676  kLHintsCenterY, 2, 2, 0, 0));
677  TGHorizontal3DLine *hline1 = new TGHorizontal3DLine(h1);
678  h1->AddFrame(hline1, new TGLayoutHints(kLHintsCenterY | kLHintsExpandX));
679  gf->AddFrame(h1, new TGLayoutHints(kLHintsExpandX));
680 
681  TGHorizontalFrame *h2 = new TGHorizontalFrame(gf);
682  TGVerticalFrame *v1 = new TGVerticalFrame(h2);
683  fMethodList = BuildMethodList(v1, kFP_MLIST);
684  fMethodList->Select(1, kFALSE);
685  fMethodList->Resize(140, 20);
686  TGListBox *lb = fMethodList->GetListBox();
687  Int_t lbe = lb->GetNumberOfEntries();
688  lb->Resize(lb->GetWidth(), lbe*16);
689  v1->AddFrame(fMethodList, new TGLayoutHints(kLHintsLeft, 0, 0, 2, 5));
690 
691  fLinearFit = new TGCheckButton(v1, "Linear fit", kFP_MLINF);
692  fLinearFit->Associate(this);
693  fLinearFit->SetToolTipText("Perform Linear fitter if selected");
694  v1->AddFrame(fLinearFit, new TGLayoutHints(kLHintsNormal, 0, 0, 8, 2));
695 
696 
697  h2->AddFrame(v1, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
698 
699  TGVerticalFrame *v2 = new TGVerticalFrame(h2);
700  TGCompositeFrame *v21 = new TGCompositeFrame(v2, 120, 20,
701  kHorizontalFrame | kFixedWidth);
702  fUserButton = new TGTextButton(v21, "User-Defined...", kFP_MUSR);
703  v21->AddFrame(fUserButton, new TGLayoutHints(kLHintsRight |
704  kLHintsCenterY |
705  kLHintsExpandX));
706  fUserButton->SetToolTipText("Open a dialog for entering a user-defined method");
707  fUserButton->SetState(kButtonDisabled);
708  v2->AddFrame(v21, new TGLayoutHints(kLHintsRight | kLHintsTop));
709 
710  TGHorizontalFrame *v1h = new TGHorizontalFrame(v2);
711  fEnableRobust = new TGCheckButton(v1h, "Robust:", -1);
712  fEnableRobust->Associate(this); // needed ???
713  fEnableRobust->SetToolTipText("Perform Linear Robust fitter if selected");
714  v1h->AddFrame(fEnableRobust, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
715  fRobustValue = new TGNumberEntry(v1h, 0.95, 5, kFP_RBUST,
716  TGNumberFormat::kNESRealTwo,
717  TGNumberFormat::kNEAPositive,
718  TGNumberFormat::kNELLimitMinMax,0.,0.99);
719  v1h->AddFrame(fRobustValue, new TGLayoutHints(kLHintsLeft));
720  v2->AddFrame(v1h, new TGLayoutHints(kLHintsNormal, 0, 0, 12, 2));
721  fRobustValue->SetState(kFALSE);
722  fRobustValue->GetNumberEntry()->SetToolTipText("Available only for graphs");
723 
724  fNoChi2 = 0;
725  // fNoChi2 = new TGCheckButton(v2, "No Chi-square", kFP_NOCHI);
726  // fNoChi2->Associate(this);
727  // fNoChi2->SetToolTipText("'C'- do not calculate Chi-square (for Linear fitter)");
728  // v2->AddFrame(fNoChi2, new TGLayoutHints(kLHintsNormal, 0, 0, 34, 2));
729 
730  h2->AddFrame(v2, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 20, 0, 0, 0));
731  gf->AddFrame(h2, new TGLayoutHints(kLHintsExpandX, 20, 0, 0, 0));
732 
733  // 'fit option' sub-group
734  TGHorizontalFrame *h3 = new TGHorizontalFrame(gf);
735  TGLabel *label5 = new TGLabel(h3, "Fit Options");
736  h3->AddFrame(label5, new TGLayoutHints(kLHintsNormal |
737  kLHintsCenterY, 2, 2, 0, 0));
738  TGHorizontal3DLine *hline2 = new TGHorizontal3DLine(h3);
739  h3->AddFrame(hline2, new TGLayoutHints(kLHintsCenterY | kLHintsExpandX));
740  gf->AddFrame(h3, new TGLayoutHints(kLHintsExpandX));
741 
742  TGHorizontalFrame *h = new TGHorizontalFrame(gf);
743  TGVerticalFrame *v3 = new TGVerticalFrame(h);
744  fIntegral = new TGCheckButton(v3, "Integral", kFP_INTEG);
745  fIntegral->Associate(this);
746  fIntegral->SetToolTipText("'I'- use integral of function instead of value in bin center");
747  v3->AddFrame(fIntegral, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
748 
749  fBestErrors = new TGCheckButton(v3, "Best errors", kFP_IMERR);
750  fBestErrors->Associate(this);
751  fBestErrors->SetToolTipText("'E'- better errors estimation using Minos technique");
752  v3->AddFrame(fBestErrors, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
753 
754  fAllWeights1 = new TGCheckButton(v3, "All weights = 1", kFP_ALLW1);
755  fAllWeights1->Associate(this);
756  fAllWeights1->SetToolTipText("'W'- all weights=1 for non empty bins; error bars ignored");
757  v3->AddFrame(fAllWeights1, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
758 
759  fEmptyBinsWghts1 = new TGCheckButton(v3, "Empty bins, weights=1", kFP_EMPW1);
760  fEmptyBinsWghts1->Associate(this);
761  fEmptyBinsWghts1->SetToolTipText("'WW'- all weights=1 including empty bins; error bars ignored");
762  v3->AddFrame(fEmptyBinsWghts1, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
763 
764  h->AddFrame(v3, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
765 
766  TGVerticalFrame *v4 = new TGVerticalFrame(h);
767  fUseRange = new TGCheckButton(v4, "Use range", kFP_USERG);
768  fUseRange->Associate(this);
769  fUseRange->SetToolTipText("'R'- fit only data within the specified function range");
770  v4->AddFrame(fUseRange, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
771 
772  fImproveResults = new TGCheckButton(v4, "Improve fit results", kFP_IFITR);
773  fImproveResults->Associate(this);
774  fImproveResults->SetToolTipText("'M'- after minimum is found, search for a new one");
775  v4->AddFrame(fImproveResults, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
776 
777  fAdd2FuncList = new TGCheckButton(v4, "Add to list", kFP_ADDLS);
778  fAdd2FuncList->Associate(this);
779  fAdd2FuncList->SetToolTipText("'+'- add function to the list without deleting the previous");
780  v4->AddFrame(fAdd2FuncList, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
781 
782  fUseGradient = new TGCheckButton(v4, "Use Gradient", kFP_ADDLS);
783  fUseGradient->Associate(this);
784  fUseGradient->SetToolTipText("'G'- Use the gradient as an aid for the fitting");
785  v4->AddFrame(fUseGradient, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
786 
787  h->AddFrame(v4, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 20, 0, 0, 0));
788  gf->AddFrame(h, new TGLayoutHints(kLHintsExpandX, 20, 0, 0, 0));
789 
790  // 'draw option' sub-group
791  TGHorizontalFrame *h5 = new TGHorizontalFrame(gf);
792  TGLabel *label6 = new TGLabel(h5, "Draw Options");
793  h5->AddFrame(label6, new TGLayoutHints(kLHintsNormal |
794  kLHintsCenterY, 2, 2, 2, 2));
795  TGHorizontal3DLine *hline3 = new TGHorizontal3DLine(h5);
796  h5->AddFrame(hline3, new TGLayoutHints(kLHintsCenterY | kLHintsExpandX));
797  gf->AddFrame(h5, new TGLayoutHints(kLHintsExpandX));
798 
799  TGHorizontalFrame *h6 = new TGHorizontalFrame(gf);
800  TGVerticalFrame *v5 = new TGVerticalFrame(h6);
801 
802  fDrawSame = new TGCheckButton(v5, "SAME", kFP_DSAME);
803  fDrawSame->Associate(this);
804  fDrawSame->SetToolTipText("Superimpose on previous picture in the same pad");
805  v5->AddFrame(fDrawSame, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
806 
807  fNoDrawing = new TGCheckButton(v5, "No drawing", kFP_DNONE);
808  fNoDrawing->Associate(this);
809  fNoDrawing->SetToolTipText("'0'- do not draw function graphics");
810  v5->AddFrame(fNoDrawing, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
811 
812  fNoStoreDrawing = new TGCheckButton(v5, "Do not store/draw", kFP_DNOST);
813  fNoStoreDrawing->Associate(this);
814  fNoStoreDrawing->SetToolTipText("'N'- do not store the function, do not draw it");
815  v5->AddFrame(fNoStoreDrawing, new TGLayoutHints(kLHintsNormal, 0, 0, 2, 2));
816 
817  h6->AddFrame(v5, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
818 
819  TGVerticalFrame *v6 = new TGVerticalFrame(h6);
820  TGCompositeFrame *v61 = new TGCompositeFrame(v6, 120, 20,
821  kHorizontalFrame | kFixedWidth);
822  fDrawAdvanced = new TGTextButton(v61, "&Advanced...", kFP_DADVB);
823  v61->AddFrame(fDrawAdvanced, new TGLayoutHints(kLHintsRight |
824  kLHintsCenterY |
825  kLHintsExpandX));
826  fDrawAdvanced->SetToolTipText("Open a dialog for advanced draw options");
827  fDrawAdvanced->SetState(kButtonDisabled);
828 
829  v6->AddFrame(v61, new TGLayoutHints(kLHintsRight | kLHintsTop,
830  0, 0, (4+fDrawSame->GetHeight())*2, 0));
831 
832  h6->AddFrame(v6, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
833  gf->AddFrame(h6, new TGLayoutHints(kLHintsExpandX, 20, 0, 2, 0));
834 
835  fGeneral->AddFrame(gf, new TGLayoutHints(kLHintsExpandX |
836  kLHintsExpandY, 5, 5, 0, 0));
837  // sliderX
838  fSliderXParent = new TGHorizontalFrame(fGeneral);
839  TGLabel *label8 = new TGLabel(fSliderXParent, "X");
840  fSliderXParent->AddFrame(label8, new TGLayoutHints(kLHintsLeft |
841  kLHintsCenterY, 0, 5, 0, 0));
842 
843  fSliderXMin = new TGNumberEntry(fSliderXParent, 0, 5, kFP_XMIN,
844  TGNumberFormat::kNESRealTwo,
845  TGNumberFormat::kNEAAnyNumber,
846  TGNumberFormat::kNELLimitMinMax, -1,1);
847  fSliderXParent->AddFrame(fSliderXMin, new TGLayoutHints(kLHintsLeft | kLHintsCenterY));
848 
849  fSliderX = new TGDoubleHSlider(fSliderXParent, 1, kDoubleScaleBoth);
850  fSliderX->SetScale(5);
851  fSliderXParent->AddFrame(fSliderX, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY));
852 
853 
854  fSliderXMax = new TGNumberEntry(fSliderXParent, 0, 5, kFP_XMIN,
855  TGNumberFormat::kNESRealTwo,
856  TGNumberFormat::kNEAAnyNumber,
857  TGNumberFormat::kNELLimitMinMax, -1,1);
858  fSliderXParent->AddFrame(fSliderXMax, new TGLayoutHints(kLHintsRight | kLHintsCenterY));
859  fGeneral->AddFrame(fSliderXParent, new TGLayoutHints(kLHintsExpandX, 5, 5, 0, 0));
860 
861  // sliderY
862  fSliderYParent = new TGHorizontalFrame(fGeneral);
863  TGLabel *label9 = new TGLabel(fSliderYParent, "Y");
864  fSliderYParent->AddFrame(label9, new TGLayoutHints(kLHintsLeft |
865  kLHintsCenterY, 0, 5, 0, 0));
866 
867  fSliderYMin = new TGNumberEntry(fSliderYParent, 0, 5, kFP_YMIN,
868  TGNumberFormat::kNESRealTwo,
869  TGNumberFormat::kNEAAnyNumber,
870  TGNumberFormat::kNELLimitMinMax, -1,1);
871  fSliderYParent->AddFrame(fSliderYMin, new TGLayoutHints(kLHintsLeft | kLHintsCenterY));
872 
873  fSliderY = new TGDoubleHSlider(fSliderYParent, 1, kDoubleScaleBoth);
874  fSliderY->SetScale(5);
875  fSliderYParent->AddFrame(fSliderY, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY));
876 
877  fSliderYMax = new TGNumberEntry(fSliderYParent, 0, 5, kFP_YMIN,
878  TGNumberFormat::kNESRealTwo,
879  TGNumberFormat::kNEAAnyNumber,
880  TGNumberFormat::kNELLimitMinMax, -1,1);
881  fSliderYParent->AddFrame(fSliderYMax, new TGLayoutHints(kLHintsRight | kLHintsCenterY));
882  fGeneral->AddFrame(fSliderYParent, new TGLayoutHints(kLHintsExpandX, 5, 5, 0, 0));
883 
884  // sliderZ
885  fSliderZParent = new TGHorizontalFrame(fGeneral);
886  TGLabel *label10 = new TGLabel(fSliderZParent, "Z:");
887  fSliderZParent->AddFrame(label10, new TGLayoutHints(kLHintsLeft |
888  kLHintsCenterY, 0, 5, 0, 0));
889  fSliderZ = new TGDoubleHSlider(fSliderZParent, 1, kDoubleScaleBoth);
890  fSliderZ->SetScale(5);
891  fSliderZParent->AddFrame(fSliderZ, new TGLayoutHints(kLHintsExpandX |
892  kLHintsCenterY));
893  fGeneral->AddFrame(fSliderZParent, new TGLayoutHints(kLHintsExpandX, 5, 5, 0, 0));
894 }
895 
896 
897 ////////////////////////////////////////////////////////////////////////////////
898 /// Create 'Minimization' tab.
899 
900 void TFitEditor::CreateMinimizationTab()
901 {
902  fTabContainer = fTab->AddTab("Minimization");
903  fMinimization = new TGCompositeFrame(fTabContainer, 10, 10, kVerticalFrame);
904  fTabContainer->AddFrame(fMinimization, new TGLayoutHints(kLHintsTop |
905  kLHintsExpandX,
906  5, 5, 2, 2));
907  MakeTitle(fMinimization, "Library");
908 
909  TGHorizontalFrame *hl = new TGHorizontalFrame(fMinimization);
910  fLibMinuit = new TGRadioButton(hl, "Minuit", kFP_LMIN);
911  fLibMinuit->Associate(this);
912  fLibMinuit->SetToolTipText("Use minimization from libMinuit (default)");
913  hl->AddFrame(fLibMinuit, new TGLayoutHints(kLHintsNormal, 40, 0, 0, 1));
914  fStatusBar->SetText("LIB Minuit",1);
915 
916  fLibMinuit2 = new TGRadioButton(hl, "Minuit2", kFP_LMIN2);
917  fLibMinuit2->Associate(this);
918  fLibMinuit2->SetToolTipText("New C++ version of Minuit");
919  hl->AddFrame(fLibMinuit2, new TGLayoutHints(kLHintsNormal, 35, 0, 0, 1));
920 
921  fLibFumili = new TGRadioButton(hl, "Fumili", kFP_LFUM);
922  fLibFumili->Associate(this);
923  fLibFumili->SetToolTipText("Use minimization from libFumili");
924  hl->AddFrame(fLibFumili, new TGLayoutHints(kLHintsNormal, 30, 0, 0, 1));
925  fMinimization->AddFrame(hl, new TGLayoutHints(kLHintsExpandX, 20, 0, 5, 1));
926 
927  TGHorizontalFrame *hl2 = new TGHorizontalFrame(fMinimization);
928 
929  fLibGSL = new TGRadioButton(hl2, "GSL", kFP_LGSL);
930  #ifdef R__HAS_MATHMORE
931  fLibGSL->Associate(this);
932  fLibGSL->SetToolTipText("Use minimization from libGSL");
933  #else
934  fLibGSL->SetState(kButtonDisabled);
935  fLibGSL->SetToolTipText("Needs GSL to be compiled");
936  #endif
937  hl2->AddFrame(fLibGSL, new TGLayoutHints(kLHintsNormal, 40, 0, 0, 1));
938 
939  fLibGenetics = new TGRadioButton(hl2, "Genetics", kFP_LGAS);
940  if (gPluginMgr->FindHandler("ROOT::Math::Minimizer","Genetic") ||
941  gPluginMgr->FindHandler("ROOT::Math::Minimizer","GAlibMin") )
942  {
943  fLibGenetics->Associate(this);
944  fLibGenetics->SetToolTipText("Different GAs implementations");
945  } else {
946  fLibGenetics->SetState(kButtonDisabled);
947  fLibGenetics->SetToolTipText("Needs any of the genetic"
948  "minimizers to be compiled");
949  }
950  hl2->AddFrame(fLibGenetics, new TGLayoutHints(kLHintsNormal, 45, 0, 0, 1));
951 
952  fMinimization->AddFrame(hl2, new TGLayoutHints(kLHintsExpandX, 20, 0, 5, 1));
953 
954  MakeTitle(fMinimization, "Method");
955 
956  TGHorizontalFrame *hm0 = new TGHorizontalFrame(fMinimization);
957  fMinMethodList = new TGComboBox(hm0, kFP_MINMETHOD);
958  fMinMethodList->Resize(290, 20);
959  fMinMethodList->Select(kFP_GAUS, kFALSE);
960 
961  TGListBox *lb = fMinMethodList->GetListBox();
962  lb->Resize(lb->GetWidth(), 500);
963  fMinMethodList->Associate(this);
964 
965  hm0->AddFrame(fMinMethodList, new TGLayoutHints(kLHintsNormal));
966  fMinimization->AddFrame(hm0, new TGLayoutHints(kLHintsExpandX, 60, 0, 5, 1));
967 
968  // Set the status to the default minimization options!
969  if ( ROOT::Math::MinimizerOptions::DefaultMinimizerType() == "Fumili" ) {
970  fLibFumili->SetState(kButtonDown);
971  } else if ( ROOT::Math::MinimizerOptions::DefaultMinimizerType() == "Minuit" ) {
972  fLibMinuit->SetState(kButtonDown);
973  } else {
974  fLibMinuit2->SetState(kButtonDown);
975  }
976  FillMinMethodList();
977 
978  MakeTitle(fMinimization, "Settings");
979  TGLabel *hslabel1 = new TGLabel(fMinimization,"Use ENTER key to validate a new value or click");
980  fMinimization->AddFrame(hslabel1, new TGLayoutHints(kLHintsNormal, 61, 0, 5, 1));
981  TGLabel *hslabel2 = new TGLabel(fMinimization,"on Reset button to set the defaults.");
982  fMinimization->AddFrame(hslabel2, new TGLayoutHints(kLHintsNormal, 61, 0, 1, 10));
983 
984  TGHorizontalFrame *hs = new TGHorizontalFrame(fMinimization);
985 
986  TGVerticalFrame *hsv1 = new TGVerticalFrame(hs, 180, 10, kFixedWidth);
987  TGLabel *errlabel = new TGLabel(hsv1,"Error definition (default = 1): ");
988  hsv1->AddFrame(errlabel, new TGLayoutHints(kLHintsLeft | kLHintsCenterY,
989  1, 1, 5, 7));
990  TGLabel *tollabel = new TGLabel(hsv1,"Max tolerance (precision): ");
991  hsv1->AddFrame(tollabel, new TGLayoutHints(kLHintsLeft | kLHintsCenterY,
992  1, 1, 5, 7));
993  TGLabel *itrlabel = new TGLabel(hsv1,"Max number of iterations: ");
994  hsv1->AddFrame(itrlabel, new TGLayoutHints(kLHintsLeft | kLHintsCenterY,
995  1, 1, 5, 5));
996  hs->AddFrame(hsv1, new TGLayoutHints(kLHintsNormal, 60, 0, 0, 0));
997 
998  TGVerticalFrame *hsv2 = new TGVerticalFrame(hs, 90,10, kFixedWidth);
999  fErrorScale = new TGNumberEntryField(hsv2, kFP_MERR, ROOT::Math::MinimizerOptions::DefaultErrorDef(),
1000  TGNumberFormat::kNESRealTwo,
1001  TGNumberFormat::kNEAPositive,
1002  TGNumberFormat::kNELLimitMinMax,0.,100.);
1003  hsv2->AddFrame(fErrorScale, new TGLayoutHints(kLHintsLeft | kLHintsExpandX,
1004  1, 1, 0, 3));
1005  fTolerance = new TGNumberEntryField(hsv2, kFP_MTOL, ROOT::Math::MinimizerOptions::DefaultTolerance(),
1006  TGNumberFormat::kNESReal,
1007  TGNumberFormat::kNEAPositive,
1008  TGNumberFormat::kNELLimitMinMax, 0., 1.);
1009  fTolerance->SetNumber(ROOT::Math::MinimizerOptions::DefaultTolerance());
1010  hsv2->AddFrame(fTolerance, new TGLayoutHints(kLHintsLeft | kLHintsExpandX,
1011  1, 1, 3, 3));
1012  fIterations = new TGNumberEntryField(hsv2, kFP_MITR, 5000,
1013  TGNumberFormat::kNESInteger,
1014  TGNumberFormat::kNEAPositive,
1015  TGNumberFormat::kNELNoLimits);
1016  fIterations->SetNumber(ROOT::Math::MinimizerOptions::DefaultMaxIterations());
1017  hsv2->AddFrame(fIterations, new TGLayoutHints(kLHintsLeft | kLHintsExpandX,
1018  1, 1, 3, 3));
1019  hs->AddFrame(hsv2, new TGLayoutHints(kLHintsNormal, 0, 0, 0, 0));
1020  fMinimization->AddFrame(hs, new TGLayoutHints(kLHintsExpandX, 0, 0, 1, 1));
1021  fStatusBar->SetText(Form("Itr: %d",ROOT::Math::MinimizerOptions::DefaultMaxIterations()),3);
1022 
1023  MakeTitle(fMinimization, "Print Options");
1024 
1025  TGHorizontalFrame *h8 = new TGHorizontalFrame(fMinimization);
1026  fOptDefault = new TGRadioButton(h8, "Default", kFP_PDEF);
1027  fOptDefault->Associate(this);
1028  fOptDefault->SetToolTipText("Default is between Verbose and Quiet");
1029  h8->AddFrame(fOptDefault, new TGLayoutHints(kLHintsNormal, 40, 0, 0, 1));
1030  fOptDefault->SetState(kButtonDown);
1031  fStatusBar->SetText("Prn: DEF",4);
1032 
1033  fOptVerbose = new TGRadioButton(h8, "Verbose", kFP_PVER);
1034  fOptVerbose->Associate(this);
1035  fOptVerbose->SetToolTipText("'V'- print results after each iteration");
1036  h8->AddFrame(fOptVerbose, new TGLayoutHints(kLHintsNormal, 30, 0, 0, 1));
1037 
1038  fOptQuiet = new TGRadioButton(h8, "Quiet", kFP_PQET);
1039  fOptQuiet->Associate(this);
1040  fOptQuiet->SetToolTipText("'Q'- no print");
1041  h8->AddFrame(fOptQuiet, new TGLayoutHints(kLHintsNormal, 25, 0, 0, 1));
1042 
1043  fMinimization->AddFrame(h8, new TGLayoutHints(kLHintsExpandX, 20, 0, 5, 1));
1044 
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////////////////
1048 /// Connect GUI signals to fit panel slots.
1049 
1050 void TFitEditor::ConnectSlots()
1051 {
1052  // list of data sets to fit
1053  fDataSet -> Connect("Selected(Int_t)", "TFitEditor", this, "DoDataSet(Int_t)");
1054  // list of predefined functions
1055  fTypeFit -> Connect("Selected(Int_t)", "TFitEditor", this, "FillFunctionList(Int_t)");
1056  // list of predefined functions
1057  fFuncList -> Connect("Selected(Int_t)", "TFitEditor", this, "DoFunction(Int_t)");
1058  // entered formula or function name
1059  fEnteredFunc -> Connect("ReturnPressed()", "TFitEditor", this, "DoEnteredFunction()");
1060  // set parameters dialog
1061  fSetParam -> Connect("Clicked()", "TFitEditor", this, "DoSetParameters()");
1062  // allowed function operations
1063  fAdd -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoAddition(Bool_t)");
1064  //fNormAdd -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoNormAddition(Bool_t)");
1065  //fConv -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoConvolution(Bool_t)");
1066  // fit options
1067  fAllWeights1 -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoAllWeights1()");
1068  fUseRange -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoUseFuncRange()");
1069  fEmptyBinsWghts1 -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoEmptyBinsAllWeights1()");
1070  // linear fit
1071  fLinearFit -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLinearFit()");
1072  fEnableRobust -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoRobustFit()");
1073  //fNoChi2->Connect("Toggled(Bool_t)","TFitEditor",this,"DoNoChi2()");
1074  // draw options
1075  fNoStoreDrawing -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoNoStoreDrawing()");
1076  // fit, reset, close buttons
1077  fUpdateButton -> Connect("Clicked()", "TFitEditor", this, "DoUpdate()");
1078  fFitButton -> Connect("Clicked()", "TFitEditor", this, "DoFit()");
1079  fResetButton -> Connect("Clicked()", "TFitEditor", this, "DoReset()");
1080  fCloseButton -> Connect("Clicked()", "TFitEditor", this, "DoClose()");
1081  // user method button
1082  fUserButton -> Connect("Clicked()", "TFitEditor", this, "DoUserDialog()");
1083  // advanced draw options
1084  fDrawAdvanced -> Connect("Clicked()", "TFitEditor", this, "DoAdvancedOptions()");
1085 
1086  if (fType != kObjectTree)
1087  {
1088  fSliderX -> Connect("PositionChanged()","TFitEditor",this, "DoSliderXMoved()");
1089  fSliderXMax -> Connect("ValueSet(Long_t)", "TFitEditor",this, "DoNumericSliderXChanged()");
1090  fSliderXMin -> Connect("ValueSet(Long_t)", "TFitEditor",this, "DoNumericSliderXChanged()");
1091  }
1092  if (fDim > 1)
1093  {
1094  fSliderY -> Connect("PositionChanged()","TFitEditor",this, "DoSliderYMoved()");
1095  fSliderYMax -> Connect("ValueSet(Long_t)", "TFitEditor",this, "DoNumericSliderYChanged()");
1096  fSliderYMin -> Connect("ValueSet(Long_t)", "TFitEditor",this, "DoNumericSliderYChanged()");
1097  }
1098  if (fDim > 2)
1099  fSliderZ -> Connect("PositionChanged()","TFitEditor",this, "DoSliderZMoved()");
1100 
1101  if ( fParentPad )
1102  fParentPad -> Connect("RangeAxisChanged()","TFitEditor",this, "UpdateGUI()");
1103  // 'Minimization' tab
1104  // library
1105  fLibMinuit -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLibrary(Bool_t)");
1106  fLibMinuit2 -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLibrary(Bool_t)");
1107  fLibFumili -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLibrary(Bool_t)");
1108  fLibGSL -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLibrary(Bool_t)");
1109  fLibGenetics -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoLibrary(Bool_t)");
1110 
1111  // minimization method
1112  fMinMethodList -> Connect("Selected(Int_t)", "TFitEditor", this, "DoMinMethod(Int_t)");
1113  // fitter settings
1114  fIterations -> Connect("ReturnPressed()", "TFitEditor", this, "DoMaxIterations()");
1115  // print options
1116  fOptDefault -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoPrintOpt(Bool_t)");
1117  fOptVerbose -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoPrintOpt(Bool_t)");
1118  fOptQuiet -> Connect("Toggled(Bool_t)", "TFitEditor", this, "DoPrintOpt(Bool_t)");
1119 
1120 }
1121 
1122 ////////////////////////////////////////////////////////////////////////////////
1123 /// Disconnect GUI signals from fit panel slots.
1124 
1125 void TFitEditor::DisconnectSlots()
1126 {
1127  Disconnect("CloseWindow()");
1128 
1129  fFuncList -> Disconnect("Selected(Int_t)");
1130  fEnteredFunc -> Disconnect("ReturnPressed()");
1131  fSetParam -> Disconnect("Clicked()");
1132  fAdd -> Disconnect("Toggled(Bool_t)");
1133  // fNormAdd -> Disconnect("Toggled(Bool_t)");
1134  // fConv -> Disconnect("Toggled(Bool_t)");
1135 
1136  // fit options
1137  fAllWeights1 -> Disconnect("Toggled(Bool_t)");
1138  fEmptyBinsWghts1 -> Disconnect("Toggled(Bool_t)");
1139 
1140  // linear fit
1141  fLinearFit -> Disconnect("Toggled(Bool_t)");
1142  fEnableRobust -> Disconnect("Toggled(Bool_t)");
1143  //fNoChi2->Disconnect("Toggled(Bool_t)");
1144 
1145  // draw options
1146  fNoStoreDrawing -> Disconnect("Toggled(Bool_t)");
1147 
1148  // fit, reset, close buttons
1149  fFitButton -> Disconnect("Clicked()");
1150  fResetButton -> Disconnect("Clicked()");
1151 
1152  // other methods
1153  fUserButton -> Disconnect("Clicked()");
1154  fDrawAdvanced -> Disconnect("Clicked()");
1155 
1156  if (fType != kObjectTree)
1157  {
1158  fSliderX -> Disconnect("PositionChanged()");
1159  fSliderXMax -> Disconnect("ValueChanged(Long_t)");
1160  fSliderXMin -> Disconnect("ValueChanged(Long_t)");
1161  }
1162  if (fDim > 1)
1163  {
1164  fSliderY -> Disconnect("PositionChanged()");
1165  fSliderYMax -> Disconnect("ValueChanged(Long_t)");
1166  fSliderYMin -> Disconnect("ValueChanged(Long_t)");
1167  }
1168  if (fDim > 2)
1169  fSliderZ -> Disconnect("PositionChanged()");
1170  // slots related to 'Minimization' tab
1171  fLibMinuit -> Disconnect("Toggled(Bool_t)");
1172  fLibMinuit2 -> Disconnect("Toggled(Bool_t)");
1173  fLibFumili -> Disconnect("Toggled(Bool_t)");
1174  fLibGSL -> Disconnect("Toggled(Bool_t)");
1175  fLibGenetics -> Disconnect("Toggled(Bool_t)");
1176  // minimization method
1177  fMinMethodList -> Disconnect("Selected(Int_t)");
1178  // fitter settings
1179  fIterations -> Disconnect("ReturnPressed()");
1180  // print options
1181  fOptDefault -> Disconnect("Toggled(Bool_t)");
1182  fOptVerbose -> Disconnect("Toggled(Bool_t)");
1183  fOptQuiet -> Disconnect("Toggled(Bool_t)");
1184 
1185 }
1186 
1187 ////////////////////////////////////////////////////////////////////////////////
1188 /// Connect to another canvas.
1189 
1190 void TFitEditor::SetCanvas(TCanvas * /*newcan*/)
1191 {
1192  // The next line is commented because it is stablishing a
1193  // connection with the particular canvas, while right the following
1194  // line will connect all the canvas in a general way.
1195 
1196  // It would also make the fitpanel crash if there is no object
1197  // defined to be fitted in the construction (as a side effect of
1198  // it).
1199 
1200 // newcan->Connect("Selected(TVirtualPad*,TObject*,Int_t)", "TFitEditor",
1201 // this, "SetFitObject(TVirtualPad *, TObject *, Int_t)");
1202 
1203  TQObject::Connect("TCanvas", "Selected(TVirtualPad *, TObject *, Int_t)",
1204  "TFitEditor",this,
1205  "SetFitObject(TVirtualPad *, TObject *, Int_t)");
1206  TQObject::Connect("TCanvas", "Closed()", "TFitEditor", this, "DoNoSelection()");
1207 }
1208 
1209 ////////////////////////////////////////////////////////////////////////////////
1210 /// Hide the fit panel and set it to non-active state.
1211 
1212 void TFitEditor::Hide()
1213 {
1214  if (fgFitDialog) {
1215  fgFitDialog->UnmapWindow();
1216  }
1217  if (fParentPad) {
1218  fParentPad->Disconnect("RangeAxisChanged()");
1219  DoReset();
1220  TQObject::Disconnect("TCanvas", "Selected(TVirtualPad *, TObject *, Int_t)",
1221  this, "SetFitObject(TVirtualPad *, TObject *, Int_t)");
1222  }
1223  fParentPad = 0;
1224  fFitObject = 0;
1225  gROOT->GetListOfCleanups()->Remove(this);
1226 }
1227 
1228 ////////////////////////////////////////////////////////////////////////////////
1229 /// Show the fit panel (possible only via context menu).
1230 
1231 void TFitEditor::Show(TVirtualPad* pad, TObject *obj)
1232 {
1233  if (!gROOT->GetListOfCleanups()->FindObject(this))
1234  gROOT->GetListOfCleanups()->Add(this);
1235 
1236  if (!fgFitDialog->IsMapped()) {
1237  fgFitDialog->MapWindow();
1238  gVirtualX->RaiseWindow(GetId());
1239  }
1240  fParentPad = static_cast<TPad*>(pad);
1241  SetCanvas(pad->GetCanvas());
1242  SetFitObject(pad, obj, kButton1Down);
1243 }
1244 
1245 ////////////////////////////////////////////////////////////////////////////////
1246 /// Close fit panel window.
1247 
1248 void TFitEditor::CloseWindow()
1249 {
1250  Hide();
1251 }
1252 
1253 //______________________________________________________________________________
1254 // TFitEditor *&TFitEditor::GetFP()
1255 // {
1256 // // Static: return main fit panel
1257 // return fgFitDialog;
1258 // }
1259 
1260 ////////////////////////////////////////////////////////////////////////////////
1261 /// Called to delete the fit panel.
1262 
1263 void TFitEditor::Terminate()
1264 {
1265  TQObject::Disconnect("TCanvas", "Closed()");
1266  delete fgFitDialog;
1267  fgFitDialog = 0;
1268 }
1269 
1270 ////////////////////////////////////////////////////////////////////////////////
1271 /// Set the fit panel GUI according to the selected object.
1272 
1273 void TFitEditor::UpdateGUI()
1274 {
1275  if (!fFitObject) return;
1276 
1277  DrawSelection(true);
1278 
1279  if ( fType == kObjectTree )
1280  // Don't do anything with the sliders, as they work with TAxis
1281  // that are not defined for the TTree
1282  return;
1283 
1284  // sliders
1285  if (fType != kObjectTree) { // This is as fDim > 0
1286  TH1* hist = 0;
1287  switch (fType) {
1288  case kObjectHisto:
1289  hist = (TH1*)fFitObject;
1290  break;
1291 
1292  case kObjectGraph:
1293  hist = ((TGraph*)fFitObject)->GetHistogram();
1294  break;
1295 
1296  case kObjectMultiGraph:
1297  hist = ((TMultiGraph*)fFitObject)->GetHistogram();
1298  break;
1299 
1300  case kObjectGraph2D:
1301  hist = ((TGraph2D*)fFitObject)->GetHistogram("empty");
1302  break;
1303 
1304  case kObjectHStack:
1305  hist = (TH1 *)((THStack *)fFitObject)->GetHists()->First();
1306 
1307  case kObjectTree:
1308  default:
1309  break;
1310  }
1311 
1312 
1313  if (!hist) {
1314  Error("UpdateGUI","No hist is present - this should not happen, please report."
1315  "The FitPanel might be in an inconsistent state");
1316  //assert(hist);
1317  return;
1318  }
1319 
1320  fSliderX->Disconnect("PositionChanged()");
1321  fSliderXMin->Disconnect("ValueChanged()");
1322  fSliderXMax->Disconnect("ValueChanged()");
1323 
1324  if (!fSliderXParent->IsMapped())
1325  fSliderXParent->MapWindow();
1326 
1327  fXaxis = hist->GetXaxis();
1328  fYaxis = hist->GetYaxis();
1329  fZaxis = hist->GetZaxis();
1330  Int_t ixrange = fXaxis->GetNbins();
1331  Int_t ixmin = fXaxis->GetFirst();
1332  Int_t ixmax = fXaxis->GetLast();
1333 
1334  if (ixmin > 1 || ixmax < ixrange) {
1335  fSliderX->SetRange(ixmin,ixmax);
1336  fSliderX->SetPosition(ixmin, ixmax);
1337  } else {
1338  fSliderX->SetRange(1,ixrange);
1339  fSliderX->SetPosition(ixmin,ixmax);
1340  }
1341 
1342  fSliderX->SetScale(5);
1343 
1344  fSliderXMin->SetLimits(TGNumberFormat::kNELLimitMinMax,
1345  fXaxis->GetBinLowEdge( static_cast<Int_t>( fSliderX->GetMinPosition() ) ),
1346  fXaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderX->GetMaxPosition() ) ));
1347  fSliderXMin->SetNumber( fXaxis->GetBinLowEdge( static_cast<Int_t>( fSliderX->GetMinPosition() ) ));
1348  fSliderXMax->SetLimits(TGNumberFormat::kNELLimitMinMax,
1349  fXaxis->GetBinLowEdge( static_cast<Int_t>( fSliderX->GetMinPosition() ) ),
1350  fXaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderX->GetMaxPosition() ) ));
1351  fSliderXMax->SetNumber( fXaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderX->GetMaxPosition() ) ));
1352 
1353  fSliderX->Connect("PositionChanged()","TFitEditor",this, "DoSliderXMoved()");
1354  fSliderXMax->Connect("ValueSet(Long_t)", "TFitEditor", this, "DoNumericSliderXChanged()");
1355  fSliderXMin->Connect("ValueSet(Long_t)", "TFitEditor", this, "DoNumericSliderXChanged()");
1356  }
1357 
1358  if (fDim > 1) {
1359  fSliderY->Disconnect("PositionChanged()");
1360  fSliderYMin->Disconnect("ValueChanged()");
1361  fSliderYMax->Disconnect("ValueChanged()");
1362 
1363  if (!fSliderYParent->IsMapped())
1364  fSliderYParent->MapWindow();
1365  if (fSliderZParent->IsMapped())
1366  fSliderZParent->UnmapWindow();
1367 
1368  Int_t iymin = 0, iymax = 0, iyrange = 0;
1369  switch (fType) {
1370  case kObjectHisto:
1371  case kObjectGraph2D:
1372  case kObjectHStack:
1373  iyrange = fYaxis->GetNbins();
1374  iymin = fYaxis->GetFirst();
1375  iymax = fYaxis->GetLast();
1376  break;
1377 
1378  case kObjectGraph:
1379  case kObjectMultiGraph:
1380  case kObjectTree:
1381  default:
1382  //not implemented
1383  break;
1384  }
1385 
1386  if (iymin > 1 || iymax < iyrange) {
1387  fSliderY->SetRange(iymin,iymax);
1388  fSliderY->SetPosition(iymin, iymax);
1389  } else {
1390  fSliderY->SetRange(1,iyrange);
1391  fSliderY->SetPosition(iymin,iymax);
1392  }
1393 
1394  fSliderY->SetScale(5);
1395 
1396  fSliderYMin->SetLimits(TGNumberFormat::kNELLimitMinMax,
1397  fYaxis->GetBinLowEdge( static_cast<Int_t>( fSliderY->GetMinPosition() ) ),
1398  fYaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderY->GetMaxPosition() ) ));
1399  fSliderYMin->SetNumber(fYaxis->GetBinLowEdge( static_cast<Int_t>( fSliderY->GetMinPosition() ) ));
1400  fSliderYMax->SetLimits(TGNumberFormat::kNELLimitMinMax,
1401  fYaxis->GetBinLowEdge( static_cast<Int_t>( fSliderY->GetMinPosition() ) ),
1402  fYaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderY->GetMaxPosition() ) ));
1403  fSliderYMax->SetNumber( fYaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderY->GetMaxPosition() ) ));
1404 
1405  fSliderY->Connect("PositionChanged()","TFitEditor",this, "DoSliderYMoved()");
1406  fSliderYMax->Connect("ValueSet(Long_t)", "TFitEditor", this, "DoNumericSliderYChanged()");
1407  fSliderYMin->Connect("ValueSet(Long_t)", "TFitEditor", this, "DoNumericSliderYChanged()");
1408  }
1409 
1410 
1411  if (fDim > 2) {
1412  fSliderZ->Disconnect("PositionChanged()");
1413 
1414  if (!fSliderZParent->IsMapped())
1415  fSliderZParent->MapWindow();
1416 
1417  Int_t izmin = 0, izmax = 0, izrange = 0;
1418  switch (fType) {
1419  case kObjectHStack:
1420  case kObjectHisto:
1421  izrange = fZaxis->GetNbins();
1422  izmin = fZaxis->GetFirst();
1423  izmax = fZaxis->GetLast();
1424  break;
1425 
1426  case kObjectGraph:
1427  case kObjectGraph2D:
1428  case kObjectMultiGraph:
1429  case kObjectTree:
1430  default:
1431  //not implemented
1432  break;
1433  }
1434 
1435  if (izmin > 1 || izmax < izrange) {
1436  fSliderZ->SetRange(izmin,izmax);
1437  fSliderZ->SetPosition(izmin, izmax);
1438  } else {
1439  fSliderZ->SetRange(1,izrange);
1440  fSliderZ->SetPosition(izmin,izmax);
1441  }
1442 
1443  fSliderZ->SetScale(5);
1444  fSliderZ->Connect("PositionChanged()","TFitEditor",this, "DoSliderZMoved()");
1445  }
1446 }
1447 
1448 ////////////////////////////////////////////////////////////////////////////////
1449 /// Slot called when the user clicks on an object inside a canvas.
1450 /// Updates pointers to the parent pad and the selected object
1451 /// for fitting (if suitable).
1452 
1453 void TFitEditor::SetFitObject(TVirtualPad *pad, TObject *obj, Int_t event)
1454 {
1455  if (event != kButton1Down) return;
1456 
1457  if ( !obj ) {
1458  DoNoSelection();
1459  return;
1460  }
1461 
1462  // is obj suitable for fitting?
1463  if (!SetObjectType(obj)) return;
1464 
1465  fParentPad = pad;
1466  fFitObject = obj;
1467  ShowObjectName(obj);
1468  UpdateGUI();
1469 
1470  ConnectSlots();
1471 
1472  TF1* fitFunc = HasFitFunction();
1473 
1474  if (fitFunc)
1475  {
1476  //fFuncPars = FuncParams_t( fitFunc->GetNpar() );
1477  GetParameters(fFuncPars, fitFunc);
1478 
1479  TString tmpStr = fitFunc->GetExpFormula();
1480  TGLBEntry *en = 0;
1481  // If the function comes from a C raw function.
1482  if ( tmpStr.Length() == 0 )
1483  {
1484  // Show the name of the function
1485  fEnteredFunc->SetText(fitFunc->GetName());
1486  en= fFuncList->FindEntry(fitFunc->GetName());
1487  // Don't allow edition!
1488  SetEditable(kFALSE);
1489  }
1490  // otherwise, it's got a formula
1491  else
1492  {
1493  // Show the formula
1494  fEnteredFunc->SetText(fitFunc->GetExpFormula().Data());
1495  en= fFuncList->FindEntry(fitFunc->GetExpFormula().Data());
1496  SetEditable(kTRUE);
1497  }
1498  // Select the proper entry in the function list
1499  if (en) fFuncList->Select(en->EntryId());
1500  }
1501  else
1502  { // if there is no fit function in the object
1503  // Use the selected function in fFuncList
1504  TGTextLBEntry *te = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
1505  // Add the text to fEnteredFunc
1506  if (te && fNone->GetState() == kButtonDown)
1507  fEnteredFunc->SetText(te->GetTitle());
1508  else if (te && fAdd->GetState() == kButtonDown)
1509  {
1510  TString tmpStr = fEnteredFunc->GetText();
1511  tmpStr += '+';
1512  tmpStr += te->GetTitle();
1513  fEnteredFunc->SetText(tmpStr);
1514  }
1515  else if (te && fNormAdd->GetState() == kButtonDown)
1516  {
1517  TString tmpStr = fEnteredFunc->GetText();
1518  tmpStr += '+';
1519  tmpStr += te -> GetTitle();
1520  fEnteredFunc -> SetText(tmpStr);
1521  }
1522  else if (te && fConv->GetState() == kButtonDown)
1523  {
1524  TString tmpStr = fEnteredFunc->GetText();
1525  tmpStr += '*';
1526  tmpStr +=te->GetTitle();
1527  fEnteredFunc->SetText(tmpStr);
1528  }
1529  else if ( !te )
1530  // If there is no space, an error message is shown:
1531  // Error in <TString::AssertElement>: out of bounds: i = -1, Length = 0
1532  // If there is no function selected, then put nothing.
1533  fEnteredFunc->SetText(" ");
1534  }
1535  fEnteredFunc->SelectAll();
1536 
1537 
1538  // Update the information about the selected object.
1539  if (fSetParam->GetState() == kButtonDisabled)
1540  fSetParam->SetEnabled(kTRUE);
1541  if (fFitButton->GetState() == kButtonDisabled)
1542  fFitButton->SetEnabled(kTRUE);
1543  if (fResetButton->GetState() == kButtonDisabled)
1544  fResetButton->SetEnabled(kTRUE);
1545  DoLinearFit();
1546 }
1547 
1548 ////////////////////////////////////////////////////////////////////////////////
1549 /// Slot called when users close a TCanvas or when the user select
1550 /// no object.
1551 
1552 void TFitEditor::DoNoSelection()
1553 {
1554  if (gROOT->GetListOfCanvases()->IsEmpty()) {
1555  Terminate();
1556  return;
1557  }
1558 
1559  // Minimize user interaction until an object is selected
1560  DisconnectSlots();
1561  fParentPad = 0;
1562  fFitObject = 0;
1563  fStatusBar->SetText("No selection",0);
1564  fDataSet->Select(kFP_NOSEL, kFALSE);
1565  Layout();
1566 
1567  fSetParam->SetEnabled(kFALSE);
1568  fFitButton->SetEnabled(kFALSE);
1569  fResetButton->SetEnabled(kFALSE);
1570  fDrawAdvanced->SetState(kButtonDisabled);
1571 }
1572 
1573 ////////////////////////////////////////////////////////////////////////////////
1574 /// When obj is deleted, clear fFitObject if fFitObject = obj.
1575 
1576 void TFitEditor::RecursiveRemove(TObject* obj)
1577 {
1578  if (obj == fFitObject) {
1579  fFitObject = 0;
1580  DisconnectSlots();
1581  fStatusBar->SetText("No selection",0);
1582  fDataSet->Select(kFP_NOSEL, kFALSE);
1583  Layout();
1584 
1585  fFitButton->SetEnabled(kFALSE);
1586  fResetButton->SetEnabled(kFALSE);
1587  fSetParam->SetEnabled(kFALSE);
1588 
1589  TQObject::Connect("TCanvas", "Selected(TVirtualPad *, TObject *, Int_t)",
1590  "TFitEditor",this,
1591  "SetFitObject(TVirtualPad *, TObject *, Int_t)");
1592  TQObject::Connect("TCanvas", "Closed()", "TFitEditor", this,
1593  "DoNoSelection()");
1594 
1595  DoUpdate();
1596  return;
1597  }
1598  if (obj == fParentPad) {
1599  fFitObject = 0;
1600  fParentPad = 0;
1601  DisconnectSlots();
1602  fStatusBar->SetText("No selection",0);
1603  fDataSet->Select(kFP_NOSEL, kFALSE);
1604  Layout();
1605 
1606  fFitButton->SetEnabled(kFALSE);
1607  fResetButton->SetEnabled(kFALSE);
1608  fSetParam->SetEnabled(kFALSE);
1609  }
1610 }
1611 
1612 ////////////////////////////////////////////////////////////////////////////////
1613 /// Fills the list of functions depending on the type of fit
1614 /// selected.
1615 
1616 void TFitEditor::FillFunctionList(Int_t)
1617 {
1618  fFuncList->RemoveAll();
1619  // Case when the user has selected predefined functions in 1D.
1620  if ( fTypeFit->GetSelected() == kFP_PRED1D && fDim <= 1 ) {
1621  // Fill function list combo box.
1622  fFuncList->AddEntry("gaus" , kFP_GAUS);
1623  fFuncList->AddEntry("gausn", kFP_GAUSN);
1624  fFuncList->AddEntry("expo", kFP_EXPO);
1625  fFuncList->AddEntry("landau", kFP_LAND);
1626  fFuncList->AddEntry("landaun",kFP_LANDN);
1627  fFuncList->AddEntry("pol0", kFP_POL0);
1628  fFuncList->AddEntry("pol1", kFP_POL1);
1629  fFuncList->AddEntry("pol2", kFP_POL2);
1630  fFuncList->AddEntry("pol3", kFP_POL3);
1631  fFuncList->AddEntry("pol4", kFP_POL4);
1632  fFuncList->AddEntry("pol5", kFP_POL5);
1633  fFuncList->AddEntry("pol6", kFP_POL6);
1634  fFuncList->AddEntry("pol7", kFP_POL7);
1635  fFuncList->AddEntry("pol8", kFP_POL8);
1636  fFuncList->AddEntry("pol9", kFP_POL9);
1637  fFuncList->AddEntry("cheb0", kFP_CHEB0);
1638  fFuncList->AddEntry("cheb1", kFP_CHEB1);
1639  fFuncList->AddEntry("cheb2", kFP_CHEB2);
1640  fFuncList->AddEntry("cheb3", kFP_CHEB3);
1641  fFuncList->AddEntry("cheb4", kFP_CHEB4);
1642  fFuncList->AddEntry("cheb5", kFP_CHEB5);
1643  fFuncList->AddEntry("cheb6", kFP_CHEB6);
1644  fFuncList->AddEntry("cheb7", kFP_CHEB7);
1645  fFuncList->AddEntry("cheb8", kFP_CHEB8);
1646  fFuncList->AddEntry("cheb9", kFP_CHEB9);
1647  fFuncList->AddEntry("user", kFP_USER);
1648 
1649  // Need to be setted this way, otherwise when the functions
1650  // are removed, the list doesn't show them.
1651  TGListBox *lb = fFuncList->GetListBox();
1652  lb->Resize(lb->GetWidth(), 200);
1653 
1654  // Select Gaus1D by default
1655  fFuncList->Select(kFP_GAUS);
1656 
1657  }
1658  // Case for predefined 2D functions
1659  else if ( fTypeFit->GetSelected() == kFP_PRED2D && fDim == 2 ) {
1660  fFuncList->AddEntry("xygaus", kFP_XYGAUS);
1661  fFuncList->AddEntry("bigaus", kFP_BIGAUS);
1662  fFuncList->AddEntry("xyexpo", kFP_XYEXP);
1663  fFuncList->AddEntry("xylandau", kFP_XYLAN);
1664  fFuncList->AddEntry("xylandaun", kFP_XYLANN);
1665 
1666  // Need to be setted this way, otherwise when the functions
1667  // are removed, the list doesn't show them.x
1668  TGListBox *lb = fFuncList->GetListBox();
1669  lb->Resize(lb->GetWidth(), 200);
1670 
1671  // Select Gaus2D by default
1672  fFuncList->Select(kFP_XYGAUS);
1673  }
1674  // Case for user defined functions. References to these functions
1675  // are kept by the fitpanel, so the information is gathered from
1676  // there.
1677  else if ( fTypeFit->GetSelected() == kFP_UFUNC ) {
1678  Int_t newid = kFP_ALTFUNC;
1679 
1680  // Add system functions
1681  for (auto f : fSystemFuncs) {
1682  // Don't include system functions that has been previously
1683  // used to fit, as those are included under the kFP_PREVFIT
1684  // section.
1685  if ( strncmp(f->GetName(), "PrevFit", 7) != 0 ) {
1686  // If the dimension of the object coincides with the
1687  // dimension of the function, then include the function in
1688  // the list. It will also include de function if the
1689  // dimension of the object is 0 (i.e. a multivariable
1690  // TTree) as it is currently imposible to know how many
1691  // dimensions a TF1 coming from a C raw function has.
1692  if ( f->GetNdim() == fDim || fDim == 0) {
1693  fFuncList->AddEntry(f->GetName(), newid++);
1694  }
1695  }
1696  }
1697 
1698  // If no function was added
1699  if ( newid != kFP_ALTFUNC )
1700  fFuncList->Select(newid-1);
1701  else if( fDim == 1 ) {
1702  // Select predefined 1D functions for 1D objects
1703  fTypeFit->Select(kFP_PRED1D, kTRUE);
1704  } else if( fDim == 2 ) {
1705  // Select predefined 2D functions for 2D objects
1706  fTypeFit->Select(kFP_PRED2D, kTRUE);
1707  }
1708  }
1709  // Case for previously used functions.
1710  else if ( fTypeFit->GetSelected() == kFP_PREVFIT ) {
1711  Int_t newid = kFP_ALTFUNC;
1712 
1713  // Look only for those functions used in the selected object
1714  std::pair<fPrevFitIter, fPrevFitIter> look = fPrevFit.equal_range(fFitObject);
1715  // Then go over all those functions and add them to the list
1716  for ( fPrevFitIter it = look.first; it != look.second; ++it ) {
1717  fFuncList->AddEntry(it->second->GetName(), newid++);
1718  }
1719 
1720  // If no functions were added.
1721  if ( newid == kFP_ALTFUNC ) {
1722  // Remove the entry previous fit from fTypeFit
1723  fTypeFit->RemoveEntry(kFP_PREVFIT);
1724  if( fDim == 1 )
1725  // Select predefined 1D functions for 1D objects
1726  fTypeFit->Select(kFP_PRED1D, kTRUE);
1727  else if ( fDim == 2 )
1728  // Select predefined 2D functions for 2D objects
1729  fTypeFit->Select(kFP_PRED2D, kTRUE);
1730  else
1731  // For more than 2 dimensions, select the user functions.
1732  fTypeFit->Select(kFP_UFUNC, kTRUE);
1733  }
1734  else
1735  // If there is there are previously used functions, select
1736  // the last one inserted.
1737  fFuncList->Select(newid-1, kTRUE);
1738  }
1739 }
1740 
1741 ////////////////////////////////////////////////////////////////////////////////
1742 /// Fills the list of methods depending on the minimization library
1743 /// selected.
1744 
1745 void TFitEditor::FillMinMethodList(Int_t)
1746 {
1747  fMinMethodList->RemoveAll();
1748 
1749  if ( fLibMinuit->GetState() == kButtonDown )
1750  {
1751  fMinMethodList->AddEntry("MIGRAD" , kFP_MIGRAD);
1752  fMinMethodList->AddEntry("SIMPLEX" , kFP_SIMPLX);
1753  fMinMethodList->AddEntry("SCAN" , kFP_SCAN);
1754  fMinMethodList->AddEntry("Combination" , kFP_COMBINATION);
1755  fMinMethodList->Select(kFP_MIGRAD, kFALSE);
1756  fStatusBar->SetText("MIGRAD",2);
1757  } else if ( fLibFumili->GetState() == kButtonDown )
1758  {
1759  fMinMethodList->AddEntry("FUMILI" , kFP_FUMILI);
1760  fMinMethodList->Select(kFP_FUMILI, kFALSE);
1761  fStatusBar->SetText("FUMILI",2);
1762  } else if ( fLibGSL->GetState() == kButtonDown )
1763  {
1764  fMinMethodList->AddEntry("Fletcher-Reeves conjugate gradient" , kFP_GSLFR);
1765  fMinMethodList->AddEntry("Polak-Ribiere conjugate gradient" , kFP_GSLPR);
1766  fMinMethodList->AddEntry("BFGS conjugate gradient" , kFP_BFGS);
1767  fMinMethodList->AddEntry("BFGS conjugate gradient (Version 2)", kFP_BFGS2);
1768  fMinMethodList->AddEntry("Levenberg-Marquardt" , kFP_GSLLM);
1769  fMinMethodList->AddEntry("Simulated Annealing" , kFP_GSLSA);
1770  fMinMethodList->Select(kFP_GSLFR, kFALSE);
1771  fStatusBar->SetText("CONJFR",2);
1772  } else if ( fLibGenetics->GetState() == kButtonDown )
1773  {
1774  if ( gPluginMgr->FindHandler("ROOT::Math::Minimizer","GAlibMin") ) {
1775  fMinMethodList->AddEntry("GA Lib Genetic Algorithm" , kFP_GALIB);
1776  fMinMethodList->Select(kFP_GALIB, kFALSE);
1777  } else if (gPluginMgr->FindHandler("ROOT::Math::Minimizer","Genetic")) {
1778  fMinMethodList->AddEntry("TMVA Genetic Algorithm" , kFP_TMVAGA);
1779  fMinMethodList->Select(kFP_TMVAGA, kFALSE);
1780  }
1781  } else // if ( fLibMinuit2->GetState() == kButtonDown )
1782  {
1783  fMinMethodList->AddEntry("MIGRAD" , kFP_MIGRAD);
1784  fMinMethodList->AddEntry("SIMPLEX" , kFP_SIMPLX);
1785  fMinMethodList->AddEntry("FUMILI" , kFP_FUMILI);
1786  fMinMethodList->AddEntry("SCAN" , kFP_SCAN);
1787  fMinMethodList->AddEntry("Combination" , kFP_COMBINATION);
1788  fMinMethodList->Select(kFP_MIGRAD, kFALSE);
1789  fStatusBar->SetText("MIGRAD",2);
1790  }
1791 }
1792 
1793 void SearchCanvases(TSeqCollection* canvases, std::vector<TObject*>& objects)
1794 {
1795  // Auxiliary function to recursively search for objects inside the
1796  // current canvases.
1797 
1798  TIter canvasIter(canvases);
1799  // Iterate over all the canvases in canvases.
1800  while(TObject* obj = (TObject*) canvasIter()) {
1801  // If the object is another canvas, call this function
1802  // recursively.
1803  if ( TPad* can = dynamic_cast<TPad*>(obj))
1804  SearchCanvases(can->GetListOfPrimitives(), objects);
1805  // Otherwhise, if it's a recognised object, add it to the vector
1806  else if ( dynamic_cast<TH1*>(obj)
1807  || dynamic_cast<TGraph*>(obj)
1808  || dynamic_cast<TGraph2D*>(obj)
1809  || dynamic_cast<TMultiGraph*>(obj)
1810  || dynamic_cast<THStack*>(obj)
1811  || dynamic_cast<TTree*>(obj) ) {
1812  bool insertNew = true;
1813  // Be careful no to insert the same element twice.
1814  for ( std::vector<TObject*>::iterator i = objects.begin(); i != objects.end(); ++i )
1815  if ( (*i) == obj ) {
1816  insertNew = false;
1817  break;
1818  }
1819  // If the object is not already in the vector, then insert
1820  // it.
1821  if ( insertNew ) objects.push_back(obj);
1822  }
1823  }
1824 }
1825 
1826 ////////////////////////////////////////////////////////////////////////////////
1827 /// Create a combo box with all the possible objects to be fitted.
1828 
1829 void TFitEditor::FillDataSetList()
1830 {
1831  // Get the title of the entry selected, so that we can select it
1832  // again once the fDataSet has been refilled.
1833  TGTextLBEntry * entry = (TGTextLBEntry*) fDataSet->GetSelectedEntry();
1834  TString selEntryStr;
1835  if ( entry ) {
1836  selEntryStr = entry->GetTitle();
1837  }
1838 
1839  // Remove all the elements
1840  fDataSet->RemoveAll();
1841  std::vector<TObject*> objects;
1842 
1843  // Get all the objects registered in gDirectory
1844  if (gDirectory) {
1845  TList * l = gDirectory->GetList();
1846  if (l) {
1847  TIter next(l);
1848  TObject* obj = NULL;
1849  while ( (obj = (TObject*) next()) ) {
1850  // But only if they are of a type recognized by the FitPanel
1851  if ( dynamic_cast<TH1*>(obj) ||
1852  dynamic_cast<TGraph2D*>(obj) ||
1853  dynamic_cast<TTree*>(obj) ) {
1854  objects.push_back(obj);
1855  }
1856  }
1857  }
1858  }
1859 
1860  // Look for all the drawn objects. The method will take care the
1861  // same objects are not inserted twice.
1862  SearchCanvases(gROOT->GetListOfCanvases(), objects);
1863 
1864  // Add all the objects stored in the vector
1865  int selected = kFP_NOSEL;
1866  // Add the No selection.
1867  Int_t newid = kFP_NOSEL;
1868  fDataSet->AddEntry("No Selection", newid++);
1869  for ( std::vector<TObject*>::iterator i = objects.begin(); i != objects.end(); ++i ) {
1870  // Insert the name as the class name followed by the name of the
1871  // object.
1872  TString name = (*i)->ClassName(); name.Append("::"); name.Append((*i)->GetName());
1873  // Check whether the names are the same!
1874  if ( selEntryStr && name == selEntryStr )
1875  selected = newid;
1876  fDataSet->AddEntry(name, newid++);
1877  }
1878 
1879  // If there was an entry selected (which should be always the case
1880  // except the first time this method is executed), then make it the
1881  // selected one again.
1882  if (entry) {
1883  fDataSet->Select(selected);
1884  }
1885 }
1886 
1887 ////////////////////////////////////////////////////////////////////////////////
1888 /// Create method list in a combo box.
1889 
1890 TGComboBox* TFitEditor::BuildMethodList(TGFrame* parent, Int_t id)
1891 {
1892  TGComboBox *c = new TGComboBox(parent, id);
1893  c->AddEntry("Chi-square", kFP_MCHIS);
1894  c->AddEntry("Binned Likelihood", kFP_MBINL);
1895  c->AddEntry("Unbinned Likelihood", kFP_MUBIN);
1896  //c->AddEntry("User", kFP_MUSER); //for later use
1897  c->Select(kFP_MCHIS);
1898  return c;
1899 }
1900 
1901 ////////////////////////////////////////////////////////////////////////////////
1902 /// Slot connected to advanced option button (opens a dialog).
1903 
1904 void TFitEditor::DoAdvancedOptions()
1905 {
1906  new TAdvancedGraphicsDialog( fClient->GetRoot(), GetMainFrame());
1907 }
1908 
1909 ////////////////////////////////////////////////////////////////////////////////
1910 /// Slot connected to 'include emtry bins and forse all weights to 1' setting.
1911 
1912 void TFitEditor::DoEmptyBinsAllWeights1()
1913 {
1914  if (fEmptyBinsWghts1->GetState() == kButtonDown)
1915  if (fAllWeights1->GetState() == kButtonDown)
1916  fAllWeights1->SetState(kButtonUp, kTRUE);
1917 }
1918 
1919 ////////////////////////////////////////////////////////////////////////////////
1920 
1921 void TFitEditor::DoUseFuncRange()
1922 {
1923  if ( fUseRange->GetState() == kButtonDown ) {
1924  if (fNone->GetState() == kButtonDown || fNone->GetState() == kButtonDisabled) {
1925  // Get the function
1926  TF1* tmpTF1 = FindFunction();
1927  if ( !tmpTF1 ) {
1928  if (GetFitObjectListOfFunctions()) {
1929  TGTextLBEntry *te = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
1930  tmpTF1 = (TF1*) GetFitObjectListOfFunctions()->FindObject( te->GetTitle() );
1931  }
1932  }
1933  // If the function has been retrieved, i.e. is a registered function.
1934  if ( tmpTF1 ) {
1935  Double_t xmin, ymin, zmin, xmax, ymax, zmax;
1936  // Get the range
1937  tmpTF1->GetRange(xmin, ymin, zmin, xmax, ymax, zmax);
1938  // And set the sliders
1939  if ( fType != kObjectTree ) {
1940  fSliderXMin->SetNumber( xmin );
1941  fSliderXMax->SetNumber( xmax );
1942  DoNumericSliderXChanged();
1943  if ( fDim > 1 ) {
1944  fSliderYMin->SetNumber( ymin );
1945  fSliderYMax->SetNumber( ymax );
1946  DoNumericSliderYChanged();
1947  }
1948  }
1949  }
1950  }
1951  fUseRange->SetState(kButtonDown);
1952  }
1953 }
1954 
1955 ////////////////////////////////////////////////////////////////////////////////
1956 /// Slot connected to 'set all weights to 1' setting.
1957 
1958 void TFitEditor::DoAllWeights1()
1959 {
1960  if (fAllWeights1->GetState() == kButtonDown)
1961  if (fEmptyBinsWghts1->GetState() == kButtonDown)
1962  fEmptyBinsWghts1->SetState(kButtonUp, kTRUE);
1963 }
1964 
1965 ////////////////////////////////////////////////////////////////////////////////
1966 /// Close the fit panel.
1967 
1968 void TFitEditor::DoClose()
1969 {
1970  Hide();
1971 }
1972 
1973 ////////////////////////////////////////////////////////////////////////////////
1974 /// Easy here!
1975 
1976 void TFitEditor::DoUpdate()
1977 {
1978  GetFunctionsFromSystem();
1979  FillDataSetList();
1980 }
1981 
1982 ////////////////////////////////////////////////////////////////////////////////
1983 /// Perform a fit with current parameters' settings.
1984 
1985 void TFitEditor::DoFit()
1986 {
1987  if (!fFitObject) return;
1988  //if (!fParentPad) return;
1989 
1990  // If fNone->GetState() == kButtonDisabled means the function is
1991  // not editable, i.e. it comes from a raw C function. So in this
1992  // case, it is editable and we have to check wheather the formula
1993  // is well built.
1994  if ( fNone->GetState() != kButtonDisabled && CheckFunctionString(fEnteredFunc->GetText()) )
1995  {
1996  // If not, then show an error message and leave.
1997  new TGMsgBox(fClient->GetRoot(), GetMainFrame(),
1998  "Error...", "2) Verify the entered function string!",
1999  kMBIconStop,kMBOk, 0);
2000  return;
2001  }
2002 
2003  // Set the button so that the user cannot use it while fitting, set
2004  // the mouse to watch type and so on.
2005  fFitButton->SetState(kButtonEngaged);
2006  if (gPad && gPad->GetVirtCanvas()) gPad->GetVirtCanvas()->SetCursor(kWatch);
2007  gVirtualX->SetCursor(GetId(), gVirtualX->CreateCursor(kWatch));
2008 
2009  TVirtualPad *save = nullptr;
2010  if ( fParentPad ) {
2011  fParentPad->Disconnect("RangeAxisChanged()");
2012  save = gPad;
2013  gPad = fParentPad;
2014  fParentPad->cd();
2015 
2016  if (fParentPad->GetCanvas())
2017  fParentPad->GetCanvas()->SetCursor(kWatch);
2018  }
2019 
2020  // Get the ranges from the sliders
2021  ROOT::Fit::DataRange drange;
2022  GetRanges(drange);
2023 
2024  // Create a static pointer to fitFunc. Every second call to the
2025  // DoFit method, the old fitFunc is deleted. We need not to delete
2026  // the function after the fitting in case we want to do Advaced
2027  // graphics. The VirtualFitter need the function to be alived. One
2028  // problem, after the last fit the function is never deleted, but
2029  // ROOT's garbage collector will do the job for us.
2030  static TF1 *fitFunc = nullptr;
2031  if ( fitFunc ) {
2032  //std::cout << "TFitEditor::DoFit - deleting fit function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2033  delete fitFunc;
2034  }
2035  fitFunc = GetFitFunction();
2036 
2037  std::cout << "TFitEditor::DoFit - using function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2038  // This assert
2039  if (!fitFunc) {
2040  Error("DoFit","This should have never happend, the fitfunc pointer is NULL! - Please Report" );
2041  return;
2042  }
2043 
2044  // set parameters from panel in function
2045  SetParameters(fFuncPars, fitFunc);
2046  // Get the options stored in the GUI elements.
2047  ROOT::Math::MinimizerOptions mopts;
2048  Foption_t fitOpts;
2049  TString strDrawOpts;
2050  RetrieveOptions(fitOpts, strDrawOpts, mopts, fitFunc->GetNpar());
2051 
2052  // Call the fit method, depending on the object to fit.
2053  switch (fType) {
2054  case kObjectHisto: {
2055 
2056  TH1 *hist = dynamic_cast<TH1*>(fFitObject);
2057  if (hist)
2058  ROOT::Fit::FitObject(hist, fitFunc, fitOpts, mopts, strDrawOpts, drange);
2059 
2060  break;
2061  }
2062  case kObjectGraph: {
2063 
2064  TGraph *gr = dynamic_cast<TGraph*>(fFitObject);
2065  if (gr)
2066  FitObject(gr, fitFunc, fitOpts, mopts, strDrawOpts, drange);
2067  break;
2068  }
2069  case kObjectMultiGraph: {
2070 
2071  TMultiGraph *mg = dynamic_cast<TMultiGraph*>(fFitObject);
2072  if (mg)
2073  FitObject(mg, fitFunc, fitOpts, mopts, strDrawOpts, drange);
2074 
2075  break;
2076  }
2077  case kObjectGraph2D: {
2078 
2079  TGraph2D *g2d = dynamic_cast<TGraph2D*>(fFitObject);
2080  if (g2d)
2081  FitObject(g2d, fitFunc, fitOpts, mopts, strDrawOpts, drange);
2082 
2083  break;
2084  }
2085  case kObjectHStack: {
2086  // N/A
2087  break;
2088  }
2089  case kObjectTree: {
2090  // The three is a much more special case. The steps for
2091  // fitting have to be done manually here until they are
2092  // properly implemented within a FitObject method in
2093  // THFitImpl.cxx
2094 
2095  // Retrieve the variables and cuts selected from the current
2096  // tree.
2097  TString variables;
2098  TString cuts;
2099  GetTreeVarsAndCuts(fDataSet, variables, cuts);
2100 
2101  // This should be straight forward and the return should
2102  // never be called.
2103  TTree *tree = dynamic_cast<TTree*>(fFitObject);
2104  if ( !tree ) return;
2105 
2106  // These method calls are just to set up everything for the
2107  // fitting. It's taken from another script.
2108  gROOT->ls();
2109  tree->Draw(variables,cuts,"goff");
2110 
2111  TTreePlayer * player = (TTreePlayer*) tree->GetPlayer();
2112  if ( !player ) {
2113  Error("DoFit","Player reference is NULL");
2114  return;
2115  }
2116 
2117  TSelectorDraw * selector = (TSelectorDraw* ) player->GetSelector();
2118  if ( !selector ) {
2119  Error("DoFit","Selector reference is NULL");
2120  return;
2121  }
2122 
2123  // use pointer stored in the tree (not copy the data in)
2124  unsigned int ndim = player->GetDimension();
2125  if ( ndim == 0 ) {
2126  Error("DoFit","NDIM == 0");
2127  return;
2128  }
2129 
2130  std::vector<double *> vlist;
2131  for (unsigned int i = 0; i < ndim; ++i) {
2132  double * v = selector->GetVal(i);
2133  if (v != 0) vlist.push_back(v);
2134  else
2135  std::cerr << "pointer for variable " << i << " is zero" << std::endl;
2136  }
2137  if (vlist.size() != ndim) {
2138  Error("DoFit","Vector is not complete");
2139  return;
2140  }
2141 
2142  // fill the data
2143  Long64_t nrows = player->GetSelectedRows();
2144  if ( !nrows ) {
2145  Error("DoFit","NROWS == 0");
2146  return;
2147  }
2148 
2149  ROOT::Fit::UnBinData * fitdata = new ROOT::Fit::UnBinData(nrows, ndim, vlist.begin());
2150 
2151  for ( int i = 0; i < std::min(int(fitdata->Size()),10); ++i) {
2152  // print j coordinate
2153  for (unsigned int j = 0; j < ndim; ++j) {
2154  printf(" x_%d [%d] = %f \n", j, i,*(fitdata->Coords(i)+j) );
2155  }
2156  printf("\n");
2157  }
2158 
2159 
2160  //TVirtualFitter::SetDefaultFitter("Minuit");
2161  Foption_t fitOption;
2162  ROOT::Math::MinimizerOptions minOption;
2163  fitOption.Verbose=1;
2164 
2165  // After all the set up is performed, then do the Fit!!
2166  ROOT::Fit::UnBinFit(fitdata, fitFunc, fitOption, minOption);
2167 
2168  break;
2169  }
2170  }
2171 
2172  // if SAME is set re-plot the function
2173  // useful in case histogram was drawn with HIST
2174  // and no function will be drawm)
2175  if (fDrawSame->GetState() == kButtonDown && fitFunc)
2176  fitFunc->Draw("same");
2177 
2178 
2179  // update parameters value shown in dialog
2180  //if (!fFuncPars) fFuncPars = new Double_t[fitFunc->GetNpar()][3];
2181  GetParameters(fFuncPars,fitFunc);
2182 
2183  // Save fit data for future use as a PrevFit function.
2184  TF1* tmpTF1 = copyTF1(fitFunc);
2185  TString name = TString::Format("PrevFit-%d", (int) fPrevFit.size() + 1);
2186  if (!strstr(fitFunc->GetName(),"PrevFit"))
2187  name.Append(TString::Format("-%s", fitFunc->GetName()));
2188  tmpTF1->SetName(name.Data());
2189  fPrevFit.emplace(fFitObject, tmpTF1);
2190  fSystemFuncs.emplace_back( copyTF1(tmpTF1) );
2191 
2192  float xmin = 0.f, xmax = 0.f, ymin = 0.f, ymax = 0.f, zmin = 0.f, zmax = 0.f;
2193  if ( fParentPad ) {
2194  fParentPad->Modified();
2195  // As the range is not changed, save the old values and restore
2196  // after the GUI has been updated. It would be more elegant to
2197  // disconnect the signal from fParentPad, however, this doesn't
2198  // work for unknown reasons.
2199  if ( fType != kObjectTree ) fSliderX->GetPosition(xmin, xmax);
2200  if ( fDim > 1 ) fSliderY->GetPosition(ymin, ymax);
2201  if ( fDim > 2 ) fSliderZ->GetPosition(zmin, zmax);
2202  fParentPad->Update();
2203  }
2204 
2205  // In case the fit method draws something! Set the canvas!
2206  fParentPad = gPad;
2207  UpdateGUI();
2208 
2209  // Change the sliders if necessary.
2210  if ( fParentPad ) {
2211  if ( fType != kObjectTree ) { fSliderX->SetPosition(xmin, xmax); DoSliderXMoved(); }
2212  if ( fType != kObjectTree && fDim > 1 ) { fSliderY->SetPosition(ymin, ymax); DoSliderYMoved(); }
2213  if ( fType != kObjectTree && fDim > 2 ) { fSliderZ->SetPosition(zmin, zmax); DoSliderZMoved(); }
2214  if (fParentPad->GetCanvas())
2215  fParentPad->GetCanvas()->SetCursor(kPointer);
2216  fParentPad->Connect("RangeAxisChanged()", "TFitEditor", this, "UpdateGUI()");
2217 
2218  if (save) gPad = save;
2219  if (fSetParam->GetState() == kButtonDisabled &&
2220  fLinearFit->GetState() == kButtonUp)
2221  fSetParam->SetState(kButtonUp);
2222  }
2223 
2224  // Restore the Fit button and mouse cursor to their proper state.
2225  if (gPad && gPad->GetVirtCanvas()) gPad->GetVirtCanvas()->SetCursor(kPointer);
2226  gVirtualX->SetCursor(GetId(), gVirtualX->CreateCursor(kPointer));
2227  fFitButton->SetState(kButtonUp);
2228 
2229  if ( !fTypeFit->FindEntry("Prev. Fit") )
2230  fTypeFit->InsertEntry("Prev. Fit",kFP_PREVFIT, kFP_UFUNC);
2231 
2232  fDrawAdvanced->SetState(kButtonUp);
2233 }
2234 
2235 ////////////////////////////////////////////////////////////////////////////////
2236 /// Check entered function string.
2237 
2238 Int_t TFitEditor::CheckFunctionString(const char *fname)
2239 {
2240  Int_t rvalue = 0;
2241  if ( fDim == 1 || fDim == 0 ) {
2242  TF1 form("tmpCheck", fname);
2243  // coverity[uninit_use_in_call]
2244  rvalue = form.IsValid() ? 0 : -1;
2245  } else if ( fDim == 2 ) {
2246  TF2 form("tmpCheck", fname);
2247  // coverity[uninit_use_in_call]
2248  rvalue = form.IsValid() ? 0 : -1;
2249  } else if ( fDim == 3 ) {
2250  TF3 form("tmpCheck", fname);
2251  // coverity[uninit_use_in_call]
2252  rvalue = form.IsValid() ? 0 : -1;
2253  }
2254 
2255  return rvalue;
2256 }
2257 
2258 ////////////////////////////////////////////////////////////////////////////////
2259 /// Slot connected to addition of predefined functions. It will
2260 /// insert the next selected function with a plus sign so that it
2261 /// doesn't override the current content of the formula.
2262 
2263 void TFitEditor::DoAddition(Bool_t on)
2264 {
2265  static Bool_t first = kFALSE;
2266  TString s = fEnteredFunc->GetText();
2267  if (on) {
2268  if (!first) {
2269  fSelLabel->SetText(s.Sizeof()>30?s(0,30)+"...":s);
2270  s += "(0)";
2271  fEnteredFunc->SetText(s.Data());
2272  first = kTRUE;
2273  ((TGCompositeFrame *)fSelLabel->GetParent())->Layout();
2274  }
2275  } else {
2276  first = kFALSE;
2277  }
2278 }
2279 ////////////////////////////////////////////////////////////////////////////////
2280 /// Slot connected to addition of predefined functions. It will
2281 /// insert the next selected function with a plus sign so that it
2282 /// doesn't override the current content of the formula.
2283 
2284 void TFitEditor::DoNormAddition(Bool_t on)
2285 {
2286  /*
2287  static Bool_t first = kFALSE;
2288  TString s = fEnteredFunc->GetText();
2289  if (on) {
2290  if (!first) {
2291  fSelLabel->SetText(s.Sizeof()>30?s(0,30)+"...":s);
2292  fEnteredFunc->SetText(s.Data());
2293  first = kTRUE;
2294  ((TGCompositeFrame *)fSelLabel->GetParent())->Layout();
2295  }
2296  } else {
2297  first = kFALSE;
2298  }*/
2299 
2300  if (on) Info("DoNormAddition","Normalized addition is selected");
2301 }
2302 
2303 ////////////////////////////////////////////////////////////////////////////////
2304 /// Slot connected to addition of predefined functions. It will
2305 /// insert the next selected function with a plus sign so that it
2306 /// doesn't override the current content of the formula.
2307 
2308 void TFitEditor::DoConvolution(Bool_t on)
2309 {
2310  /*
2311  static Bool_t first = kFALSE;
2312  TString s = fEnteredFunc->GetText();
2313  if (on) {
2314  if (!first) {
2315  fSelLabel->SetText(s.Sizeof()>30?s(0,30)+"...":s);
2316  // s += "(0)";
2317  fEnteredFunc->SetText(s.Data());
2318  first = kTRUE;
2319  ((TGCompositeFrame *)fSelLabel->GetParent())->Layout();
2320  }
2321  } else
2322  first = kFALSE;*/
2323 
2324  if (on) Info("DoConvolution","Convolution is selected");
2325 }
2326 
2327 ////////////////////////////////////////////////////////////////////////////////
2328 /// Selects the data set to be fitted
2329 
2330 void TFitEditor::DoDataSet(Int_t selected)
2331 {
2332  if ( selected == kFP_NOSEL ) {
2333  DoNoSelection();
2334  return;
2335  }
2336 
2337  // Get the name and class of the selected object.
2338  TGTextLBEntry* textEntry = static_cast<TGTextLBEntry*>(fDataSet->GetListBox()->GetEntry(selected));
2339  if (!textEntry) return;
2340  TString textEntryStr = textEntry->GetText()->GetString();
2341  TString name = textEntry->GetText()->GetString()+textEntry->GetText()->First(':')+2;
2342  TString className = textEntryStr(0,textEntry->GetText()->First(':'));
2343 
2344  // Check the object exists in the ROOT session and it is registered
2345  TObject* objSelected(0);
2346  if ( className == "TTree" ) {
2347  // It's a tree, so the name is before the space (' ')
2348  TString lookStr;
2349  if ( name.First(' ') == kNPOS )
2350  lookStr = name;
2351  else
2352  lookStr = name(0, name.First(' '));
2353  //std::cout << "\t1 SITREE: '" << lookStr << "'" << std::endl;
2354  objSelected = gROOT->FindObject(lookStr);
2355  } else {
2356  // It's not a tree, so the name is the complete string
2357  //std::cout << "\t1 NOTREE: '" << name << "'" << std::endl;
2358  objSelected = gROOT->FindObject(name);
2359  }
2360  if ( !objSelected )
2361  {
2362  //std::cerr << "Object not found! Please report the error! " << std::endl;
2363  return;
2364  }
2365 
2366  // If it is a tree, and there are no variables selected, show a dialog
2367  if ( objSelected->InheritsFrom(TTree::Class()) &&
2368  name.First(' ') == kNPOS ) {
2369  char variables[256] = {0}; char cuts[256] = {0};
2370  strlcpy(variables, "Sin input!", 256);
2371  new TTreeInput( fClient->GetRoot(), GetMainFrame(), variables, cuts );
2372  if ( strcmp ( variables, "" ) == 0 ) {
2373  DoNoSelection();
2374  return;
2375  }
2376  ProcessTreeInput(objSelected, selected, variables, cuts);
2377  }
2378 
2379  // Search the canvas where the object is drawn, if any
2380  TPad* currentPad = NULL;
2381  bool found = false;
2382  std::queue<TPad*> stPad;
2383  TIter padIter( gROOT->GetListOfCanvases() );
2384  while ( TObject* canvas = static_cast<TObject*>(padIter() ) ) {
2385  if ( dynamic_cast<TPad*>(canvas) )
2386  stPad.push(dynamic_cast<TPad*>(canvas));
2387  }
2388 
2389  while ( !stPad.empty() && !found ) {
2390  currentPad = stPad.front();
2391  stPad.pop();
2392  TIter elemIter( currentPad->GetListOfPrimitives() );
2393  while ( TObject* elem = static_cast<TObject*>(elemIter() ) ) {
2394  if ( elem == objSelected ) {
2395  found = true;
2396  break;
2397  } else if ( dynamic_cast<TPad*>(elem) )
2398  stPad.push( dynamic_cast<TPad*>(elem) );
2399  }
2400  }
2401 
2402  // Set the proper object and canvas (if found!)
2403  SetFitObject( found ? currentPad : nullptr, objSelected, kButton1Down);
2404 }
2405 
2406 void TFitEditor::ProcessTreeInput(TObject* objSelected, Int_t selected, TString variables, TString cuts)
2407 {
2408  // If the input is valid, insert the tree with the selections as an entry to fDataSet
2409  TString entryName = (objSelected)->ClassName(); entryName.Append("::"); entryName.Append((objSelected)->GetName());
2410  entryName.Append(" (\""); entryName.Append(variables); entryName.Append("\", \"");
2411  entryName.Append(cuts); entryName.Append("\")");
2412  Int_t newid = fDataSet->GetNumberOfEntries() + kFP_NOSEL;
2413  fDataSet->InsertEntry(entryName, newid, selected );
2414  fDataSet->Select(newid);
2415 }
2416 
2417 ////////////////////////////////////////////////////////////////////////////////
2418 /// Slot connected to predefined fit function settings.
2419 
2420 void TFitEditor::DoFunction(Int_t selected)
2421 {
2422  TGTextLBEntry *te = (TGTextLBEntry *)fFuncList->GetSelectedEntry();
2423 
2424  // check that selected passesd value is the correct one in the TextEntry
2425  R__ASSERT( selected == te->EntryId());
2426  //std::cout << "calling do function " << selected << " " << te->GetTitle() << " function " << te->EntryId() << std::endl;
2427  //selected = te->EntryId();
2428 
2429  bool editable = false;
2430  if (fNone -> GetState() == kButtonDown || fNone->GetState() == kButtonDisabled)
2431  {
2432  // Get the function selected and check weather it is a raw C
2433  // function or not
2434  TF1* tmpTF1 = FindFunction();
2435  if ( !tmpTF1 )
2436  {
2437  if (GetFitObjectListOfFunctions())
2438  tmpTF1 = (TF1*) GetFitObjectListOfFunctions()->FindObject( te->GetTitle() );
2439  }
2440  if ( tmpTF1 && strcmp(tmpTF1->GetExpFormula(), "") )
2441  {
2442  editable = kTRUE;
2443  fEnteredFunc->SetText(tmpTF1->GetExpFormula());
2444  }
2445  else
2446  {
2447  if ( selected <= kFP_USER )
2448  editable = kTRUE;
2449  else
2450  editable = kFALSE;
2451  fEnteredFunc->SetText(te->GetTitle());
2452  }
2453  // Once you have the function, set the editable.
2454  SetEditable(editable);
2455  }
2456  else if (fAdd -> GetState() == kButtonDown)
2457  {
2458  // If the add button is down don't replace the fEnteredFunc text
2459  Int_t np = 0;
2460  TString s = "";
2461  if (!strcmp(fEnteredFunc->GetText(), ""))
2462  {
2463  fEnteredFunc->SetText(te->GetTitle());
2464  }
2465  else
2466  {
2467  s = fEnteredFunc->GetTitle();
2468  TFormula tmp("tmp", fEnteredFunc->GetText());
2469  np = tmp.GetNpar();
2470  }
2471  if (np)
2472  s += TString::Format("+%s(%d)", te->GetTitle(), np);
2473  else
2474  s += TString::Format("%s(%d)", te->GetTitle(), np);
2475  fEnteredFunc->SetText(s.Data());
2476  editable = true;
2477  }
2478  else if (fNormAdd->GetState() == kButtonDown)
2479  {
2480  // If the normadd button is down don't replace the fEnteredFunc text
2481  Int_t np = 0;
2482  TString s = "";
2483  if (!strcmp(fEnteredFunc->GetText(), ""))
2484  {
2485  fEnteredFunc->SetText(te->GetTitle());
2486  }
2487  else
2488  {
2489  s = fEnteredFunc->GetTitle();
2490  TFormula tmp("tmp", fEnteredFunc->GetText());
2491  np = tmp.GetNpar();
2492  }
2493  if (np)
2494  s += TString::Format("+%s", te->GetTitle());
2495  else
2496  s += TString::Format("%s", te->GetTitle());
2497  fEnteredFunc->SetText(s.Data());
2498  //std::cout <<fEnteredFunc->GetText()<<std::endl;
2499  editable = true;
2500  }
2501  else if (fConv->GetState() == kButtonDown)
2502  {
2503  // If the normadd button is down don't replace the fEnteredFunc text
2504  Int_t np = 0;
2505  TString s = "";
2506  if (!strcmp(fEnteredFunc->GetText(), ""))
2507  fEnteredFunc->SetText(te->GetTitle());
2508  else
2509  {
2510  s = fEnteredFunc->GetTitle();
2511  TFormula tmp("tmp", fEnteredFunc->GetText());
2512  np = tmp.GetNpar();
2513  }
2514  if (np)
2515  s += TString::Format("*%s", te->GetTitle());
2516  else
2517  s += TString::Format("%s", te->GetTitle());
2518  fEnteredFunc->SetText(s.Data());
2519  //std::cout <<fEnteredFunc->GetText()<<std::endl;
2520  editable = true;
2521  }
2522 
2523 
2524  // Get the final name in fEnteredFunc to process the function that
2525  // it would create
2526  TString tmpStr = fEnteredFunc->GetText();
2527 
2528  // create TF1 with the passed string. Delete previous one if existing
2529  if (tmpStr.Contains("pol") || tmpStr.Contains("++")) {
2530  fLinearFit->SetState(kButtonDown, kTRUE);
2531  } else {
2532  fLinearFit->SetState(kButtonUp, kTRUE);
2533  }
2534 
2535  fEnteredFunc->SelectAll();
2536  fSelLabel->SetText(tmpStr.Sizeof()>30?tmpStr(0,30)+"...":tmpStr);
2537  ((TGCompositeFrame *)fSelLabel->GetParent())->Layout();
2538 
2539  // reset function parameters if the number of parameters of the new
2540  // function is different from the old one!
2541  TF1* fitFunc = GetFitFunction();
2542  //std::cout << "TFitEditor::DoFunction - using function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2543 
2544  if ( fitFunc && (unsigned int) fitFunc->GetNpar() != fFuncPars.size() )
2545  fFuncPars.clear();
2546  if ( fitFunc ) {
2547  //std::cout << "TFitEditor::DoFunction - deleting function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2548  delete fitFunc;
2549  }
2550 }
2551 
2552 ////////////////////////////////////////////////////////////////////////////////
2553 /// Slot connected to entered function in text entry.
2554 
2555 void TFitEditor::DoEnteredFunction()
2556 {
2557  if (!strcmp(fEnteredFunc->GetText(), "")) return;
2558 
2559  // Check if the function is well built
2560  Int_t ok = CheckFunctionString(fEnteredFunc->GetText());
2561 
2562  if (ok != 0) {
2563  new TGMsgBox(fClient->GetRoot(), GetMainFrame(),
2564  "Error...", "3) Verify the entered function string!",
2565  kMBIconStop,kMBOk, 0);
2566  return;
2567  }
2568 
2569  // And set the label with the entered text if everything is fine.
2570  TString s = fEnteredFunc->GetText();
2571  fSelLabel->SetText(s.Sizeof()>30?s(0,30)+"...":s);
2572  ((TGCompositeFrame *)fSelLabel->GetParent())->Layout();
2573 }
2574 
2575 ////////////////////////////////////////////////////////////////////////////////
2576 /// Slot connected to linear fit settings.
2577 
2578 void TFitEditor::DoLinearFit()
2579 {
2580  if (fLinearFit->GetState() == kButtonDown) {
2581  //fSetParam->SetState(kButtonDisabled);
2582  fBestErrors->SetState(kButtonDisabled);
2583  fImproveResults->SetState(kButtonDisabled);
2584  fEnableRobust->SetState(kButtonUp);
2585  //fNoChi2->SetState(kButtonUp);
2586  } else {
2587  //fSetParam->SetState(kButtonUp);
2588  fBestErrors->SetState(kButtonUp);
2589  fImproveResults->SetState(kButtonUp);
2590  fEnableRobust->SetState(kButtonDisabled);
2591  fRobustValue->SetState(kFALSE);
2592  //fNoChi2->SetState(kButtonDisabled);
2593  }
2594 }
2595 
2596 ////////////////////////////////////////////////////////////////////////////////
2597 /// Slot connected to 'no chi2' option settings.
2598 
2599 void TFitEditor::DoNoChi2()
2600 {
2601  //LM: no need to do operations here
2602  // if (fLinearFit->GetState() == kButtonUp)
2603  // fLinearFit->SetState(kButtonDown, kTRUE);
2604 }
2605 ////////////////////////////////////////////////////////////////////////////////
2606 /// Slot connected to 'robust fitting' option settings.
2607 
2608 void TFitEditor::DoRobustFit()
2609 {
2610  if (fEnableRobust->GetState() == kButtonDown)
2611  fRobustValue->SetState(kTRUE);
2612  else
2613  fRobustValue->SetState(kFALSE);
2614 }
2615 
2616 ////////////////////////////////////////////////////////////////////////////////
2617 /// Slot connected to 'no storing, no drawing' settings.
2618 
2619 void TFitEditor::DoNoStoreDrawing()
2620 {
2621  if (fNoDrawing->GetState() == kButtonUp)
2622  fNoDrawing->SetState(kButtonDown);
2623 }
2624 
2625 ////////////////////////////////////////////////////////////////////////////////
2626 /// Slot connected to print option settings.
2627 
2628 void TFitEditor::DoPrintOpt(Bool_t on)
2629 {
2630  // Change the states of the buttons depending of which one is
2631  // selected.
2632  TGButton *btn = (TGButton *) gTQSender;
2633  Int_t id = btn->WidgetId();
2634  switch (id) {
2635  case kFP_PDEF:
2636  if (on) {
2637  fOptDefault->SetState(kButtonDown);
2638  fOptVerbose->SetState(kButtonUp);
2639  fOptQuiet->SetState(kButtonUp);
2640  }
2641  fStatusBar->SetText("Prn: DEF",4);
2642  break;
2643  case kFP_PVER:
2644  if (on) {
2645  fOptVerbose->SetState(kButtonDown);
2646  fOptDefault->SetState(kButtonUp);
2647  fOptQuiet->SetState(kButtonUp);
2648  }
2649  fStatusBar->SetText("Prn: VER",4);
2650  break;
2651  case kFP_PQET:
2652  if (on) {
2653  fOptQuiet->SetState(kButtonDown);
2654  fOptDefault->SetState(kButtonUp);
2655  fOptVerbose->SetState(kButtonUp);
2656  }
2657  fStatusBar->SetText("Prn: QT",4);
2658  default:
2659  break;
2660  }
2661 }
2662 
2663 ////////////////////////////////////////////////////////////////////////////////
2664 /// Reset all fit parameters.
2665 
2666 void TFitEditor::DoReset()
2667 {
2668  if ( fParentPad ) {
2669  fParentPad->Modified();
2670  fParentPad->Update();
2671  }
2672  fEnteredFunc->SetText("gaus");
2673 
2674  // To restore temporary points and sliders
2675  UpdateGUI();
2676 
2677  if (fLinearFit->GetState() == kButtonDown)
2678  fLinearFit->SetState(kButtonUp, kTRUE);
2679  if (fBestErrors->GetState() == kButtonDown)
2680  fBestErrors->SetState(kButtonUp, kFALSE);
2681  if (fUseRange->GetState() == kButtonDown)
2682  fUseRange->SetState(kButtonUp, kFALSE);
2683  if (fAllWeights1->GetState() == kButtonDown)
2684  fAllWeights1->SetState(kButtonUp, kFALSE);
2685  if (fEmptyBinsWghts1->GetState() == kButtonDown)
2686  fEmptyBinsWghts1->SetState(kButtonUp, kFALSE);
2687  if (fImproveResults->GetState() == kButtonDown)
2688  fImproveResults->SetState(kButtonUp, kFALSE);
2689  if (fAdd2FuncList->GetState() == kButtonDown)
2690  fAdd2FuncList->SetState(kButtonUp, kFALSE);
2691  if (fUseGradient->GetState() == kButtonDown)
2692  fUseGradient->SetState(kButtonUp, kFALSE);
2693  if (fEnableRobust->GetState() == kButtonDown)
2694  fEnableRobust->SetState(kButtonUp, kFALSE);
2695  // if (fNoChi2->GetState() == kButtonDown)
2696  // fNoChi2->SetState(kButtonUp, kFALSE);
2697  if (fDrawSame->GetState() == kButtonDown)
2698  fDrawSame->SetState(kButtonUp, kFALSE);
2699  if (fNoDrawing->GetState() == kButtonDown)
2700  fNoDrawing->SetState(kButtonUp, kFALSE);
2701  if (fNoStoreDrawing->GetState() == kButtonDown)
2702  fNoStoreDrawing->SetState(kButtonUp, kFALSE);
2703  fNone->SetState(kButtonDown, kTRUE);
2704  fFuncList->Select(1, kTRUE);
2705 
2706  // minimization tab
2707  if (fLibMinuit->GetState() != kButtonDown)
2708  fLibMinuit->SetState(kButtonDown, kTRUE);
2709  FillMinMethodList();
2710  if (fOptDefault->GetState() != kButtonDown)
2711  fOptDefault->SetState(kButtonDown, kTRUE);
2712  if (fErrorScale->GetNumber() != ROOT::Math::MinimizerOptions::DefaultErrorDef()) {
2713  fErrorScale->SetNumber(ROOT::Math::MinimizerOptions::DefaultErrorDef());
2714  fErrorScale->ReturnPressed();
2715  }
2716  if (fTolerance->GetNumber() != ROOT::Math::MinimizerOptions::DefaultTolerance()) {
2717  fTolerance->SetNumber(ROOT::Math::MinimizerOptions::DefaultTolerance());
2718  fTolerance->ReturnPressed();
2719  }
2720  if (fIterations->GetNumber() != ROOT::Math::MinimizerOptions::DefaultMaxIterations()) {
2721  fIterations->SetIntNumber(ROOT::Math::MinimizerOptions::DefaultMaxIterations());
2722  fIterations->ReturnPressed();
2723  }
2724 }
2725 
2726 ////////////////////////////////////////////////////////////////////////////////
2727 /// Open set parameters dialog.
2728 
2729 void TFitEditor::DoSetParameters()
2730 {
2731  // Get the function.
2732  TF1* fitFunc = GetFitFunction();
2733  //std::cout << "TFitEditor::DoSetParameters - using function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2734 
2735  if (!fitFunc) { Error("DoSetParameters","NUll function"); return; }
2736 
2737  // case of special functions (gaus, expo, etc...) if the function
2738  // has not defined the parameters yet. For those, don't let the
2739  // parameters to be all equal to 0, as we can provide some good
2740  // starting value.
2741  if (fFuncPars.size() == 0) {
2742  switch (fType) {
2743  case kObjectHisto:
2744  InitParameters( fitFunc, (TH1*)fFitObject) ;
2745  break;
2746  case kObjectGraph:
2747  InitParameters( fitFunc, ((TGraph*)fFitObject));
2748  break;
2749  case kObjectMultiGraph:
2750  InitParameters( fitFunc, ((TMultiGraph*)fFitObject));
2751  break;
2752  case kObjectGraph2D:
2753  InitParameters( fitFunc, ((TGraph2D*)fFitObject));
2754  break;
2755  case kObjectHStack:
2756  case kObjectTree:
2757  default:
2758  break;
2759  }
2760  // The put these parameters into the fFuncPars structure
2761  GetParameters(fFuncPars, fitFunc);
2762  }
2763  else {
2764  // Otherwise, put the parameters in the function
2765  SetParameters(fFuncPars, fitFunc);
2766  }
2767 
2768  if ( fParentPad ) fParentPad->Disconnect("RangeAxisChanged()");
2769  Int_t ret = 0;
2770  /// fit parameter dialog willbe deleted automatically when closed
2771  new TFitParametersDialog(gClient->GetDefaultRoot(), GetMainFrame(),
2772  fitFunc, fParentPad, &ret);
2773 
2774  // Once the parameters are set in the fitfunction, save them.
2775  GetParameters(fFuncPars, fitFunc);
2776 
2777  // check return code to see if parameters settings have been modified
2778  // in this case we need to set the B option when fitting
2779  if (ret) fChangedParams = kTRUE;
2780 
2781 
2782  if ( fParentPad ) fParentPad->Connect("RangeAxisChanged()", "TFitEditor", this, "UpdateGUI()");
2783 
2784  if ( fNone->GetState() != kButtonDisabled ) {
2785  //std::cout << "TFitEditor::DoSetParameters - deleting function " << fitFunc->GetName() << " " << fitFunc << std::endl;
2786  delete fitFunc;
2787  }
2788 }
2789 
2790 ////////////////////////////////////////////////////////////////////////////////
2791 /// Slot connected to range settings on x-axis.
2792 
2793 void TFitEditor::DoSliderXMoved()
2794 {
2795  if ( !fFitObject ) return;
2796 
2797  fSliderXMin->SetNumber( fXaxis->GetBinLowEdge( static_cast<Int_t>( fSliderX->GetMinPosition() ) ) );
2798  fSliderXMax->SetNumber( fXaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderX->GetMaxPosition() ) ) );
2799 
2800  fUseRange->SetState(kButtonUp);
2801 
2802  DrawSelection();
2803 }
2804 
2805 ////////////////////////////////////////////////////////////////////////////////
2806 /// Draws the square around the object showing where the limits for
2807 /// fitting are.
2808 
2809 void TFitEditor::DrawSelection(bool restore)
2810 {
2811  static Int_t px1old, py1old, px2old, py2old; // to remember the square drawn.
2812 
2813  if ( !fParentPad ) return;
2814 
2815  if (restore) {
2816  px1old = fParentPad->XtoAbsPixel(fParentPad->GetUxmin());
2817  py1old = fParentPad->YtoAbsPixel(fParentPad->GetUymin());
2818  px2old = fParentPad->XtoAbsPixel(fParentPad->GetUxmax());
2819  py2old = fParentPad->YtoAbsPixel(fParentPad->GetUymax());
2820  return;
2821  }
2822 
2823  Int_t px1,py1,px2,py2;
2824 
2825  TVirtualPad *save = 0;
2826  save = gPad;
2827  gPad = fParentPad;
2828  gPad->cd();
2829 
2830  Double_t xleft = 0;
2831  Double_t xright = 0;
2832  xleft = fXaxis->GetBinLowEdge((Int_t)((fSliderX->GetMinPosition())+0.5));
2833  xright = fXaxis->GetBinUpEdge((Int_t)((fSliderX->GetMaxPosition())+0.5));
2834 
2835  Float_t ymin, ymax;
2836  if ( fDim > 1 )
2837  {
2838  ymin = fYaxis->GetBinLowEdge((Int_t)((fSliderY->GetMinPosition())+0.5));//gPad->GetUymin();
2839  ymax = fYaxis->GetBinUpEdge((Int_t)((fSliderY->GetMaxPosition())+0.5));//gPad->GetUymax();
2840  }
2841  else
2842  {
2843  ymin = gPad->GetUymin();
2844  ymax = gPad->GetUymax();
2845  }
2846 
2847  px1 = gPad->XtoAbsPixel(xleft);
2848  py1 = gPad->YtoAbsPixel(ymin);
2849  px2 = gPad->XtoAbsPixel(xright);
2850  py2 = gPad->YtoAbsPixel(ymax);
2851 
2852  if (gPad->GetCanvas()) gPad->GetCanvas()->FeedbackMode(kTRUE);
2853  gPad->SetLineWidth(1);
2854  gPad->SetLineColor(2);
2855 
2856  gVirtualX->DrawBox(px1old, py1old, px2old, py2old, TVirtualX::kHollow);
2857  gVirtualX->DrawBox(px1, py1, px2, py2, TVirtualX::kHollow);
2858 
2859  px1old = px1;
2860  py1old = py1;
2861  px2old = px2 ;
2862  py2old = py2;
2863 
2864  if(save) gPad = save;
2865 }
2866 
2867 ////////////////////////////////////////////////////////////////////////////////
2868 /// Sincronize the numeric sliders with the graphical one.
2869 
2870 void TFitEditor::DoNumericSliderXChanged()
2871 {
2872  if ( fSliderXMin->GetNumber() > fSliderXMax->GetNumber() ) {
2873  float xmin, xmax;
2874  fSliderX->GetPosition(xmin, xmax);
2875  fSliderXMin->SetNumber( fXaxis->GetBinLowEdge( static_cast<Int_t>( xmin ) ) );
2876  fSliderXMax->SetNumber( fXaxis->GetBinUpEdge ( static_cast<Int_t>( xmax ) ) );
2877  return;
2878  }
2879 
2880  fSliderX->SetPosition(fXaxis->FindBin( fSliderXMin->GetNumber() ),
2881  fXaxis->FindBin( fSliderXMax->GetNumber() ));
2882 
2883  fUseRange->SetState(kButtonUp);
2884 
2885  DrawSelection();
2886 }
2887 
2888 ////////////////////////////////////////////////////////////////////////////////
2889 /// Slot connected to range settings on y-axis.
2890 
2891 void TFitEditor::DoSliderYMoved()
2892 {
2893  if ( !fFitObject ) return;
2894 
2895  fSliderYMin->SetNumber( fYaxis->GetBinLowEdge( static_cast<Int_t>( fSliderY->GetMinPosition() ) ) );
2896  fSliderYMax->SetNumber( fYaxis->GetBinUpEdge ( static_cast<Int_t>( fSliderY->GetMaxPosition() ) ) );
2897 
2898  fUseRange->SetState(kButtonUp);
2899 
2900  DrawSelection();
2901 }
2902 
2903 ////////////////////////////////////////////////////////////////////////////////
2904 ///syncronize the numeric slider with the graphical one.
2905 
2906 void TFitEditor::DoNumericSliderYChanged()
2907 {
2908  if ( fSliderYMin->GetNumber() > fSliderYMax->GetNumber() ) {
2909  float ymin, ymax;
2910  fSliderY->GetPosition(ymin, ymax);
2911  fSliderYMin->SetNumber( fYaxis->GetBinLowEdge( static_cast<Int_t>( ymin ) ) );
2912  fSliderYMax->SetNumber( fYaxis->GetBinUpEdge ( static_cast<Int_t>( ymax ) ) );
2913  return;
2914  }
2915 
2916  fSliderY->SetPosition( fYaxis->FindBin( fSliderYMin->GetNumber() ),
2917  fYaxis->FindBin( fSliderYMax->GetNumber() ));
2918 
2919  fUseRange->SetState(kButtonUp);
2920 
2921  DrawSelection();
2922 }
2923 
2924 ////////////////////////////////////////////////////////////////////////////////
2925 /// Slot connected to range settings on z-axis.
2926 
2927 void TFitEditor::DoSliderZMoved()
2928 {
2929 }
2930 
2931 ////////////////////////////////////////////////////////////////////////////////
2932 /// Open a dialog for getting a user defined method.
2933 
2934 void TFitEditor::DoUserDialog()
2935 {
2936  new TGMsgBox(fClient->GetRoot(), GetMainFrame(),
2937  "Info", "Dialog of user method is not implemented yet",
2938  kMBIconAsterisk,kMBOk, 0);
2939 }
2940 
2941 ////////////////////////////////////////////////////////////////////////////////
2942 /// Set the function to be used in performed fit.
2943 
2944 void TFitEditor::SetFunction(const char *function)
2945 {
2946  fEnteredFunc->SetText(function);
2947 }
2948 
2949 ////////////////////////////////////////////////////////////////////////////////
2950 /// Check whether the object suitable for fitting and set
2951 /// its type, dimension and method combo box accordingly.
2952 
2953 Bool_t TFitEditor::SetObjectType(TObject* obj)
2954 {
2955  Bool_t set = kFALSE;
2956 
2957  // For each kind of object, set a different status in the fit
2958  // panel.
2959  if (obj->InheritsFrom(TGraph::Class())) {
2960  fType = kObjectGraph;
2961  set = kTRUE;
2962  fDim = 1;
2963  fMethodList->RemoveAll();
2964  fMethodList->AddEntry("Chi-square", kFP_MCHIS);
2965  fMethodList->Select(kFP_MCHIS, kFALSE);
2966  fRobustValue->SetState(kTRUE);
2967  fRobustValue->GetNumberEntry()->SetToolTipText("Set robust value");
2968  } else if (obj->InheritsFrom(TGraph2D::Class())) {
2969  fType = kObjectGraph2D;
2970  set = kTRUE;
2971  fDim = 2;
2972  fMethodList->RemoveAll();
2973  fMethodList->AddEntry("Chi-square", kFP_MCHIS);
2974  fMethodList->Select(kFP_MCHIS, kFALSE);
2975  } else if (obj->InheritsFrom(THStack::Class())) {
2976  fType = kObjectHStack;
2977  set = kTRUE;
2978  TH1 *hist = (TH1 *)((THStack *)obj)->GetHists()->First();
2979  fDim = hist->GetDimension();
2980  fMethodList->RemoveAll();
2981  fMethodList->AddEntry("Chi-square", kFP_MCHIS);
2982  fMethodList->Select(kFP_MCHIS, kFALSE);
2983  } else if (obj->InheritsFrom(TTree::Class())) {
2984  fType = kObjectTree;
2985  set = kTRUE;
2986  TString variables, cuts;
2987  GetTreeVarsAndCuts(fDataSet, variables, cuts);
2988  fDim = 1;
2989  for ( int i = 0; i < variables.Length() && fDim <= 2; ++i )
2990  if ( ':' == variables[i] ) fDim += 1;
2991  // For any three of dimension bigger than 2, set the dimension
2992  // to 0, as we cannot infer the dimension from the TF1s, it's
2993  // better to have 0 as reference.
2994  if ( fDim > 2 ) fDim = 0;
2995  fMethodList->RemoveAll();
2996  fMethodList->AddEntry("Unbinned Likelihood", kFP_MUBIN);
2997  fMethodList->Select(kFP_MUBIN, kFALSE);
2998  } else if (obj->InheritsFrom(TH1::Class())){
2999  fType = kObjectHisto;
3000  set = kTRUE;
3001  fDim = ((TH1*)obj)->GetDimension();
3002  fMethodList->RemoveAll();
3003  fMethodList->AddEntry("Chi-square", kFP_MCHIS);
3004  fMethodList->AddEntry("Binned Likelihood", kFP_MBINL);
3005  fMethodList->Select(kFP_MCHIS, kFALSE);
3006  } else if (obj->InheritsFrom(TMultiGraph::Class())) {
3007  fType = kObjectMultiGraph;
3008  set = kTRUE;
3009  fDim = 1;
3010  fMethodList->RemoveAll();
3011  fMethodList->AddEntry("Chi-square", kFP_MCHIS);
3012  fMethodList->Select(kFP_MCHIS, kFALSE);
3013  fRobustValue->SetState(kTRUE);
3014  fRobustValue->GetNumberEntry()->SetToolTipText("Set robust value");
3015  }
3016 
3017  // Depending on the dimension of the object, allow the
3018  // visualization of sliders.
3019  if ( fDim < 2 || fType == kObjectTree )
3020  fGeneral->HideFrame(fSliderYParent);
3021  else
3022  fGeneral->ShowFrame(fSliderYParent);
3023 
3024  if ( fDim < 1 || fType == kObjectTree )
3025  fGeneral->HideFrame(fSliderXParent);
3026  else
3027  fGeneral->ShowFrame(fSliderXParent);
3028 
3029  // And also, depending on the dimension, add predefined functions.
3030  if ( fDim == 1 ) {
3031  if ( !fTypeFit->FindEntry("Predef-1D") )
3032  fTypeFit->InsertEntry("Predef-1D", kFP_PRED1D, kFP_PREVFIT);
3033  } else {
3034  if ( fTypeFit->FindEntry("Predef-1D") )
3035  fTypeFit->RemoveEntry(kFP_PRED1D);
3036  }
3037 
3038  if ( fDim == 2 ) {
3039  if ( !fTypeFit->FindEntry("Predef-2D") )
3040  fTypeFit->InsertEntry("Predef-2D", kFP_PRED2D, kFP_PREVFIT);
3041  } else {
3042  if ( fTypeFit->FindEntry("Predef-2D") )
3043  fTypeFit->RemoveEntry(kFP_PRED2D);
3044  }
3045 
3046  return set;
3047 }
3048 
3049 ////////////////////////////////////////////////////////////////////////////////
3050 /// Show object name on the top.
3051 
3052 void TFitEditor::ShowObjectName(TObject* obj)
3053 {
3054  TString name;
3055  bool isTree = false;
3056 
3057  // Build the string to be compared to look for the object.
3058  if (obj) {
3059  name = obj->ClassName();
3060  name.Append("::");
3061  name.Append(obj->GetName());
3062  isTree = strcmp(obj->ClassName(), "TTree") == 0;
3063  } else {
3064  name = "No object selected";
3065  }
3066  fStatusBar->SetText(name.Data(),0);
3067 
3068  // If the selection was done in the fDataSet combo box, there is no need
3069  // to search through the list
3070  TGTextLBEntry* selectedEntry = static_cast<TGTextLBEntry*> ( fDataSet->GetSelectedEntry());
3071  if ( selectedEntry ) {
3072  TString selectedName = selectedEntry->GetText()->GetString();
3073  if ( isTree )
3074  selectedName = selectedName(0, selectedName.First(' '));
3075  if ( name.CompareTo(selectedName) == 0 ) {
3076  Layout();
3077  return;
3078  }
3079  }
3080 
3081  // Search through the list for the object
3082  Int_t entryId = kFP_NOSEL+1;
3083  bool found = false;
3084  while ( TGTextLBEntry* entry = static_cast<TGTextLBEntry*>
3085  ( fDataSet->GetListBox()->GetEntry(entryId)) ) {
3086  TString compareName = entry->GetText()->GetString();
3087  if ( isTree )
3088  compareName = compareName(0, compareName.First(' '));
3089  if ( name.CompareTo(compareName) == 0 ) {
3090  // If the object is found, select it
3091  fDataSet->Select(entryId, false);
3092  found = true;
3093  break;
3094  }
3095  entryId += 1;
3096  }
3097 
3098  // If the object was not found, add it and select it.
3099  if ( !found ) {
3100  fDataSet->AddEntry(name.Data(), entryId);
3101  fDataSet->Select(entryId, kTRUE);
3102  }
3103 
3104  Layout();
3105 }
3106 
3107 ////////////////////////////////////////////////////////////////////////////////
3108 /// Get draw options of the selected object.
3109 
3110 Option_t *TFitEditor::GetDrawOption() const
3111 {
3112  if (!fParentPad) return "";
3113 
3114  TListIter next(fParentPad->GetListOfPrimitives());
3115  TObject *obj;
3116  while ((obj = next())) {
3117  if (obj == fFitObject) return next.GetOption();
3118  }
3119  return "";
3120 }
3121 
3122 ////////////////////////////////////////////////////////////////////////////////
3123 /// Set selected minimization library in use.
3124 
3125 void TFitEditor::DoLibrary(Bool_t on)
3126 {
3127  TGButton *bt = (TGButton *)gTQSender;
3128  Int_t id = bt->WidgetId();
3129 
3130  switch (id) {
3131 
3132  // Depending on the selected library, set the state of the rest
3133  // of the buttons.
3134  case kFP_LMIN:
3135  {
3136  if (on) {
3137  fLibMinuit->SetState(kButtonDown);
3138  fLibMinuit2->SetState(kButtonUp);
3139  fLibFumili->SetState(kButtonUp);
3140  if ( fLibGSL->GetState() != kButtonDisabled )
3141  fLibGSL->SetState(kButtonUp);
3142  if ( fLibGenetics->GetState() != kButtonDisabled )
3143  fLibGenetics->SetState(kButtonUp);
3144  fStatusBar->SetText("LIB Minuit", 1);
3145  }
3146 
3147  }
3148  break;
3149 
3150  case kFP_LMIN2:
3151  {
3152  if (on) {
3153  fLibMinuit->SetState(kButtonUp);
3154  fLibMinuit2->SetState(kButtonDown);
3155  fLibFumili->SetState(kButtonUp);
3156  if ( fLibGSL->GetState() != kButtonDisabled )
3157  fLibGSL->SetState(kButtonUp);
3158  if ( fLibGenetics->GetState() != kButtonDisabled )
3159  fLibGenetics->SetState(kButtonUp);
3160  fStatusBar->SetText("LIB Minuit2", 1);
3161  }
3162  }
3163  break;
3164 
3165  case kFP_LFUM:
3166  {
3167  if (on) {
3168  fLibMinuit->SetState(kButtonUp);
3169  fLibMinuit2->SetState(kButtonUp);
3170  fLibFumili->SetState(kButtonDown);
3171  if ( fLibGSL->GetState() != kButtonDisabled )
3172  fLibGSL->SetState(kButtonUp);
3173  if ( fLibGenetics->GetState() != kButtonDisabled )
3174  fLibGenetics->SetState(kButtonUp);
3175  fStatusBar->SetText("LIB Fumili", 1);
3176  }
3177  }
3178  break;
3179  case kFP_LGSL:
3180  {
3181  if (on) {
3182  fLibMinuit->SetState(kButtonUp);
3183  fLibMinuit2->SetState(kButtonUp);
3184  fLibFumili->SetState(kButtonUp);
3185  if ( fLibGSL->GetState() != kButtonDisabled )
3186  fLibGSL->SetState(kButtonDown);
3187  if ( fLibGenetics->GetState() != kButtonDisabled )
3188  fLibGenetics->SetState(kButtonUp);
3189  fStatusBar->SetText("LIB GSL", 1);
3190  }
3191  }
3192  break;
3193  case kFP_LGAS:
3194  {
3195  if (on) {
3196  fLibMinuit->SetState(kButtonUp);
3197  fLibMinuit2->SetState(kButtonUp);
3198  fLibFumili->SetState(kButtonUp);
3199  if ( fLibGSL->GetState() != kButtonDisabled )
3200  fLibGSL->SetState(kButtonUp);
3201  if ( fLibGenetics->GetState() != kButtonDisabled )
3202  fLibGenetics->SetState(kButtonDown);
3203  fStatusBar->SetText("LIB Genetics", 1);
3204  }
3205  }
3206  default:
3207  break;
3208  }
3209  FillMinMethodList();
3210 }
3211 
3212 ////////////////////////////////////////////////////////////////////////////////
3213 /// Set selected minimization method in use.
3214 
3215 void TFitEditor::DoMinMethod(Int_t )
3216 {
3217  if ( fMinMethodList->GetSelected() == kFP_MIGRAD )
3218  fStatusBar->SetText("MIGRAD",2);
3219  else if ( fMinMethodList->GetSelected() == kFP_FUMILI)
3220  fStatusBar->SetText("FUMILI",2);
3221  else if ( fMinMethodList->GetSelected() == kFP_SIMPLX )
3222  fStatusBar->SetText("SIMPLEX",2);
3223  else if ( fMinMethodList->GetSelected() == kFP_SCAN )
3224  fStatusBar->SetText("SCAN",2);
3225  else if ( fMinMethodList->GetSelected() == kFP_COMBINATION )
3226  fStatusBar->SetText("Combination",2);
3227  else if ( fMinMethodList->GetSelected() == kFP_GSLFR )
3228  fStatusBar->SetText("CONJFR",2);
3229  else if ( fMinMethodList->GetSelected() == kFP_GSLPR )
3230  fStatusBar->SetText("CONJPR",2);
3231  else if ( fMinMethodList->GetSelected() == kFP_BFGS )
3232  fStatusBar->SetText("BFGS",2);
3233  else if ( fMinMethodList->GetSelected() == kFP_BFGS2 )
3234  fStatusBar->SetText("BFGS2",2);
3235  else if ( fMinMethodList->GetSelected() == kFP_GSLLM )
3236  fStatusBar->SetText("GSLLM",2);
3237  else if ( fMinMethodList->GetSelected() == kFP_GSLSA)
3238  fStatusBar->SetText("SimAn",2);
3239  else if ( fMinMethodList->GetSelected() == kFP_TMVAGA )
3240  fStatusBar->SetText("TMVAGA",2);
3241  else if ( fMinMethodList->GetSelected() == kFP_GALIB )
3242  fStatusBar->SetText("GALIB",2);
3243 
3244 
3245 }
3246 
3247 ////////////////////////////////////////////////////////////////////////////////
3248 /// Set the maximum number of iterations.
3249 
3250 void TFitEditor::DoMaxIterations()
3251 {
3252  Long_t itr = fIterations->GetIntNumber();
3253  fStatusBar->SetText(Form("Itr: %ld",itr),2);
3254 }
3255 
3256 ////////////////////////////////////////////////////////////////////////////////
3257 /// Create section title in the GUI.
3258 
3259 void TFitEditor::MakeTitle(TGCompositeFrame *parent, const char *title)
3260 {
3261  TGCompositeFrame *ht = new TGCompositeFrame(parent, 350, 10,
3262  kFixedWidth | kHorizontalFrame);
3263  ht->AddFrame(new TGLabel(ht, title),
3264  new TGLayoutHints(kLHintsLeft, 1, 1, 0, 0));
3265  ht->AddFrame(new TGHorizontal3DLine(ht),
3266  new TGLayoutHints(kLHintsExpandX | kLHintsCenterY, 5, 5, 2, 2));
3267  parent->AddFrame(ht, new TGLayoutHints(kLHintsTop, 5, 0, 5, 0));
3268 }
3269 
3270 ////////////////////////////////////////////////////////////////////////////////
3271 /// Look in the list of function for TF1. If a TF1 is
3272 /// found in the list of functions, it will be returned
3273 
3274 TF1* TFitEditor::HasFitFunction()
3275 {
3276  // Get the list of functions of the fit object
3277  TList *lf = GetFitObjectListOfFunctions();
3278  TF1* func = 0;
3279 
3280  // If it exists
3281  if ( lf ) {
3282  // Add the posibility to select previous fit function
3283  if ( !fTypeFit->FindEntry("Prev. Fit") )
3284  fTypeFit->InsertEntry("Prev. Fit",kFP_PREVFIT, kFP_UFUNC);
3285 
3286  // Then add all these functions to the fPrefFit structure.
3287  TObject *obj2;
3288  TIter next(lf, kIterForward);
3289  // Go over all the elements in lf
3290  while ((obj2 = next())) {
3291  if (obj2->InheritsFrom(TF1::Class())) {
3292  func = (TF1 *)obj2;
3293  fPrevFitIter it;
3294  // No go over all elements in fPrevFit
3295  for ( it = fPrevFit.begin(); it != fPrevFit.end(); ++it) {
3296  // To see wheather the object corresponds with fFitObject
3297  if ( it->first != fFitObject ) continue;
3298  // And if so, whether the function is already included
3299  if ( strcmp( func->GetName(), it->second->GetName() ) == 0 )
3300  break;
3301  if ( strcmp( func->GetName(), "PrevFitTMP" ) == 0 )
3302  break;
3303  }
3304  // Only if the function is not already in fPrevFit, the
3305  // breaks in the loops would make it to be different to
3306  // fPrevFit.end() if the function is already stored
3307  if ( it == fPrevFit.end() ) {
3308  fPrevFit.emplace(fFitObject, copyTF1(func));
3309  }
3310  }
3311  }
3312 
3313  // Select the PrevFit set
3314  fTypeFit->Select(kFP_PREVFIT);
3315  // And fill the function list
3316  FillFunctionList();
3317  fDrawAdvanced->SetState(kButtonUp);
3318 
3319 
3320  } else {
3321  // If there is no prev fit functions.
3322  fTypeFit->Select(kFP_UFUNC);
3323  // Call FillFunctionList as it might happen that the user is
3324  // changing from a TTree to another one, and thus the fFuncList
3325  // if not properly filled
3326  FillFunctionList();
3327  }
3328 
3329  fDrawAdvanced->SetState(kButtonDisabled);
3330 
3331  return func;
3332 }
3333 
3334 ////////////////////////////////////////////////////////////////////////////////
3335 /// Retrieve the fitting options from all the widgets.
3336 
3337 void TFitEditor::RetrieveOptions(Foption_t& fitOpts, TString& drawOpts, ROOT::Math::MinimizerOptions& minOpts, Int_t /*npar */)
3338 {
3339  drawOpts = "";
3340 
3341  fitOpts.Range = (fUseRange->GetState() == kButtonDown);
3342  fitOpts.Integral = (fIntegral->GetState() == kButtonDown);
3343  fitOpts.More = (fImproveResults->GetState() == kButtonDown);
3344  fitOpts.Errors = (fBestErrors->GetState() == kButtonDown);
3345  fitOpts.Like = (fMethodList->GetSelected() != kFP_MCHIS);
3346 
3347  if (fEmptyBinsWghts1->GetState() == kButtonDown)
3348  fitOpts.W1 = 2;
3349  else if (fAllWeights1->GetState() == kButtonDown)
3350  fitOpts.W1 = 1;
3351 
3352  TString tmpStr = fEnteredFunc->GetText();
3353  if ( !(fLinearFit->GetState() == kButtonDown) &&
3354  (tmpStr.Contains("pol") || tmpStr.Contains("++")) )
3355  fitOpts.Minuit = 1;
3356 
3357  // if ( (int) fFuncPars.size() == npar )
3358  // for ( Int_t i = 0; i < npar; ++i )
3359  // if ( fFuncPars[i][PAR_MIN] != fFuncPars[i][PAR_MAX] )
3360  //
3361 
3362  // //fitOpts.Bound = 1;
3363  // break;
3364  // }
3365 
3366  if (fChangedParams) {
3367  //std::cout << "Params have changed setting the Bound option " << std::endl;
3368  fitOpts.Bound = 1;
3369  fChangedParams = kFALSE; // reset
3370  }
3371 
3372  //fitOpts.Nochisq = (fNoChi2->GetState() == kButtonDown);
3373  fitOpts.Nostore = (fNoStoreDrawing->GetState() == kButtonDown);
3374  fitOpts.Nograph = (fNoDrawing->GetState() == kButtonDown);
3375  fitOpts.Plus = (fAdd2FuncList->GetState() == kButtonDown);
3376  fitOpts.Gradient = (fUseGradient->GetState() == kButtonDown);
3377  fitOpts.Quiet = ( fOptQuiet->GetState() == kButtonDown );
3378  fitOpts.Verbose = ( fOptVerbose->GetState() == kButtonDown );
3379 
3380  if ( !(fType != kObjectGraph) && (fEnableRobust->GetState() == kButtonDown) )
3381  {
3382  fitOpts.Robust = 1;
3383  fitOpts.hRobust = fRobustValue->GetNumber();
3384  }
3385 
3386  drawOpts = GetDrawOption();
3387 
3388  if ( fLibMinuit->GetState() == kButtonDown )
3389  minOpts.SetMinimizerType ( "Minuit");
3390  else if ( fLibMinuit2->GetState() == kButtonDown)
3391  minOpts.SetMinimizerType ( "Minuit2" );
3392  else if ( fLibFumili->GetState() == kButtonDown )
3393  minOpts.SetMinimizerType ("Fumili" );
3394  else if ( fLibGSL->GetState() == kButtonDown )
3395  minOpts.SetMinimizerType ("GSLMultiMin" );
3396 
3397  if ( fMinMethodList->GetSelected() == kFP_MIGRAD )
3398  minOpts.SetMinimizerAlgorithm( "Migrad" );
3399  else if ( fMinMethodList->GetSelected() == kFP_FUMILI)
3400  if ( fLibMinuit2->GetState() == kButtonDown )
3401  minOpts.SetMinimizerAlgorithm( "Fumili2" );
3402  else
3403  minOpts.SetMinimizerAlgorithm( "Fumili" );
3404  else if ( fMinMethodList->GetSelected() == kFP_SIMPLX )
3405  minOpts.SetMinimizerAlgorithm( "Simplex" );
3406  else if ( fMinMethodList->GetSelected() == kFP_SCAN )
3407  minOpts.SetMinimizerAlgorithm( "Scan" );
3408  else if ( fMinMethodList->GetSelected() == kFP_COMBINATION )
3409  minOpts.SetMinimizerAlgorithm( "Minimize" );
3410  else if ( fMinMethodList->GetSelected() == kFP_GSLFR )
3411  minOpts.SetMinimizerAlgorithm( "conjugatefr" );
3412  else if ( fMinMethodList->GetSelected() == kFP_GSLPR )
3413  minOpts.SetMinimizerAlgorithm( "conjugatepr" );
3414  else if ( fMinMethodList->GetSelected() == kFP_BFGS )
3415  minOpts.SetMinimizerAlgorithm( "bfgs" );
3416  else if ( fMinMethodList->GetSelected() == kFP_BFGS2 )
3417  minOpts.SetMinimizerAlgorithm( "bfgs2" );
3418  else if ( fMinMethodList->GetSelected() == kFP_GSLLM ) {
3419  minOpts.SetMinimizerType ("GSLMultiFit" );
3420  minOpts.SetMinimizerAlgorithm( "" );
3421  } else if ( fMinMethodList->GetSelected() == kFP_GSLSA) {
3422  minOpts.SetMinimizerType ("GSLSimAn" );
3423  minOpts.SetMinimizerAlgorithm( "" );
3424  } else if ( fMinMethodList->GetSelected() == kFP_TMVAGA) {
3425  minOpts.SetMinimizerType ("Geneti2c" );
3426  minOpts.SetMinimizerAlgorithm( "" );
3427  } else if ( fMinMethodList->GetSelected() == kFP_GALIB) {
3428  minOpts.SetMinimizerType ("GAlibMin" );
3429  minOpts.SetMinimizerAlgorithm( "" );
3430  }
3431 
3432  minOpts.SetErrorDef ( fErrorScale->GetNumber() );
3433  minOpts.SetTolerance( fTolerance->GetNumber() );
3434  minOpts.SetMaxIterations(fIterations->GetIntNumber());
3435  minOpts.SetMaxFunctionCalls(fIterations->GetIntNumber());
3436 }
3437 
3438 void TFitEditor::SetEditable(Bool_t state)
3439 {
3440  // Set the state of some input widgets depending on whether the fit
3441  // function can be defined by text or if it is an existing one.
3442  if ( state )
3443  {
3444  fEnteredFunc-> SetState(kTRUE);
3445  fAdd -> SetState(kButtonUp, kFALSE);
3446  fNormAdd -> SetState(kButtonUp, kFALSE);
3447  fConv -> SetState(kButtonUp, kFALSE);
3448  fNone -> SetState(kButtonDown,kFALSE); // fNone::State is the one used as reference
3449  }
3450  else
3451  {
3452  fEnteredFunc-> SetState(kFALSE);
3453  fAdd -> SetState(kButtonDisabled, kFALSE);
3454  fNormAdd -> SetState(kButtonDisabled, kFALSE);
3455  fConv -> SetState(kButtonDisabled, kFALSE);
3456  fNone -> SetState(kButtonDisabled, kFALSE);
3457  }
3458 }
3459 
3460 void TFitEditor::GetRanges(ROOT::Fit::DataRange& drange)
3461 {
3462  // Return the ranges selected by the sliders.
3463 
3464  // It's not working for trees as they don't have TAxis.
3465  if ( fType == kObjectTree ) return;
3466 
3467  if ( fType != kObjectTree ) {
3468  Int_t ixmin = (Int_t)(fSliderX->GetMinPosition());
3469  Int_t ixmax = (Int_t)(fSliderX->GetMaxPosition());
3470  Double_t xmin = fXaxis->GetBinLowEdge(ixmin);
3471  Double_t xmax = fXaxis->GetBinUpEdge(ixmax);
3472  drange.AddRange(0,xmin, xmax);
3473  }
3474 
3475  if ( fDim > 1 ) {
3476  assert(fYaxis);
3477  Int_t iymin = (Int_t)(fSliderY->GetMinPosition());
3478  Int_t iymax = (Int_t)(fSliderY->GetMaxPosition());
3479  Double_t ymin = fYaxis->GetBinLowEdge(iymin);
3480  Double_t ymax = fYaxis->GetBinUpEdge(iymax);
3481  drange.AddRange(1,ymin, ymax);
3482  }
3483  if ( fDim > 2 ) {
3484  assert(fZaxis);
3485  Int_t izmin = (Int_t)(fSliderZ->GetMinPosition());
3486  Int_t izmax = (Int_t)(fSliderZ->GetMaxPosition());
3487  Double_t zmin = fZaxis->GetBinLowEdge(izmin);
3488  Double_t zmax = fZaxis->GetBinUpEdge(izmax);
3489  drange.AddRange(2,zmin, zmax);
3490  }
3491 }
3492 
3493 TList* TFitEditor::GetFitObjectListOfFunctions()
3494 {
3495  // Get the list of functions previously used in the fitobject.
3496 
3497  TList *listOfFunctions = 0;
3498  if ( fFitObject ) {
3499  switch (fType) {
3500 
3501  case kObjectHisto:
3502  listOfFunctions = ((TH1 *)fFitObject)->GetListOfFunctions();
3503  break;
3504 
3505  case kObjectGraph:
3506  listOfFunctions = ((TGraph *)fFitObject)->GetListOfFunctions();
3507  break;
3508 
3509  case kObjectMultiGraph:
3510  listOfFunctions = ((TMultiGraph *)fFitObject)->GetListOfFunctions();
3511  break;
3512 
3513  case kObjectGraph2D:
3514  listOfFunctions = ((TGraph2D *)fFitObject)->GetListOfFunctions();
3515  break;
3516 
3517  case kObjectHStack:
3518  case kObjectTree:
3519  default:
3520  break;
3521  }
3522  }
3523  return listOfFunctions;
3524 }
3525 
3526 void TFitEditor::GetFunctionsFromSystem()
3527 {
3528  // Looks for all the functions registered in the current ROOT
3529  // session.
3530 
3531  // First, clean the copies stored in fSystemFunc
3532  for (auto func : fSystemFuncs)
3533  delete func;
3534 
3535  fSystemFuncs.clear();
3536 
3537  // Be carefull not to store functions that will be in the
3538  // predefined section
3539  const unsigned int nfuncs = 16;
3540  const char* fnames[nfuncs] = { "gaus" , "gausn", "expo", "landau",
3541  "landaun", "pol0", "pol1", "pol2",
3542  "pol3", "pol4", "pol5", "pol6",
3543  "pol7", "pol8", "pol9", "user"
3544  };
3545 
3546  // No go through all the objects registered in gROOT
3547  TIter functionsIter(gROOT->GetListOfFunctions());
3548  TObject* obj;
3549  while( ( obj = (TObject*) functionsIter() ) ) {
3550  // And if they are TF1s
3551  if ( TF1* func = dynamic_cast<TF1*>(obj) ) {
3552  bool addFunction = true;
3553  // And they are not already registered in fSystemFunc
3554  for ( unsigned int i = 0; i < nfuncs; ++i ) {
3555  if ( strcmp( func->GetName(), fnames[i] ) == 0 ) {
3556  addFunction = false;
3557  break;
3558  }
3559  }
3560  // Add them.
3561  if ( addFunction )
3562  fSystemFuncs.emplace_back( copyTF1(func) );
3563  }
3564  }
3565 }
3566 
3567 TList* TFitEditor::GetListOfFittingFunctions(TObject* obj)
3568 {
3569  // This function returns a TList with all the functions used in the
3570  // FitPanel to fit a given object. If the object passed is NULL,
3571  // then the object used is the currently selected one. It is
3572  // important to notice that the FitPanel is still the owner of
3573  // those functions. This means that the user SHOULD NOT delete any
3574  // of these functions, as the FitPanel will do so in the
3575  // destructor.
3576 
3577  if (!obj) obj = fFitObject;
3578 
3579  TList *retList = new TList();
3580 
3581  std::pair<fPrevFitIter, fPrevFitIter> look = fPrevFit.equal_range(obj);
3582  for ( fPrevFitIter it = look.first; it != look.second; ++it ) {
3583  retList->Add(it->second);
3584  }
3585 
3586  return retList;
3587 }
3588 
3589 TF1* TFitEditor::GetFitFunction()
3590 {
3591  // Get the fit function selected or declared in the fiteditor
3592 
3593  TF1 *fitFunc = 0;
3594  // If the function is not editable ==> it means it is registered in
3595  // gROOT
3596  if ( fNone->GetState() == kButtonDisabled )
3597  {
3598  // So we find it
3599  TF1* tmpF1 = FindFunction();
3600  // And if we don't find it, then it means there is something wrong!
3601  if ( tmpF1 == 0 )
3602  {
3603  new TGMsgBox(fClient->GetRoot(), GetMainFrame(),
3604  "Error...", "1) Verify the entered function string!",
3605  kMBIconStop,kMBOk, 0);
3606  return 0;
3607  }
3608 
3609  // Now we make a copy that will be used temporary. The caller of
3610  // the function should delete the returned function.
3611  fitFunc = (TF1*)tmpF1->IsA()->New();
3612  tmpF1->Copy(*fitFunc);
3613  // Copy the parameters of the function, if and only if the
3614  // parameters stored does not correspond with the ones of these
3615  // functions. Perhaps the user has already called
3616  // DoSetParameters. There is no way to know whether the
3617  // parameters have been modified, so we check the size of
3618  // fFuncPars against number of parameters.
3619  if ( int(fFuncPars.size()) != tmpF1->GetNpar() )
3620  {
3621  fitFunc->SetParameters(tmpF1->GetParameters());
3622  GetParameters(fFuncPars, fitFunc);
3623  } else {
3624  SetParameters(fFuncPars, fitFunc);
3625  }
3626  }
3627 
3628  // If, we have no function at this point, it means that is is
3629  // described in fEnteredFunc, so we create it from scratch.
3630  if ( fitFunc == 0 )
3631  {
3632  ROOT::Fit::DataRange drange;
3633  GetRanges(drange);
3634  double xmin, xmax, ymin, ymax, zmin, zmax;
3635  drange.GetRange(xmin, xmax, ymin, ymax, zmin, zmax);
3636 
3637  // Depending of course on the number of dimensions the object
3638  // has. These commands will raise an error message if the user
3639  // has not defined the function properly
3640  if ( fDim == 1 || fDim == 0 )
3641  {
3642 
3643  fitFunc = new TF1("PrevFitTMP",fEnteredFunc->GetText(), xmin, xmax );
3644  //std::cout << "GetFitFunction - created function PrevFitTMP " << fEnteredFunc->GetText() << " " << fitFunc << std::endl;
3645  if (fNormAdd->IsOn())
3646  {
3647  if (fSumFunc) delete fSumFunc;
3648  fSumFunc = new TF1NormSum(fEnteredFunc->GetText(), xmin, xmax);
3649  fitFunc = new TF1("PrevFitTMP", *fSumFunc, xmin, xmax, fSumFunc->GetNpar());
3650  for (int i = 0; i < fitFunc->GetNpar(); ++i) fitFunc->SetParName(i, fSumFunc->GetParName(i) );
3651  //std::cout << "create fit normalized function " << fSumFunc << " fitfunc " << fitFunc << std::endl;
3652  }
3653 
3654  if (fConv -> IsOn())
3655  {
3656  if (fConvFunc) delete fConvFunc;
3657  fConvFunc = new TF1Convolution(fEnteredFunc->GetText());
3658  fitFunc = new TF1("PrevFitTMP", *fConvFunc, xmin, xmax, fConvFunc->GetNpar());
3659  for (int i = 0; i < fitFunc->GetNpar(); ++i) fitFunc->SetParName(i, fConvFunc->GetParName(i) );
3660  //std::cout << "create fit convolution function " << fSumFunc << " fitfunc " << fitFunc << std::endl;
3661  }
3662  }
3663  else if ( fDim == 2 ) {
3664  fitFunc = new TF2("PrevFitTMP",fEnteredFunc->GetText(), xmin, xmax, ymin, ymax );
3665  }
3666  else if ( fDim == 3 ) {
3667  fitFunc = new TF3("PrevFitTMP",fEnteredFunc->GetText(), xmin, xmax, ymin, ymax, zmin, zmax );
3668  }
3669 
3670  // if the function is not a C defined
3671  if ( fNone->GetState() != kButtonDisabled )
3672  {
3673  // and the formulas are the same
3674  TF1* tmpF1 = FindFunction();
3675 // if (tmpF1)
3676  //std::cout << "GetFitFunction: found existing function " << tmpF1 << " " << tmpF1->GetName() << " " << tmpF1->GetExpFormula() << std::endl;
3677 // else
3678  //std::cout << "GetFitFunction: - no existing function found " << std::endl;
3679  if ( tmpF1 != 0 && fitFunc != 0 &&
3680  strcmp(tmpF1->GetExpFormula(), fEnteredFunc->GetText()) == 0 ) {
3681  // copy everything from the founction available in gROOT
3682  //std::cout << "GetFitFunction: copying tmp function in PrevFitTMP " << tmpF1->GetName() << " "
3683  // << tmpF1->GetExpFormula() << std::endl;
3684  tmpF1->Copy(*fitFunc);
3685  if ( int(fFuncPars.size()) != tmpF1->GetNpar() )
3686  {
3687  GetParameters(fFuncPars, fitFunc);
3688  }
3689  }
3690  }
3691  }
3692 
3693  return fitFunc;
3694 }