KaliVeda
Toolkit for HIC analysis
KVDetector.cpp
1 #include "KVDetector.h"
2 #include "TROOT.h"
3 #include "KVGroup.h"
4 #include "KVCalibrator.h"
5 #include "TPluginManager.h"
6 #include "TClass.h"
7 /*** geometry ***/
8 #include "TGeoVolume.h"
9 #include "TGeoManager.h"
10 #include "TGeoMatrix.h"
11 #include "TGeoBBox.h"
12 #include "TGeoArb8.h"
13 #include "TGeoTube.h"
14 #include "KVCalibratedSignal.h"
15 #include "KVDetectorSignalTrace.h"
16 #include "KVDetectorSignalExpression.h"
17 #include "KVZDependentCalibratedSignal.h"
18 #include "KVMaterialStack.h"
19 #include <TGeoPhysicalNode.h>
20 #include <TGraph.h>
21 
22 using namespace std;
23 
25 
27 
28 
31 
33 {
34  //default initialisations
35  fCalibrators = nullptr;
36  fParticles.SetCleanup();
37  fActiveLayer = nullptr;
38  fIdentP = fUnidentP = 0;
39  fELossF = fEResF = fRangeF = nullptr;
40  fEResforEinc = -1.;
41  fSimMode = kFALSE;
42  fPresent = kTRUE;
43  fDetecting = kTRUE;
44  fParentStrucList.SetCleanup();
45  fSingleLayer = kTRUE;
46  fNode.SetDetector(this);
47  // detector owns any signals which are defined for it
48  fDetSignals.SetOwner();
49  // adding a new signal with the same name as an existing one
50  // will delete the existing signal and replace it
51  fDetSignals.ReplaceObjects();
52 }
53 
54 
55 
58 
60 {
61 //default ctor
62  init();
63  fDetCounter++;
64  SetName(Form("Det_%d", fDetCounter));
65 }
66 
67 
68 
71 
73  const Float_t thick): KVMaterial()
74 {
75  // Create a new detector of a given material and thickness in centimetres (default value = 0.0)
76 
77  init();
78  SetType("DET");
79  fDetCounter++;
80  SetName(Form("Det_%d", fDetCounter));
81  AddAbsorber(new KVMaterial(type, thick));
82 }
83 
84 
85 
90 
91 KVDetector::KVDetector(const Char_t* gas, const Double_t thick, const Double_t pressure, const Double_t temperature)
92 {
93  // Create gaseous dteector with given type, linear thickness in cm, pressure in Torr, and temperature in degrees C (default value 19°C).
94  //
95  // \note this just defines some gas, the 'detector' has no windows!
96 
97  init();
98  SetType("DET");
99  fDetCounter++;
100  SetName(Form("Det_%d", fDetCounter));
101  AddAbsorber(new KVMaterial(gas, thick, pressure, temperature));
102 }
103 
104 
105 
108 
110 {
111 //copy ctor
112  init();
113  fDetCounter++;
114  SetName(Form("Det_%d", fDetCounter));
115 #if ROOT_VERSION_CODE >= ROOT_VERSION(3,4,0)
116  obj.Copy(*this);
117 #else
118  ((KVDetector&) obj).Copy(*this);
119 #endif
120 }
121 
122 
123 #if ROOT_VERSION_CODE >= ROOT_VERSION(3,4,0)
124 
129 
130 void KVDetector::Copy(TObject& obj) const
131 #else
132 void KVDetector::Copy(TObject& obj)
133 #endif
134 {
135  //copy 'this' to 'obj'
136  //The structure of the detector is copied, with new cloned objects for
137  //each absorber layer. The active layer is set in the new detector.
138 
139  TIter next(&fAbsorbers);
140  KVMaterial* mat;
141  while ((mat = (KVMaterial*) next())) {
142  ((KVDetector&) obj).AddAbsorber((KVMaterial*) mat->Clone());
143  }
144  //set active layer
145  Int_t in_actif = fAbsorbers.IndexOf(fActiveLayer);
146  ((KVDetector&) obj).SetActiveLayer(((KVDetector&)obj).GetAbsorber(in_actif));
147 }
148 
149 
150 
151 
153 
154 KVDetector::~KVDetector()
155 {
160 }
161 
162 
163 
168 
170 {
171  // Set material of active layer.
172  // If no absorbers have been added to the detector, create and add
173  // one (active layer by default)
174 
175  if (!GetActiveLayer())
177  else
179 }
180 
181 
182 
194 
196 {
197  //Calculate the energy loss of a charged particle traversing the detector,
198  //the particle is slowed down, it is added to the list of all particles hitting the
199  //detector. The apparent energy loss of the particle in the active layer of the
200  //detector is set.
201  //Do nothing if particle has zero (or -ve) energy.
202  //
203  //If the optional argument 'norm' is given, it is supposed to be a vector
204  //normal to the detector, oriented from the origin towards the detector.
205  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
206  //depending on its direction of motion is used for the calculation.
207 
208  if (kvp->GetKE() <= 0.)
209  return;
210 
211  AddHit(kvp); //add nucleus to list of particles hitting detector in the event
212  //set flag to say that particle has been slowed down
213  kvp->SetIsDetected();
214  //If this is the first absorber that the particle crosses, we set a "reminder" of its
215  //initial energy
216  if (!kvp->GetPInitial())
217  kvp->SetE0();
218 
219  std::vector<Double_t> thickness;
220  if (norm) {
221  // modify thicknesses of all layers according to orientation,
222  // and store original thicknesses in array
223  TVector3 p = kvp->GetMomentum();
224  thickness.reserve(fAbsorbers.GetEntries());
225  KVMaterial* abs;
226  int i = 0;
227  TIter next(&fAbsorbers);
228  while ((abs = (KVMaterial*) next())) {
229  thickness[i++] = abs->GetThickness();
230  Double_t T = abs->GetEffectiveThickness((*norm), p);
231  abs->SetThickness(T);
232  }
233  }
234  Double_t eloss = GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
235  Double_t dE = GetDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
236  if (norm) {
237  // reset thicknesses of absorbers
238  KVMaterial* abs;
239  int i = 0;
240  TIter next(&fAbsorbers);
241  while ((abs = (KVMaterial*) next())) {
242  abs->SetThickness(thickness[i++]);
243  }
244  }
245  Double_t epart = kvp->GetEnergy() - eloss;
246  if (epart < 1e-3) {
247  //printf("%s, pb d arrondi on met l energie de la particule a 0\n",GetName());
248  epart = 0.0;
249  }
250  kvp->SetEnergy(epart);
251  Double_t eloss_old = GetEnergyLoss();
252  SetEnergyLoss(eloss_old + dE);
253 }
254 
255 
256 
257 
267 
269 {
270  //Calculate the total energy loss of a charged particle traversing the detector.
271  //This does not affect the "stored" energy loss value of the detector,
272  //nor its ACQData, nor the energy of the particle.
273  //
274  //If the optional argument 'norm' is given, it is supposed to be a vector
275  //normal to the detector, oriented from the origin towards the detector.
276  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
277  //depending on its direction of motion is used for the calculation.
278 
279  std::vector<Double_t> thickness;
280  if (norm) {
281  // modify thicknesses of all layers according to orientation,
282  // and store original thicknesses in array
283  TVector3 p = kvp->GetMomentum();
284  thickness.reserve(fAbsorbers.GetEntries());
285  KVMaterial* abs;
286  int i = 0;
287  TIter next(&fAbsorbers);
288  while ((abs = (KVMaterial*) next())) {
289  thickness[i++] = abs->GetThickness();
290  Double_t T = abs->GetEffectiveThickness((*norm), p);
291  abs->SetThickness(T);
292  }
293  }
294  Double_t eloss = GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
295  if (norm) {
296  // reset thicknesses of absorbers
297  KVMaterial* abs;
298  int i = 0;
299  TIter next(&fAbsorbers);
300  while ((abs = (KVMaterial*) next())) {
301  abs->SetThickness(thickness[i++]);
302  }
303  }
304  return eloss;
305 }
306 
307 
308 
309 
319 
321 {
322  //Calculate the energy of particle 'kvn' before its passage through the detector,
323  //based on the current kinetic energy, Z & A of nucleus 'kvn', supposed to be
324  //after passing through the detector.
325  //
326  //If the optional argument 'norm' is given, it is supposed to be a vector
327  //normal to the detector, oriented from the origin towards the detector.
328  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
329  //depending on its direction of motion is used for the calculation.
330 
331  Double_t Einc = 0.0;
332  //make 'clone' of particle
333  KVNucleus clone_part(kvp->GetZ(), kvp->GetA());
334  clone_part.SetMomentum(kvp->GetMomentum());
335  //composite detector - calculate losses in all layers
336  KVMaterial* abs;
337  TIter next(&fAbsorbers, kIterBackward); //work through list backwards
338  while ((abs = (KVMaterial*) next())) {
339 
340  //calculate energy of particle before current absorber
341  Einc = abs->GetParticleEIncFromERes(&clone_part, norm);
342 
343  //set new energy of particle
344  clone_part.SetKE(Einc);
345  }
346  return Einc;
347 }
348 
349 
350 
351 
355 
356 void KVDetector::Print(Option_t* opt) const
357 {
358  //Print info on this detector
359  //if option="data" the energy loss and raw data are displayed
360 
361  if (!strcmp(opt, "data")) {
362  cout << Form("%10s -- ", GetName());
363  // print raw data signals
364  KVDetectorSignal* sig;
366  while ((sig = (KVDetectorSignal*)it())) {
367  if (sig->IsRaw()) {
368  std::cout << sig->GetName() << "=" << sig->GetValue() << " | ";
369  }
370  }
371  // print calibrated data
372  it.Reset();
373  while ((sig = (KVDetectorSignal*)it())) {
374  if (!sig->IsRaw() && !sig->GetValueNeedsExtraParameters()) {
375  std::cout << sig->GetName() << "=" << sig->GetValue() << " | ";
376  }
377  }
378  cout << " ";
380  cout << "(Belongs to an unidentified particle)";
381  cout << endl;
382  }
383  else if (!strcmp(opt, "all")) {
384  //Give full details of detector
385  //
386  TString option(" ");
387  cout << option << ClassName() << " : " << ((KVDetector*) this)->
388  GetName() << endl;
389  //composite detector - print all layers
390  KVMaterial* abs;
391  TIter next(&fAbsorbers);
392  while ((abs = (KVMaterial*) next())) {
393  if (GetActiveLayer() == abs)
394  cout << " ### ACTIVE LAYER ### " << endl;
395  cout << option << option;
396  abs->Print();
397  if (GetActiveLayer() == abs)
398  cout << " #################### " << endl;
399  }
400  if (fParticles.GetEntries()) {
401  cout << option << " --- Detected particles:" << endl;
402  fParticles.Print();
403  }
404  }
405  else {
406  //just print name
407  cout << ClassName() << ": " << ((KVDetector*) this)->
408  GetName() << endl;
409  }
410 }
411 
412 
413 
438 
440 {
441  // Associate a calibration with this detector.
442  //
443  // This will add a new signal to the list of the detector's signals.
444  //
445  // Also sets calibrator's name to `[detname]_[caltype]` where `caltype` is the type of the KVCalibration object.
446  //
447  // \param[in] cal pointer to KVCalibrator object (must be on heap, i.e. created with new: detector handles deletion)
448  // \param[in] opts
449  // \parblock
450  // can be used to pass any extra parameters/options needed by the calibrator.
451  // For example, if it contains a parameter `ZRange`:
452  //
453  //~~~~~~~~~~~~~~~
454  // ZRange=1-10
455  //~~~~~~~~~~~~~~~
456  //
457  // then the calibrator will be handled by a KVZDependentCalibratedSignal (handles several
458  // calibrators which provide the same output signal, each one is used for a specific range
459  // of atomic numbers)
460  // \endparblock
461  //
462  // \returns kFALSE in case of problems (non-existent input signal for calibrator, output signal not defined for calibrator),
463  // otherwise kTRUE
464 
465  if (!cal) return kFALSE;
466  // look for input signal
468  // input signal must exist
469  if (!in) {
470  Error("AddCalibrator", "Detector:%s has no signal %s, required as input by calibrator %s to provide output %s",
471  GetName(), cal->GetInputSignalType().Data(), cal->GetType(), cal->GetOutputSignalType().Data());
472  return kFALSE;
473  }
474  if (!fCalibrators)
475  fCalibrators = new KVList();
476 
477  cal->SetDetector(this);
478  fCalibrators->Add(cal);
479  cal->SetName(Form("%s_%s", GetName(), cal->GetType()));
480 
481  if (cal->GetOutputSignalType() == "") {
482  Warning("AddCalibrator", "%s : output signal not defined for calibrator %s. No output signal created.",
483  GetName(), cal->GetType());
484  }
485  else {
486  KVDetectorSignal* new_cal_sig(nullptr);
487  if (opts.HasParameter("ZRange")) {
488  // If 'ZRange' parameter is given we need to find the KVZDependentCalibratedSignal
489  // and add a new signal to it.
491  if (!sig) {
492  new_cal_sig = sig = new KVZDependentCalibratedSignal(in, cal->GetOutputSignalType());
493  }
494  dynamic_cast<KVZDependentCalibratedSignal*>(sig)->AddSignal(new KVCalibratedSignal(in, cal), opts.GetStringValue("ZRange"));
495  }
496  else {
497  new_cal_sig = new KVCalibratedSignal(in, cal);
498  }
499  if (new_cal_sig) fDetSignals.Add(new_cal_sig);
500  }
501  return kTRUE;
502 }
503 
504 
505 
516 
518 {
519  // Replace calibrator of given type with the given calibrator object
520  // The calibrator object should not be shared with any other detectors: it now belongs
521  // to this detector, which will delete it when necessary.
522  // If an exising calibrator with the same type is already defined, it will be
523  // deleted and removed from the detector's calibrator list
524  //
525  // Returns kFALSE in case of problems.
526  //
527  // The (optional) KVNameValueList argument can be used to pass any extra parameters/options.
528 
529  KVCalibrator* old_cal = GetCalibrator(type);
530  if (old_cal) {
531  fCalibrators->Remove(old_cal);
533  delete old_cal;
534  }
535  return AddCalibrator(cal, opts);
536 }
537 
538 
539 
544 
546 {
547  // A detector is considered to be calibrated if it has
548  // a signal "Energy" available and if depending on the supplied parameters
549  // this signal can be calculated
550 
551  if(IsSimMode())
552  return IsDetecting();
553 
554  KVCalibratedSignal* e_sig = dynamic_cast<KVCalibratedSignal*>(GetDetectorSignal("Energy"));
555  return (e_sig && e_sig->IsAvailableFor(params) && IsOK());
556 }
557 
558 
559 
560 
567 
569 {
570  //Set energy loss(es) etc. to zero
571  //
572  //If opt="N":
573  // + we do not reset acquisition parameters/raw detector signals
574  // + in SimMode we do not reset energy losses (this is called before reconstruction happens)
575 
576  bool option_N = (strncmp(opt, "N", 1) == 0);
577  bool sim_mode_option_N = option_N && IsSimMode();
578 
579  if (!sim_mode_option_N) KVMaterial::Clear(opt);
581  fIdentP = fUnidentP = 0;
584  if (!option_N) {
586  KVDetectorSignal* ds;
587  while ((ds = (KVDetectorSignal*)it())) {
588  if (ds->IsRaw() && !ds->IsExpression()) ds->Reset();
589  }
590  }
591  ClearHits();
592  if (!sim_mode_option_N) {
593  //reset all layers in detector
594  KVMaterial* mat;
595  TIter next(&fAbsorbers);
596  while ((mat = (KVMaterial*) next())) {
597  mat->Clear();
598  }
599  }
600  fEResforEinc = -1.;
601 }
602 
603 
604 
609 
611 {
612  // Add a layer of absorber material to the detector
613  // By default, the first layer added is set as the "Active" layer.
614  // Call SetActiveLayer to change this.
615  fAbsorbers.Add(mat);
616  if (!TestBit(kActiveSet))
617  SetActiveLayer(mat);
618  if (fAbsorbers.GetSize() > 1) fSingleLayer = kFALSE;
619 }
620 
621 
622 
625 
627 {
628  //Returns pointer to the i-th absorber in the detector (i=0 first absorber, i=1 second, etc.)
629 
630  if (!fAbsorbers.GetEntries()) {
631  Error("GetAbsorber", "No absorbers defined for detector");
632  return nullptr;
633  }
634  if (i < 0 || i >= fAbsorbers.GetEntries()) {
635  Error("GetAbsorber", "i=%d but valid values are 0-%d [number of absorbers in list]", i,
637  return nullptr;
638  }
639  return (KVMaterial*) fAbsorbers.At(i);
640 }
641 
642 
643 
648 
650 {
651  // Completely reset the KVDetector as if it had just been created by a call to the default constructor:
652  // + removes all absorber layers
653  // + removes all calibrators/detector signals
654 
655  Clear();
658  fAbsorbers.Clear();
662  fCalibrators = nullptr;
663  fActiveLayer = nullptr;
665  fIdentP = fUnidentP = 0;
666  fELossF = fEResF = fRangeF = nullptr;
667  fEResforEinc = -1.;
668  fSimMode = kFALSE;
669  fPresent = kTRUE;
670  fDetecting = kTRUE;
672 }
673 
674 
675 
679 
681 {
682  // Used when a calibrator object is removed or replaced
683  // We remove and delete the corresponding output signal from the list of detector signals
684 
685  if (K->GetOutputSignalType() != "") {
686  KVDetectorSignal* ds = GetDetectorSignal(K->GetOutputSignalType());
687  if (ds) {
688  fDetSignals.Remove(ds);
689  delete ds;
690  }
691  }
692 }
693 
694 
695 
701 
703 {
704  // Removes all calibrations associated to this detector: in other words, we delete all
705  // the KVCalibrator objects in list fCalibrators.
706  //
707  // We also destroy all signals provided by these calibrators
708 
709  if (fCalibrators) {
710  KVCalibrator* K;
711  TIter it(fCalibrators);
712  while ((K = (KVCalibrator*)it())) {
714  }
715  fCalibrators->Delete();
716  }
717 }
718 
719 
720 
721 
751 
753 {
754  // Returns the total energy loss in the detector for a given nucleus
755  // including inactive absorber layers.
756  // e = energy loss in active layer (if not given, we use current value)
757  // transmission = kTRUE (default): the particle is assumed to emerge with
758  // a non-zero residual energy Eres after the detector.
759  // = kFALSE: the particle is assumed to stop in the detector.
760  //
761  // WARNING: if transmission=kTRUE, and if the residual energy after the detector
762  // is known (i.e. measured in a detector placed after this one), you should
763  // first call
764  // SetEResAfterDetector(Eres);
765  // before calling this method. Otherwise, especially for heavy ions, the
766  // correction may be false for particles which are just above the punch-through energy.
767  //
768  // WARNING 2: if measured energy loss in detector active layer is greater than
769  // maximum possible theoretical value for given nucleus' Z & A, this may be because
770  // the A was not measured but calculated from Z and hence could be false, or perhaps
771  // there was an (undetected) pile-up of two or more particles in the detector.
772  // In this case we return the corrected energy
773  // corresponding to the maximum theoretical energy loss in the active layer
774  // and we add the following parameters to the particle (in nuc->GetParameters()):
775  //
776  // GetCorrectedEnergy.Warning = 1
777  // GetCorrectedEnergy.Detector = [name]
778  // GetCorrectedEnergy.MeasuredDE = [value]
779  // GetCorrectedEnergy.MaxDE = [value]
780  // GetCorrectedEnergy.Transmission = 0 or 1
781  // GetCorrectedEnergy.ERES = [value]
782 
783  Int_t z = nuc->GetZ();
784  Int_t a = nuc->GetA();
785 
786  if (e < 0.) e = GetEnergy();
787  if (e <= 0) {
789  return 0;
790  }
791 
792  // check if calling this function for a previous detector in the particle's trajectory
793  // led to using an effective incident angle for the particle: if so, use it here
794  if (nuc->GetParameters()->HasDoubleParameter("GetCorrectedEnergy.IncidentAngle")) {
795  KVMaterialStack stack(this);
796  stack.SetIncidenceAngle(nuc->GetParameters()->GetDoubleValue("GetCorrectedEnergy.IncidentAngle"));
797  // check that apparent energy loss in detector is compatible with a & z
798  Double_t maxDE = stack.GetMaxDeltaE(z, a);
799  if (e > maxDE) {
800  auto inc_angle = stack.GetMinimumIncidentAngleForDEMax(z, a, e);
801  stack.SetIncidenceAngle(inc_angle);
802  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Warning", GetName()), 1);
803  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MeasuredDE", GetName()), e);
804  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MaxDE", GetName()), maxDE);
805  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Transmission", GetName()), (Int_t)transmission);
806  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.ERES", GetName()), GetEResAfterDetector());
807  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.IncidentAngle", GetName()), inc_angle);
808  nuc->GetParameters()->SetValue("GetCorrectedEnergy.IncidentAngle", inc_angle);
809  }
810  return get_corrected_energy(&stack, nuc, e, transmission);
811  }
812  // check that apparent energy loss in detector is compatible with a & z
813  Double_t maxDE = GetMaxDeltaE(z, a);
814  if (e > maxDE) {
815  KVMaterialStack stack(this);
816  auto inc_angle = stack.GetMinimumIncidentAngleForDEMax(z, a, e);
817  stack.SetIncidenceAngle(inc_angle);
818  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Warning", GetName()), 1);
819  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MeasuredDE", GetName()), e);
820  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MaxDE", GetName()), maxDE);
821  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Transmission", GetName()), (Int_t)transmission);
822  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.ERES", GetName()), GetEResAfterDetector());
823  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.IncidentAngle", GetName()), inc_angle);
824  nuc->GetParameters()->SetValue("GetCorrectedEnergy.IncidentAngle", inc_angle);
825  return get_corrected_energy(&stack, nuc, e, transmission);
826  }
827  return get_corrected_energy(this, nuc, e, transmission);
828 }
829 
830 
831 
832 
850 
852 {
853  //For particles which stop in the first stage of an identification telescope,
854  //we can at least estimate a minimum Z value based on the energy lost in this
855  //detector.
856  //
857  //This is based on the KVMaterial::GetMaxDeltaE method, giving the maximum
858  //energy loss in the active layer of the detector for a given nucleus (A,Z).
859  //
860  //The "Zmin" is the Z of the particle which gives a maximum energy loss just greater
861  //than that measured in the detector. Particles with Z<Zmin could not lose as much
862  //energy and so are excluded.
863  //
864  //If ELOSS is not given, we use the current value of GetEnergy()
865  //Use 'mass_formula' to change the formula used to calculate the A of the nucleus
866  //from its Z. Default is valley of stability value. (see KVNucleus::GetAFromZ).
867  //
868  //If the value of ELOSS or GetEnergy() is <=0 we return Zmin=0
869 
870  ELOSS = (ELOSS < 0. ? GetEnergy() : ELOSS);
871  if (ELOSS <= 0) return 0;
872 
873  UInt_t z = 40;
874  UInt_t zmin, zmax;
875  zmin = 1;
876  zmax = 92;
877  KVNucleus particle(zmin);
878 
879  if (mass_formula > -1)
880  particle.SetMassFormula((UChar_t)mass_formula);
881 
882  if (GetMaxDeltaE(particle.GetZ(), particle.GetA()) > ELOSS)
883  return zmin; // Z=1 solution
884 
885  do {
886 
887  particle.SetZ(z);
888 
889  auto difference = GetMaxDeltaE(z, particle.GetA()) - ELOSS;
890  //if difference < 0 the z is too small
891  if (difference < 0.0) {
892 
893  zmin = z;
894  z += (UInt_t)((zmax - z) / 2 + 0.5);
895 
896  }
897  else {
898 
899  zmax = z;
900  z -= (UInt_t)((z - zmin) / 2 + 0.5);
901 
902  }
903  }
904  while (zmax > (zmin + 1));
905 
906  return zmax;
907 }
908 
909 
910 
911 
920 
922 {
923  // Calculates energy loss (in MeV) in active layer of detector, taking into account preceding layers
924  //
925  // Arguments are:
926  // x[0] is incident energy in MeV
927  // Parameters are:
928  // par[0] Z of ion
929  // par[1] A of ion
930 
931  Double_t e = x[0];
932  TIter next(&fAbsorbers);
933  KVMaterial* mat;
934  mat = (KVMaterial*)next();
935  while (fActiveLayer != mat) {
936  // calculate energy losses in absorbers before active layer
937  e = mat->GetERes(par[0], par[1], e); //residual energy after layer
938  if (e <= 0.)
939  return 0.; // return 0 if particle stops in layers before active layer
940  mat = (KVMaterial*)next();
941  }
942  //calculate energy loss in active layer
943  return mat->GetDeltaE(par[0], par[1], e);
944 }
945 
946 
947 
948 
958 
960 {
961  // Calculates range (in centimetres) of ions in detector as a function of incident energy (in MeV),
962  // taking into account all layers of the detector.
963  //
964  // Arguments are:
965  // x[0] = incident energy in MeV
966  // Parameters are:
967  // par[0] = Z of ion
968  // par[1] = A of ion
969 
970  Double_t Einc = x[0];
971  Int_t Z = (Int_t)par[0];
972  Int_t A = (Int_t)par[1];
973  Double_t range = 0.;
974  TIter next(&fAbsorbers);
975  KVMaterial* mat = (KVMaterial*)next();
976  if (!mat) return 0.;
977  do {
978  // range in this layer
979  Double_t this_range = mat->GetLinearRange(Z, A, Einc);
980  KVMaterial* next_mat = (KVMaterial*)next();
981  if (this_range > mat->GetThickness()) {
982  // particle traverses layer.
983  if (next_mat)
984  range += mat->GetThickness();
985  else // if this is last layer, the range continues to increase beyond size of detector
986  range += this_range;
987  // calculate incident energy for next layer (i.e. residual energy after this layer)
988  Einc = mat->GetERes(Z, A, Einc);
989  }
990  else {
991  // particle stops in layer
992  range += this_range;
993  return range;
994  }
995  mat = next_mat;
996  }
997  while (mat);
998  // particle traverses detector
999  return range;
1000 }
1001 
1002 
1003 
1004 
1014 
1016 {
1017  // Calculates residual energy (in MeV) of particle after traversing all layers of detector.
1018  // Returned value is -1000 if particle stops in one of the layers of the detector.
1019  //
1020  // Arguments are:
1021  // x[0] is incident energy in MeV
1022  // Parameters are:
1023  // par[0] Z of ion
1024  // par[1] A of ion
1025 
1026  Double_t e = x[0];
1027  TIter next(&fAbsorbers);
1028  KVMaterial* mat;
1029  while ((mat = (KVMaterial*)next())) {
1030  Double_t eres = mat->GetERes(par[0], par[1], e); //residual energy after layer
1031  if (eres <= 0.)
1032  return -1000.; // return -1000 if particle stops in layers before active layer
1033  e = eres;
1034  }
1035  return e;
1036 }
1037 
1038 
1039 
1040 
1055 
1057 {
1058  //Static function which will create an instance of the KVDetector-derived class
1059  //corresponding to 'name'
1060  //These are defined as 'Plugin' objects in the file $KVROOT/KVFiles/.kvrootrc :
1061  // [name_of_dataset].detector_type
1062  // detector_type
1063  // To use the dataset-dependent plugin, call this method with
1064  // name = "[name_of_dataset].detector_type"
1065  // If not, the default plugin will be used
1066  //first we check if there is a special plugin for the DataSet
1067  //if not we take the default one
1068  //
1069  //'thickness' is passed as argument to the constructor for the detector plugin
1070 
1071  //check and load plugin library
1072  TPluginHandler* ph = nullptr;
1073  KVString nom(name);
1074  if (!nom.Contains(".") && !(ph = LoadPlugin("KVDetector", name))) return nullptr;
1075  if (nom.Contains(".")) {
1076  // name format like [dataset].[det_type]
1077  // in case dataset name contains "." we parse string to find detector type: assumed after the last "."
1078  nom.RBegin(".");
1079  KVString det_type = nom.RNext();
1080  if (!(ph = LoadPlugin("KVDetector", name))) {
1081  if (!(ph = LoadPlugin("KVDetector", det_type))) {
1082  return nullptr;
1083  }
1084  }
1085  }
1086 
1087  //execute constructor/macro for detector
1088  return (KVDetector*) ph->ExecPlugin(1, thickness);
1089 }
1090 
1091 
1092 
1095 
1097 {
1098  // Return surface area of first layer of detector in cm2.
1099 
1100  if (!GetEntranceWindow().GetShape()->InheritsFrom("TGeoArb8")) {
1101  // simple shape area
1102  return GetEntranceWindow().GetShape()->GetFacetArea(1);
1103  }
1104  // Monte Carlo calculation for TGeoArb8 shapes
1105  return GetEntranceWindow().GetSurfaceArea();
1106 }
1107 
1108 
1109 
1114 
1116 {
1117  // Return pointer toTF1 giving residual energy after detector as function of incident energy,
1118  // for a given nucleus (Z,A).
1119  // The TF1::fNpx parameter is taken from environment variable KVDetector.ResidualEnergy.Npx
1120 
1121  if (!fEResF) {
1122  fEResF = new TF1(Form("KVDetector:%s:ERes", GetName()), this, &KVDetector::EResDet,
1123  0., 1.e+04, 2, "KVDetector", "EResDet");
1124  fEResF->SetNpx(gEnv->GetValue("KVDetector.ResidualEnergy.Npx", 20));
1125  }
1127  fEResF->SetRange(0., GetSmallestEmaxValid(Z, A));
1128  fEResF->SetTitle(Form("Residual energy [MeV] after detector %s for Z=%d A=%d", GetName(), Z, A));
1129 
1130  return fEResF;
1131 }
1132 
1133 
1134 
1139 
1141 {
1142  // Return pointer toTF1 giving range (in centimetres) in detector as function of incident energy,
1143  // for a given nucleus (Z,A).
1144  // The TF1::fNpx parameter is taken from environment variable KVDetector.Range.Npx
1145 
1146  if (!fRangeF) {
1147  fRangeF = new TF1(Form("KVDetector:%s:Range", GetName()), this, &KVDetector::RangeDet,
1148  0., 1.e+04, 2, "KVDetector", "RangeDet");
1149  fRangeF->SetNpx(gEnv->GetValue("KVDetector.Range.Npx", 20));
1150  }
1153  fRangeF->SetTitle(Form("Range [cm] in detector %s for Z=%d A=%d", GetName(), Z, A));
1154 
1155  return fRangeF;
1156 }
1157 
1158 
1159 
1164 
1166 {
1167  // Return pointer to TF1 giving energy loss in active layer of detector as function of incident energy,
1168  // for a given nucleus (Z,A).
1169  // The TF1::fNpx parameter is taken from environment variable KVDetector.EnergyLoss.Npx
1170 
1171  if (!fELossF) {
1172  fELossF = new TF1(Form("KVDetector:%s:ELossActive", GetName()), this, &KVDetector::ELossActive,
1173  0., 1.e+04, 2, "KVDetector", "ELossActive");
1174  fELossF->SetNpx(gEnv->GetValue("KVDetector.EnergyLoss.Npx", 20));
1175  }
1178  fELossF->SetTitle(Form("Energy loss [MeV] in detector %s for Z=%d A=%d", GetName(), Z, A));
1179  return fELossF;
1180 }
1181 
1182 
1183 
1188 
1190 {
1191  // Overrides KVMaterial::GetEIncOfMaxDeltaE
1192  // Returns incident energy corresponding to maximum energy loss in the
1193  // active layer of the detector, for a given nucleus.
1194 
1195  return GetELossFunction(Z, A)->GetMaximumX();
1196 }
1197 
1198 
1199 
1204 
1206 {
1207  // Overrides KVMaterial::GetMaxDeltaE
1208  // Returns maximum energy loss in the
1209  // active layer of the detector, for a given nucleus.
1210 
1211  return GetELossFunction(Z, A)->GetMaximum();
1212 }
1213 
1214 
1215 
1220 
1222 {
1223  // Overrides KVMaterial::GetDeltaE
1224  // Returns energy loss of given nucleus in the active layer of the detector.
1225 
1226  // optimization for single-layer detectors
1227  if (fSingleLayer) {
1228  return fActiveLayer->GetDeltaE(Z, A, Einc);
1229  }
1230  return GetELossFunction(Z, A)->Eval(Einc);
1231 }
1232 
1233 
1234 
1238 
1240 {
1241  // Returns calculated total energy loss of ion in ALL layers of the detector.
1242  // This is just (Einc - GetERes(Z,A,Einc))
1243 
1244  return Einc - GetERes(Z, A, Einc);
1245 }
1246 
1247 
1248 
1253 
1255 {
1256  // Overrides KVMaterial::GetERes
1257  // Returns residual energy of given nucleus after the detector.
1258  // Returns 0 if Einc<=0
1259 
1260  if (Einc <= 0.) return 0.;
1261  Double_t eres = GetEResFunction(Z, A)->Eval(Einc);
1262  // Eres function returns -1000 when particle stops in detector,
1263  // in order for function inversion (GetEIncFromEres) to work
1264  if (eres < 0.) eres = 0.;
1265  return eres;
1266 }
1267 
1268 
1269 
1292 
1294 {
1295  // Overrides KVMaterial::GetIncidentEnergy
1296  // Returns incident energy corresponding to energy loss delta_e in active layer of detector for a given nucleus.
1297  // If delta_e is not given, the current energy loss in the active layer is used.
1298  //
1299  // By default the solution corresponding to the highest incident energy is returned
1300  // This is the solution found for Einc greater than the maximum of the dE(Einc) curve.
1301  // If you want the low energy solution set SolType = KVIonRangeTable::kEmin.
1302  //
1303  // WARNING: calculating the incident energy of a particle using only the dE in a detector
1304  // is ambiguous, as in general (and especially for very heavy ions) the maximum of the dE
1305  // curve occurs for Einc greater than the punch-through energy, therefore it is not always
1306  // true to assume that if the particle does not stop in the detector the required solution
1307  // is that for type=KVIonRangeTable::kEmax. For a range of energies between punch-through
1308  // and dE_max, the required solution is still that for type=KVIonRangeTable::kEmin.
1309  // If the residual energy of the particle is unknown, there is no way to know which is the
1310  // correct solution.
1311  //
1312  // WARNING 2
1313  // If the given energy loss in the active layer is greater than the maximum theoretical dE
1314  // for given Z & A, (dE > GetMaxDeltaE(Z,A)) then we return a NEGATIVE incident energy
1315  // corresponding to the maximum, GetEIncOfMaxDeltaE(Z,A)
1316 
1317  if (Z < 1) return 0.;
1318 
1319  Double_t DE = (delta_e > 0 ? delta_e : GetEnergyLoss());
1320 
1321  // If the given energy loss in the active layer is greater than the maximum theoretical dE
1322  // for given Z & A, (dE > GetMaxDeltaE(Z,A)) then we return a NEGATIVE incident energy
1323  // corresponding to the maximum, GetEIncOfMaxDeltaE(Z,A)
1324  if (DE > GetMaxDeltaE(Z, A)) return -GetEIncOfMaxDeltaE(Z, A);
1325 
1326  TF1* dE = GetELossFunction(Z, A);
1327  Double_t e1, e2;
1328  dE->GetRange(e1, e2);
1329  switch (type) {
1330  case kEmin:
1331  e2 = GetEIncOfMaxDeltaE(Z, A);
1332  break;
1333  case kEmax:
1334  e1 = GetEIncOfMaxDeltaE(Z, A);
1335  break;
1336  }
1337  KVBase::GetX_status status;
1338  Double_t EINC = ProtectedGetX(dE, DE, status, e1, e2);
1340 // Warning("GetIncidentEnergy",
1341 // "In %s : Called for Z=%d A=%d with dE=%f sol_type %d",
1342 // GetName(), Z, A, DE, type);
1343 // Warning("GetIncidentEnergy",
1344 // "Max DeltaE in this case is %f MeV",
1345 // GetMaxDeltaE(Z, A));
1346 // Warning("GetIncidentEnergy",
1347 // "Between Einc limits [%f,%f] no solution found",
1348 // e1,e2);
1349 // Warning("GetIncidentEnergy",
1350 // "Returned value is -Einc for %s dE, %f",
1351 // (status>0 ? "maximum" : "minimum"), EINC);
1352  return -EINC;
1353  }
1354  return EINC;
1355 }
1356 
1357 
1358 
1364 
1366 {
1367  // Overrides KVMaterial::GetDeltaEFromERes
1368  //
1369  // Calculate energy loss in active layer of detGetAlignedDetector for nucleus (Z,A)
1370  // having a residual kinetic energy Eres (MeV)
1371 
1372  if (Z < 1 || Eres <= 0.) return 0.;
1373  Double_t Einc = GetIncidentEnergyFromERes(Z, A, Eres);
1374  if (Einc <= 0.) return 0.;
1375  return GetELossFunction(Z, A)->Eval(Einc);
1376 }
1377 
1378 
1379 
1386 
1388 {
1389  // Overrides KVMaterial::GetIncidentEnergyFromERes
1390  //
1391  // Calculate incident energy of nucleus from residual energy.
1392  //
1393  // Returns -1 if Eres is out of defined range of values
1394 
1395  if (Z < 1 || Eres <= 0.) return 0.;
1396  //return GetEResFunction(Z, A)->GetX(Eres);
1397  KVBase::GetX_status status;
1398  Double_t einc = KVBase::ProtectedGetX(GetEResFunction(Z, A), Eres, status);
1399  if (status == KVBase::GetX_status::above_maximum || status == KVBase::GetX_status::below_minimum){// problem with inversion - value out of defined range of function
1400  return -1;
1401  }
1402  return einc;
1403 }
1404 
1405 
1406 
1410 
1412 {
1413  // Returns the smallest maximum energy for which range tables are valid
1414  // for all absorbers in the detector, and given ion (Z,A)
1415 
1416  Double_t maxmin = -1.;
1417  TIter next(&fAbsorbers);
1418  KVMaterial* abs;
1419  while ((abs = (KVMaterial*)next())) {
1420  if (maxmin < 0.) maxmin = abs->GetEmaxValid(Z, A);
1421  else {
1422  if (abs->GetEmaxValid(Z, A) < maxmin) maxmin = abs->GetEmaxValid(Z, A);
1423  }
1424  }
1425  return maxmin;
1426 }
1427 
1428 
1429 
1447 
1449 {
1450  // Create detector from text file in 'TEnv' format.
1451  //
1452  // Example:
1453  // ========
1454  //
1455  // Layer: Gold
1456  // Gold.Material: Au
1457  // Gold.AreaDensity: 200.*KVUnits::ug
1458  // +Layer: Gas1
1459  // Gas1.Material: C3F8
1460  // Gas1.Thickness: 5.*KVUnits::cm
1461  // Gas1.Pressure: 50.*KVUnits::mbar
1462  // Gas1.Active: yes
1463  // +Layer: Si1
1464  // Si1.Material: Si
1465  // Si1.Thickness: 300.*KVUnits::um
1466 
1467  TEnv fEnvFile(envrc);
1468 
1469  KVString layers(fEnvFile.GetValue("Layer", ""));
1470  layers.Begin(" ");
1471  while (!layers.End()) {
1472  KVString layer = layers.Next();
1473  KVString mat = fEnvFile.GetValue(Form("%s.Material", layer.Data()), "");
1474  KVString tS = fEnvFile.GetValue(Form("%s.Thickness", layer.Data()), "");
1475  KVString pS = fEnvFile.GetValue(Form("%s.Pressure", layer.Data()), "");
1476  KVString dS = fEnvFile.GetValue(Form("%s.AreaDensity", layer.Data()), "");
1477  Double_t thick, dens, press;
1478  thick = dens = press = 0.;
1479  KVMaterial* M = 0;
1480  if (pS != "" && tS != "") {
1481  press = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", pS.Data()));
1482  press /= 1.e+12;
1483  thick = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", tS.Data()));
1484  thick /= 1.e+12;
1485  M = new KVMaterial(mat.Data(), thick, press);
1486  }
1487  else if (tS != "") {
1488  thick = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", tS.Data()));
1489  thick /= 1.e+12;
1490  M = new KVMaterial(mat.Data(), thick);
1491  }
1492  else if (dS != "") {
1493  dens = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", dS.Data()));
1494  dens /= 1.e+12;
1495  M = new KVMaterial(dens, mat.Data());
1496  }
1497  if (M) {
1498  AddAbsorber(M);
1499  if (fEnvFile.GetValue(Form("%s.Active", layer.Data()), kFALSE)) SetActiveLayer(M);
1500  }
1501  }
1502 }
1503 
1504 
1505 
1509 
1511 {
1512  // WARNING: SAME AS KVDetector::GetLinearRange
1513  // Only linear range in centimetres is calculated for detectors!
1514  return GetLinearRange(Z, A, Einc);
1515 }
1516 
1517 
1518 
1524 
1526 {
1527  // Returns range of ion in centimetres in this detector,
1528  // taking into account all layers.
1529  // Note that for Einc > punch through energy, this range is no longer correct
1530  // (but still > total thickness of detector).
1531  return GetRangeFunction(Z, A)->Eval(Einc);
1532 }
1533 
1534 
1535 
1539 
1541 {
1542  // Returns energy (in MeV) necessary for ion (Z,A) to punch through all
1543  // layers of this detector
1544 
1545  if (fSingleLayer) {
1546  // Optimize calculation time for single-layer detector
1547  return fActiveLayer->GetPunchThroughEnergy(Z, A);
1548  }
1549  //return GetRangeFunction(Z, A)->GetX(GetTotalThicknessInCM());
1550  KVBase::GetX_status status;
1551  return ProtectedGetX(GetRangeFunction(Z, A),GetTotalThicknessInCM(),status);
1552 }
1553 
1554 
1555 
1556 
1561 
1563 {
1564  // Creates and fills a KVDrawable<TGraph> with the punch through energy in MeV vs. Z for the given detector,
1565  // for Z=1-92. The mass of each nucleus is calculated according to the given mass formula
1566  // (see KVNucleus).
1567 
1568  TGraph* punch = new TGraph(92);
1569  punch->SetName(Form("KVDetpunchthrough_%s_mass%d", GetName(), massform));
1570  punch->SetTitle(Form("Simple Punch-through %s (MeV) (mass formula %d)", GetName(), massform));
1571  KVNucleus nuc;
1572  nuc.SetMassFormula(massform);
1573  for (int Z = 1; Z <= 92; Z++) {
1574  nuc.SetZ(Z);
1575  punch->SetPoint(Z - 1, Z, GetPunchThroughEnergy(nuc.GetZ(), nuc.GetA()));
1576  }
1577  return punch;
1578 }
1579 
1580 
1581 
1586 
1588 {
1589  // Creates and fills a KVDrawable<TGraph> with the punch through energy in MeV/nucleon vs. Z for the given detector,
1590  // for Z=1-92. The mass of each nucleus is calculated according to the given mass formula
1591  // (see KVNucleus).
1592 
1593  TGraph* punch = new TGraph(92);
1594  punch->SetName(Form("KVDetpunchthroughEsurA_%s_mass%d", GetName(), massform));
1595  punch->SetTitle(Form("Simple Punch-through %s (AMeV) (mass formula %d)", GetName(), massform));
1596  KVNucleus nuc;
1597  nuc.SetMassFormula(massform);
1598  for (int Z = 1; Z <= 92; Z++) {
1599  nuc.SetZ(Z);
1600  punch->SetPoint(Z - 1, Z, GetPunchThroughEnergy(nuc.GetZ(), nuc.GetA()) / nuc.GetA());
1601  }
1602  return punch;
1603 }
1604 
1605 
1606 
1607 
1609 
1611 {
1612  return (KVGroup*)GetParentStructure("GROUP");
1613 }
1614 
1615 
1616 
1618 
1620 {
1621  return (GetGroup() ? GetGroup()->GetNumber() : 0);
1622 }
1623 
1624 
1625 
1627 
1629 {
1630  fParentStrucList.Add(elem);
1631 }
1632 
1633 
1634 
1636 
1638 {
1639  fParentStrucList.Remove(elem);
1640 }
1641 
1642 
1643 
1647 
1649 {
1650  // Get parent geometry structure element of given type.
1651  // Give unique name of structure if more than one element of same type is possible.
1652  KVGeoStrucElement* el = 0;
1653  if (strcmp(name, "")) {
1655  el = (KVGeoStrucElement*)strucs->FindObject(name);
1656  delete strucs;
1657  }
1658  else
1660  return el;
1661 }
1662 
1663 
1664 
1667 
1669 {
1670  // Set ROOT geometry global matrix transformation to coordinate frame of active layer volume
1671  SetMatrix(m);
1672 }
1673 
1674 
1675 
1678 
1680 {
1681  // Set ROOT geometry shape of active layer volume
1682  SetShape(s);
1683 }
1684 
1685 
1686 
1689 
1691 {
1692  // Set ROOT geometry global matrix transformation to coordinate frame of entrance window
1694 }
1695 
1696 
1697 
1700 
1702 {
1703  // Set ROOT geometry shape of entrance window
1704  fEWPosition.SetShape(s);
1705 }
1706 
1707 
1708 
1719 
1721 {
1722  // Overrides KVMaterial::SetThickness
1723  //
1724  // If ROOT geometry is defined, we modify the DZ thickness of the volume representing
1725  // this detector in accordance with the new thickness.
1726  //
1727  // This is only implemented for single-layer detectors with the following shapes:
1728  // - TGeoBBox (rectangular box)
1729  // - TGeoTube (tube)
1730  // - TGeoArb8 (arbitrary trapezoid with less than 8 vertices standing on two parallel planes perpendicular to Z axis)
1731 
1732  if (ROOTGeo() && fSingleLayer) {
1735  TGeoBBox* shape = (TGeoBBox*)pn->GetShape();
1736  TGeoShape* newshape = nullptr;
1737  // bad kludge - is there no better way to clone a shape and change its dZ?
1738  if (shape->IsA() == TGeoBBox::Class()) {
1739  newshape = new TGeoBBox(shape->GetDX(), shape->GetDY(), 0.5 * thick);
1740  }
1741  else if (shape->IsA() == TGeoTube::Class()) {
1742  TGeoTube* oldtube = static_cast<TGeoTube*>(shape);
1743  newshape = new TGeoTube(oldtube->GetRmin(), oldtube->GetRmax(), 0.5 * thick);
1744  }
1745  else if (shape->IsA() == TGeoArb8::Class()) {
1746  TGeoArb8* oldtube = static_cast<TGeoArb8*>(shape);
1747  auto vert = oldtube->GetVertices();
1748  newshape = new TGeoArb8(0.5 * thick, vert);
1749  }
1750  else {
1751  Error("SetThickness", "No implementation for %s (%s)", shape->IsA()->GetName(), GetName());
1752  }
1753  if (newshape) {
1754  pn->Align(nullptr, newshape);
1756  }
1757  }
1758  KVMaterial::SetThickness(thick);
1759 }
1760 
1761 
1762 
1768 
1770 {
1771  // Return kTRUE if the two detectors have the same internal structure, i.e.
1772  // - the same number of absorber layers
1773  // - in the same order
1774  // - with the same material & thickness
1775 
1776  int nabs = GetNumberOfAbsorberLayers();
1777  if (other->GetNumberOfAbsorberLayers() != nabs) return kFALSE;
1778  bool same = true;
1779  for (int iabs = 0; iabs < nabs; ++iabs) {
1780  KVMaterial* this_abs = GetAbsorber(iabs);
1781  KVMaterial* other_abs = other->GetAbsorber(iabs);
1782  if (!this_abs->IsType(other_abs->GetType())
1783  || this_abs->GetMass() != other_abs->GetMass()
1784  || this_abs->GetThickness() != other_abs->GetThickness())
1785  same = false;
1786  }
1787  return same;
1788 }
1789 
1790 
1791 
1799 
1801 {
1802  // Add a new signal to the list of detector's signals.
1803  // \param[in] type define the name of the signal to add
1804  // \returns pointer to the new signal object
1805  // \note do not `delete`{.cpp} the signal object: the detector handles deletion
1806  //
1807  // If the type is "SignalTrace", we add a special KVDetectorSignalTrace object
1808 
1809  if(type=="SignalTrace")
1810  return AddDetectorSignalTrace();
1811  auto signal = new KVDetectorSignal(type, this);
1812  fDetSignals.Add(signal);
1813  return signal;
1814 }
1815 
1816 
1817 
1823 
1825 {
1826  // Add a new signal trace (with type "SignalTrace") to the list of detector's signals.
1827  //
1828  // \returns pointer to the new signal object
1829  // \note do not `delete`{.cpp} the signal object: the detector handles deletion
1830 
1831  auto signal = new KVDetectorSignalTrace(this);
1832  fDetSignals.Add(signal);
1833  return signal;
1834 }
1835 
1836 
1837 
1845 
1847 {
1848  // Add a new KVDetectorSignalExpression to this detector
1849  //
1850  // \param[in] type the name/type of the new signal
1851  // \param[in] _expr mathematical expression using any of the known signals of the detector
1852  //
1853  // \note If the expression is not valid, no signal will be created and method returns kFALSE.
1854 
1856  if (!ds->IsValid()) {
1857  delete ds;
1858  ds = nullptr;
1859  }
1860  else
1861  AddDetectorSignal(ds);
1862  return (ds != nullptr);
1863 }
1864 
1865 
1866 
1875 
1877 {
1878  // \param[in] P pressure in [Torr]
1879  //
1880  // For a gaseous detector, set/change the pressure of the active gas layer.
1881  //
1882  // For ROOT geometries, we change the medium/material of the corresponding node in the geometry
1883  // in order to reflect the change in pressure (gases are represented by different media/materials
1884  // for each pressure/temperature) so that it will be taken into account for example when filtering simulated data.
1885 
1887  if (ROOTGeo()) {
1888  // find node in geometry
1891  // use new medium reflecting change in pressure
1893  }
1894 }
1895 
1896 
1897 
1906 
1908 {
1909  // \param[in] T pressure in [deg. C]
1910  //
1911  // For a gaseous detector, set/change the temperature of the active gas layer.
1912  //
1913  // For ROOT geometries, we change the medium/material of the corresponding node in the geometry
1914  // in order to reflect the change in temperature (gases are represented by different media/materials
1915  // for each pressure/temperature) so that it will be taken into account for example when filtering simulated data.
1916 
1918  if (ROOTGeo()) {
1919  // find node in geometry
1922  // use new medium reflecting change in pressure
1924  }
1925 }
1926 
1927 
int Int_t
unsigned int UInt_t
#define SafeDelete(p)
#define e(i)
bool Bool_t
unsigned char UChar_t
char Char_t
float Float_t
constexpr Bool_t kFALSE
double Double_t
constexpr Bool_t kTRUE
const char Option_t
const Bool_t kIterBackward
R__EXTERN TEnv * gEnv
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
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 winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
R__EXTERN TGeoManager * gGeoManager
#define gROOT
char * Form(const char *fmt,...)
virtual const Char_t * GetType() const
Definition: KVBase.h:176
GetX_status
Definition: KVBase.h:320
void Error(const char *method, const char *msgfmt,...) const override
Definition: KVBase.cpp:1709
static Double_t ProtectedGetX(const TF1 *func, Double_t val, GetX_status &status, std::optional< Double_t > xmin={}, std::optional< Double_t > xmax={})
Definition: KVBase.cpp:1623
virtual Bool_t IsType(const Char_t *typ) const
Definition: KVBase.h:184
virtual void SetType(const Char_t *str)
Definition: KVBase.h:172
static TPluginHandler * LoadPlugin(const Char_t *base, const Char_t *uri="0")
Definition: KVBase.cpp:796
void Warning(const char *method, const char *msgfmt,...) const override
Definition: KVBase.cpp:1696
UInt_t GetNumber() const
Definition: KVBase.h:219
Output signal from detector obtained by calibration.
Bool_t IsAvailableFor(const KVNameValueList &params) const override
Base class for all detector calibrations.
Definition: KVCalibrator.h:99
virtual void SetDetector(KVDetector *d)
Definition: KVCalibrator.h:236
TString GetInputSignalType() const
Definition: KVCalibrator.h:228
TString GetOutputSignalType() const
Definition: KVCalibrator.h:232
Signal output from a mathematical combination of other signals.
Detector signal waveform.
Base class for output signal data produced by a detector.
virtual Bool_t IsExpression() const
virtual Bool_t IsRaw() const
virtual Bool_t GetValueNeedsExtraParameters() const
virtual Double_t GetValue(const KVNameValueList &params="") const
virtual void Reset()
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:160
static KVDetector * MakeDetector(const Char_t *name, Float_t thick)
void SetThickness(Double_t thick) override
virtual Bool_t IsSimMode() const
Definition: KVDetector.h:638
virtual Bool_t IsOK() const
Definition: KVDetector.h:667
KVPosition fEWPosition
position of entrance window i.e. first volume in detector geometry
Definition: KVDetector.h:163
KVMaterial * GetActiveLayer() const override
Definition: KVDetector.h:313
KVUniqueNameList fParentStrucList
list of geometry structures which directly contain this detector
Definition: KVDetector.h:164
Int_t GetNumberOfAbsorberLayers() const
Definition: KVDetector.h:328
void SetMaterial(const Char_t *type) override
Definition: KVDetector.cpp:169
Double_t ELossActive(Double_t *x, Double_t *par)
Definition: KVDetector.cpp:921
virtual KVDrawable< TGraph > DrawPunchThroughEnergyVsZ(Int_t massform=KVNucleus::kBetaMass)
void SetTemperature(Double_t T) override
KVList * fCalibrators
list of associated calibrator objects
Definition: KVDetector.h:258
KVGeoStrucElement * GetParentStructure(const Char_t *type, const Char_t *name="") const
KVGroup * GetGroup() const
void AddDetectorSignal(KVDetectorSignal *ds)
Definition: KVDetector.h:278
Double_t GetRange(Int_t Z, Int_t A, Double_t Einc) override
Double_t GetIncidentEnergyFromERes(Int_t Z, Int_t A, Double_t Eres) override
Bool_t IsCalibrated(const KVNameValueList &params={}) const
Definition: KVDetector.cpp:545
Bool_t fDetecting
=kTRUE if detector is "detecting", =kFALSE if not
Definition: KVDetector.h:274
Bool_t ReplaceCalibrator(const Char_t *type, KVCalibrator *cal, const KVNameValueList &opts="")
Definition: KVDetector.cpp:517
virtual Double_t GetTotalDeltaE(Int_t Z, Int_t A, Double_t Einc)
virtual Double_t GetEnergy() const
Definition: KVDetector.h:365
virtual TF1 * GetEResFunction(Int_t Z, Int_t A)
static Int_t fDetCounter
Definition: KVDetector.h:166
void AddAbsorber(KVMaterial *)
Definition: KVDetector.cpp:610
KVDetectorSignalTrace * AddDetectorSignalTrace()
virtual Double_t GetEResAfterDetector() const
Definition: KVDetector.h:622
Double_t GetIncidentEnergy(Int_t Z, Int_t A, Double_t delta_e=-1.0, enum SolType type=kEmax) override
Double_t GetPunchThroughEnergy(Int_t Z, Int_t A) override
void AddParentStructure(KVGeoStrucElement *elem)
Double_t GetDeltaE(Int_t Z, Int_t A, Double_t Einc, Double_t=0.) override
Double_t fEResforEinc
used by GetIncidentEnergy & GetCorrectedEnergy
Definition: KVDetector.h:270
void Print(Option_t *option="") const override
Definition: KVDetector.cpp:356
virtual KVDrawable< TGraph > DrawPunchThroughEsurAVsZ(Int_t massform=KVNucleus::kBetaMass)
virtual Int_t FindZmin(Double_t ELOSS=-1., Char_t mass_formula=-1)
Definition: KVDetector.cpp:851
TF1 * fELossF
parametric function dE in active layer vs. incident energy
Definition: KVDetector.h:266
Double_t GetLinearRange(Int_t Z, Int_t A, Double_t Einc) override
const KVPosition & GetEntranceWindow() const
Definition: KVDetector.h:684
KVMaterial * GetAbsorber(Int_t i) const
Returns pointer to the i-th absorber in the detector (i=0 first absorber, i=1 second,...
Definition: KVDetector.cpp:626
@ kIdentifiedParticle
Definition: KVDetector.h:174
@ kUnidentifiedParticle
Definition: KVDetector.h:173
void ClearHits()
Definition: KVDetector.h:433
void SetEnergyLoss(Double_t e) const override
Definition: KVDetector.h:389
void remove_signal_for_calibrator(KVCalibrator *K)
Definition: KVDetector.cpp:680
TF1 * fEResF
parametric function Eres residual energy after all layers of detector
Definition: KVDetector.h:267
Bool_t HasSameStructureAs(const KVDetector *) const
UInt_t GetGroupNumber()
virtual KVDetectorSignal * GetDetectorSignal(const KVString &type) const
Definition: KVDetector.h:534
virtual void ReadDefinitionFromFile(const Char_t *)
Double_t GetEnergyLoss() const override
Definition: KVDetector.h:385
void SetShape(TGeoBBox *s) override
Definition: KVDetector.h:187
void Copy(TObject &obj) const override
Definition: KVDetector.cpp:130
virtual TF1 * GetELossFunction(Int_t Z, Int_t A)
KVUnownedList fParticles
list of particles hitting detector in an event
Definition: KVDetector.h:259
void SetActiveLayer(KVMaterial *actif)
Definition: KVDetector.h:303
KVDetector()
default ctor
Definition: KVDetector.cpp:59
Bool_t BelongsToUnidentifiedParticle() const
Definition: KVDetector.h:562
void DetectParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:195
Double_t RangeDet(Double_t *x, Double_t *par)
Definition: KVDetector.cpp:959
Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:320
virtual void RemoveCalibrators()
Definition: KVDetector.cpp:702
virtual Double_t GetEntranceWindowSurfaceArea()
Return surface area of first layer of detector in cm2.
TGeoBBox * GetShape() const override
Definition: KVDetector.h:195
KVUniqueNameList fDetSignals
list of signals associated with detector
Definition: KVDetector.h:224
Double_t get_corrected_energy(AbsorberStack *stack, KVNucleus *nuc, Double_t e, Bool_t transmission)
Definition: KVDetector.h:230
Int_t fUnidentP
temporary counters, determine state of identified/unidentified particle flags
Definition: KVDetector.h:178
TF1 * fRangeF
parametric function range of particles in detector
Definition: KVDetector.h:268
Bool_t AddDetectorSignalExpression(const KVString &type, const KVString &_expr)
virtual void SetEResAfterDetector(Double_t e)
Definition: KVDetector.h:618
void SetActiveLayerMatrix(const TGeoHMatrix *)
Set ROOT geometry global matrix transformation to coordinate frame of active layer volume.
Double_t GetERes(Int_t Z, Int_t A, Double_t Einc, Double_t=0.) override
virtual Bool_t IsDetecting() const
Definition: KVDetector.h:657
Double_t GetMaxDeltaE(Int_t Z, Int_t A) override
void RemoveParentStructure(KVGeoStrucElement *elem)
virtual Double_t GetSmallestEmaxValid(Int_t Z, Int_t A) const
const KVSeqCollection & GetListOfDetectorSignals() const
Definition: KVDetector.h:779
KVGeoDetectorNode * GetNode()
Definition: KVDetector.h:345
Bool_t fSimMode
=kTRUE when using to simulate detector response, =kFALSE when analysing data
Definition: KVDetector.h:272
Double_t GetDeltaEFromERes(Int_t Z, Int_t A, Double_t Eres) override
void SetMatrix(const TGeoHMatrix *m) override
Definition: KVDetector.h:183
void SetEntranceWindowMatrix(const TGeoHMatrix *)
Set ROOT geometry global matrix transformation to coordinate frame of entrance window.
Double_t EResDet(Double_t *x, Double_t *par)
KVMaterial * fActiveLayer
The active absorber in the detector.
Definition: KVDetector.h:167
void AddHit(KVNucleus *part)
Definition: KVDetector.h:415
void RemoveAllAbsorbers()
Definition: KVDetector.cpp:649
Double_t GetEIncOfMaxDeltaE(Int_t Z, Int_t A) override
Double_t GetTotalThicknessInCM() const
Definition: KVDetector.h:334
KVCalibrator * GetCalibrator(const Char_t *name, const Char_t *type) const
Definition: KVDetector.h:825
Int_t fIdentP
temporary counters, determine state of identified/unidentified particle flags
Definition: KVDetector.h:177
void SetPressure(Double_t P) override
Double_t GetELostByParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:268
void SetEntranceWindowShape(TGeoBBox *)
Set ROOT geometry shape of entrance window.
Bool_t fPresent
=kTRUE if detector is present, =kFALSE if it has been removed
Definition: KVDetector.h:273
void SetActiveLayerShape(TGeoBBox *)
Set ROOT geometry shape of active layer volume.
void SetAnalysed(Bool_t b=kTRUE)
Definition: KVDetector.h:448
Bool_t fSingleLayer
=kTRUE if detector has a single absorber layer
Definition: KVDetector.h:276
virtual TF1 * GetRangeFunction(Int_t Z, Int_t A)
virtual Double_t GetCorrectedEnergy(KVNucleus *, Double_t e=-1., Bool_t transmission=kTRUE)
Definition: KVDetector.cpp:752
void init()
default initialisations
Definition: KVDetector.cpp:32
void Clear(Option_t *opt="") override
Definition: KVDetector.cpp:568
KVList fAbsorbers
list of absorbers making up the detector
Definition: KVDetector.h:260
Bool_t AddCalibrator(KVCalibrator *cal, const KVNameValueList &opts="")
Definition: KVDetector.cpp:439
Simple wrapper for objects which can be drawn (graphs, histograms)
Definition: KVDrawable.h:29
const Char_t * GetFullPathToNode() const
Base class describing elements of array geometry.
Group of detectors which can be treated independently of all others in array.
Definition: KVGroup.h:20
Extended TList class which owns its objects by default.
Definition: KVList.h:22
A stack of materials in which successive energy losses of charged particles can be calculated ,...
Double_t GetMinimumIncidentAngleForDEMax(Int_t Z, Int_t A, Double_t Emax)
void SetIncidenceAngle(double psi)
Double_t GetMaxDeltaE(Int_t Z, Int_t A)
Description of physical materials used to construct detectors & targets; interface to range tables.
Definition: KVMaterial.h:90
virtual void SetPressure(Double_t)
Definition: KVMaterial.cpp:580
virtual void SetTemperature(Double_t)
Definition: KVMaterial.cpp:646
virtual void SetThickness(Double_t thick)
Definition: KVMaterial.cpp:451
virtual Double_t GetThickness() const
Definition: KVMaterial.cpp:484
virtual TGeoMedium * GetGeoMedium(const Char_t *="")
void Clear(Option_t *opt="") override
Reset absorber - set stored energy lost by particles in absorber to zero.
virtual Double_t GetPunchThroughEnergy(Int_t Z, Int_t A)
virtual void SetMaterial(const Char_t *type)
Definition: KVMaterial.cpp:217
virtual Double_t GetERes(Int_t Z, Int_t A, Double_t Einc, Double_t dx=0.)
KVMaterial()
default ctor
Definition: KVMaterial.cpp:73
virtual Double_t GetDeltaE(Int_t Z, Int_t A, Double_t Einc, Double_t dx=0.)
Definition: KVMaterial.cpp:833
virtual Double_t GetLinearRange(Int_t Z, Int_t A, Double_t Einc)
Definition: KVMaterial.cpp:901
Double_t GetMass() const
Definition: KVMaterial.cpp:302
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)
const Char_t * GetStringValue(const Char_t *name) const
Bool_t HasDoubleParameter(const Char_t *name) const
Bool_t HasParameter(const Char_t *name) const
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
Int_t GetA() const
Definition: KVNucleus.cpp:796
void SetZ(Int_t z, Char_t mt=-1)
Definition: KVNucleus.cpp:700
void SetMassFormula(UChar_t mt)
Definition: KVNucleus.h:341
Int_t GetZ() const
Return the number of proton / atomic number.
Definition: KVNucleus.cpp:767
TVector3 * GetPInitial() const
Definition: KVParticle.h:729
TVector3 GetMomentum() const
Definition: KVParticle.h:607
KVNameValueList * GetParameters() const
Definition: KVParticle.h:818
Double_t GetEnergy() const
Definition: KVParticle.h:624
void SetKE(Double_t ecin)
Definition: KVParticle.cpp:246
void SetMomentum(const TVector3 *v)
Definition: KVParticle.h:545
void SetE0(TVector3 *e=0)
Definition: KVParticle.h:718
void SetIsDetected()
Definition: KVParticle.h:733
Double_t GetKE() const
Definition: KVParticle.h:617
void SetEnergy(Double_t e)
Definition: KVParticle.h:602
Base class used for handling geometry in a multidetector array.
Definition: KVPosition.h:91
virtual void SetShape(TGeoBBox *)
Definition: KVPosition.cpp:758
virtual Double_t GetSurfaceArea(int npoints=100000) const
Definition: KVPosition.cpp:989
virtual void SetMatrix(const TGeoHMatrix *)
Definition: KVPosition.cpp:717
virtual TGeoBBox * GetShape() const
Definition: KVPosition.cpp:805
virtual Bool_t ROOTGeo() const
Definition: KVPosition.h:210
KaliVeda extensions to ROOT collection classes.
TObject * Remove(TObject *obj) override
Remove object from list.
void Add(TObject *obj) override
TObject * FindObject(const char *name) const override
KVSeqCollection * GetSubListWithType(const Char_t *retvalue) const
Int_t GetSize() const override
void Clear(Option_t *option="") override
virtual TObject * FindObjectByType(const Char_t *) const
TObject * At(Int_t idx) const override
void Delete(Option_t *option="") override
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
void RBegin(TString delim) const
Definition: KVString.cpp:768
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
KVString RNext(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:841
void Add(TObject *obj) override
Handle several calibrations valid for different Z ranges.
virtual void Print(Option_t *option, const char *wildcard, Int_t recurse=1) const
virtual Int_t GetEntries() const
virtual const char * GetValue(const char *name, const char *dflt) const
virtual void SetRange(Double_t xmin, Double_t xmax)
void SetTitle(const char *title="") override
virtual void SetNpx(Int_t npx=100)
virtual void GetRange(Double_t &xmin, Double_t &xmax) const
virtual void SetParameters(const Double_t *params)
virtual Double_t Eval(Double_t x, Double_t y=0, Double_t z=0, Double_t t=0) const
virtual Double_t GetMaximum(Double_t xmin=0, Double_t xmax=0, Double_t epsilon=1.E-10, Int_t maxiter=100, Bool_t logx=false) const
virtual Double_t GetMaximumX(Double_t xmin=0, Double_t xmax=0, Double_t epsilon=1.E-10, Int_t maxiter=100, Bool_t logx=false) const
Double_t * GetVertices()
static TClass * Class()
virtual Double_t GetDX() const
virtual Double_t GetFacetArea(Int_t index=0) const
virtual Double_t GetDY() const
static TClass * Class()
TClass * IsA() const override
void RefreshPhysicalNodes(Bool_t lock=kTRUE)
TGeoPhysicalNode * MakePhysicalNode(const char *path=nullptr)
TObjArray * GetListOfPhysicalNodes()
Bool_t Align(TGeoMatrix *newmat=nullptr, TGeoShape *newshape=nullptr, Bool_t check=kFALSE, Double_t ovlp=0.001)
TGeoVolume * GetVolume(Int_t level=-1) const
TGeoShape * GetShape(Int_t level=-1) const
virtual Double_t GetRmin() const
static TClass * Class()
virtual Double_t GetRmax() const
virtual void SetMedium(TGeoMedium *medium)
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
void SetName(const char *name="") override
void SetTitle(const char *title="") override
void Reset()
TObject * Clone(const char *newname="") const override
const char * GetName() const override
virtual void SetName(const char *name)
TObject * FindObject(const char *name) const override
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
virtual const char * ClassName() const
virtual Bool_t InheritsFrom(const char *classname) const
void ResetBit(UInt_t f)
Longptr_t ExecPlugin(int nargs)
const char * Data() const
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
RVec< PromoteType< T > > abs(const RVec< T > &v)
Double_t x[n]
gr SetName("gr")
double T(double x)
void init()
constexpr Double_t K()
TMarker m
TArc a
ClassImp(TPyArg)