er  dev
ERCalibrationSSD.cxx
1 namespace ERCalibrationSSD {
2 /*
3  Namespace includes code for a Silicon Strip Detector (SSD) calibration.
4  The common scheme of handling process
5 
6  Prerequisites for program module usage:
7  * Files with calibration run data in *.root format converted by FLNR TNeEvent classes
8 
9  Terminology.
10  Sensor - an array of a readout channel concerned with a certain ROOT-tree leaf.
11 
12  Platforms.
13  The code was tested only in the Linux OS, but the ROOT-framework methods used work in
14  Windows also. Methods which are used but work on Linux only are:
15  * TString GetFileNameBaseFromPath (TString const &path)
16  * void IOManager::MakeDir(TString &dirname)
17  For them, path name separators should be extended to Windows ones.
18 
19  ROOT versions - ???
20 */
21 
22 /* @TODO
23  * Sorting stations by name for reproducible results (path names)
24  * Replace SetRunInfo class by RunInfo which will contain several sensors info with their common
25  run id.
26  * More log messages for each significant step
27 */
28 
29 TString GetFileNameBaseFromPath(const TString& path);
30 
36 public:
37  SensorRunInfo() = default;
38  SensorRunInfo(const TString& name, const Int_t stripAmount,
39  const Int_t binAmount, const TString& runId = "");
40  ~SensorRunInfo() = default;
41 
51  void SetThresholdFile(const TString &path) {fThresholdFilePath = path;}
52 
53  void SetNoiseThreshold(const Int_t noiseThreshold) {fNoiseThreshold = noiseThreshold;}
54  void SetDeadLayersPerStrip(const std::vector<Double_t> &deadLayers);
55 
56  void ReadThresholds();
57 public:
58  TString fName; // name of a propper leaf in a tree
59  TString fThresholdFilePath;
60  TString fCalibFilePath;
61  Int_t fStripAmount = 16;
62  Int_t fBinAmount = 1024;
63  TString fRunId;
64  Int_t fNoiseThreshold = 0;
65 
66  Bool_t fIsDeadLayerPerStripsSet = false;
67  std::vector<Double_t> fDeadLayers = std::vector<Double_t>();
68 };
69 
70 SensorRunInfo::SensorRunInfo(const TString& name, const Int_t stripAmount,
71  const Int_t binAmount, const TString& runId = ""):
72  fName(name),
73  fStripAmount(stripAmount),
74  fBinAmount(binAmount),
75  fRunId(GetFileNameBaseFromPath(runId)) {
76 }
77 
78 void SensorRunInfo::SetDeadLayersPerStrip(const std::vector<Double_t> &deadLayersPerStrip) {
79  if (deadLayersPerStrip.size() != this->fStripAmount) {
80  Error(
81  "SensorRunInfo::SetDeadLayersPerStrip",
82  "Dead thickness amount set by user (%ld) doesn't equal strips amount (%d)",
83  deadLayersPerStrip.size(), this->fStripAmount);
84  exit(1);
85  }
86  fIsDeadLayerPerStripsSet = true;
87  fDeadLayers = deadLayersPerStrip;
88 }
89 
94 template<typename T>
95 Double_t CalculateAvg(T values) {
96  Double_t sum = 0.;
97  Int_t counterNotNaN = 0;
98  for (const auto& value: values) {
99  if (!std::isnan(value)) {
100  sum += value;
101  counterNotNaN++;
102  }
103  }
104  return sum / counterNotNaN;
105 }
106 
116 void DrawSensorSpectraByStrip(TTree* tree,
117  const SensorRunInfo* sensor,
118  const std::vector<UShort_t>& thresholds) {
119  const auto canvas = new TCanvas(Form("canvas_%s", sensor->fName.Data()));
120  // prepare approximately square placing of pads on canvas
121  Int_t canvFirtsDim = std::round(std::sqrt(sensor->fStripAmount));
122  Int_t canvSecondDim = 1;
123  for (; canvSecondDim*canvFirtsDim < sensor->fStripAmount; canvSecondDim++) {}
124  canvas->Divide(canvFirtsDim, canvSecondDim);
125 
126  for (Int_t iStrip = 0; iStrip < sensor->fStripAmount; iStrip++) {
127  const TString histParams = Form("(%d,%d,%d)", sensor->fBinAmount, 0, sensor->fBinAmount);
128  const TString histName = Form("strip_%d", iStrip);
129  const TString drawExpression = Form(
130  "%s[%d]>>%s%s", sensor->fName.Data(), iStrip, histName.Data(), histParams.Data()
131  );
132  const TString cutExpression = Form(
133  "%s[%d]>%d", sensor->fName.Data(), iStrip, thresholds[iStrip]
134  );
135  canvas->cd(iStrip + 1);
136  tree->Draw(drawExpression, cutExpression, "");
137  const auto hist = static_cast<TH1D*>(gDirectory->Get(histName));
138  hist->Write();
139  }
140  canvas->Write();
141 }
142 
156 void DrawSensorSpectraByPixel(TTree* tree,
157  const SensorRunInfo* sensorDraw,
158  const SensorRunInfo* sensorSelect,
159  const std::vector<UShort_t>& thresholdsDraw,
160  const std::vector<UShort_t>& thresholdsSelect) {
161  // prepare approximately square placing of pads on canvas
162  Int_t canvFirtsDim = std::round(std::sqrt(sensorDraw->fStripAmount));
163  Int_t canvSecondDim = 1;
164  for (; canvSecondDim*canvFirtsDim < sensorDraw->fStripAmount; canvSecondDim++) {}
165 
166  for (Int_t iStripDraw = 0; iStripDraw < sensorDraw->fStripAmount; iStripDraw++) {
167  const auto canvasName = Form("canvas_%s[%d]", sensorDraw->fName.Data(), iStripDraw);
168  const auto canvas = new TCanvas(canvasName);
169  canvas->Divide(canvFirtsDim, canvSecondDim);
170  for (Int_t iStripSelect = 0; iStripSelect < sensorSelect->fStripAmount; iStripSelect++) {
171  Info("DrawSensorSpectraByPixel", "Pixel %s[%d]-%s[%d] in progress",
172  sensorDraw->fName.Data(), iStripDraw,
173  sensorSelect->fName.Data(), iStripSelect);
174  const auto histParams = Form("(%d,%d,%d)",
175  sensorDraw->fBinAmount, 0, sensorDraw->fBinAmount);
176  const auto histName = Form("pixel_%s[%d]_%s[%d]", sensorDraw->fName.Data(), iStripDraw,
177  sensorSelect->fName.Data(), iStripSelect);
178  const auto drawExpression = Form("%s[%d]>>%s%s", sensorDraw->fName.Data(), iStripDraw,
179  histName, histParams);
180  const auto cutExpression = Form("%s[%d]>%d&&%s[%d]>%d",
181  sensorDraw->fName.Data(), iStripDraw,
182  thresholdsDraw[iStripDraw],
183  sensorSelect->fName.Data(), iStripSelect,
184  thresholdsSelect[iStripSelect]);
185  canvas->cd(iStripSelect + 1);
186  tree->Draw(drawExpression, cutExpression, "");
187  const auto hist = static_cast<TH1D*>(gDirectory->Get(histName));
188  hist->Write();
189  }
190  canvas->Write();
191  }
192 }
193 
194 // External fuctions begin
201 int CheckDataMultiplicity(const std::vector<UShort_t>& data,
202  const std::vector<UShort_t>& thresholds) {
203  int multiplicity = 0;
204  for (Int_t i = 0; i < data.size(); i++) {
205  if (data[i] > thresholds[i]) {
206  multiplicity++;
207  if (multiplicity > 1) {
208  break;
209  }
210  }
211  }
212  return multiplicity;
213 }
214 
220 Bool_t CheckIfSingleMultiplicity(const std::vector<SensorRunInfo*>* sensors,
221  const std::vector<std::vector<UShort_t>>* data,
222  const std::vector<std::vector<UShort_t>>* thresholds) {
223  Bool_t ifSingleMult = true;
224  for (Int_t i = 0; i < sensors->size(); i++) {
225  const int multiplicity = CheckDataMultiplicity(data->at(i), thresholds->at(i));
226  if (multiplicity != 1) {
227  ifSingleMult = false;
228  break;
229  }
230  }
231  return ifSingleMult;
232 }
233 
241 TObject* GetObjectFromRootFile(const TString& filePath, const TString& objName = "") {
242  auto file = TFile::Open(filePath.Data()); // ATTENTION! file is not closed
243  auto obj = (objName.Length())
244  ? file->Get(objName)
245  : file->Get(file->GetListOfKeys()->At(0)->GetName());
246  return obj;
247 }
248 
255 TObject* GetObjectFromRootFile(TFile* file, const unsigned object_ind) {
256  auto obj = file->Get(file->GetListOfKeys()->At(object_ind)->GetName());
257  Info("Info", "%s", obj->GetName());
258  return obj;
259 }
260 
261 
268 TObject* GetObjectFromRootFile(TFile* file, const TString& objName = "") {
269  // save current directory
270  auto obj = (objName.Length())
271  ? file->Get(objName)
272  : file->Get(file->GetListOfKeys()->At(0)->GetName());
273  return obj;
274 }
275 
276 
281 TString GetFileNameBaseFromPath(const TString& path) {
282  TString fileName = gSystem->BaseName(path);
283  // remove file extension. Extension is considered as part of the name after last "." symbol
284  Int_t lastDotPos = fileName.Last('.');
285  if (lastDotPos > 0) {
286  fileName.Remove(lastDotPos, fileName.Length());
287  }
288  return fileName;
289 }
290 
291 
298 template<typename T>
299 void DumpVector(const std::vector<T>& vec, ofstream& file, const TString& delimiter = "\n") {
300  for (const auto &itVec : vec) {
301  file << itVec << delimiter;
302  }
303 }
304 
311 template<typename T>
312 void Dump2DVector(const T& vec2d, ofstream& file,
313  const TString& delimiter = " ") {
314  for (const auto &vec: vec2d) {
315  for (const auto &elem: vec) {
316  file << elem << delimiter;
317  }
318  file << endl;
319  }
320 }
321 
327 template<typename T>
328 void Dump2DVector(const T& vec2d, const TString& delimiter = " ") {
329  for (const auto &vec: vec2d) {
330  for (const auto &elem: vec) {
331  std::cout << elem << delimiter;
332  }
333  std::cout << std::endl;
334  }
335 }
336 
337 
342 template<typename T>
343 std::vector<T> ReadVectorFromFile(const TString& filePath) {
344  std::ifstream file(filePath);
345  if (!file.is_open()) {
346  Error("ReadVectorFromFile", "Failed to open file: %s", filePath.Data());
347  }
348  std::vector<T> vec;
349  T value;
350  while (file >> value) {
351  vec.push_back(value);
352  }
353  return vec;
354 }
355 
360 template<typename T>
361 std::vector<std::vector<T>> Read2DVectorFromFile(const TString& filePath) {
362  std::ifstream file(filePath);
363  if (!file.is_open()) {
364  Error("Read2DVectorFromFile", "Failed to open file: %s", filePath.Data());
365  }
366  std::vector<std::vector<T>> vec2d;
367  T value;
368  std::string line;
369  while (std::getline(file, line)) {
370  std::vector<T> vec;
371  std::istringstream iss(line);
372  T value;
373  while (iss >> value) {
374  vec.push_back(value);
375  }
376  vec2d.push_back(vec);
377  }
378  file.close();
379  return vec2d;
380 }
381 
386 std::vector<Double_t> ReadDoubleVectorFromFile(const TString& filePath) {
387  std::ifstream file(filePath);
388  if (!file.is_open()) {
389  Error("ReadDoubleVectorFromFile", "Failed to open file: %s", filePath.Data());
390  }
391  std::vector<Double_t> vec;
392  std::string str_val;
393  while (file >> str_val) {
394  vec.push_back(std::stod(str_val));
395  }
396  file.close();
397 
398  return vec;
399 }
400 
401 
406 std::vector<std::vector<Double_t>> Read2DDoubleVectorFromFile(const TString& filePath) {
407  std::ifstream file(filePath);
408  if (!file.is_open()) {
409  Error("Read2DDoubleVectorFromFile", "Failed to open file: %s", filePath.Data());
410  }
411  std::vector<std::vector<Double_t>> vec2d;
412  std::string line;
413  while (std::getline(file, line)) {
414  std::vector<Double_t> vec;
415  std::istringstream iss(line);
416  std::string str_val;
417  while (iss >> str_val) {
418  vec.push_back(std::stod(str_val));
419  }
420  vec2d.push_back(vec);
421  }
422  file.close();
423 
424  return vec2d;
425 }
426 
427 
428 // External functions end
429 
430 enum ApproxOrder {
431  LINEAR,
432  QUAD,
433  TRI
434 };
435 
436 class IOManager {
437 public:
438  IOManager() = default;
439  IOManager(const TString& workdir) = delete;
440  ~IOManager() = default; // ought to be virtual
441 
448  TFile* CreateRootFile(const TString& filePath);
449 
454  TFile* OpenRootFile(const TString& filePath);
455 
461  std::ofstream CreateTextFile(const TString& filePath);
462 
467  std::ifstream OpenTextFile(const TString& filePath);
468 
469 
474  void Write(const TObjArray* arr);
475 
480  void Write(TObject* obj);
481 
486  void MakeDir(const TString& dirname);
487 
492  void ChangeDir(const TString& dirname);
493 protected:
494  TString fWorkDir = ".";
495  Bool_t fRecreate = true; // 'true' if all the produced files are recreated, 'false' to use existing ones
496 };
497 
498 TFile* IOManager::CreateRootFile(const TString& filePath) {
499  const TString dirPath = gSystem->DirName(filePath);
500  this->MakeDir(dirPath);
501  auto file = TFile::Open(filePath, "RECREATE");
502  if (file) {
503  Info("IOManager::CreateRootFile", "Created ROOT file: %s", filePath.Data());
504  } else {
505  Error("IOManager::CreateRootFile", "Failed to create ROOT file: %s", filePath.Data());
506  }
507  return file;
508 }
509 
510 TFile* IOManager::OpenRootFile(const TString& filePath) {
511  auto file = TFile::Open(filePath);
512  if (!file->IsOpen()) {
513  Error("IOManager::OpenRootFile", "Failed open ROOT file: %s", filePath.Data());
514  }
515  return file;
516 }
517 
518 std::ofstream IOManager::CreateTextFile(const TString& filePath) {
519  const TString dirPath = gSystem->DirName(filePath);
520  this->MakeDir(dirPath);
521  std::ofstream file(filePath, ios::trunc);
522  if (file.is_open()) {
523  Info("IOManager::CreateTextFile", "Created ASCII file: %s", filePath.Data());
524  } else {
525  Error("IOManager::CreateTextFile", "Failed to create ASCII file: %s", filePath.Data());
526  }
527  return file;
528 }
529 
530 std::ifstream IOManager::OpenTextFile(const TString& filePath) {
531  std::ifstream file(filePath);
532  if (!file.is_open()) {
533  Error("IOManager::OpenTextFile", "Failed open ASCII file: %s", filePath.Data());
534  }
535  return file;
536 }
537 
538 
539 void IOManager::Write(const TObjArray* arr) {
540  Info(
541  "IOManager::Write", "save to a directory %s the following objects:",
542  gDirectory->GetPath()
543  );
544  for (const auto *obj: *arr) {
545  Info("", "%s", obj->GetName());
546  obj->Write();
547  }
548 }
549 
550 void IOManager::Write(TObject* obj) {
551  auto arr = new TObjArray();
552  arr->Add(obj);
553  Write(arr);
554 }
555 
556 
557 void IOManager::MakeDir(const TString& dirname) {
558  std::vector<TString> endSym= {".", "/", "~"}; // unix only
559  TString dirPath = dirname;
560  std::vector<TString> subdirs;
561  // find all subdirs
562  do {
563  subdirs.push_back(gSystem->BaseName(dirPath));
564  dirPath = gSystem->DirName(dirPath);
565  } while (dirPath != "." && dirPath != "/" && dirPath != "~"); // only unix now
566 
567  // create sequently all the subdirs
568  for (auto subdirIter = subdirs.rbegin(); subdirIter != subdirs.rend(); subdirIter++) {
569  TString subdirName = *subdirIter;
570  dirPath = gSystem->PrependPathName(dirPath, subdirName);
571  gSystem->MakeDirectory(dirPath);
572  }
573 }
574 
575 void IOManager::ChangeDir(const TString& dirname) {
576  TString dirPath = dirname;
577  fWorkDir = gSystem->PrependPathName(fWorkDir, dirPath);
578 }
579 
580 enum FileType {
581  ROOT_INPUT_REDUCED_TREE_PATH, // *.root file with only tree leaves treated in analysis
582  ROOT_MULT_SELECTED_PATH, // *.root ROOT_INPUT_REDUCED_TREE_PATH after excluding non-single multiplycity stations
583  ROOT_HIST_SPECTRA_PATH, // *.root strip histograms after multiplycity selection and cut on thresholds
584  ROOT_HIST_PEAKS_PATH, // *.root strip histograms with marked peaks found by TSpectrum and chosen algorithm
585  ROOT_HIST_PIXEL_PATH, // *.root pixel spectra histograms
586  ROOT_HIST_NON_UNIFORM_MAP_PATH, // *.root pixel effective thickness map
587  TXT_PEAK_DATA_PATH, // *.root contains three 1D histograms for low middle and high energy peaks
588  TXT_THRESHOLD_PATH, // *.txt noise thresholds for sensor
589  TXT_DEAD_LAYER_PATH, // *.txt noise thresholds for sensor
590  TXT_CALIB_COEFF_PATH, // calibration coefficients
591  TXT_REPORT_PATH, // calibration results report
592  TXT_HIGH_E_PEAK_PATH, // *.root table of high energy peak values in thick sensor
593  TXT_HIST_NON_UNIFORM_MAP_PATH // *.txt pixel effective thickness map
594 };
595 
596 class CalibIOManager: public IOManager {
597 public:
598 
599  CalibIOManager() = default;
600  CalibIOManager(const TString &workdir) = delete;
601  ~CalibIOManager() = default; // ought to be virtual
606  TString ConstructSensorFilePath(const std::set<TString>& subdirs,
607  const TString& prefix,
608  const TString& nameRoot,
609  const std::vector<SensorRunInfo*>* sensors,
610  const TString& extension = "root");
611 
616  TString ConstructFilePath(const std::set<TString>& subdirs,
617  const TString& prefix,
618  const TString& nameRoot,
619  const std::vector<SensorRunInfo*>* sensors,
620  const TString& extension = "root");
621 
628  TString GetPath(const Int_t fileType, const TString& nameRoot,
629  const std::vector<SensorRunInfo*>* sensors = nullptr);
630 
636  TString GetPath(const Int_t fileType, const TString& nameRoot,
637  const SensorRunInfo* sensor = nullptr);
638 
645  template<typename T>
646  std::vector<T> GetSensorThresholds(const SensorRunInfo* sensor,
647  const TString& runId);
648 
649  template<typename T>
650  std::vector<std::vector<T>> GetCalibCoefficients(const SensorRunInfo* sensor,
651  const TString& runId);
652 };
653 
654 // CalibIOManager::CalibIOManager(const TString &workdir)
655 // : IOManager(workdir) {
656 // }
657 
658 
659 TString CalibIOManager::ConstructFilePath(const std::set<TString>& subdirs,
660  const TString& prefix,
661  const TString& nameRoot,
662  const std::vector<SensorRunInfo*>* sensors,
663  const TString& extension = "root") {
664  TString fileName = prefix + "_" + nameRoot;
665  for (const auto *sensor: *sensors) {
666  fileName += Form("_%s", sensor->fName.Data());
667  }
668  fileName += Form(".%s", extension.Data());
669  TString dirPath = fWorkDir;
670  TString runId = nameRoot;
671  dirPath = gSystem->PrependPathName(dirPath, runId);
672  for (auto subdir: subdirs) {
673  dirPath = gSystem->PrependPathName(dirPath, subdir);
674  }
675  const TString filePath = gSystem->PrependPathName(dirPath, fileName);
676  return filePath;
677 }
678 
679 TString CalibIOManager::ConstructSensorFilePath(const std::set<TString>& subdirs,
680  const TString& prefix,
681  const TString& nameRoot,
682  const std::vector<SensorRunInfo*>* sensors,
683  const TString& extension = "root") {
684  TString fileName = prefix + "_" + nameRoot;
685  TString sensorNames = "";
686  for (const auto *sensor: *sensors) {
687  sensorNames += Form("_%s", sensor->fName.Data());
688  }
689  TString sensorSubdir = sensorNames(1, sensorNames.Length());
690  fileName += Form("%s.%s", sensorNames.Data(), extension.Data());
691  TString dirPath = fWorkDir;
692  TString runId = nameRoot;
693  dirPath = gSystem->PrependPathName(dirPath, runId);
694  dirPath = gSystem->PrependPathName(dirPath, sensorSubdir);
695  for (auto subdir: subdirs) {
696  dirPath = gSystem->PrependPathName(dirPath, subdir);
697  }
698  const TString filePath = gSystem->PrependPathName(dirPath, fileName);
699  return filePath;
700 }
701 
702 TString CalibIOManager::GetPath(const Int_t fileType,
703  const TString& nameRoot,
704  const std::vector<SensorRunInfo*>* sensors = nullptr) {
705  TString path;
706  switch (fileType) {
707  case ROOT_INPUT_REDUCED_TREE_PATH:
708  path = this->ConstructFilePath({"input"}, "input", nameRoot, sensors);
709  break;
710  case ROOT_MULT_SELECTED_PATH:
711  path = this->ConstructFilePath({"input"}, "mult_one", nameRoot, sensors);
712  break;
713  case ROOT_HIST_SPECTRA_PATH:
714  path = this->ConstructSensorFilePath(
715  {"draw"}, "spectra", nameRoot, sensors, "root"
716  );
717  break;
718  case ROOT_HIST_PEAKS_PATH:
719  path = this->ConstructSensorFilePath(
720  {"draw"}, "peaks", nameRoot, sensors, "root"
721  );
722  break;
723  case ROOT_HIST_PIXEL_PATH:
724  path = this->ConstructSensorFilePath(
725  {"draw"}, "pixels", nameRoot, sensors, "root"
726  );
727  break;
728  case ROOT_HIST_NON_UNIFORM_MAP_PATH:
729  path = this->ConstructSensorFilePath(
730  {"draw"}, "map", nameRoot, sensors, "root"
731  );
732  break;
733  case TXT_PEAK_DATA_PATH:
734  path = this->ConstructSensorFilePath(
735  {"txt"}, "peakpos", nameRoot, sensors, "txt"
736  );
737  break;
738  case TXT_THRESHOLD_PATH:
739  path = this->ConstructSensorFilePath(
740  {"txt"}, "threshold", nameRoot, sensors, "txt"
741  );
742  break;
743  case TXT_DEAD_LAYER_PATH:
744  path = this->ConstructSensorFilePath(
745  {"txt"}, "dead", nameRoot, sensors, "txt"
746  );
747  break;
748  case TXT_CALIB_COEFF_PATH:
749  path = this->ConstructSensorFilePath(
750  {"txt"}, "coeff", nameRoot, sensors, "txt"
751  );
752  break;
753  case TXT_REPORT_PATH:
754  path = this->ConstructSensorFilePath(
755  {""}, "report", nameRoot, sensors, "txt"
756  );
757  break;
758  case TXT_HIGH_E_PEAK_PATH:
759  path = this->ConstructSensorFilePath(
760  {"txt"}, "high_map", nameRoot, sensors, "txt"
761  );
762  break;
763  case TXT_HIST_NON_UNIFORM_MAP_PATH:
764  path = this->ConstructSensorFilePath(
765  {"txt"}, "map", nameRoot, sensors, "txt"
766  );
767  break;
768  }
769  return path;
770 }
771 
772 TString CalibIOManager::GetPath(const Int_t fileType,
773  const TString& nameRoot,
774  const SensorRunInfo* sensor = nullptr) {
775  std::vector<SensorRunInfo*>* sensors;
776  if (sensor == nullptr) {
777  sensors = nullptr; // new std::vector<SensorRunInfo*>;
778  } else {
779  sensors = new std::vector<SensorRunInfo*>(1, const_cast<SensorRunInfo*>(sensor));
780  }
781  TString path = GetPath(fileType, nameRoot, sensors);
782  delete sensors;
783  return path;
784 }
785 
786 template<typename T>
788  const TString& runId) {
789  const TString filePath = (sensor->fThresholdFilePath == "")
790  ? this->GetPath(TXT_THRESHOLD_PATH, runId, sensor)
791  : sensor->fThresholdFilePath;
792  auto thresholds = ReadVectorFromFile<T>(filePath);
793  return thresholds;
794 }
795 
796 template<typename T>
797 std::vector<std::vector<T>>
798 CalibIOManager::GetCalibCoefficients(const SensorRunInfo* sensor,
799  const TString& runId)
800 {
801  const TString filePath = (sensor->fCalibFilePath == "")
802  ? this->GetPath(TXT_CALIB_COEFF_PATH, runId, sensor)
803  : sensor->fCalibFilePath;
804  auto coeffs = Read2DVectorFromFile<T>(filePath);
805  return coeffs;
806 }
807 
808 class TaskManager {
816 public:
817  TaskManager() = default;
818  TaskManager(const TString& rawDataPath);
819  ~TaskManager() = default;
820 
821 
822 protected:
823  CalibIOManager *fIOManager = nullptr;
824  TString fWorkDir = "result";
825  TString fRunId = "";
826  TString fRawDataPath = "";
827 };
828 
829 TaskManager::TaskManager(const TString& rawDataPath)
830  : fIOManager(new CalibIOManager()), fRawDataPath(rawDataPath) {
831  TString rawFileNameBase = GetFileNameBaseFromPath(fRawDataPath);
832  fRunId = GetFileNameBaseFromPath(fRawDataPath);
833  fIOManager->ChangeDir(fWorkDir);
834 }
835 
836 class Preprocessing: public TaskManager {
847 public:
848  Preprocessing() = default;
849  Preprocessing(const TString& rawDataPath);
850  ~Preprocessing() = default;
851 
856  void AddSensor(SensorRunInfo* sensor) {fSensors->push_back(sensor);}
857 
868  void ConvertTree(const TString& option = "neevent");
869 
880  void FindThresholds(const TString& opt = "draw_off");
881 
889  void MultiplicitySelection(const SensorRunInfo* sensor, std::vector<SensorRunInfo*> sensorsZeroSignal = std::vector<SensorRunInfo*>());
890 
897  void MultiplicitySelection(std::vector<SensorRunInfo*> sensors, std::vector<SensorRunInfo*> sensorsZeroSignal = std::vector<SensorRunInfo*>());
898 
903  void CreateSpectraHists(const SensorRunInfo* sensor);
904 
905  void Exec();
906 
907 private:
908  std::vector<SensorRunInfo*> *fSensors = nullptr; // all the sensors are from one data file
909 };
910 
911 Preprocessing::Preprocessing(const TString& rawDataPath) : TaskManager(rawDataPath) {
912  fSensors = new std::vector<SensorRunInfo*>();
913 }
914 
915 void Preprocessing::ConvertTree(const TString& option = "neevent") {
916  if (option == "neevent") {
917  auto inFile = fIOManager->OpenRootFile(fRawDataPath);
918  const auto tree = static_cast<TTree*>(GetObjectFromRootFile(inFile));
919  Info(
920  "Preprocessing::ConvertTree", "Converting a tree '%s' from the file '%s'",
921  tree->GetName(), fRawDataPath.Data()
922  );
923  // leave in a tree sensors for analysis
924  tree->SetBranchStatus("*", 0);
925  for (const auto *sensor: *fSensors) {
926  const TString brName = Form("NeEvent.%s[%d]", sensor->fName.Data(), sensor->fStripAmount);
927  tree->SetBranchStatus(brName, 1);
928  tree->SetAlias(sensor->fName, brName);
929  }
930  const TString outFilePath = fIOManager->GetPath(ROOT_INPUT_REDUCED_TREE_PATH, fRunId, fSensors);
931  const auto outFile = fIOManager->CreateRootFile(outFilePath);
932  const auto *newtree = tree->CloneTree();
933  tree->Write();
934  outFile->Write();
935  outFile->Close();
936  inFile->Close();
937  }
938  if (option == "aqqdaq") {
939  /*aqqdaq convertion code will be here*/
940  }
941 }
942 
943 void Preprocessing::FindThresholds(const TString& opt = "draw_off") {
944  for (const auto *sensor: *fSensors) {
945  std::vector<Double_t> thersholdArray;
946  if (sensor->fNoiseThreshold > 0) {
947  thersholdArray = std::vector<Double_t>(sensor->fStripAmount, sensor->fNoiseThreshold);
948  } else { // automatic threshold search
949  thersholdArray.resize(sensor->fStripAmount);
950  // read tree from a generated input file name
951  const TString filePath = fIOManager->GetPath(ROOT_INPUT_REDUCED_TREE_PATH, fRunId, fSensors);
952  auto inFile = fIOManager->OpenRootFile(filePath);
953  const auto tree = static_cast<TTree*>(GetObjectFromRootFile(inFile));
954  Info("Preprocessing::FindThresholds", "Tree entries: %lld", tree->GetEntries());
955  // parameters exclude zero bin from a histograms because in the zero bin
956  // a high amplitude value is occured sometimes
957  const Int_t excludeBins = 1;
958  const TString histParams = Form(
959  "(%d,%d,%d)", sensor->fBinAmount - excludeBins, excludeBins, sensor->fBinAmount
960  );
961  for (Int_t iStrip = 0; iStrip < sensor->fStripAmount; iStrip++) {
962  const TString histName = Form("threshold_strip_%d", iStrip);
963  const TString drawExpression = Form(
964  "%s[%d]>>%s%s", sensor->fName.Data(), iStrip, histName.Data(), histParams.Data()
965  );
966  tree->Draw(drawExpression,"","");
967  const TH1F *histThreshold = static_cast<TH1F*>(gDirectory->Get(histName));
968  const Int_t binsAmount = histThreshold->GetXaxis()->GetNbins();
969  // Get a number of a bin with the maximal amplitude
970  const Int_t maxBinNb = histThreshold->GetMaximumBin();
971  Bool_t minBinObtained = false;
972  Int_t thresholdBinNb = 0;
973  Int_t prevBinContent = histThreshold->GetBinContent(maxBinNb);
974  // Starting from the maximum value bin, find the first bin with not decreasing value
975  for (Int_t binNb = maxBinNb + 1; binNb < binsAmount && !minBinObtained; binNb++) {
976  const Int_t binContent = histThreshold->GetBinContent(binNb);
977  if (prevBinContent <= binContent) {
978  minBinObtained = true;
979  thresholdBinNb = binNb;
980  }
981  prevBinContent = binContent;
982  }
983  thersholdArray[iStrip] = --thresholdBinNb;
984  }
985  inFile->Close();
986  }
987  const TString thresholdsPath = fIOManager->GetPath(TXT_THRESHOLD_PATH, fRunId, sensor);
988  auto file = fIOManager->CreateTextFile(thresholdsPath);
989  DumpVector(thersholdArray, file);
990  file.close();
991  }
992 }
993 
995  const SensorRunInfo* sensor, std::vector<SensorRunInfo*> sensorsZeroSignal = std::vector<SensorRunInfo*>()) {
996  // Read input file
997  const TString inFilePath = fIOManager->GetPath(ROOT_INPUT_REDUCED_TREE_PATH, fRunId, fSensors);
998  auto inFile = fIOManager->OpenRootFile(inFilePath);
999  const auto inTree = static_cast<TTree*>(GetObjectFromRootFile(inFile));
1000  // Create output file and tree
1001  const TString outFilePath = fIOManager->GetPath(ROOT_MULT_SELECTED_PATH, fRunId, fSensors);
1002  auto outFile = fIOManager->CreateRootFile(outFilePath);
1003  TTree *outTree = new TTree(inTree->GetName(), "Tree with a single multiplicity");
1004  // Create internal tree objects structure
1005  inTree->SetMakeClass(1);
1006  std::vector<UShort_t> sensorData = std::vector<UShort_t>(sensor->fStripAmount);
1007  std::vector<UShort_t> sensorThresholds = fIOManager->GetSensorThresholds<UShort_t>(sensor, fRunId);
1008  TString brName = inTree->GetAlias(sensor->fName);
1009  inTree->SetBranchAddress(brName, &(sensorData[0]));
1010  outTree->Branch(sensor->fName, &(sensorData[0]), brName + "/s");
1011 
1012  auto *zeroSignalSensorData = new std::vector<std::vector<UShort_t>>();
1013  auto *zeroSignalSensorThresholds = new std::vector<std::vector<UShort_t>>();
1014  for (const auto *zeroSignalSensor: sensorsZeroSignal) {
1015  zeroSignalSensorData->push_back(std::vector<UShort_t>(zeroSignalSensor->fStripAmount));
1016  TString branchName = inTree->GetAlias(zeroSignalSensor->fName);
1017  inTree->SetBranchAddress(branchName, &(zeroSignalSensorData->back()[0]));
1018  // Connect data variables with tree branches
1019  outTree->Branch(zeroSignalSensor->fName, &(zeroSignalSensorData->back()[0]), branchName + "/s");
1020  // Read sensor's thresholds
1021  auto sensorThresholds = fIOManager->GetSensorThresholds<UShort_t>(zeroSignalSensor, fRunId);
1022  zeroSignalSensorThresholds->push_back(sensorThresholds);
1023  }
1024  Info("Preprocessing::MultiplicitySelection", "Begin multiplicity selection");
1025  Info("Preprocessing::MultiplicitySelection", "Input tree entries: %lld", inTree->GetEntries());
1026  for (Long64_t eventNb = 0; eventNb < inTree->GetEntries(); eventNb++) {
1027  inTree->GetEntry(eventNb);
1028  bool saveEvent = true;
1029  const int sensorMult = CheckDataMultiplicity(sensorData, sensorThresholds);
1030  if (sensorMult != 1) {
1031  saveEvent = false;
1032  continue;
1033  }
1034  for (int j = 0; j < sensorsZeroSignal.size(); j++) {
1035  int multiplicityNoSignalSensor = CheckDataMultiplicity(zeroSignalSensorData->at(j), zeroSignalSensorThresholds->at(j));
1036  if (multiplicityNoSignalSensor != 0) {
1037  saveEvent = false;
1038  }
1039  }
1040  if (saveEvent) {
1041  outTree->Fill();
1042  } else {
1043  continue;
1044  }
1045  }
1046  Info("Preprocessing::MultiplicitySelection", "Output tree entries: %lld", outTree->GetEntries());
1047  outTree->Write();
1048  outFile->Write();
1049  outFile->Close();
1050  inFile->Close();
1051  CreateSpectraHists(sensor);
1052 }
1053 
1054 void Preprocessing::MultiplicitySelection(std::vector<SensorRunInfo*> sensors,
1055  std::vector<SensorRunInfo*> sensorsZeroSignal = std::vector<SensorRunInfo*>()) {
1056  // Read input file
1057  const TString inFilePath = fIOManager->GetPath(ROOT_INPUT_REDUCED_TREE_PATH, fRunId, fSensors);
1058  auto inFile = fIOManager->OpenRootFile(inFilePath);
1059  const auto inTree = static_cast<TTree*>(GetObjectFromRootFile(inFile));
1060  // Create output file and tree
1061  const TString outFilePath = fIOManager->GetPath(ROOT_MULT_SELECTED_PATH, fRunId, fSensors);
1062  auto outFile = fIOManager->CreateRootFile(outFilePath);
1063  TTree *outTree = new TTree(inTree->GetName(), "Tree with a single multiplicity");
1064  // Create internal tree objects structure
1065  inTree->SetMakeClass(1);
1066 
1067  std::vector<std::vector<UShort_t>> sensorsData;
1068  std::vector<std::vector<UShort_t>> sensorsThresholds;
1069 
1070  for (const auto &sensor: sensors) {
1071  sensorsData.push_back(std::vector<UShort_t>(sensor->fStripAmount));
1072  sensorsThresholds.push_back(fIOManager->GetSensorThresholds<UShort_t>(sensor, fRunId));
1073  TString brName = inTree->GetAlias(sensor->fName);
1074  inTree->SetBranchAddress(brName, &(sensorsData.back()[0]));
1075  outTree->Branch(sensor->fName, &(sensorsData.back()[0]), brName + "/s");
1076  }
1077 
1078 
1079  auto *zeroSignalSensorData = new std::vector<std::vector<UShort_t>>();
1080  auto *zeroSignalSensorThresholds = new std::vector<std::vector<UShort_t>>();
1081  for (const auto *zeroSignalSensor: sensorsZeroSignal) {
1082  zeroSignalSensorData->push_back(std::vector<UShort_t>(zeroSignalSensor->fStripAmount));
1083  TString branchName = inTree->GetAlias(zeroSignalSensor->fName);
1084  inTree->SetBranchAddress(branchName, &(zeroSignalSensorData->back()[0]));
1085  // Connect data variables with tree branches
1086  outTree->Branch(zeroSignalSensor->fName, &(zeroSignalSensorData->back()[0]), branchName + "/s");
1087  // Read sensor's thresholds
1088  auto sensorThresholds = fIOManager->GetSensorThresholds<UShort_t>(zeroSignalSensor, fRunId);
1089  zeroSignalSensorThresholds->push_back(sensorThresholds);
1090  }
1091  Info("Preprocessing::MultiplicitySelection", "Begin multiplicity selection");
1092  Info("Preprocessing::MultiplicitySelection", "Input tree entries: %lld", inTree->GetEntries());
1093  for (Long64_t eventNb = 0; eventNb < inTree->GetEntries(); eventNb++) {
1094  inTree->GetEntry(eventNb);
1095  bool saveEvent = true;
1096  if (!(eventNb % 100000)) {
1097  std::cout << "Event number " << eventNb << std::endl;
1098  }
1099  for (int sensorNb = 0; sensorNb < sensors.size(); sensorNb++) {
1100  const int sensorMult = CheckDataMultiplicity(sensorsData[sensorNb], sensorsThresholds[sensorNb]);
1101  if (sensorMult != 1) {
1102  saveEvent = false;
1103  break;
1104  }
1105  for (int j = 0; j < sensorsZeroSignal.size(); j++) {
1106  int multiplicityNoSignalSensor = CheckDataMultiplicity(zeroSignalSensorData->at(j), zeroSignalSensorThresholds->at(j));
1107  if (multiplicityNoSignalSensor != 0) {
1108  saveEvent = false;
1109  break;
1110  }
1111  }
1112  }
1113  if (saveEvent) {
1114  outTree->Fill();
1115  } else {
1116  continue;
1117  }
1118  }
1119  Info("Preprocessing::MultiplicitySelection", "Output tree entries: %lld", outTree->GetEntries());
1120  outTree->Write();
1121  outFile->Write();
1122  outFile->Close();
1123  inFile->Close();
1124  for (int sensorNb = 0; sensorNb < sensors.size(); sensorNb++) {
1125  CreateSpectraHists(sensors[sensorNb]);
1126  }
1127 }
1128 
1129 
1131  const TString multSelectPath = fIOManager->GetPath(ROOT_MULT_SELECTED_PATH, fRunId, fSensors);
1132  auto inFile = fIOManager->OpenRootFile(multSelectPath);
1133  const auto tree = static_cast<TTree*>(GetObjectFromRootFile(inFile));
1134  auto thresholds = fIOManager->GetSensorThresholds<UShort_t>(sensor, fRunId);
1135  const TString histSpectraPath = fIOManager->GetPath(ROOT_HIST_SPECTRA_PATH, fRunId, sensor);
1136  auto histSpectraFile = fIOManager->CreateRootFile(histSpectraPath);
1137  DrawSensorSpectraByStrip(tree, sensor, thresholds);
1138  histSpectraFile->Close();
1139  inFile->Close();
1140 }
1141 
1142 void Preprocessing::Exec() {
1143  // ConvertTree();
1144  Error("Preprocessing::Exec", "Method is obsolete, please use the sequence:");
1145  Error("Preprocessing::Exec", " ConvertTree() -> FindThresholds() -> MultiplicitySelection()");
1146  // FindThresholds();
1147  // MultiplicitySelection();
1148 }
1149 
1150 class PeakSearch {
1151 public:
1152  enum PeakSearchAlgorithm {
1153  SLIDING_WINDOW,
1154  GAUSS
1155  };
1156 
1157  PeakSearch() = default;
1158  ~PeakSearch() = default;
1159 
1160  void SetPeakSearchMethod(const TString& peakSearchAlgorithm);
1161  void SetFitMinSigma(const Double_t value) {fFitMinSigma = value;}
1162  void SetFitPeakThreshold(const Double_t value) {fFitPeakThreshold = value;}
1163  void SetSearchRadius(const Int_t value) {fSearchRadius = value;}
1164  void SetSlideWindowWidth(const Int_t value) {fSlideWindowWidth = value;}
1169  std::list<Double_t> GetPeaksTSpectrum(TH1* hist,
1170  const Double_t fitMinSigma,
1171  const Double_t fitPeakThreshold);
1172 
1194  std::list<Double_t> SlidingWindowPeakSearch(TH1* hist, const std::list<Double_t>& initGuess,
1195  const Int_t windowWidth,
1196  const Int_t searchRadius);
1197 
1213  std::list<Double_t> GaussPeakSearch(TH1* hist, const std::list<Double_t>& initGuess,
1214  const Int_t searchRadius);
1215 
1222  std::list<Double_t> GetPeaks(TH1* hist, const std::list<Double_t>& initGuess);
1223 
1224 protected:
1225  Int_t fPeakSearchMethod = SLIDING_WINDOW;
1226  // Peak search algoritm common parameters
1227  Double_t fFitMinSigma = 6.;
1228  Double_t fFitPeakThreshold = 0.7;
1229 
1230  Int_t fSearchRadius = 10; // radius of algorithm search aroun initial guess points (applicable for Sliding window (SW) and Gauss)
1231  Int_t fSlideWindowWidth = 10; // sliding window width (applicable for SW)
1232 
1233  std::vector<std::vector<float>> fIntegralInWindow; // stores events integral for peaks found by SLIDINIG_WINDOW algorithm
1234 };
1235 
1236 void PeakSearch::SetPeakSearchMethod(const TString& peakSearchAlgorithm) {
1237  if (peakSearchAlgorithm == "sliding_window") {
1238  fPeakSearchMethod = SLIDING_WINDOW;
1239  }
1240  if (peakSearchAlgorithm == "gauss") {
1241  fPeakSearchMethod = GAUSS;
1242  }
1243 }
1244 
1245 
1246 std::list<Double_t> PeakSearch::GetPeaksTSpectrum(TH1* hist,
1247  const Double_t fitMinSigma,
1248  const Double_t fitPeakThreshold)
1249 {
1250  TSpectrum sc;
1251  sc.Search(hist, fitMinSigma, "", fitPeakThreshold);
1252  const Int_t peaksAmount = sc.GetNPeaks();
1253  Info("PeakSearch::GetPeaksTSpectrum", "Occured peaks amount is %d", peaksAmount);
1254  Double_t* peaksPos = sc.GetPositionX();
1255  std::list<Double_t> peaks(peaksPos, peaksPos + peaksAmount);
1256  peaks.sort();
1257  // remove markers from the histogram
1258  // auto functions = hist->GetListOfFunctions();
1259  // auto pm = static_cast<TPolyMarker*>(functions->FindObject("TPolyMarker"));
1260  // functions->Remove(pm);
1261  return peaks;
1262 }
1263 
1264 
1265 std::list<Double_t>
1266 PeakSearch::SlidingWindowPeakSearch(TH1* hist, const std::list<Double_t>& initGuess,
1267  const Int_t windowWidth,
1268  const Int_t searchRadius)
1269 {
1270  std::list<Double_t> peaks;
1271  std::vector<float> peaksIntegral;
1272  for (const auto& guessPos: initGuess) {
1273  // gStyle->SetStatFormat("6.8g");
1274  const Int_t peakBinNb = hist->GetXaxis()->FindBin(guessPos);
1275  Int_t maxIntegral = numeric_limits<Int_t>::min();
1276  Double_t peakMean;
1277  // Double_t peakRMS;
1278  for (Int_t i = peakBinNb - searchRadius; i < peakBinNb + searchRadius - windowWidth; i++) {
1279  hist->GetXaxis()->SetRange(i, i + windowWidth - 1 /*to not include the last bin*/);
1280  const Int_t integral = hist->Integral();
1281  if (maxIntegral < integral) {
1282  maxIntegral = integral;
1283  peakMean = hist->GetMean();
1284  // peakRMS = hist->GetStdDev();
1285  }
1286  }
1287  peaksIntegral.push_back(maxIntegral);
1288  peaks.push_back(peakMean);
1289  }
1290  fIntegralInWindow.push_back(peaksIntegral);
1291  return peaks;
1292 }
1293 
1294 std::list<Double_t>
1295 PeakSearch::GaussPeakSearch(TH1* hist, const std::list<Double_t>& initGuess,
1296  const Int_t searchRadius)
1297 {
1298  std::list<Double_t> peaks;
1299  for (const auto& guessPos: initGuess) {
1300  // get bin position
1301  const Int_t peakBinNb = hist->GetXaxis()->FindBin(guessPos);
1302  // make initial 'clear' gauss fit
1303  auto gausInit = new TF1("gausInit", "gaus", peakBinNb - searchRadius,
1304  peakBinNb + searchRadius);
1305  auto fitRes = hist->Fit("gausInit", "RS");
1306  // make gauss + pol1 fit based on initial preliminary clear gauss fit
1307  auto gausPol = new TF1("gausPol", "gaus(0) + pol1(3)", peakBinNb - searchRadius,
1308  peakBinNb + searchRadius);
1309  gausPol->SetParameter(0, fitRes->Parameter(0)); // constant (height)
1310  gausPol->SetParameter(1, fitRes->Parameter(1)); // mean
1311  gausPol->SetParameter(2, fitRes->Parameter(2)); // sigma
1312  fitRes = hist->Fit("gausPol", "RS+");
1313  peaks.push_back(fitRes->Parameter(1));
1314  }
1315  return peaks;
1316 }
1317 
1318 std::list<Double_t> PeakSearch::GetPeaks(TH1* hist, const std::list<Double_t>& initGuess) {
1319  std::list<Double_t> peaks;
1320  switch (fPeakSearchMethod) {
1321  case SLIDING_WINDOW:
1322  peaks = SlidingWindowPeakSearch(hist, initGuess, fSlideWindowWidth, fSearchRadius);
1323  break;
1324  case GAUSS:
1325  peaks = GaussPeakSearch(hist, initGuess, fSearchRadius);
1326  break;
1327  default:
1328  Error("PeakSearch::SearchPeaks", "Unknown peak search method is set");
1329  }
1330  // restore hist range
1331  hist->GetXaxis()->SetRange(0, hist->GetXaxis()->GetNbins());
1332  // std::sort(peaks.begin(), peaks.end(), [](const Double_t& first,const Double_t& second) {
1333  // return first < second;
1334  // });
1335  peaks.sort();
1336  for (const auto &peak: peaks) {
1337  std::cout << peak << " ";
1338  }
1339  std::cout << std::endl;
1340  return peaks;
1341 }
1342 
1346 const static std::vector<Double_t> fAlphaE = {4.7844, 6.0024, 7.6869};
1351 const static std::vector<std::vector<Double_t>> fElossApprox = {{0.0010319, 0.146954, 0.00181655},
1352  {0.0004273, 0.127711, 0.00106127},
1353  {0.0001624, 0.108467, 0.000589357}};
1354 
1355 class Calibration: public TaskManager, public PeakSearch {
1356 /* @class Calibration
1357  @brief Class implements SSD calibration procedure described
1358  in http://er.jinr.ru/si_detector_calibration.html.
1359 */
1360 public:
1361  Calibration() = default;
1362  Calibration(const TString& rawDataPath);
1363  ~Calibration() = default;
1364 
1365  void SetSensor(SensorRunInfo* sensor) {fSensor = sensor;}
1372  void Exec();
1373 
1374  void SearchPeaks();
1375 
1376  void DeadLayerEstimation();
1377  void CalcCalibrationCoefficients(Bool_t fitLastTwoPoints = false);
1378 
1379  /* Set path containing user's custom spectra. If set, prepocessing results are ignored,
1380  only spectra from the defined folder are used.
1381  */
1382  void SetPathToCustomSpectra(const TString& path) {fSpectraHistPath = path;}
1383 
1384 protected:
1398  void PrintReport(const std::vector<std::vector<Double_t>>& peaks,
1399  const std::vector<Double_t>& deadVec,
1400  const Double_t avgDead,
1401  const std::vector<std::vector<Double_t>>& coeffsAB);
1402 
1403  std::vector<Double_t> GetAlphaEnergiesAfterDeadLayer (const Double_t dead);
1404 
1405 
1412  Double_t GetDeadLayerByEta (const Double_t eta);
1413 
1414 protected:
1415  TString fSpectraHistPath = "";
1416  SensorRunInfo* fSensor = nullptr;
1417 };
1418 
1419 Calibration::Calibration(const TString& rawDataPath) : TaskManager(rawDataPath) {
1420  fSensor = new SensorRunInfo();
1421 }
1422 
1423 void Calibration::SearchPeaks() {
1424  if (fSpectraHistPath == "") {
1425  fSpectraHistPath = fIOManager->GetPath(ROOT_HIST_SPECTRA_PATH, fRunId, fSensor);
1426  }
1427  const auto histFile = fIOManager->OpenRootFile(fSpectraHistPath);
1428 
1429  const TString peaksHistPath = fIOManager->GetPath(ROOT_HIST_PEAKS_PATH, fRunId, fSensor);
1430  const auto peakHists = fIOManager->CreateRootFile(peaksHistPath);
1431 
1432  std::vector<std::list<Double_t>> peaks;
1433  for (Int_t iStrip = 0; iStrip < fSensor->fStripAmount; iStrip++) {
1434  const TString histName = Form("strip_%d", iStrip);
1435  // const auto hist = static_cast<TH1D*>(GetObjectFromRootFile(histFile, histName));
1436  // TODO: check if hists in file deordered and we should not get object by key id
1437  const auto hist = static_cast<TH1D*>(GetObjectFromRootFile(histFile, iStrip));
1438  if (fSensor->fNoiseThreshold > 0) {
1439  hist->GetXaxis()->SetRange(fSensor->fNoiseThreshold, fSensor->fBinAmount);
1440  }
1441  const auto peaksTSpec = GetPeaksTSpectrum(hist, fFitMinSigma, fFitPeakThreshold);
1442  auto stripPeaks = GetPeaks(hist, peaksTSpec);
1443  if (stripPeaks.size() == 4) {
1444  // delete the second element from the list
1445  auto itDelete = stripPeaks.begin();
1446  std::advance(itDelete, 1);
1447  stripPeaks.erase(itDelete);
1448  } else {
1449  Warning(
1450  "Calibration::SearchPeaks", "Found peaks amount doesn't equal 4 (%zu)", stripPeaks.size()
1451  );
1452  Warning("Calibration::SearchPeaks", "By default values are set to Nan");
1453  stripPeaks.clear();
1454  stripPeaks = std::list<Double_t>(3, std::numeric_limits<double>::quiet_NaN());
1455  }
1456  peaks.push_back(stripPeaks);
1457  hist->Write();
1458  }
1459 
1460  const TString peakDataPath = fIOManager->GetPath(TXT_PEAK_DATA_PATH, fRunId, fSensor);
1461  // @TODO add methods to set peak markers on histograms
1462  auto peaksFile = fIOManager->CreateTextFile(peakDataPath);
1463  Dump2DVector(peaks, peaksFile);
1464  peaksFile.close();
1465  histFile->Close();
1466 }
1467 
1468 Double_t Calibration::GetDeadLayerByEta (const Double_t eta) {
1469  // quad fit for elosses caliculated with 1e-5um step
1470  return (-5272.9763 + 19011.5041 * eta - 17102.8129 * eta * eta);
1471 }
1472 
1473 
1474 void Calibration::DeadLayerEstimation() {
1475  // read peaks from file
1476  const TString peakDataPath = fIOManager->GetPath(TXT_PEAK_DATA_PATH, fRunId, fSensor);
1477  auto peaksFile = fIOManager->OpenTextFile(peakDataPath);
1478  auto peaks = Read2DDoubleVectorFromFile(peakDataPath);
1479 
1480  vector<Double_t> deadVec;
1481  for (const auto stripPeaks: peaks) {
1482  const Double_t eta = (stripPeaks[2] - stripPeaks[1]) / (stripPeaks[2] - stripPeaks[0]);
1483  const Double_t deadLayer = GetDeadLayerByEta(eta); // [um]
1484  deadVec.push_back(deadLayer);
1485  }
1486 
1487  const TString deadPath = fIOManager->GetPath(TXT_DEAD_LAYER_PATH, fRunId, fSensor);
1488  auto file = fIOManager->CreateTextFile(deadPath);
1489  DumpVector(deadVec, file);
1490 }
1491 
1492 std::vector<Double_t> Calibration::GetAlphaEnergiesAfterDeadLayer (const Double_t dead) {
1493  std::vector<Double_t> energies;
1494  for (Int_t i = 0; i < fElossApprox.size(); i++) {
1495  const Double_t energy = fAlphaE[i]
1496  - fElossApprox[i][2] * pow(dead, 2)
1497  - fElossApprox[i][1] * dead
1498  - fElossApprox[i][0];
1499  energies.push_back(energy);
1500  }
1501  return energies;
1502 }
1503 
1504 void Calibration::CalcCalibrationCoefficients(Bool_t fitOnlyLastTwoPointsNvsE = false) {
1505  // read peaks from file
1506  const TString peakDataPath = fIOManager->GetPath(TXT_PEAK_DATA_PATH, fRunId, fSensor);
1507  auto peaks = Read2DDoubleVectorFromFile(peakDataPath);
1508  std::vector<Double_t> deadVec;
1509  std::vector<std::vector<Double_t>> energies;
1510  Double_t avgDead;
1511  if (fSensor->fIsDeadLayerPerStripsSet) {
1512  for (Int_t iStrip = 0; iStrip < fSensor->fStripAmount; iStrip++) {
1513  energies.push_back(GetAlphaEnergiesAfterDeadLayer(fSensor->fDeadLayers[iStrip]));
1514  deadVec = fSensor->fDeadLayers;
1515  avgDead = CalculateAvg(deadVec);
1516  }
1517  } else {
1518  // read dead layers from file
1519  const TString deadDataPath = fIOManager->GetPath(TXT_DEAD_LAYER_PATH, fRunId, fSensor);
1520  deadVec = ReadDoubleVectorFromFile(deadDataPath);
1521  avgDead = CalculateAvg(deadVec);
1522  auto energies_avg = GetAlphaEnergiesAfterDeadLayer(avgDead);
1523  for (Int_t iStrip = 0; iStrip < fSensor->fStripAmount; iStrip++) {
1524  energies.push_back(energies_avg);
1525  }
1526  }
1527 
1528  std::vector<std::vector<Double_t>> coeffsAB;
1529  for (Int_t iStrip = 0; iStrip < peaks.size(); iStrip++) {
1530  TGraph* gr = (fitOnlyLastTwoPointsNvsE)
1531  ? new TGraph(energies[0].size() - 1, &peaks[iStrip][1], &energies[iStrip][1])
1532  : new TGraph(energies[0].size(), &peaks[iStrip][0], &energies[iStrip][0]);
1533  TFitResultPtr fitRes = gr->Fit("pol1","S");
1534  const Double_t a = fitRes->Parameter(1);
1535  const Double_t b = fitRes->Parameter(0);
1536  std::vector<Double_t> coeffs = {a, b};
1537  coeffsAB.push_back(coeffs);
1538  }
1539 
1540  const TString calibPath = fIOManager->GetPath(TXT_CALIB_COEFF_PATH, fRunId, fSensor);
1541  auto fileCalib = fIOManager->CreateTextFile(calibPath);
1542  Dump2DVector(coeffsAB, fileCalib);
1543  fileCalib.close();
1544 
1545  PrintReport(peaks, deadVec, avgDead, coeffsAB);
1546 }
1547 
1548 void Calibration::PrintReport(const std::vector<std::vector<Double_t>>& peaks,
1549  const std::vector<Double_t>& deadVec,
1550  const Double_t avgDead,
1551  const std::vector<std::vector<Double_t>>& coeffsAB) {
1552  const TString reportPath = fIOManager->GetPath(TXT_REPORT_PATH, fRunId, fSensor);
1553  auto report = fIOManager->CreateTextFile(reportPath);
1554  report << std::right;
1555  report << "Calibration results. " << endl << endl;
1556  report << "File ID is " << fRunId << endl;
1557  if (fPeakSearchMethod == SLIDING_WINDOW) {
1558  report << "Peak search method: SLIDING_WINDOW" << endl;
1559  report << "Sliding window algorithm parameters: " << endl;
1560  report << " window width: " << fSlideWindowWidth << endl;
1561  report << " search region around TSpectrum peak: +-" << fSearchRadius << endl;
1562  report << " peak RMS: " << fFitMinSigma << endl;
1563  report << " peak amplitude threshold (with respect to maximal): "
1564  << fFitPeakThreshold << endl;
1565  }
1566  if (fPeakSearchMethod == GAUSS) {
1567  report << "Peak search method: GAUSS (gaus + pol1)" << endl;
1568  report << "Algorithm parameters: " << endl;
1569  report << " search region around TSpectrum peak: +-" << fSearchRadius << endl;
1570  report << " peak RMS: " << fFitMinSigma << endl;
1571  report << " peak amplitude threshold (with respect to maximal): "
1572  << fFitPeakThreshold << endl;
1573  }
1574  report << endl;
1575  report << "Determined peak positions (in [ADC-channels]):" << endl;
1576  report << "StripNb" << std::right
1577  << setw(20) << "E_low"
1578  << setw(20) << "E_middle"
1579  << setw(20) << "E_high" << endl;
1580  Int_t iStrip = 0;
1581  for (const auto& stripPeaks: peaks) {
1582  report << iStrip++ << std::right
1583  << setw(20) << stripPeaks[0]
1584  << setw(20) << stripPeaks[1]
1585  << setw(20) << stripPeaks[2] << endl;
1586  }
1587  report << endl;
1588 
1589  report << "Integral over the window ([Counts]):" << endl;
1590  report << "StripNb" << std::right
1591  << setw(20) << "E_low"
1592  << setw(20) << "E_middle"
1593  << setw(20) << "E_high" << endl;
1594  iStrip = 0;
1595  for (const auto& integral: fIntegralInWindow) {
1596  report << iStrip++ << std::right
1597  << setw(20) << integral[0]
1598  << setw(20) << integral[1]
1599  << setw(20) << integral[2] << endl;
1600  }
1601  report << endl;
1602 
1603  report << "Dead layer estimation [um] by strips: " << endl;
1604  report << "StripNb" << setw(20) << "Dead layer"<< endl;
1605  iStrip = 0;
1606  for (const auto& dead: deadVec) {
1607  report << iStrip++ << std::right
1608  << setw(20) << dead << endl;
1609  }
1610  report << "Avg:" << setw(20) << avgDead << endl;
1611  report << "Max-Min:" << setw(20)
1612  << *std::max_element(deadVec.begin(), deadVec.end()) - *std::min_element(deadVec.begin(), deadVec.end()) << endl;
1613  report << endl;
1614  report << "Calibration coefficients: " << endl;
1615  report << "StripNb" << std::right
1616  << setw(20) << "a"
1617  << setw(20) << "b"<< endl;
1618  iStrip = 0;
1619  for (const auto& stripCoeffsAB: coeffsAB) {
1620  report << iStrip++ << std::right
1621  << setw(20) << stripCoeffsAB[0]
1622  << setw(20) << stripCoeffsAB[1] << endl;
1623  }
1624  report.close();
1625 }
1626 
1628  SearchPeaks();
1629  DeadLayerEstimation();
1630  CalcCalibrationCoefficients();
1631 }
1632 
1634 public:
1635  NonUniformityMapBuilder() = default;
1636  NonUniformityMapBuilder(const TString& mapRunDataPath);
1637  ~NonUniformityMapBuilder() = default;
1638 
1639  void SetThickSensor(SensorRunInfo* sensor) {fMapSensors->at(0) = sensor;}
1640  void SetThinSensor(SensorRunInfo* sensor) {fMapSensors->at(1) = sensor;}
1641  void SetThickCalibSensor(SensorRunInfo* sensor) {fSensorCalib = sensor;}
1642 
1649  void DrawPixelSpectra();
1650  void SearchPixelHighEnergyPeak();
1651  void CreateThinSensorMap();
1652  void Exec();
1653 private:
1654  // fMapSensors->at(0) - thick sensor info, fMapSensors->at(1) - thin sensor info
1655  std::vector<SensorRunInfo*>* fMapSensors = new std::vector<SensorRunInfo*>(2, nullptr);
1656  SensorRunInfo* fSensorCalib = nullptr; // info about thick sensor from a calibration run
1657 };
1658 
1659 NonUniformityMapBuilder::NonUniformityMapBuilder(const TString& mapRunDataPath)
1660  : TaskManager(mapRunDataPath) {
1661 }
1662 
1663 
1664 void NonUniformityMapBuilder::Exec() {
1665  DrawPixelSpectra();
1666  SearchPixelHighEnergyPeak();
1667  CreateThinSensorMap();
1668 }
1669 
1670 
1671 // Quadratic approximation of the D(dE)
1672 // by dead layer points 8, 12, 16, 20, 24, 28, 32, 36 um
1673 // for the 7.6869 MeV alpha-particle
1674 // D(dE) = p0 + p1*dE + p2*dE^2,
1675 // where D - effective dead layer high energy alpha-particle passes through [um],
1676 // dE - energy loss [MeV]
1677 const std::vector<double> quad_coeffs = {0.159428, 0.0837999, 0.0014907}; // highE
1678 // Cubic approximation of the D(dE)
1679 // by dead layer points 8, 12, 16, 20, 24, 28, 32, 36 um
1680 // for the 7.6869 MeV alpha-particle
1681 // D(dE) = p0 + p1*dE + p2*dE^2 + p3*dE^3,
1682 // where D - effective dead layer high energy alpha-particle passes through [um],
1683 // dE - energy loss [MeV]
1684 const std::vector<double> cube_coeffs = {0.00805579, 9.18781, -0.401229, -0.0044059};
1685 
1693 double GetThicknessByHighElossQuad(double dE) {
1694  return (-quad_coeffs[1] + sqrt(pow(quad_coeffs[1], 2)
1695  - 4*quad_coeffs[2]*(quad_coeffs[0] - dE)))
1696  / (2 * quad_coeffs[2]);
1697 }
1698 
1706 double GetThicknessByHighElossCubic (double dE) {
1707  return cube_coeffs[0] + cube_coeffs[1]*dE
1708  + cube_coeffs[2] * pow(dE, 2)
1709  + cube_coeffs[3] * pow(dE, 3);
1710 }
1711 
1712 
1714  // Get input tree
1715  const TString multSelectPath = fIOManager->GetPath(
1716  ROOT_MULT_SELECTED_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1717  );
1718  auto multSelectFile = fIOManager->OpenRootFile(multSelectPath);
1719  auto tree = static_cast<TTree*>(GetObjectFromRootFile(multSelectFile));
1720  // Create output file
1721  const TString pixelSpectraPath = fIOManager->GetPath(
1722  ROOT_HIST_PIXEL_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1723  );
1724  auto outFile = fIOManager->CreateRootFile(pixelSpectraPath);
1725  // Read thresholds
1726  const TString thresholdThickPath = fIOManager->GetPath(
1727  TXT_THRESHOLD_PATH, fMapSensors->at(0)->fRunId, fMapSensors->at(0)
1728  );
1729  const TString thresholdThinPath = fIOManager->GetPath(
1730  TXT_THRESHOLD_PATH, fMapSensors->at(1)->fRunId, fMapSensors->at(1)
1731  );
1732  const auto thresholdThick = ReadVectorFromFile<UShort_t>(thresholdThickPath);
1733  const auto thresholdThin = ReadVectorFromFile<UShort_t>(thresholdThinPath);
1734 
1735  DrawSensorSpectraByPixel(tree, fMapSensors->at(0), fMapSensors->at(1),
1736  thresholdThick, thresholdThin);
1737  multSelectFile->Close();
1738  outFile->Close();
1739 }
1740 
1741 void NonUniformityMapBuilder::SearchPixelHighEnergyPeak() {
1742  const TString pixelSpectraPath = fIOManager->GetPath(
1743  ROOT_HIST_PIXEL_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1744  );
1745  auto histFile = fIOManager->OpenRootFile(pixelSpectraPath);
1746 
1747  const TString peaksHistPath = fIOManager->GetPath(
1748  ROOT_HIST_PEAKS_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1749  );
1750  const auto peakHists = fIOManager->CreateRootFile(peaksHistPath);
1751 
1752  std::vector<std::vector<Double_t>> peaks;
1753  for (Int_t iStripThick = 0; iStripThick < fMapSensors->at(0)->fStripAmount; iStripThick++) {
1754  std::vector<Double_t> stripPeaks;
1755  for (Int_t iStripThin = 0; iStripThin < fMapSensors->at(1)->fStripAmount; iStripThin++) {
1756  const auto pixelName = Form("%s[%d]_%s[%d]", fMapSensors->at(0)->fName.Data(),
1757  iStripThick,
1758  fMapSensors->at(1)->fName.Data(),
1759  iStripThin);
1760  Info("SearchPixelHighEnergyPeak", "Search high energy peak in pixel %s", pixelName);
1761  const auto histName = Form("pixel_%s", pixelName);
1762  const auto hist = static_cast<TH1D*>(GetObjectFromRootFile(histFile, histName));
1763  const auto peaksTSpec = GetPeaksTSpectrum(hist, fFitMinSigma, fFitPeakThreshold);
1764  auto pixelPeaks = GetPeaks(hist, peaksTSpec);
1765  Double_t peakPos;
1766  if (pixelPeaks.size()) {
1767  peakPos = pixelPeaks.back();
1768  } else {
1769  Warning("Calibration::SearchPeaks", "Peaks are not found");
1770  Warning("Calibration::SearchPeaks", "By default value is set to Nan");
1771  peakPos = std::numeric_limits<double>::quiet_NaN();
1772  }
1773  stripPeaks.push_back(peakPos);
1774  hist->Write();
1775  }
1776  peaks.push_back(stripPeaks);
1777  }
1778  const TString highEPeaksPath = fIOManager->GetPath(
1779  TXT_HIGH_E_PEAK_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1780  );
1781  auto peaksFile = fIOManager->CreateTextFile(highEPeaksPath);
1782  Dump2DVector(peaks, peaksFile);
1783  peaksFile.close();
1784  histFile->Close();
1785  peakHists->Close();
1786 }
1787 
1788 void NonUniformityMapBuilder::CreateThinSensorMap() {
1789  // read data for a thin sensor effective thickness map building
1790  const TString pixelPeakMapPath = fIOManager->GetPath(
1791  TXT_HIGH_E_PEAK_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1792  );
1793  const TString peaksThickCalibPath = fIOManager->GetPath(
1794  TXT_PEAK_DATA_PATH, fSensorCalib->fRunId, fSensorCalib
1795  );
1796  const TString thickCalibCoeffsPath = fIOManager->GetPath(
1797  TXT_CALIB_COEFF_PATH, fSensorCalib->fRunId, fSensorCalib
1798  );
1799  const TString deadLayerThickPath = fIOManager->GetPath(
1800  TXT_DEAD_LAYER_PATH, fSensorCalib->fRunId, fSensorCalib
1801  );
1802  auto peaksPixelHighEMap = Read2DDoubleVectorFromFile(pixelPeakMapPath);
1803  auto peaksThickCalib = Read2DDoubleVectorFromFile(peaksThickCalibPath);
1804  auto calibCoeffsThick = Read2DDoubleVectorFromFile(thickCalibCoeffsPath);
1805  auto deadLayerThickVec = ReadDoubleVectorFromFile(deadLayerThickPath);
1806  const Int_t thickStripAmount = fMapSensors->at(0)->fStripAmount;
1807  const Int_t thinStripAmount = fMapSensors->at(1)->fStripAmount;
1808  // create output map root file
1809  const TString mapRootPath = fIOManager->GetPath(
1810  ROOT_HIST_NON_UNIFORM_MAP_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1811  );
1812  auto outFile = fIOManager->CreateRootFile(mapRootPath);
1813  auto hist = new TH2D("map", Form("Map of the sensor %s effective",
1814  fMapSensors->at(1)->fName.Data()),
1815  thickStripAmount, 0, thickStripAmount,
1816  thinStripAmount, 0, thinStripAmount);
1817  std::vector<std::vector<Double_t>> sensorMap;
1818  const Double_t deadLayerThick = CalculateAvg(deadLayerThickVec);
1819  for (Int_t iStripThick = 0; iStripThick < thickStripAmount; iStripThick++) {
1820  std::vector<Double_t> stripMap;
1821  for (Int_t iStripThin = 0; iStripThin < thinStripAmount; iStripThin++) {
1822  const Double_t N2 = peaksThickCalib[iStripThick][2];
1823  const Double_t N1 = peaksPixelHighEMap[iStripThick][iStripThin];
1824  const Double_t dE = (N2 - N1) * calibCoeffsThick[iStripThick][0];
1825  const Double_t pixelThickness = GetThicknessByHighElossCubic(dE) - deadLayerThick;
1826  hist->SetBinContent(iStripThick + 1, iStripThin + 1, pixelThickness);
1827  stripMap.push_back(pixelThickness);
1828  }
1829  sensorMap.push_back(stripMap);
1830  }
1831 
1832  const TString mapTxtPath = fIOManager->GetPath(
1833  TXT_HIST_NON_UNIFORM_MAP_PATH, fMapSensors->at(0)->fRunId, fMapSensors
1834  );
1835  auto mapFile = fIOManager->CreateTextFile(mapTxtPath);
1836  Dump2DVector(sensorMap, mapFile);
1837 
1838  mapFile.close();
1839  hist->Write();
1840  outFile->Close();
1841 }
1842 
1843 } // namespace ERCalibrationSSD
Double_t GetDeadLayerByEta(const Double_t eta)
Returns dead layer thickness [um] by eta parameter value. d(eta) is a qudratic approximation // in fo...
std::ifstream OpenTextFile(const TString &filePath)
Opens output text file.
void Write(const TObjArray *arr)
Serilizes list of objects to a current opened ROOT file directory.
TString ConstructSensorFilePath(const std::set< TString > &subdirs, const TString &prefix, const TString &nameRoot, const std::vector< SensorRunInfo * > *sensors, const TString &extension="root")
Returns file path according to sensor names, prefix and extension by scheme [WORK_DIR]/(sensor_name_1...
std::list< Double_t > GetPeaks(TH1 *hist, const std::list< Double_t > &initGuess)
Returns peaks according to set options. Restores histogram bin range (0, Nbins) after search by any m...
std::ofstream CreateTextFile(const TString &filePath)
Creates output text file Creates a file and all the needed subdirectories.
void MultiplicitySelection(const SensorRunInfo *sensor, std::vector< SensorRunInfo * > sensorsZeroSignal=std::vector< SensorRunInfo * >())
Performs multiplicity selection of a data. Method creates a tree where in each event analyzed sensors...
void FindThresholds(const TString &opt="draw_off")
Finds noise thresholds, saves results to a file. Algorithm: 1) Find bin number with maximal amplitude...
TFile * OpenRootFile(const TString &filePath)
Opens ROOT file.
TFile * CreateRootFile(const TString &filePath)
Creates output ROOT-file Creates a file and all the needed subdirectories.
TString ConstructFilePath(const std::set< TString > &subdirs, const TString &prefix, const TString &nameRoot, const std::vector< SensorRunInfo * > *sensors, const TString &extension="root")
Returns file path according to subdirs list, prefix and extension by scheme [WORK_DIR]/(subdirs)/(pre...
std::list< Double_t > GaussPeakSearch(TH1 *hist, const std::list< Double_t > &initGuess, const Int_t searchRadius)
Searchs peaks on a histogram by the &#39;gaus + pol1&#39; fit. Algorithm:
std::list< Double_t > SlidingWindowPeakSearch(TH1 *hist, const std::list< Double_t > &initGuess, const Int_t windowWidth, const Int_t searchRadius)
Searchs peaks on a histogram by the "sliding window" algorithm. Algorithm:
void DrawPixelSpectra()
Draws thick sensor pixels and saves histograms to the file.
void ChangeDir(const TString &dirname)
Changes working directory.
void SetThresholdFile(const TString &path)
Sets threshold file path. Threshold integer values for each strip are listed in a file in ascending s...
void AddSensor(SensorRunInfo *sensor)
Adds sensor to a current preprocessing. Sensors are form common file.
void Exec()
Executes all calibration steps 1) Peaks position determination. 2) Dead layer estimation. 3) Calibration coefficients calculation. 4) Report file printing.
void CreateSpectraHists(const SensorRunInfo *sensor)
Creates strips spectra for the further analysis analysis. Saves resulting hists for each sensor by pa...
TString GetPath(const Int_t fileType, const TString &nameRoot, const std::vector< SensorRunInfo * > *sensors=nullptr)
Returns a path to a desired file File storing structure is fixed for the calibrations procedure...
std::list< Double_t > GetPeaksTSpectrum(TH1 *hist, const Double_t fitMinSigma, const Double_t fitPeakThreshold)
void PrintReport(const std::vector< std::vector< Double_t >> &peaks, const std::vector< Double_t > &deadVec, const Double_t avgDead, const std::vector< std::vector< Double_t >> &coeffsAB)
Finds peaks with a set algorithm method. Stores statistic files in the directory [WORK_DIR]/run_id/se...
std::vector< T > GetSensorThresholds(const SensorRunInfo *sensor, const TString &runId)
Returns a std::vector of sensor noise threshold. If user defined file was set for sensor...
void ConvertTree(const TString &option="neevent")
Prepares raw input tree by leaving only leaves needed for the further analysis. As a result file [WOR...
void MakeDir(const TString &dirname)
Creates directory in a current working directory.