KaliVeda
Toolkit for HIC analysis
KVItvFinderDialog.cpp
1 //Created by KVClassFactory on Mon Jan 23 10:03:13 2017
2 //Author: Diego Gruyer
3 
4 #include "KVItvFinderDialog.h"
5 #include "TRandom.h"
6 #include "TRootEmbeddedCanvas.h"
7 #include "TStyle.h"
8 #include "TSystem.h"
9 #include "TROOT.h"
10 #include "TGMsgBox.h"
11 #include "TGFileDialog.h"
12 #include "KVTestIDGridDialog.h"
13 #include "KVIdentificationResult.h"
14 #include "KVNameValueListGUI.h"
15 #include <KVMultiGaussIsotopeFit.h>
16 #include "KeySymbols.h"
17 #include <thread>
18 #include "KVIDGridEditor.h"
19 #include "KVInputDialog.h"
21 //ClassImp(interval_painter)
22 
23 // Set default values for mass-fit parameters
24 
25 
28  {"Limit range of fit", false},
29  {"PID min for fit", 0.},
30  {"PID max for fit", 10.},
31  {"Minimum probability [%]", 50.},
32  {"Minimum #sigma", 1.e-2},
33  {"Maximum #sigma", 5.e-2},
34  {"+ve bkg. slope", false}
35 };
36 
37 
38 
42 
44 {
45  // remove painter from list and modify the 'left_painter' and 'right_painter' references
46  // in any adjacent painters/intervals, then delete painter
47 
48  std::unique_ptr<KVPIDIntervalPainter> _p(p);
49  auto pleft = p->get_left_interval();
50  auto pright = p->get_right_interval();
51  if (pleft) pleft->set_right_interval(pright);
52  if (pright) pright->set_left_interval(pleft);
54 }
55 
56 
57 
59 
61 {
62  fGrid = gg;
63  fHisto = hh;
64 
65  fPoints = new TGraph;
67  fNPoints = 0;
68 
69  gStyle->SetOptStat(0);
70  gStyle->SetOptTitle(0);
71 
72  gROOT->ProcessLine(Form("KVItvFinderDialog* _dummy_itv=(KVItvFinderDialog*)%p", this));
73 
74  fMain = new TGTransientFrame(gClient->GetDefaultRoot(), gClient->GetDefaultRoot(), 10, 10);
75  // Here is the recipe for cleanly closing a window
76  // (see https://root-forum.cern.ch/t/error-in-rootx11errorhandler-baddrawable-quot/8095/6)
77  fMain->Connect("CloseWindow()", "KVItvFinderDialog", this, "DoClose()");
80  // afterwards, in the destructor do fMain->CloseWindow(), and in DoClose(), do 'delete this'
81 
82  // Default constructor
83  TGHorizontalFrame* fCanvasFrame = new TGHorizontalFrame(fMain, 627, 7000, kHorizontalFrame);
84  // fCanvasFrame->SetBackgroundColor(fColor);
85 
86 
87  TRootEmbeddedCanvas* fRootEmbeddedCanvas615 = new TRootEmbeddedCanvas(0, fCanvasFrame, 800, 440);
88  // to replace the TCanvas in a TRootEmbeddedCanvas, just delete the original like so:
89  // (see https://root-forum.cern.ch/t/error-in-rootx11errorhandler-baddrawable-quot/8095/6)
90  auto WID = fRootEmbeddedCanvas615->GetCanvasWindowId();
91  delete fRootEmbeddedCanvas615->GetCanvas();
92  fCanvas = new TCanvas("c123", 10, 10, WID);
93  fCanvas->AddExec("toto", "if(_dummy_itv)_dummy_itv->HandleKey();");
94  fRootEmbeddedCanvas615->AdoptCanvas(fCanvas);
95  fPad = fCanvas->cd();
96  fCanvas->SetRightMargin(0.02);
97  fCanvas->SetTopMargin(0.02);
98  fCanvas->SetLeftMargin(0.08);
99  fCanvas->SetBottomMargin(0.07);
100 
101  fCanvasFrame->AddFrame(fRootEmbeddedCanvas615, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 2, 2, 2, 2));
102  fMain->AddFrame(fCanvasFrame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 0, 0, 0, 0));
103 
104  TGVerticalFrame* fControlOscillo = new TGVerticalFrame(fCanvasFrame, 2000, 7000, kVerticalFrame);
105 
106  {
107  const char* xpms[] = {
108  "filesaveas.xpm",
109  "profile_t.xpm",
110  "bld_copy.png",
111  "ed_new.png",
112  "refresh2.xpm",
113  "sm_delete.xpm",
114  "h1_t.xpm",
115  "query_new.xpm",
116  "tb_back.xpm",
117  "bld_colorselect.png",
118  "latex.xpm",
119  "move_cursor.png",
120  0
121  };
122  // toolbar tool tip text
123  const char* tips[] = {
124  "Save intervals in current grid",
125  "Find intervals",
126  "Create a new interval set",
127  "Create a new interval",
128  "Update interval lists",
129  "Remove selected intervals",
130  "Multigauss fit to isotopes in interval set",
131  "Set parameters for fit",
132  "Remove fit from selected interval set",
133  "Test identification",
134  "Set log scale on y axis",
135  "Unzoom the histogram",
136  0
137  };
138  int spacing[] = {
139  5,
140  20,
141  0,
142  0,
143  0,
144  20,
145  50,
146  0,
147  0,
148  50,
149  80,
150  0,
151  0
152  };
153  const char* method[] = {
154  "SaveGrid()",
155  "Identify()",
156  "NewIntervalSet()",
157  "NewInterval()",
158  "UpdateLists()",
159  "RemoveInterval()",
160  "FitIsotopes()",
161  "SetFitParameters()",
162  "RemoveFit()",
163  "TestIdent()",
164  "SetLogy()",
165  "UnzoomHisto()",
166  0
167  };
168  fNbButtons = 0;
169  ToolBarData_t t[50];
170  fToolBar = new TGToolBar(fControlOscillo, 450, 80);
171  int i = 0;
172  while (xpms[i]) {
173  t[i].fPixmap = xpms[i];
174  t[i].fTipText = tips[i];
175  t[i].fStayDown = kFALSE;
176  t[i].fId = i + 1;
177  t[i].fButton = NULL;
178  TGButton* bb = fToolBar->AddButton(fControlOscillo, &t[i], spacing[i]);
179  bb->Connect("Clicked()", "KVItvFinderDialog", this, method[i]);
180  fNbButtons++;
181  i++;
182  }
183  fControlOscillo->AddFrame(fToolBar, new TGLayoutHints(kLHintsTop | kLHintsExpandX));
184  }
185 
186  fIntervalSetListView = new KVListView(interval_set::Class(), fControlOscillo, 450, 200);
188  fIntervalSetListView->SetDataColumn(0, "Z", "GetZ", kTextLeft);
189  fIntervalSetListView->SetDataColumn(1, "PIDs", "GetNPID", kTextCenterX);
190  fIntervalSetListView->SetDataColumn(2, "Masses", "GetListOfMasses", kTextLeft);
191  fIntervalSetListView->Connect("SelectionChanged()", "KVItvFinderDialog", this, "DisplayPIDint()");
192  fIntervalSetListView->SetDoubleClickAction("KVItvFinderDialog", this, "ZoomOnCanvas()");
194  fControlOscillo->AddFrame(fIntervalSetListView, new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY, 2, 2, 2, 2));
195 
196  fIntervalListView = new KVListView(interval::Class(), fControlOscillo, 450, 180);
198  fIntervalListView->SetDataColumn(0, "Z", "GetZ", kTextLeft);
199  fIntervalListView->SetDataColumn(1, "A", "GetA", kTextCenterX);
200  fIntervalListView->SetDataColumn(2, "min", "GetPIDmin", kTextCenterX);
201  fIntervalListView->SetDataColumn(3, "pid", "GetPID", kTextCenterX);
202  fIntervalListView->SetDataColumn(4, "max", "GetPIDmax", kTextCenterX);
203 
204 
205 
206  {
207  const char* xpms[] = {
208  "arrow_down.xpm",
209  "arrow_up.xpm",
210  0
211  };
212  const char* tips[] = {
213  "Decrease A by one",
214  "Increase A by one",
215  0
216  };
217  int spacing[] = {
218  120,
219  0,
220  0
221  };
222  const char* method[] = {
223  "MassesDown()",
224  "MassesUp()",
225  0
226  };
227  fNbButtons = 0;
228  ToolBarData_t t[50];
229  fToolBar2 = new TGToolBar(fControlOscillo, 450, 80);
230  int i = 0;
231  while (xpms[i]) {
232  t[i].fPixmap = xpms[i];
233  t[i].fTipText = tips[i];
234  t[i].fStayDown = kFALSE;
235  t[i].fId = i + 1;
236  t[i].fButton = NULL;
237  TGButton* bb = fToolBar2->AddButton(fControlOscillo, &t[i], spacing[i]);
238  bb->Connect("Clicked()", "KVItvFinderDialog", this, method[i]);
239  fNbButtons++;
240  i++;
241  }
242  fControlOscillo->AddFrame(fToolBar2, new TGLayoutHints(kLHintsTop | kLHintsExpandX));
243  }
244 
245  // fCurrentView->ActivateSortButtons();
246  fIntervalListView->Connect("SelectionChanged()", "KVItvFinderDialog", this, "SelectionITVChanged()");
247  // fCurrentView->SetDoubleClickAction("FZCustomFrameManager",this,"ChangeParValue()");
249 
250  fControlOscillo->AddFrame(fIntervalListView, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 2, 2, 2, 2));
251 
252  fCanvasFrame->AddFrame(fControlOscillo, new TGLayoutHints(kLHintsExpandY, 0, 0, 0, 0));
253 
254 
255  //layout and display window
256  fMain->MapSubwindows();
258 
259  // position relative to the parent's window
261 
262  fMain->SetWindowName("Masses Identification");
263  fMain->RequestFocus();
264  fMain->MapWindow();
265 
266  fIntervalSetListView->Display(((KVIDZAFromZGrid*)fGrid)->GetIntervalSets());
267  current_interval_set = nullptr;
268  fPad->cd();
269 
270  LinearizeHisto(100);
273  fLinearHisto->Draw("hist");
274 
275  int tmp[30] = {3, 3, 3, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
276  for (int ii = 0; ii < 30; ii++) fNpeaks[ii] = tmp[ii];
277 
278  fSig = 0.1;
279  fRat = 0.0001;
280 
281  DrawIntervals();
282  PrintHelp();
283 
284 }
285 
286 
287 
288 
290 
292 {
294  Int_t nSelected = list.GetSize();
295  if (nSelected == 1) {
296  current_interval_set = (interval_set*)list.At(0);
298  }
299  else {
300  current_interval_set = nullptr;
302  }
304 }
305 
306 
307 
309 
311 {
312  fPad->cd();
313  fItvPaint.Execute("HighLight", "0");
314 
316  int zz = ((interval*)fIntervalListView->GetLastSelectedObject())->GetZ();
317  int aa = ((interval*)fIntervalListView->GetLastSelectedObject())->GetA();
318  KVPIDIntervalPainter* painter = (KVPIDIntervalPainter*)fItvPaint.FindObject(Form("%d_%d", zz, aa));
319  if (!painter) Info("SelectionITVChanged", "%d %d not found...", zz, aa);
320  painter->HighLight();
321  }
322  fCanvas->Modified();
323  fCanvas->Update();
324 }
325 
326 
327 
329 
331 {
333  Int_t nSelected = list.GetEntries();
334  if (nSelected == 1) {
335  current_interval_set = (interval_set*)list.At(0);
337  }
338  else {
339  current_interval_set = nullptr;
341  }
342 }
343 
344 
345 
348 
350 {
351  // Display the interval set for a given Z when the user double clicks on it
352 
354  current_interval_set = nullptr;
355  return;
356  }
358  auto zz = current_interval_set->GetZ();
359 
360  fLinearHisto->GetXaxis()->SetRangeUser(zz - 0.5, zz + 0.5);
361 
362  fItvPaint.Execute("SetDisplayLabel", "0");
363 
364  std::unique_ptr<KVSeqCollection> tmp(fItvPaint.GetSubListWithMethod(Form("%d", zz), "GetZ"));
365 
366  tmp->Execute("SetDisplayLabel", "1");
367 
368  // Check - if no mass fit is displayed, we look to see if the grid has a saved
369  // multigauss fit from a previous session, and if so we display it
370  if (!fPad->GetPrimitive(KVMultiGaussIsotopeFit::get_name_of_multifit(zz))) {
371  if (fGrid->GetParameters()->HasParameter(Form("MASSFIT_%d", zz))) {
372  KVString massfit = fGrid->GetParameters()->GetTStringValue(Form("MASSFIT_%d", zz));
373  massfit.ReplaceAll(":", "=");
374  KVNameValueList fitparams;
375  fitparams.Set(massfit);
376  KVMultiGaussIsotopeFit fitfunc(zz, fitparams);
377  fitfunc.DrawFitWithGaussians("same");
378  // deactivate intervals in painter
379  tmp->Execute("DeactivateIntervals", "");
380  }
381  }
382 
383  fCanvas->Modified();
384  fCanvas->Update();
385 }
386 
387 
388 
390 
392 {
393  interval_set* itvs = 0;
394  last_drawn_interval = nullptr;
395  TIter it(fGrid->GetIntervalSets());
396  while ((itvs = (interval_set*)it())) {
397  DrawInterval(itvs);
398  }
399 }
400 
401 
402 
404 
406 {
407  fPad->cd();
408  interval* itv = nullptr;
409  // give a different colour to each interval
410  auto nitv = itvs->GetIntervals()->GetEntries();
411  auto cstep = TColor::GetPalette().GetSize() / (nitv + 1);
412  int i = 1;
413  auto deactivate_intervals = fGrid->GetParameters()->HasParameter(Form("MASSFIT_%d", itvs->GetZ()));
414 
415  TIter itt(itvs->GetIntervals());
416  while ((itv = (interval*)itt())) {
418  ++i;
419  if (label) dummy->SetDisplayLabel();
420  if (deactivate_intervals) dummy->DeactivateIntervals();
421  dummy->Draw();
422  dummy->SetCanvas(fCanvas);
423  dummy->Connect("IntMod()", "KVItvFinderDialog", this, "UpdatePIDList()");
424  fItvPaint.Add(dummy);
425  last_drawn_interval = dummy;
426  }
427 }
428 
429 
430 
435 
437 {
438  // empty an interval set, effectively removing it from the interval sets which will be saved with the grid.
439  //
440  // we also remove any previous fits from the grid's parameters
441 
442  std::vector<int> alist;
443  for (int ii = 0; ii < itvs->GetNPID(); ii++) {
444  interval* itv = (interval*)itvs->GetIntervals()->At(ii);
445  KVPIDIntervalPainter* pid = (KVPIDIntervalPainter*)fItvPaint.FindObject(Form("%d_%d", itv->GetZ(), itv->GetA()));
447  alist.push_back(itv->GetA());
448  }
449  itvs->GetIntervals()->Clear();
451  fGrid->RemoveIntervalSet(itvs);
452  UpdateLists();
453  // remove any fit displayed in pad
454  KVMultiGaussIsotopeFit fitfunc(itvs->GetZ(), alist);
455  fitfunc.UnDraw(fPad);
456  // mop up any stray gaussians (from intervals which have been removed)
457  KVMultiGaussIsotopeFit::UnDrawAnyGaussian(itvs->GetZ(), fPad);
458 
459  // remove from grid parameters
460  if (fGrid->GetParameters()->HasParameter(Form("MASSFIT_%d", itvs->GetZ()))) {
461  fGrid->GetParameters()->RemoveParameter(Form("MASSFIT_%d", itvs->GetZ()));
462  KVNumberList zlist(fGrid->GetParameters()->GetStringValue("MASSFITS"));
463  zlist.Remove(itvs->GetZ());
464  fGrid->GetParameters()->SetValue("MASSFITS", zlist.AsString());
465  }
466  fCanvas->Modified();
467  fCanvas->Update();
468 }
469 
470 
471 
473 
475 {
476  Double_t zmin = ((KVIDentifier*)fGrid->GetIdentifiers()->First())->GetPID() - 1.0;
477  Double_t zmax = 0;
478 
479  for (int iz = 1; iz < fGrid->GetIdentifiers()->GetSize() + 1; iz++) {
481  if (tmp && tmp->GetPID() > zmax) zmax = tmp->GetPID();
482  }
483 
484  Int_t zbins = (Int_t)(zmax - zmin) * nbins;
485 
486  fLinearHisto = new TH1F("fLinearHisto", "fLinearHisto", zbins, zmin, zmax);
487 
488  fGrid->SetOnlyZId();
489 
490  // use multi-threading capacities
491  auto available_cpu = WITH_MULTICORE_CPU;
492  Int_t xbins_per_cpu = fHisto->GetNbinsX() / available_cpu;
493 
494  std::vector<std::thread> jobs; // threads to do the work
495 
496  // to clean up copies of grid
497  KVList grid_copies;
498 
499  // do not add copies of grid to ID grid manager
500  auto save_auto_add = KVIDGraph::GetAutoAdd();
501  KVIDGraph::SetAutoAdd(false);
502 
503  std::cout << "Will run " << available_cpu << " threads, each for " << xbins_per_cpu << " bins in X" << std::endl;
504 
505  int nthreads = available_cpu;
506  // join threads
507  std::cout << "Histo linearization using " << nthreads << " threads..." << std::endl;
508 
509  for (int job = 0; job < available_cpu; ++job) {
510  auto imin = 1 + job * xbins_per_cpu;
511  auto imax = (job + 1) * xbins_per_cpu;
512  if (job == available_cpu - 1) imax = fHisto->GetNbinsX();
513 
514  // make new copy of grid
515  auto grid_copy = new KVIDZAFromZGrid(*fGrid);
516  grid_copy->Initialize();
517  grid_copies.Add(grid_copy);
518 
519  // start new thread
520  jobs.push_back(std::thread([ =, &nthreads]() {
521 
523 
524  bool no_mass_id_zone_defined = (grid_copy->GetInfos()->FindObject("MassID") == nullptr);
525 
526  for (int i = imin; i <= imax; ++i) {
527  for (int j = 1; j <= fHisto->GetNbinsY(); j++) {
528  Stat_t poids = fHisto->GetBinContent(i, j);
529  if (poids == 0) continue;
530 
531  Axis_t x0 = fHisto->GetXaxis()->GetBinCenter(i);
532  Axis_t y0 = fHisto->GetYaxis()->GetBinCenter(j);
533  Axis_t wx = fHisto->GetXaxis()->GetBinWidth(i);
534  Axis_t wy = fHisto->GetYaxis()->GetBinWidth(j);
535 
536  if (x0 < 4) continue;
537 
538  Double_t x, y;
539  Int_t kmax = (Int_t) TMath::Min(20., poids);
540  Double_t weight = (kmax == 20 ? poids / 20. : 1.);
541  for (int k = 0; k < kmax; k++) {
542  x = gRandom->Uniform(x0 - .5 * wx, x0 + .5 * wx);
543  y = gRandom->Uniform(y0 - .5 * wy, y0 + .5 * wy);
544  if (grid_copy->IsIdentifiable(x, y)) {
545  idr.Clear();
546  grid_copy->KVIDZAGrid::Identify(x, y, &idr);
547  if (no_mass_id_zone_defined || idr.HasFlag(grid_copy->GetName(), "MassID")) {
548  Float_t PID = idr.PID;
549  fLinearHisto->Fill(PID, weight);
550  }
551  }
552  }
553  }
554  }
555  --nthreads;
556  std::cout << "...remaining threads: " << nthreads << std::endl;
557  }));
558  }
559  for (auto& j : jobs) {
560  if (j.joinable()) j.join();
561  }
562 
563  // reset automatic grid adding to previous state
564  KVIDGraph::SetAutoAdd(save_auto_add);
565 }
566 
567 
568 
571 
573 {
574  // KVBase::OpenContextMenu("Identify(double,double)",this);
575  Identify(0.1, 0.001);
576 }
577 
578 
579 
581 
582 void KVItvFinderDialog::Identify(double sigma, double ratio)
583 {
584  fSig = sigma;
585  fRat = ratio;
586 
587  fPad->cd();
589  if (list.IsEmpty()) {
591  for (int ii = 0; ii < fGrid->GetIntervalSets()->GetSize(); ii++) DrawInterval((interval_set*)fGrid->GetIntervalSets()->At(ii), 0);
592  }
593  else {
594  for (int ii = 0; ii < list.GetEntries(); ii++) {
595  interval_set* itvs = (interval_set*) list.At(ii);
596  ProcessIdentification(itvs->GetZ(), itvs->GetZ());
597  DrawInterval(itvs, 0);
598  }
599  }
600 
601  fCanvas->Modified();
602  fCanvas->Update();
603 
604 }
605 
606 
607 
609 
611 {
612  ExportToGrid();
613 
614  TString currentdir(gSystem->ExpandPathName("."));
615 
616  TString fn = fHisto->GetName();
617  fn += ".dat";
618 
619  Int_t ret_code;
620  new TGMsgBox(
621  gClient->GetRoot(),
622  gClient->GetDefaultRoot(),
623  "KVIDGridEditor::SaveCurrentGrid", Form("Do you wat to save the grid here : %s", fn.Data()),
624  kMBIconExclamation, kMBYes | kMBNo, &ret_code
625  );
626 
627  if (ret_code == kMBYes) {
628  fGrid->WriteAsciiFile(Form("%s", fn.Data()));
629  return;
630  }
631 
632  static TString dir(".");
633  const char* filetypes[] = {
634  "ID Grid files", "*.dat",
635  "All files", "*",
636  0, 0
637  };
638  TGFileInfo fi;
639  fi.fFileTypes = filetypes;
640  fi.fIniDir = StrDup(dir);
641  new TGFileDialog(gClient->GetDefaultRoot(), gClient->GetDefaultRoot(), kFDSave, &fi);
642  if (fi.fFilename) {
643  TString filenam(fi.fFilename);
644  if (filenam.Contains("toto")) filenam.ReplaceAll("toto", fGrid->GetName());
645  if (!filenam.Contains('.')) filenam += ".dat";
646  fGrid->WriteAsciiFile(filenam.Data());
647  }
648  dir = fi.fIniDir;
650 
651  fIntervalSetListView->Display(((KVIDZAFromZGrid*)fGrid)->GetIntervalSets());
652  current_interval_set = nullptr;
654 
655  fItvPaint.Clear();
656  DrawIntervals();
657 }
658 
659 
660 
663 
665 {
666  // Write all PID intervals in grid parameters "PIDRANGE", "PIDRANGE%d", etc.
667 
669  KVNumberList pids;
670  interval_set* itvs = 0;
671  TIter npid(fGrid->GetIntervalSets());
672  while ((itvs = (interval_set*)npid())) {
673  if (!itvs->GetNPID()) continue;
674  pids.Add(itvs->GetZ());
675  }
676  fGrid->GetParameters()->SetValue("PIDRANGE", pids.AsString());
677 
678  itvs = 0;
679  TIter next(fGrid->GetIntervalSets());
680  while ((itvs = (interval_set*)next())) {
681  if (!itvs->GetNPID()) continue;
682  KVString par = Form("PIDRANGE%d", itvs->GetZ());
683  KVString val = "";
684  interval* itv = 0;
685  TIter ni(itvs->GetIntervals());
686  while ((itv = (interval*)ni())) {
687  val += Form("%d:%lf,%lf,%lf|", itv->GetA(), itv->GetPIDmin(), itv->GetPID(), itv->GetPIDmax());
688  }
689  val.Remove(val.Length() - 1);
690  fGrid->GetParameters()->SetValue(par.Data(), val.Data());
691  }
692 }
693 
694 
695 
697 
699 {
701  if (list.IsEmpty() || list.GetEntries() > 1) {
702  current_interval_set = nullptr;
703  return;
704  }
705 
706  current_interval_set = (interval_set*)list.At(0);
707 
708  fPad->WaitPrimitive("TMarker");
709  auto mm = dynamic_cast<TMarker*>(fPad->GetListOfPrimitives()->Last());
710  assert(mm);
711  double pid = mm->GetX();
712  delete mm;
713 
714  int aa = 0;
715  int iint = 0;
716 
717  // try to guess mass from position (PID)
718  // typical isotope separation in PID is 0.12 (e.g. for carbon isotopes)
719  // assume that PID=z means A=2*Z
720  auto aa_guessstimate = TMath::Nint(current_interval_set->GetZ() * 2 + (pid - current_interval_set->GetZ()) / 0.12);
721 //Info("NewINt","pid = %f guess a=%d",pid,aa_guessstimate);
722  if (!current_interval_set->GetNPID()) {
723  aa = aa_guessstimate;
724  iint = 0;
725  }
726  else if (pid < ((interval*)current_interval_set->GetIntervals()->First())->GetPID()) { // to left of all others
727  aa = ((interval*)current_interval_set->GetIntervals()->First())->GetA() - 1;
728  // NO MORE : use guesstimate as long as it is smaller than A of previously defined interval with largest PID
729  // NOW : use 'aa_guessstimate' only for first interval
730  //Info("NewInt","before first interval, with a=%d",aa+1);
731 // if (aa_guessstimate < aa + 1) aa = aa_guessstimate;
732  iint = 0;
733  }
734  else if (pid > ((interval*)current_interval_set->GetIntervals()->Last())->GetPID()) { // to right of all others
735  aa = ((interval*)current_interval_set->GetIntervals()->Last())->GetA() + 1;
736  // NO MORE : use guesstimate as long as it is larger than A of previously defined interval with smallest PID
737  // NOW : use 'aa_guessstimate' only for first interval
738  //Info("NewInt","after last interval, with a=%d",aa-1);
739 // if (aa_guessstimate > aa - 1) aa = aa_guessstimate;
740  iint = current_interval_set->GetNPID();
741  }
742  else {
743  // look for intervals between which the new one is places
744  for (int ii = 1; ii < current_interval_set->GetNPID(); ii++) {
745  if (pid > ((interval*)current_interval_set->GetIntervals()->At(ii - 1))->GetPID()
746  && pid < ((interval*)current_interval_set->GetIntervals()->At(ii))->GetPID()) {
747  aa = ((interval*)current_interval_set->GetIntervals()->At(ii - 1))->GetA() + 1;
748  // use guesstimate if it is in between masses of adjacent intervals (in terms of PID)
749  if ((aa_guessstimate > (aa - 1)) &&
750  (aa_guessstimate < ((interval*)current_interval_set->GetIntervals()->At(ii))->GetA()))
751  aa = aa_guessstimate;
752  iint = ii;
753  break;
754  }
755  }
756  }
757 
758  interval* itv = new interval(current_interval_set->GetZ(), aa, mm->GetX(), mm->GetX() - 0.05, mm->GetX() + 0.05);
759  current_interval_set->GetIntervals()->AddAt(itv, iint);
760 
761  // find intervals which are now left (smaller mass) and right (higher mass) than this one
762  interval* left_interval = iint > 0 ? (interval*)current_interval_set->GetIntervals()->At(iint - 1) : nullptr;
763  interval* right_interval = iint < current_interval_set->GetIntervals()->GetEntries() - 1 ? (interval*)current_interval_set->GetIntervals()->At(iint + 1) : nullptr;
764  // find the corresponding painters
765  KVPIDIntervalPainter* left_painter{nullptr}, *right_painter{nullptr};
766  TIter next_painter(&fItvPaint);
767  KVPIDIntervalPainter* pidpnt;
768  while ((pidpnt = (KVPIDIntervalPainter*)next_painter())) {
769  if (pidpnt->GetInterval() == left_interval) left_painter = pidpnt;
770  else if (pidpnt->GetInterval() == right_interval) right_painter = pidpnt;
771  }
772 
773  // give a different colour to each interval
774  auto nitv = current_interval_set->GetIntervals()->GetEntries();
775  auto cstep = TColor::GetPalette().GetSize() / (nitv + 1);
776 
777  KVPIDIntervalPainter* dummy = new KVPIDIntervalPainter(itv, fLinearHisto, TColor::GetPalette()[cstep * (iint + 1)],
778  left_painter);
779  // set up links between painters
780  if (right_painter) {
781  right_painter->set_left_interval(dummy);
782  dummy->set_right_interval(right_painter);
783  }
784  fPad->cd();
785  dummy->Draw();
786  dummy->Connect("IntMod()", "KVItvFinderDialog", this, "UpdatePIDList()");
787  dummy->SetDisplayLabel(1);
788  dummy->SetCanvas(fCanvas);
789  fItvPaint.Add(dummy);
790 
792 
793  fItvPaint.Execute("Update", "");
794 
795  fCanvas->Modified();
796  fCanvas->Update();
797 }
798 
799 
800 
802 
804 {
806  if (list.IsEmpty() || list.GetEntries() > 1) {
807  current_interval_set = nullptr;
808  return;
809  }
810 
811  current_interval_set = (interval_set*)list.At(0);
812 
813  int aa = 0;
814  int iint = 0;
815 
816  // try to guess mass from position (PID)
817  // typical isotope separation in PID is 0.12 (e.g. for carbon isotopes)
818  // assume that PID=z means A=2*Z
819  auto aa_guessstimate = TMath::Nint(current_interval_set->GetZ() * 2 + (pid - current_interval_set->GetZ()) / 0.12);
820 //Info("NewINt","pid = %f guess a=%d",pid,aa_guessstimate);
821  if (!current_interval_set->GetNPID()) {
822  aa = aa_guessstimate;
823  iint = 0;
824  }
825  else if (pid < ((interval*)current_interval_set->GetIntervals()->First())->GetPID()) { // to left of all others
826  aa = ((interval*)current_interval_set->GetIntervals()->First())->GetA() - 1;
827  // NO MORE : use guesstimate as long as it is smaller than A of previously defined interval with largest PID
828  // NOW : use 'aa_guessstimate' only for first interval
829  //Info("NewInt","before first interval, with a=%d",aa+1);
830 // if (aa_guessstimate < aa + 1) aa = aa_guessstimate;
831  iint = 0;
832  }
833  else if (pid > ((interval*)current_interval_set->GetIntervals()->Last())->GetPID()) { // to right of all others
834  aa = ((interval*)current_interval_set->GetIntervals()->Last())->GetA() + 1;
835  // NO MORE : use guesstimate as long as it is larger than A of previously defined interval with smallest PID
836  // NOW : use 'aa_guessstimate' only for first interval
837  //Info("NewInt","after last interval, with a=%d",aa-1);
838 // if (aa_guessstimate > aa - 1) aa = aa_guessstimate;
839  iint = current_interval_set->GetNPID();
840  }
841  else {
842  // look for intervals between which the new one is places
843  for (int ii = 1; ii < current_interval_set->GetNPID(); ii++) {
844  if (pid > ((interval*)current_interval_set->GetIntervals()->At(ii - 1))->GetPID()
845  && pid < ((interval*)current_interval_set->GetIntervals()->At(ii))->GetPID()) {
846  aa = ((interval*)current_interval_set->GetIntervals()->At(ii - 1))->GetA() + 1;
847  // use guesstimate if it is in between masses of adjacent intervals (in terms of PID)
848  if ((aa_guessstimate > (aa - 1)) &&
849  (aa_guessstimate < ((interval*)current_interval_set->GetIntervals()->At(ii))->GetA()))
850  aa = aa_guessstimate;
851  iint = ii;
852  break;
853  }
854  }
855  }
856 
857  interval* itv = new interval(current_interval_set->GetZ(), aa, pid, pid - 0.05, pid + 0.05);
858  current_interval_set->GetIntervals()->AddAt(itv, iint);
859 
860  // find intervals which are now left (smaller mass) and right (higher mass) than this one
861  interval* left_interval = iint > 0 ? (interval*)current_interval_set->GetIntervals()->At(iint - 1) : nullptr;
862  interval* right_interval = iint < current_interval_set->GetIntervals()->GetEntries() - 1 ? (interval*)current_interval_set->GetIntervals()->At(iint + 1) : nullptr;
863  // find the corresponding painters
864  KVPIDIntervalPainter* left_painter{nullptr}, *right_painter{nullptr};
865  TIter next_painter(&fItvPaint);
866  KVPIDIntervalPainter* pidpnt;
867  while ((pidpnt = (KVPIDIntervalPainter*)next_painter())) {
868  if (pidpnt->GetInterval() == left_interval) left_painter = pidpnt;
869  else if (pidpnt->GetInterval() == right_interval) right_painter = pidpnt;
870  }
871 
872  // give a different colour to each interval
873  auto nitv = current_interval_set->GetIntervals()->GetEntries();
874  auto cstep = TColor::GetPalette().GetSize() / (nitv + 1);
875 
876  KVPIDIntervalPainter* dummy = new KVPIDIntervalPainter(itv, fLinearHisto, TColor::GetPalette()[cstep * (iint + 1)],
877  left_painter);
878  // set up links between painters
879  if (right_painter) {
880  right_painter->set_left_interval(dummy);
881  dummy->set_right_interval(right_painter);
882  }
883  fPad->cd();
884  dummy->Draw();
885  dummy->Connect("IntMod()", "KVItvFinderDialog", this, "UpdatePIDList()");
886  dummy->SetDisplayLabel(1);
887  dummy->SetCanvas(fCanvas);
888  fItvPaint.Add(dummy);
889 
891 
892  fItvPaint.Execute("Update", "");
893 
894  fCanvas->Modified();
895  fCanvas->Update();
896 
897 }
898 
899 
900 
902 
904 {
905  if (fGrid->GetIntervalSets()->GetSize() == 0) fNextIntervalZ = 1;
906  else fNextIntervalZ = ((interval_set*)fGrid->GetIntervalSets()->Last())->GetZ() + 1;
907  // open dialog asking for user to confirm (or change) Z of new interval set
908  bool ok = false; TString myZ; myZ.Form("%d", fNextIntervalZ);
909  new KVInputDialog(fMain, "Enter Z for new set of isotopes:", &myZ, &ok);
910  if(ok && myZ.IsDigit())
911  {
912  fNextIntervalZ = myZ.Atoi();
914  UpdateLists();
915  }
916 }
917 
918 
919 
921 
923 {
924  KVPIDIntervalPainter* pid = (KVPIDIntervalPainter*)fItvPaint.FindObject(Form("%d_%d", itv->GetZ(), itv->GetA()));
925  itvs->GetIntervals()->Remove(itv);
927  if (remove_fit) {
928  // remove any fits from pad corresponding to intervals
929  KVMultiGaussIsotopeFit::UnDrawGaussian(itvs->GetZ(), itv->GetA(), fPad);
930  }
931 }
932 
933 
934 
936 
938 {
940  Int_t nSelected = list.GetEntries();
941  current_interval_set = nullptr;
942 
943  if (nSelected == 1) {
944  current_interval_set = (interval_set*)list.At(0);
946  nSelected = list.GetEntries();
947  if (nSelected >= 1) {
948  for (int ii = 0; ii < nSelected; ii++) {
949  interval* itv = (interval*) list.At(ii);
951  }
953  fCanvas->Modified();
954  fCanvas->Update();
955  }
957  }
958  else if (nSelected > 1) {
959  for (int ii = 0; ii < nSelected; ii++) {
960  auto itvs = (interval_set*)list.At(ii);
961  ClearInterval(itvs);
962  }
963  }
964  gIDGridEditor->ResetGridColors();
965  gIDGridEditor->UpdateViewer();
966 }
967 
968 
969 
971 
973 {
975  Int_t nSelected = list.GetEntries();
976 
977  current_interval_set = nullptr;
978  if (nSelected == 1) {
979  current_interval_set = (interval_set*)list.At(0);
980 
982  nSelected = list.GetSize();
983 
984  if (nSelected == 1) {
985  interval* itv = (interval*) list.At(0);
986  itv->SetA(itv->GetA() + 1);
987  fItvPaint.Execute("Update", "");
988  // change the name of any gaussian in the pad associated with this isotope
989  auto gfit = (TNamed*)fPad->GetPrimitive(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA() - 1));
990  if (gfit) gfit->SetName(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA()));
991  fCanvas->Modified();
992  fCanvas->Update();
993  }
994  else {
995  TIter next_itv(&list);
996  interval* itv;
997  while ((itv = (interval*)next_itv())) {
998  itv->SetA(itv->GetA() + 1);
999  // change the name of any gaussian in the pad associated with this isotope
1000  auto gfit = (TNamed*)fPad->GetPrimitive(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA() - 1));
1001  if (gfit) gfit->SetName(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA()));
1002  }
1003  fItvPaint.Execute("Update", "");
1004  fCanvas->Modified();
1005  fCanvas->Update();
1006  }
1007  }
1008 }
1009 
1010 
1011 
1013 
1015 {
1017  Int_t nSelected = list.GetEntries();
1018 
1019  current_interval_set = nullptr;
1020  if (nSelected == 1) {
1021  current_interval_set = (interval_set*)list.At(0);
1023  nSelected = list.GetEntries();
1024 
1025  if (nSelected == 1) {
1026  interval* itv = (interval*) list.At(0);
1027  itv->SetA(itv->GetA() - 1);
1028  fItvPaint.Execute("Update", "");
1029  // change the name of any gaussian in the pad associated with this isotope
1030  auto gfit = (TNamed*)fPad->GetPrimitive(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA() + 1));
1031  if (gfit) gfit->SetName(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA()));
1032  fCanvas->Modified();
1033  fCanvas->Update();
1034  }
1035  else {
1036  TIter next_itv(&list);
1037  interval* itv;
1038  while ((itv = (interval*)next_itv())) {
1039  itv->SetA(itv->GetA() - 1);
1040  // change the name of any gaussian in the pad associated with this isotope
1041  auto gfit = (TNamed*)fPad->GetPrimitive(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA() + 1));
1042  if (gfit) gfit->SetName(KVMultiGaussIsotopeFit::get_name_of_isotope_gaussian(itv->GetZ(), itv->GetA()));
1043  }
1044  fItvPaint.Execute("Update", "");
1045  fCanvas->Modified();
1046  fCanvas->Update();
1047  }
1048  }
1049 }
1050 
1051 
1052 
1054 
1056 {
1057  fIntervalSetListView->Display(((KVIDZAFromZGrid*)fGrid)->GetIntervalSets());
1059  Int_t nSelected = list.GetEntries();
1060  interval_set* itvs = 0;
1061  if (nSelected == 1) {
1062  current_interval_set = (interval_set*)list.At(0);
1064  }
1065  else {
1066  current_interval_set = nullptr;
1068  }
1069 }
1070 
1071 
1072 
1075 
1077 {
1078  //fGrid->SetOnlyZId(0);
1079  fGrid->Initialize();
1080  ExportToGrid();
1081 
1083 
1084  fIntervalSetListView->Display(((KVIDZAFromZGrid*)fGrid)->GetIntervalSets());
1085  current_interval_set = nullptr;
1087 
1088  fItvPaint.Clear();
1089  DrawIntervals();
1090 
1091  new KVTestIDGridDialog(gClient->GetDefaultRoot(), gClient->GetDefaultRoot(), 10, 10, fGrid, fHisto);
1092 }
1093 
1094 
1095 
1097 
1099 {
1101  fCanvas->Modified();
1102  fCanvas->Update();
1103 }
1104 
1105 
1106 
1108 
1110 {
1111  fItvPaint.Execute("SetDisplayLabel", "0");
1112  current_interval_set = nullptr;
1114  fCanvas->Modified();
1115  fCanvas->Update();
1116 }
1117 
1118 
1119 
1130 
1132 {
1133  // fit the PID spectrum for the currently selected interval set (Z).
1134  //
1135  // for an interval with N isotopes, we use N gaussians plus an exponential (decreasing)
1136  // background. each gaussian has the same width. the centroids of the gaussians are first
1137  // fixed to the positions of the PID markers, the intensity and width of the peaks
1138  // (plus the background) are fitted.
1139  // then another fit is performed without constraining the centroids.
1140  //
1141  // finally the PID markers (PID of each interval) are modified according to the fitted centroid positions.
1142 
1143  if (!current_interval_set) return;
1144 
1145  KVNumberList alist;
1146  std::vector<double> pidlist;
1148  interval* intvl = nullptr;
1149  while ((intvl = (interval*)nxt_int())) {
1150  alist.Add(intvl->GetA());
1151  pidlist.push_back(intvl->GetPID());
1152  }
1155  alist, pidlist);
1156 
1157  bool fit_limited = false;
1158  // check user fit parameters
1159  if (mass_fit_parameters.GetBoolValue("Limit range of fit")) {
1160  // if the user's range is not valid for the current interval set, we ignore it
1161  if (mass_fit_parameters.GetDoubleValue("PID min for fit") >= current_interval_set->GetZ() - 0.5
1162  && mass_fit_parameters.GetDoubleValue("PID max for fit") <= current_interval_set->GetZ() + 0.5)
1163  {
1164  fitfunc.SetFitRange(mass_fit_parameters.GetDoubleValue("PID min for fit"),
1165  mass_fit_parameters.GetDoubleValue("PID max for fit"));
1166  fit_limited = true;
1167  }
1168  }
1169  fitfunc.SetSigmaLimits(mass_fit_parameters.GetDoubleValue("Minimum #sigma"),
1170  mass_fit_parameters.GetDoubleValue("Maximum #sigma"));
1172  fitfunc.PositiveBkgSlope(mass_fit_parameters.GetBoolValue("+ve bkg. slope"));
1173 
1174  fLinearHisto->Fit(&fitfunc, "NR");
1175 
1176  // now release the centroids
1177  fitfunc.ReleaseCentroids();
1178 
1179  fLinearHisto->Fit(&fitfunc, "NRME");
1180 
1181  // if fit was limited to a range, remove the limits
1182  if(fit_limited)
1183  fitfunc.SetFitRange(current_interval_set->GetZ() - 0.5,current_interval_set->GetZ() + 0.5);
1184 
1185  // remove any previous fit from pad
1186  fitfunc.UnDraw();
1187  // mop up any stray gaussians (from intervals which have been removed)
1188  KVMultiGaussIsotopeFit::UnDrawAnyGaussian(current_interval_set->GetZ(), fPad);
1189 
1190  // draw fit with individual gaussians
1191  fitfunc.DrawFitWithGaussians("same");
1192 
1193  // deactivate intervals for fitted masses
1194  std::unique_ptr<KVSeqCollection> tmp(fItvPaint.GetSubListWithMethod(Form("%d", current_interval_set->GetZ()), "GetZ"));
1195  tmp->Execute("DeactivateIntervals", "");
1196 
1197  // set interval limits according to regions of most probable mass
1198  int most_prob_A = 0;
1199  nxt_int.Reset();
1200  // minimum probability for which isotopes are taken into account
1201  double min_proba = mass_fit_parameters.GetDoubleValue("Minimum probability [%]") / 100.;
1202  double delta_pid = 0.001;
1203  TList accepted_intervals;//any intervals not in this list at the end of the procedure will be removed
1204  for (double pid = fitfunc.GetPIDmin() ; pid <= fitfunc.GetPIDmax(); pid += delta_pid) {
1205  double proba;
1206  auto Amax = fitfunc.GetMostProbableA(pid, proba);
1207  if(!Amax)
1208  continue;
1209  if (proba > min_proba) {
1210  if (most_prob_A) {
1211  if (*Amax > most_prob_A) {
1212 // std::cout << pid << " " << *Amax << " " << proba << std::endl;
1213 // std::cout << "got PIDmax for A=" << intvl->GetA() << std::endl;
1214  intvl->SetPIDmax(pid - delta_pid);
1215  most_prob_A = *Amax;
1216  intvl = (interval*)nxt_int();
1217  while (intvl->GetA() < most_prob_A) {
1218  intvl = (interval*)nxt_int();
1219  }
1220  accepted_intervals.Add(intvl);
1221  intvl->SetPIDmin(pid);
1222 // std::cout << "got PIDmin for A=" << intvl->GetA() << std::endl;
1223  }
1224  }
1225  else {
1226  most_prob_A = *Amax;
1227  intvl = (interval*)nxt_int();
1228  while (intvl->GetA() < most_prob_A) {
1229  intvl = (interval*)nxt_int();
1230  }
1231  accepted_intervals.Add(intvl);
1232  intvl->SetPIDmin(pid);
1233 // std::cout << pid << " " << *Amax << " " << proba << std::endl;
1234 // std::cout << "got PIDmin for A=" << intvl->GetA() << std::endl;
1235  }
1236  }
1237  else if (most_prob_A) {
1238  intvl->SetPIDmax(pid - delta_pid);
1239 // std::cout << pid << " " << *Amax << " " << proba << std::endl;
1240 // std::cout << "got PIDmax for A=" << intvl->GetA() << std::endl;
1241  most_prob_A = 0;
1242  }
1243  }
1244  nxt_int.Reset();
1245 // TList intervals_to_remove;
1246 // while ((intvl = (interval*)nxt_int())) {
1247 // if (!accepted_intervals.FindObject(intvl)) intervals_to_remove.Add(intvl);
1248 // }
1249 // if (intervals_to_remove.GetEntries()) {
1250 // // remove intervals below minimum probability (leave gaussians on display)
1251 // TIter it_rem(&intervals_to_remove);
1252 // while ((intvl = (interval*)it_rem())) remove_interval_from_interval_set(current_interval_set, intvl, false);
1253 // }
1254 // intervals_to_remove.Clear();
1255  int ig(1);
1256  // update PID positions from fitted centroids
1257  nxt_int.Reset();
1258  KVNumberList remaining_gaussians, remaining_alist;
1259  auto vec_alist = alist.GetArray();
1260  while ((intvl = (interval*)nxt_int())) {
1261  // in case we removed some peaks
1262  while (vec_alist[ig - 1] < intvl->GetA()) {
1263  ++ig;
1264  }
1265  intvl->SetPID(fitfunc.GetCentroid(ig));
1266  remaining_gaussians.Add(ig);
1267  remaining_alist.Add(intvl->GetA());
1268  ++ig;
1269  }
1270 // if (intervals_to_remove.GetEntries()) {
1271 // // remove intervals with centroids outside PID limits
1272 // TIter it_rem(&intervals_to_remove);
1273 // while ((intvl = (interval*)it_rem())) remove_interval_from_interval_set(current_interval_set, intvl, false);
1274 // }
1275  UpdatePIDList();
1276  fItvPaint.Execute("Update", "");
1277 
1278  fPad->Modified();
1279  fPad->Update();
1280 
1281  // save results in grid parameters
1282  KVNumberList zlist;
1283  if (fGrid->GetParameters()->HasStringParameter("MASSFITS"))
1284  zlist.Set(fGrid->GetParameters()->GetStringValue("MASSFITS"));
1285  zlist.Add(current_interval_set->GetZ());
1286  fGrid->GetParameters()->SetValue("MASSFITS", zlist.AsString());
1287  TString massfit = Form("MASSFIT_%d", current_interval_set->GetZ());
1288  KVNameValueList fitparams;
1289  fitparams.SetValue("Ng", alist.GetNValues());
1290  fitparams.SetValue("Alist", alist.AsQuotedString());
1291  fitparams.SetValue("PIDmin", fitfunc.GetPIDmin());
1292  fitparams.SetValue("PIDmax", fitfunc.GetPIDmax());
1293  fitparams.SetValue("Bkg_cst", fitfunc.GetBackgroundConstant());
1294  fitparams.SetValue("Bkg_slp", fitfunc.GetBackgroundSlope());
1295  fitparams.SetValue("GausWid", fitfunc.GetGaussianWidth(0));
1296  fitparams.SetValue("PIDvsA_a0", fitfunc.GetPIDvsAfit_a0());
1297  fitparams.SetValue("PIDvsA_a1", fitfunc.GetPIDvsAfit_a1());
1298  fitparams.SetValue("PIDvsA_a2", fitfunc.GetPIDvsAfit_a2());
1299  for (ig = 1; ig <= alist.GetNValues(); ++ig) {
1300  fitparams.SetValue(Form("Norm_%d", ig), fitfunc.GetGaussianNorm(ig));
1301  }
1302  auto sanitized = fitparams.Get().ReplaceAll("=", ":");
1303  fGrid->GetParameters()->SetValue(massfit, sanitized);
1304  gIDGridEditor->ResetGridColors();
1305  gIDGridEditor->UpdateViewer();
1306 }
1307 
1308 
1309 
1312 
1314 {
1315  // Open dialog to modify parameters for multigauss mass fit
1316 
1317  bool cancel = false;
1318  auto bkg_slope = mass_fit_parameters.GetBoolValue("+ve bkg. slope");
1319  auto dialog = new KVNameValueListGUI(fMain, &mass_fit_parameters, &cancel);
1320  dialog->EnableDependingOnBool("PID min for fit", "Limit range of fit");
1321  dialog->EnableDependingOnBool("PID max for fit", "Limit range of fit");
1322  dialog->DisplayDialog();
1323  negative_bkg_slope_changed = (mass_fit_parameters.GetBoolValue("+ve bkg. slope") != bkg_slope);
1324 }
1325 
1326 
1327 
1330 
1332 {
1333  // Remove fit of currently selected interval set from pad
1334 
1335  if (!current_interval_set) return;
1336 
1337  std::vector<int> alist;
1339  interval* intvl = nullptr;
1340  while ((intvl = (interval*)nxt_int())) {
1341  alist.push_back(intvl->GetA());
1342  }
1344 
1345  fitfunc.UnDraw(fPad);
1346  // mop up any stray gaussians (from intervals which have been removed)
1347  KVMultiGaussIsotopeFit::UnDrawAnyGaussian(current_interval_set->GetZ(), fPad);
1348 
1349  fPad->Modified();
1350  fPad->Update();
1351 }
1352 
1353 
1354 
1356 
1358 {
1359 
1360  if (!fCanvas) return;
1361  if (fCanvas->GetEvent() == kMouseMotion) return;
1362 
1363  switch (fCanvas->GetEvent()) {
1364  case kButton2Up:
1365  FitIsotopes();
1366  break;
1367  case kButton1Double:
1369  break;
1370  case kButton1Shift:
1372  break;
1373  }
1374 
1375 }
1376 
1377 
1378 
1380 
1382 {
1383  std::cout << "Mouse shortcuts : Wheel-click Fit intervals of current Z" << std::endl;
1384  std::cout << " Double-click Set/Unset log scale on Y axis" << std::endl;
1385  std::cout << " Shift-click Add an interval where clicked" << std::endl;
1386 }
1387 
1388 
1389 
1391 
1393 {
1394  interval_set* itvs = fGrid->GetIntervalSet(zz);
1395  if (!itvs) {
1396  itvs = new interval_set(zz, KVIDZAFromZGrid::kIntType);
1397  fGrid->AddIntervalSet(itvs);
1398  }
1399  else ClearInterval(itvs);
1400 
1401 
1402  if (zz == 1) fLinearHisto->SetAxisRange(0.9, zz + 0.5, "X");
1403  else fLinearHisto->SetAxisRange(zz - 0.5, zz + 0.5, "X");
1404 
1405  int nfound = fSpectrum.Search(fLinearHisto, fSig, "goff", ((zz == 2) ? 0.1 * fRat : fRat));
1406 
1407 #if ROOT_VERSION_CODE > ROOT_VERSION(5,99,01)
1408  Double_t* xpeaks = fSpectrum.GetPositionX();
1409 // Double_t* ypeaks = fSpectrum.GetPositionY();
1410 #else
1411  Float_t* xpeaks = fSpectrum.GetPositionX();
1412 // Float_t* ypeaks = fSpectrum.GetPositionY();
1413 #endif
1414 
1415  nfound = TMath::Min(fNpeaks[zz - 1], nfound);
1416 
1417  int idx[nfound];
1418  TMath::Sort(nfound, xpeaks, idx, 0);
1419 
1420  int zrefs[] = {1, 4, 7, 9, 11, 12, 15, 16, 19, 21, 23, 25, 27, 29, 31, 34, 35, 38, 40, 42, 44, 47, 49, 51, 53};
1421  int zref = zrefs[zz - 1];
1422 
1423  int idref = -1;
1424  for (int p = 0; p < nfound; p++) {
1425  if (std::abs(xpeaks[idx[p]] - xpeaks[0]) < .0001) idref = p;
1426  }
1427  Info("FindPIDIntervals", "Z=%d : idref = %d ", zz, idref);
1428 
1429  for (int p = 0; p < nfound; p++) {
1430 // Info("FindPIDIntervals","Z=%d : (%.2lf %.2lf) (%d %d) ",zz,xpeaks[p],ypeaks[p],idx[p],p);
1431  double pid = xpeaks[idx[p]];//ff->GetParameter(3 * ii + 1);
1432  itvs->add(zref + (p - idref), pid, pid - 0.05, pid + 0.05);
1433  }
1434 
1435 
1436 }
1437 
1438 
1439 
1441 
1443 {
1444  Double_t result = 0;
1445  int np = par[0];
1446  for (Int_t p = 0; p < np; p++) {
1447  Double_t norm = par[3 * p + 3];
1448  Double_t mean = par[3 * p + 1];
1449  Double_t sigma = par[3 * p + 2];
1450  result += norm * TMath::Gaus(x[0], mean, sigma);
1451  }
1452  return result;
1453 }
1454 
1455 
1457 
1459 {
1460 
1461  if (zmin < 0) zmin = ((KVIDentifier*)fGrid->GetIdentifiers()->First())->GetZ();
1462  if (zmax < 0) zmax = ((KVIDentifier*)fGrid->GetIdentifiers()->Last())->GetZ();
1463 
1464  for (int z = zmin; z <= zmax; z++) FindPIDIntervals(z);
1465 
1466 }
1467 
1468 
1469 
1470 
1471 
1472 
1473 
1474 
1475 
1476 
kMouseMotion
kButton1Double
kButton1Shift
kButton2Up
int Int_t
kVerticalFrame
kHorizontalFrame
float Float_t
double Axis_t
constexpr Bool_t kFALSE
double Double_t
double Stat_t
kGray
kBlack
#define gClient
kFDSave
kDeepCleanup
kLHintsExpandY
kLHintsTop
kLHintsExpandX
kMBNo
kMBYes
kMBIconExclamation
kTextCenterX
kTextLeft
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t np
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
#define gROOT
R__EXTERN TRandom * gRandom
char * Form(const char *fmt,...)
char * StrDup(const char *str)
R__EXTERN TStyle * gStyle
R__EXTERN TSystem * gSystem
static void SetAutoAdd(Bool_t yes=kTRUE)
Definition: KVIDGraph.h:156
static Bool_t GetAutoAdd()
Definition: KVIDGraph.h:162
const Char_t * GetName() const override
Definition: KVIDGraph.cpp:1414
const KVNameValueList * GetParameters() const
Definition: KVIDGraph.h:357
void WriteAsciiFile(const Char_t *filename)
Open, write and close ascii file containing this grid.
Definition: KVIDGraph.cpp:406
const KVList * GetIdentifiers() const
Definition: KVIDGraph.h:367
Hybrid charge & mass identification grid.
const KVList * GetIntervalSets() const
void Initialize() override
interval_set * GetIntervalSet(int zint) const
void AddIntervalSet(interval_set *)
add an interval set to the grid, updating the corresponding parameters
void SetOnlyZId(Bool_t=kTRUE) override
void RemoveIntervalSet(int zint)
Remove interval set for given Z from grid.
Base class for graphical cuts used in particle identification.
Definition: KVIDentifier.h:28
virtual Double_t GetPID() const
Full result of one attempted particle identification.
Double_t PID
= "real" Z if Zident==kTRUE and Aident==kFALSE, "real" A if Zident==Aident==kTRUE
void Clear(Option_t *opt="") override
Reset to initial values.
Bool_t HasFlag(std::string grid_name, TString flag)
General purpose dialog box asking for some input in the form of a string.
Definition: KVInputDialog.h:24
GUI for finding/fixing mass identification intervals.
KVListView * fIntervalListView
void DrawInterval(interval_set *itvs, bool label=0)
KVIDZAFromZGrid * fGrid
TGTransientFrame * fMain
void ClearInterval(interval_set *itvs)
void ProcessIdentification(Int_t zmin=-1, Int_t zmax=-1)
void AddInterval(double pid)
void delete_painter_from_painter_list(KVPIDIntervalPainter *)
TVirtualPad * fPad
void Identify()
KVBase::OpenContextMenu("Identify(double,double)",this);.
void SetFitParameters()
Open dialog to modify parameters for multigauss mass fit.
interval_set * current_interval_set
void FindPIDIntervals(Int_t zz)
KVItvFinderDialog(KVIDZAFromZGrid *gg, TH2 *hh)
KVListView * fIntervalSetListView
static KVNameValueList mass_fit_parameters
for user control of multi-gaussian fit
void RemoveFit()
Remove fit of currently selected interval set from pad.
void ExportToGrid()
Write all PID intervals in grid parameters "PIDRANGE", "PIDRANGE%d", etc.
void TestIdent()
fGrid->SetOnlyZId(0);
void LinearizeHisto(int nbins)
Double_t fpeaks(Double_t *x, Double_t *par)
void remove_interval_from_interval_set(interval_set *itvs, interval *itv, bool remove_fit=true)
KVPIDIntervalPainter * last_drawn_interval
void ZoomOnCanvas()
Display the interval set for a given Z when the user double clicks on it.
Enhanced version of ROOT TGListView widget.
Definition: KVListView.h:147
virtual void SetDataColumns(Int_t ncolumns)
Definition: KVListView.cpp:91
void SetDoubleClickAction(const char *receiver_class, void *receiver, const char *slot)
Definition: KVListView.cpp:210
virtual void Display(const TCollection *l)
Definition: KVListView.h:174
KVUnownedList GetSelectedObjects() const
Definition: KVListView.h:253
TObject * GetLastSelectedObject() const
Definition: KVListView.h:239
virtual void RemoveAll()
Definition: KVListView.h:194
void AllowContextMenu(Bool_t on=kTRUE)
Definition: KVListView.h:292
virtual void SetDataColumn(Int_t index, const Char_t *name, const Char_t *method="", Int_t mode=kTextCenterX)
Definition: KVListView.cpp:106
Extended TList class which owns its objects by default.
Definition: KVList.h:22
Function for fitting PID mass spectra.
GUI for setting KVNameValueList parameters.
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
Double_t GetDoubleValue(const Char_t *name) const
void SetValue(const Char_t *name, value_type value)
void RemoveParameter(const Char_t *name)
Bool_t HasStringParameter(const Char_t *name) const
Bool_t GetBoolValue(const Char_t *name) const
KVString Get() const
const Char_t * GetStringValue(const Char_t *name) const
bool Set(const KVString &)
Bool_t HasParameter(const Char_t *name) const
TString GetTStringValue(const Char_t *name) const
Strings used to represent a set of ranges of values.
Definition: KVNumberList.h:85
const Char_t * AsQuotedString() const
const Char_t * AsString(Int_t maxchars=0) const
void Remove(Int_t)
Remove value 'n' from the list.
Int_t GetNValues() const
void Add(Int_t)
Add value 'n' to the list.
void Set(const TString &l)
Definition: KVNumberList.h:135
IntArray GetArray() const
Graphical representation of a PID interval in the KVIDZAFromZGrid mass assignation GUI.
void SetCanvas(TCanvas *cc)
interval * GetInterval() const
void Draw(Option_t *option="") override
void SetDisplayLabel(bool dis=true)
void HighLight(bool hi=true)
void set_right_interval(KVPIDIntervalPainter *i)
void Execute(const char *method, const char *params, Int_t *error=0) override
TObject * First() const override
KVSeqCollection * GetSubListWithMethod(const Char_t *retvalue, const Char_t *method) const
TObject * Remove(TObject *obj) override
Remove object from list.
void Add(TObject *obj) override
TObject * FindObject(const char *name) const override
TObject * Last() const override
Int_t GetSize() const override
void Clear(Option_t *option="") override
TObject * At(Int_t idx) const override
void AddAt(TObject *obj, Int_t idx) override
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
GUI for testing identification grids.
Int_t GetSize() const
virtual void SetFillColor(Color_t fcolor)
virtual void SetLineColor(Color_t lcolor)
virtual void SetMarkerStyle(Style_t mstyle=1)
virtual void SetBottomMargin(Float_t bottommargin)
virtual void SetLeftMargin(Float_t leftmargin)
virtual void SetRightMargin(Float_t rightmargin)
virtual void SetTopMargin(Float_t topmargin)
virtual void UnZoom()
virtual void SetRangeUser(Double_t ufirst, Double_t ulast)
Int_t GetEventX() const override
TVirtualPad * cd(Int_t subpadnumber=0) override
void Update() override
Int_t GetEvent() const override
virtual Int_t GetEntries() const
static const TArrayI & GetPalette()
TGDimension GetDefaultSize() const override
virtual void AddFrame(TGFrame *f, TGLayoutHints *l=nullptr)
void MapSubwindows() override
void SetCleanup(Int_t mode=kLocalCleanup) override
char * fFilename
const char ** fFileTypes
char * fIniDir
virtual void Resize(TGDimension size)
void MapWindow() override
void DontCallClose()
void SetWindowName(const char *name=nullptr) override
virtual TGButton * AddButton(const TGWindow *w, TGPictureButton *button, Int_t spacing=0)
virtual void CenterOnParent(Bool_t croot=kTRUE, EPlacement pos=kCenter)
virtual void RequestFocus()
virtual Int_t GetNbinsY() const
TAxis * GetXaxis()
virtual TFitResultPtr Fit(const char *formula, Option_t *option="", Option_t *goption="", Double_t xmin=0, Double_t xmax=0)
virtual Int_t GetNbinsX() const
TAxis * GetYaxis()
void Draw(Option_t *option="") override
virtual Int_t Fill(const char *name, Double_t w)
virtual void SetAxisRange(Double_t xmin, Double_t xmax, Option_t *axis="X")
virtual Double_t GetBinContent(Int_t bin) const
void Reset()
void Add(TObject *obj) override
TObject * Last() const override
const char * GetName() const override
static TClass * Class()
virtual void Execute(const char *method, const char *params, Int_t *error=nullptr)
void AddExec(const char *name, const char *command) override
Double_t AbsPixeltoX(Int_t px) override
void Modified(Bool_t flag=1) override
void SetLogy(Int_t value=1) override
Int_t GetLogy() const override
Bool_t Connect(const char *signal, const char *receiver_class, void *receiver, const char *slot)
virtual Double_t Uniform(Double_t x1, Double_t x2)
void AdoptCanvas(TCanvas *c)
TCanvas * GetCanvas() const
Int_t GetCanvasWindowId() const
virtual Int_t Search(const TH1 *hist, Double_t sigma=2, Option_t *option="", Double_t threshold=0.05)
Double_t * GetPositionX() const
Ssiz_t Length() const
Int_t Atoi() const
const char * Data() const
Bool_t IsDigit() const
void Form(const char *fmt,...)
TString & Remove(EStripType s, char c)
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
TString & ReplaceAll(const char *s1, const char *s2)
void SetOptTitle(Int_t tit=1)
void SetOptStat(Int_t stat=1)
virtual char * ExpandPathName(const char *path)
virtual void Modified(Bool_t flag=1)=0
virtual TList * GetListOfPrimitives() const=0
virtual TVirtualPad * cd(Int_t subpadnumber=0)=0
virtual void Update()=0
virtual TObject * WaitPrimitive(const char *pname="", const char *emode="")=0
virtual TObject * GetPrimitive(const char *name) const=0
void add(int aa, double pid, double pidmin=-1., double pidmax=-1.)
KVList * GetIntervals()
bool SetPID(double pid)
double GetPID()
double GetPIDmin()
void SetPIDmin(double pidmin)
void SetA(int aa)
double GetPIDmax()
void SetPIDmax(double pidmax)
const Double_t sigma
Double_t y[n]
Double_t x[n]
void Info(const char *location, const char *fmt,...)
Double_t Min(Double_t a, Double_t b)
Double_t Gaus(Double_t x, Double_t mean=0, Double_t sigma=1, Bool_t norm=kFALSE)
Int_t Nint(T x)
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
const char * fTipText
TGButton * fButton
Bool_t fStayDown
const char * fPixmap
ClassImp(TPyArg)