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 
199 
201 {
202  //Calculate the energy loss of a charged particle traversing the detector,
203  //the particle is slowed down, it is added to the list of all particles hitting the
204  //detector.
205  //
206  //The apparent energy loss of the particle in the active layer of the
207  //detector is set.
208  //
209  //If the optional argument 'norm' is given, it is supposed to be a vector
210  //normal to the detector, oriented from the origin towards the detector.
211  //
212  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
213  //depending on its direction of motion is used for the calculation.
214  //
215  //Note that if the detector is part of an array geometry, GetEntranceWindow().GetNormalIntoShape()
216  // returns a TVector3 unit vector which is the normal to the detector.
217 
218  if (kvp->GetKE() <= 0.)
219  return;
220 
221  AddHit(kvp); //add nucleus to list of particles hitting detector in the event
222  //set flag to say that particle has been slowed down
223  kvp->SetIsDetected();
224  //If this is the first absorber that the particle crosses, we set a "reminder" of its
225  //initial energy
226  if (!kvp->GetPInitial())
227  kvp->SetE0();
228 
229  Double_t eloss(0), dE(0);
230  if (norm)
231  {
232  KVMaterialStack stack(this);
234  eloss = stack.GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
235  dE = stack.GetDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
236  }
237  else
238  {
239  eloss = GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
240  dE = GetDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
241  }
242  auto epart = kvp->GetEnergy() - eloss;
243  if (epart < 1e-3) {
244  //printf("%s, pb d arrondi on met l energie de la particule a 0\n",GetName());
245  epart = 0.0;
246  }
247  kvp->SetEnergy(epart);
248  auto eloss_old = GetEnergyLoss();
249  SetEnergyLoss(eloss_old + dE);
250 }
251 
252 
253 
254 
265 
267 {
268  //Calculate the total energy loss of a charged particle traversing the detector.
269  //
270  //This does not affect the "stored" energy loss value of the detector nor the energy of the particle.
271  //
272  //If the optional argument 'norm' is given, it is supposed to be a vector
273  //normal to the detector, oriented from the origin towards the detector.
274  //
275  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
276  //depending on its direction of motion is used for the calculation.
277 
278  if (norm)
279  {
280  KVMaterialStack stack(this);
282  return stack.GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
283  }
284  return GetTotalDeltaE(kvp->GetZ(), kvp->GetA(), kvp->GetEnergy());
285 }
286 
287 
288 
289 
300 
302 {
303  //Calculate the energy of particle 'kvn' before its passage through the detector,
304  //based on the current kinetic energy, Z & A of nucleus 'kvn', supposed to be
305  //after passing through the detector.
306  //
307  //If the optional argument 'norm' is given, it is supposed to be a vector
308  //normal to the detector, oriented from the origin towards the detector.
309  //
310  //In this case the effective thicknesses of the detector's absorbers 'seen' by the particle
311  //depending on its direction of motion is used for the calculation.
312 
313  Double_t Einc = 0.0;
314  //make 'clone' of particle
315  KVNucleus clone_part(kvp->GetZ(), kvp->GetA());
316  clone_part.SetMomentum(kvp->GetMomentum());
317  //composite detector - calculate losses in all layers
318  KVMaterial* abs;
319  TIter next(&fAbsorbers, kIterBackward); //work through list backwards
320  while ((abs = (KVMaterial*) next())) {
321 
322  //calculate energy of particle before current absorber
323  Einc = abs->GetParticleEIncFromERes(&clone_part, norm);
324 
325  //set new energy of particle
326  clone_part.SetKE(Einc);
327  }
328  return Einc;
329 }
330 
331 
332 
333 
337 
338 void KVDetector::Print(Option_t* opt) const
339 {
340  //Print info on this detector
341  //if option="data" the energy loss and raw data are displayed
342 
343  if (!strcmp(opt, "data")) {
344  cout << Form("%10s -- ", GetName());
345  // print raw data signals
346  KVDetectorSignal* sig;
348  while ((sig = (KVDetectorSignal*)it())) {
349  if (sig->IsRaw()) {
350  std::cout << sig->GetName() << "=" << sig->GetValue() << " | ";
351  }
352  }
353  // print calibrated data
354  it.Reset();
355  while ((sig = (KVDetectorSignal*)it())) {
356  if (!sig->IsRaw() && !sig->GetValueNeedsExtraParameters()) {
357  std::cout << sig->GetName() << "=" << sig->GetValue() << " | ";
358  }
359  }
360  cout << " ";
362  cout << "(Belongs to an unidentified particle)";
363  cout << endl;
364  }
365  else if (!strcmp(opt, "all")) {
366  //Give full details of detector
367  //
368  TString option(" ");
369  cout << option << ClassName() << " : " << ((KVDetector*) this)->
370  GetName() << endl;
371  //composite detector - print all layers
372  KVMaterial* abs;
373  TIter next(&fAbsorbers);
374  while ((abs = (KVMaterial*) next())) {
375  if (GetActiveLayer() == abs)
376  cout << " ### ACTIVE LAYER ### " << endl;
377  cout << option << option;
378  abs->Print();
379  if (GetActiveLayer() == abs)
380  cout << " #################### " << endl;
381  }
382  if (fParticles.GetEntries()) {
383  cout << option << " --- Detected particles:" << endl;
384  fParticles.Print();
385  }
386  }
387  else {
388  //just print name
389  cout << ClassName() << ": " << ((KVDetector*) this)->
390  GetName() << endl;
391  }
392 }
393 
394 
395 
420 
422 {
423  // Associate a calibration with this detector.
424  //
425  // This will add a new signal to the list of the detector's signals.
426  //
427  // Also sets calibrator's name to `[detname]_[caltype]` where `caltype` is the type of the KVCalibration object.
428  //
429  // \param[in] cal pointer to KVCalibrator object (must be on heap, i.e. created with new: detector handles deletion)
430  // \param[in] opts
431  // \parblock
432  // can be used to pass any extra parameters/options needed by the calibrator.
433  // For example, if it contains a parameter `ZRange`:
434  //
435  //~~~~~~~~~~~~~~~
436  // ZRange=1-10
437  //~~~~~~~~~~~~~~~
438  //
439  // then the calibrator will be handled by a KVZDependentCalibratedSignal (handles several
440  // calibrators which provide the same output signal, each one is used for a specific range
441  // of atomic numbers)
442  // \endparblock
443  //
444  // \returns kFALSE in case of problems (non-existent input signal for calibrator, output signal not defined for calibrator),
445  // otherwise kTRUE
446 
447  if (!cal) return kFALSE;
448  // look for input signal
450  // input signal must exist
451  if (!in) {
452  KVError::Error(this, "AddCalibrator", "Detector:%s has no signal %s, required as input by calibrator %s to provide output %s",
453  GetName(), cal->GetInputSignalType().Data(), cal->GetType(), cal->GetOutputSignalType().Data());
454  return kFALSE;
455  }
456  if (!fCalibrators)
457  fCalibrators = new KVList();
458 
459  cal->SetDetector(this);
460  fCalibrators->Add(cal);
461  cal->SetName(Form("%s_%s", GetName(), cal->GetType()));
462 
463  if (cal->GetOutputSignalType() == "") {
464  KVError::Warning(this, "AddCalibrator", "%s : output signal not defined for calibrator %s. No output signal created.",
465  GetName(), cal->GetType());
466  }
467  else {
468  KVDetectorSignal* new_cal_sig(nullptr);
469  if (opts.HasParameter("ZRange")) {
470  // If 'ZRange' parameter is given we need to find the KVZDependentCalibratedSignal
471  // and add a new signal to it.
473  if (!sig) {
474  new_cal_sig = sig = new KVZDependentCalibratedSignal(in, cal->GetOutputSignalType());
475  }
476  dynamic_cast<KVZDependentCalibratedSignal*>(sig)->AddSignal(new KVCalibratedSignal(in, cal), opts.GetStringValue("ZRange"));
477  }
478  else {
479  new_cal_sig = new KVCalibratedSignal(in, cal);
480  }
481  if (new_cal_sig) fDetSignals.Add(new_cal_sig);
482  }
483  return kTRUE;
484 }
485 
486 
487 
498 
500 {
501  // Replace calibrator of given type with the given calibrator object
502  // The calibrator object should not be shared with any other detectors: it now belongs
503  // to this detector, which will delete it when necessary.
504  // If an exising calibrator with the same type is already defined, it will be
505  // deleted and removed from the detector's calibrator list
506  //
507  // Returns kFALSE in case of problems.
508  //
509  // The (optional) KVNameValueList argument can be used to pass any extra parameters/options.
510 
511  KVCalibrator* old_cal = GetCalibrator(type);
512  if (old_cal) {
513  fCalibrators->Remove(old_cal);
515  delete old_cal;
516  }
517  return AddCalibrator(cal, opts);
518 }
519 
520 
521 
526 
528 {
529  // A detector is considered to be calibrated if it has
530  // a signal "Energy" available and if depending on the supplied parameters
531  // this signal can be calculated
532 
533  if(IsSimMode())
534  return IsDetecting();
535 
536  KVCalibratedSignal* e_sig = dynamic_cast<KVCalibratedSignal*>(GetDetectorSignal("Energy"));
537  return (e_sig && e_sig->IsAvailableFor(params) && IsOK());
538 }
539 
540 
541 
542 
549 
551 {
552  //Set energy loss(es) etc. to zero
553  //
554  //If opt="N":
555  // + we do not reset acquisition parameters/raw detector signals
556  // + in SimMode we do not reset energy losses (this is called before reconstruction happens)
557 
558  bool option_N = (strncmp(opt, "N", 1) == 0);
559  bool sim_mode_option_N = option_N && IsSimMode();
560 
561  if (!sim_mode_option_N) KVMaterial::Clear(opt);
563  fIdentP = fUnidentP = 0;
566  if (!option_N) {
568  KVDetectorSignal* ds;
569  while ((ds = (KVDetectorSignal*)it())) {
570  if (ds->IsRaw() && !ds->IsExpression()) ds->Reset();
571  }
572  }
573  ClearHits();
574  if (!sim_mode_option_N) {
575  //reset all layers in detector
576  KVMaterial* mat;
577  TIter next(&fAbsorbers);
578  while ((mat = (KVMaterial*) next())) {
579  mat->Clear();
580  }
581  }
582  fEResforEinc = -1.;
583 }
584 
585 
586 
591 
593 {
594  // Add a layer of absorber material to the detector
595  // By default, the first layer added is set as the "Active" layer.
596  // Call SetActiveLayer to change this.
597  fAbsorbers.Add(mat);
598  if (!TestBit(kActiveSet))
599  SetActiveLayer(mat);
600  if (fAbsorbers.GetSize() > 1) fSingleLayer = kFALSE;
601 }
602 
603 
604 
607 
609 {
610  //Returns pointer to the i-th absorber in the detector (i=0 first absorber, i=1 second, etc.)
611 
612  if (!fAbsorbers.GetEntries()) {
613  KVError::Error(this, "GetAbsorber", "No absorbers defined for detector");
614  return nullptr;
615  }
616  if (i < 0 || i >= fAbsorbers.GetEntries()) {
617  KVError::Error(this, "GetAbsorber", "i=%d but valid values are 0-%d [number of absorbers in list]", i,
619  return nullptr;
620  }
621  return (KVMaterial*) fAbsorbers.At(i);
622 }
623 
624 
625 
630 
632 {
633  // Completely reset the KVDetector as if it had just been created by a call to the default constructor:
634  // + removes all absorber layers
635  // + removes all calibrators/detector signals
636 
637  Clear();
640  fAbsorbers.Clear();
644  fCalibrators = nullptr;
645  fActiveLayer = nullptr;
647  fIdentP = fUnidentP = 0;
648  fELossF = fEResF = fRangeF = nullptr;
649  fEResforEinc = -1.;
650  fSimMode = kFALSE;
651  fPresent = kTRUE;
652  fDetecting = kTRUE;
654 }
655 
656 
657 
661 
663 {
664  // Used when a calibrator object is removed or replaced
665  // We remove and delete the corresponding output signal from the list of detector signals
666 
667  if (K->GetOutputSignalType() != "") {
668  KVDetectorSignal* ds = GetDetectorSignal(K->GetOutputSignalType());
669  if (ds) {
670  fDetSignals.Remove(ds);
671  delete ds;
672  }
673  }
674 }
675 
676 
677 
683 
685 {
686  // Removes all calibrations associated to this detector: in other words, we delete all
687  // the KVCalibrator objects in list fCalibrators.
688  //
689  // We also destroy all signals provided by these calibrators
690 
691  if (fCalibrators) {
692  KVCalibrator* K;
693  TIter it(fCalibrators);
694  while ((K = (KVCalibrator*)it())) {
696  }
697  fCalibrators->Delete();
698  }
699 }
700 
701 
702 
703 
761 
763 {
764  // \returns the calculated *total* energy loss in the detector for a given nucleus including inactive absorber layers.
765  //
766  // \param[in] e [MeV] energy loss of nucleus in active layer - if not given, we use current value
767  // \param[in] transmission
768  // + if kTRUE (default): the particle is assumed to emerge with a non-zero residual energy \f$E_{res}\f$ after the detector
769  // + if kFALSE: the particle is assumed to stop in the detector.
770  //
771  // \warning if transmission=kTRUE, and if the residual energy after the detector
772  // is known (i.e. measured in a detector placed after this one), you should
773  // first call method SetEResAfterDetector() with the value of the residual energy
774  // before calling this method. Otherwise, especially for heavy ions, the
775  // correction may be false for particles which are just above the punch-through energy.
776  //
777  // #### Angle of incidence and effective thickness
778  // It is possible that the measured energy loss in the active layer is greater than the maximum
779  // theoretical value calculated from range tables. Apart from the uncertainty in the actual measurement
780  // (plus the uncertainty of the detector calibration), for any detector covering a finite solid angle
781  // the angles of incidence of particles hitting the detector will have a distribution, with very
782  // few (even none) arriving in a direction perpendicular to the detector's surface, i.e. in the direction of
783  // the axis along which the detector's nominal thickness is defined.
784  //
785  // In this case, the effective thickness of the detector is increased by a factor \f$1/\cos\psi\f$, where \f$\psi\f$
786  // is the angle between the particle's trajectory and the normal to the detector. We take this into account when
787  // trying to decide if the measured energy loss is consistent with the nucleus in question, by using a
788  // KVMaterialStack.
789  //
790  // KVMaterialStack can calculate the minimum value of \f$\psi_{\Delta E}\f$ that would be compatible
791  // with a given energy loss (i.e. that for which the maximum possible energy loss is that which was measured): see KVMaterialStack::GetMinimumIncidentAngleForDEMax().
792  // We can then check if such an angle is compatible with the geometry of the detector - GetMaximumMisalignmentAngle()
793  // gives the largest possible value, \f$\psi_{max}\f$, for particles impinging on the detector.
794  //
795  // If a minimum angle of incidence \f$\psi_{\Delta E}\f$ which is consistent with the geometry can be found,
796  // it is stored in the parameters of the reconstructed nucleus with name `GetCorrectedEnergy.IncidenceAngle`
797  // i.e. for any reconstructed nucleus you can do
798  //
799  //~~~{.cpp}
800  // KVReconstructedNucleus& rnuc; // reference to a reconstructed nucleus
801  // if( rnuc.GetParameters()->HasParameter("GetCorrectedEnergy.IncidenceAngle") )
802  // {
803  // auto psi = rnuc.GetParameters()->GetDoubleValue("GetCorrectedEnergy.IncidenceAngle");
804  // }
805  //~~~
806  //
807  // If \f$\psi_{\Delta E}>\psi_{max}\f$, we use the (apparently impossible) incidence angle in order to calculate the
808  // corrected energy, and we add the following warning parameters to the particle, each of which begins with the
809  // name of the detector (unlike the previous one):
810  //
811  //~~~
812  // [det].GetCorrectedEnergy.Warning = 1
813  // [det].GetCorrectedEnergy.MeasuredDE = [value]
814  // [det].GetCorrectedEnergy.MaxDE = [value]
815  // [det].GetCorrectedEnergy.Transmission = 0 or 1
816  // [det].GetCorrectedEnergy.ERES = [value]
817  // [det].GetCorrectedEnergy.RequiredIncidenceAngle = [value]
818  // [det].GetCorrectedEnergy.MaximumIncidenceAngle = [value]
819  //~~~
820 
821  Int_t z = nuc->GetZ();
822  Int_t a = nuc->GetA();
823 
824  if (e < 0.) e = GetEnergy();
825  if (e <= 0) {
827  return 0;
828  }
829 
830  auto get_stack_correct_energy = [&](KVMaterialStack& stack, double maxDE, bool save_angle_if_good = false)
831  {
832  auto inc_angle = stack.GetMinimumIncidentAngleForDEMax(z, a, e);
833  stack.SetIncidenceAngle(inc_angle);
834  // check incidence angle is consistent with geometry
836  {
837  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Warning", GetName()), 1);
838  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MeasuredDE", GetName()), e);
839  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MaxDE", GetName()), maxDE);
840  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.Transmission", GetName()), (Int_t)transmission);
841  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.ERES", GetName()), GetEResAfterDetector());
842  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.RequiredIncidenceAngle", GetName()), inc_angle);
843  nuc->GetParameters()->SetValue(Form("%s.GetCorrectedEnergy.MaximumIncidenceAngle", GetName()), GetEntranceWindow().GetMaximumMisalignmentAngle());
844  }
845  else
846  {
847  if(save_angle_if_good)
848  {
849  // if the incidence angle is consistent with geometry, we keep it for use with other detectors on the particle's
850  // trajectory - in principle it should be the same for all
851  nuc->GetParameters()->SetValue("GetCorrectedEnergy.IncidenceAngle", inc_angle);
852  }
853  }
854  };
855  // check if calling this function for a previous detector in the particle's trajectory
856  // led to using an effective incident angle for the particle: if so, use it here
857  if (nuc->GetParameters()->HasDoubleParameter("GetCorrectedEnergy.IncidenceAngle")) {
858  KVMaterialStack stack(this);
859  stack.SetIncidenceAngle(nuc->GetParameters()->GetDoubleValue("GetCorrectedEnergy.IncidenceAngle"));
860  // check that apparent energy loss in detector is compatible with a & z
861  Double_t maxDE = stack.GetMaxDeltaE(z, a);
862  if (e > maxDE)
863  get_stack_correct_energy(stack,maxDE);
864  return get_corrected_energy(&stack, nuc, e, transmission);
865  }
866  // check that apparent energy loss in detector is compatible with a & z
867  Double_t maxDE = GetMaxDeltaE(z, a);
868  if (e > maxDE) {
869  KVMaterialStack stack(this);
870  get_stack_correct_energy(stack,maxDE,true);
871  return get_corrected_energy(&stack, nuc, e, transmission);
872  }
873  return get_corrected_energy(this, nuc, e, transmission);
874 }
875 
876 
877 
878 
896 
898 {
899  //For particles which stop in the first stage of an identification telescope,
900  //we can at least estimate a minimum Z value based on the energy lost in this
901  //detector.
902  //
903  //This is based on the KVMaterial::GetMaxDeltaE method, giving the maximum
904  //energy loss in the active layer of the detector for a given nucleus (A,Z).
905  //
906  //The "Zmin" is the Z of the particle which gives a maximum energy loss just greater
907  //than that measured in the detector. Particles with Z<Zmin could not lose as much
908  //energy and so are excluded.
909  //
910  //If ELOSS is not given, we use the current value of GetEnergy()
911  //Use 'mass_formula' to change the formula used to calculate the A of the nucleus
912  //from its Z. Default is valley of stability value. (see KVNucleus::GetAFromZ).
913  //
914  //If the value of ELOSS or GetEnergy() is <=0 we return Zmin=0
915 
916  ELOSS = (ELOSS < 0. ? GetEnergy() : ELOSS);
917  if (ELOSS <= 0) return 0;
918 
919  UInt_t z = 40;
920  UInt_t zmin, zmax;
921  zmin = 1;
922  zmax = 92;
923  KVNucleus particle(zmin);
924 
925  if (mass_formula > -1)
926  particle.SetMassFormula((UChar_t)mass_formula);
927 
928  if (GetMaxDeltaE(particle.GetZ(), particle.GetA()) > ELOSS)
929  return zmin; // Z=1 solution
930 
931  do {
932 
933  particle.SetZ(z);
934 
935  auto difference = GetMaxDeltaE(z, particle.GetA()) - ELOSS;
936  //if difference < 0 the z is too small
937  if (difference < 0.0) {
938 
939  zmin = z;
940  z += (UInt_t)((zmax - z) / 2 + 0.5);
941 
942  }
943  else {
944 
945  zmax = z;
946  z -= (UInt_t)((z - zmin) / 2 + 0.5);
947 
948  }
949  }
950  while (zmax > (zmin + 1));
951 
952  return zmax;
953 }
954 
955 
956 
957 
966 
968 {
969  // Calculates energy loss (in MeV) in active layer of detector, taking into account preceding layers
970  //
971  // Arguments are:
972  // x[0] is incident energy in MeV
973  // Parameters are:
974  // par[0] Z of ion
975  // par[1] A of ion
976 
977  Double_t e = x[0];
978  TIter next(&fAbsorbers);
979  KVMaterial* mat;
980  mat = (KVMaterial*)next();
981  while (fActiveLayer != mat) {
982  // calculate energy losses in absorbers before active layer
983  e = mat->GetERes(par[0], par[1], e); //residual energy after layer
984  if (e <= 0.)
985  return 0.; // return 0 if particle stops in layers before active layer
986  mat = (KVMaterial*)next();
987  }
988  //calculate energy loss in active layer
989  return mat->GetDeltaE(par[0], par[1], e);
990 }
991 
992 
993 
994 
1004 
1006 {
1007  // Calculates range (in centimetres) of ions in detector as a function of incident energy (in MeV),
1008  // taking into account all layers of the detector.
1009  //
1010  // Arguments are:
1011  // x[0] = incident energy in MeV
1012  // Parameters are:
1013  // par[0] = Z of ion
1014  // par[1] = A of ion
1015 
1016  Double_t Einc = x[0];
1017  Int_t Z = (Int_t)par[0];
1018  Int_t A = (Int_t)par[1];
1019  Double_t range = 0.;
1020  TIter next(&fAbsorbers);
1021  KVMaterial* mat = (KVMaterial*)next();
1022  if (!mat) return 0.;
1023  do {
1024  // range in this layer
1025  Double_t this_range = mat->GetLinearRange(Z, A, Einc);
1026  KVMaterial* next_mat = (KVMaterial*)next();
1027  if (this_range > mat->GetThickness()) {
1028  // particle traverses layer.
1029  if (next_mat)
1030  range += mat->GetThickness();
1031  else // if this is last layer, the range continues to increase beyond size of detector
1032  range += this_range;
1033  // calculate incident energy for next layer (i.e. residual energy after this layer)
1034  Einc = mat->GetERes(Z, A, Einc);
1035  }
1036  else {
1037  // particle stops in layer
1038  range += this_range;
1039  return range;
1040  }
1041  mat = next_mat;
1042  }
1043  while (mat);
1044  // particle traverses detector
1045  return range;
1046 }
1047 
1048 
1049 
1050 
1060 
1062 {
1063  // Calculates residual energy (in MeV) of particle after traversing all layers of detector.
1064  // Returned value is -1000 if particle stops in one of the layers of the detector.
1065  //
1066  // Arguments are:
1067  // x[0] is incident energy in MeV
1068  // Parameters are:
1069  // par[0] Z of ion
1070  // par[1] A of ion
1071 
1072  Double_t e = x[0];
1073  TIter next(&fAbsorbers);
1074  KVMaterial* mat;
1075  while ((mat = (KVMaterial*)next())) {
1076  Double_t eres = mat->GetERes(par[0], par[1], e); //residual energy after layer
1077  if (eres <= 0.)
1078  return -1000.; // return -1000 if particle stops in layers before active layer
1079  e = eres;
1080  }
1081  return e;
1082 }
1083 
1084 
1085 
1086 
1101 
1103 {
1104  //Static function which will create an instance of the KVDetector-derived class
1105  //corresponding to 'name'
1106  //These are defined as 'Plugin' objects in the file $KVROOT/KVFiles/.kvrootrc :
1107  // [name_of_dataset].detector_type
1108  // detector_type
1109  // To use the dataset-dependent plugin, call this method with
1110  // name = "[name_of_dataset].detector_type"
1111  // If not, the default plugin will be used
1112  //first we check if there is a special plugin for the DataSet
1113  //if not we take the default one
1114  //
1115  //'thickness' is passed as argument to the constructor for the detector plugin
1116 
1117  //check and load plugin library
1118  TPluginHandler* ph = nullptr;
1119  KVString nom(name);
1120  if (!nom.Contains(".") && !(ph = LoadPlugin("KVDetector", name))) return nullptr;
1121  if (nom.Contains(".")) {
1122  // name format like [dataset].[det_type]
1123  // in case dataset name contains "." we parse string to find detector type: assumed after the last "."
1124  nom.RBegin(".");
1125  KVString det_type = nom.RNext();
1126  if (!(ph = LoadPlugin("KVDetector", name))) {
1127  if (!(ph = LoadPlugin("KVDetector", det_type))) {
1128  return nullptr;
1129  }
1130  }
1131  }
1132 
1133  //execute constructor/macro for detector
1134  return (KVDetector*) ph->ExecPlugin(1, thickness);
1135 }
1136 
1137 
1138 
1141 
1143 {
1144  // Return surface area of first layer of detector in cm2.
1145 
1146  if (!GetEntranceWindow().GetShape()->InheritsFrom("TGeoArb8")) {
1147  // simple shape area
1148  return GetEntranceWindow().GetShape()->GetFacetArea(1);
1149  }
1150  // Monte Carlo calculation for TGeoArb8 shapes
1151  return GetEntranceWindow().GetSurfaceArea();
1152 }
1153 
1154 
1155 
1160 
1162 {
1163  // Return pointer toTF1 giving residual energy after detector as function of incident energy,
1164  // for a given nucleus (Z,A).
1165  // The TF1::fNpx parameter is taken from environment variable KVDetector.ResidualEnergy.Npx
1166 
1167  if (!fEResF) {
1168  fEResF = new TF1(Form("KVDetector:%s:ERes", GetName()), this, &KVDetector::EResDet,
1169  0., 1.e+04, 2, "KVDetector", "EResDet");
1170  fEResF->SetNpx(gEnv->GetValue("KVDetector.ResidualEnergy.Npx", 20));
1171  }
1173  fEResF->SetRange(0., GetSmallestEmaxValid(Z, A));
1174  fEResF->SetTitle(Form("Residual energy [MeV] after detector %s for Z=%d A=%d", GetName(), Z, A));
1175 
1176  return fEResF;
1177 }
1178 
1179 
1180 
1185 
1187 {
1188  // Return pointer toTF1 giving range (in centimetres) in detector as function of incident energy,
1189  // for a given nucleus (Z,A).
1190  // The TF1::fNpx parameter is taken from environment variable KVDetector.Range.Npx
1191 
1192  if (!fRangeF) {
1193  fRangeF = new TF1(Form("KVDetector:%s:Range", GetName()), this, &KVDetector::RangeDet,
1194  0., 1.e+04, 2, "KVDetector", "RangeDet");
1195  fRangeF->SetNpx(gEnv->GetValue("KVDetector.Range.Npx", 20));
1196  }
1199  fRangeF->SetTitle(Form("Range [cm] in detector %s for Z=%d A=%d", GetName(), Z, A));
1200 
1201  return fRangeF;
1202 }
1203 
1204 
1205 
1210 
1212 {
1213  // Return pointer to TF1 giving energy loss in active layer of detector as function of incident energy,
1214  // for a given nucleus (Z,A).
1215  // The TF1::fNpx parameter is taken from environment variable KVDetector.EnergyLoss.Npx
1216 
1217  if (!fELossF) {
1218  fELossF = new TF1(Form("KVDetector:%s:ELossActive", GetName()), this, &KVDetector::ELossActive,
1219  0., 1.e+04, 2, "KVDetector", "ELossActive");
1220  fELossF->SetNpx(gEnv->GetValue("KVDetector.EnergyLoss.Npx", 20));
1221  }
1224  fELossF->SetTitle(Form("Energy loss [MeV] in detector %s for Z=%d A=%d", GetName(), Z, A));
1225  return fELossF;
1226 }
1227 
1228 
1229 
1233 
1235 {
1236  // Returns incident energy corresponding to maximum energy loss in the
1237  // active layer of the detector, for a given nucleus.
1238 
1239  return GetELossFunction(Z, A)->GetMaximumX();
1240 }
1241 
1242 
1243 
1247 
1249 {
1250  // Returns maximum energy loss in the
1251  // active layer of the detector, for a given nucleus.
1252 
1253  return GetELossFunction(Z, A)->GetMaximum();
1254 }
1255 
1256 
1257 
1261 
1263 {
1264  // Returns energy loss of given nucleus in the active layer of the detector.
1265 
1266  // optimization for single-layer detectors
1267  if (fSingleLayer) {
1268  return fActiveLayer->GetDeltaE(Z, A, Einc);
1269  }
1270  return GetELossFunction(Z, A)->Eval(Einc);
1271 }
1272 
1273 
1274 
1278 
1280 {
1281  // Returns calculated total energy loss of ion in ALL layers of the detector.
1282  // This is just (Einc - GetERes(Z,A,Einc))
1283 
1284  return Einc - GetERes(Z, A, Einc);
1285 }
1286 
1287 
1288 
1292 
1294 {
1295  // Returns residual energy of given nucleus after the detector.
1296  // Returns 0 if Einc<=0
1297 
1298  if (Einc <= 0.) return 0.;
1299  Double_t eres = GetEResFunction(Z, A)->Eval(Einc);
1300  // Eres function returns -1000 when particle stops in detector,
1301  // in order for function inversion (GetEIncFromEres) to work
1302  if (eres < 0.) eres = 0.;
1303  return eres;
1304 }
1305 
1306 
1307 
1328 
1330 {
1331  // Returns incident energy corresponding to energy loss delta_e in active layer of detector for a given nucleus.
1332  // If delta_e is not given, the current energy loss in the active layer is used.
1333  //
1334  // By default the solution corresponding to the highest incident energy is returned
1335  // This is the solution found for Einc greater than the maximum of the dE(Einc) curve.
1336  // If you want the low energy solution set SolType = KVIonRangeTable::kEmin.
1337  //
1338  // \warning Calculating the incident energy of a particle using only the dE in a detector
1339  // is ambiguous, as in general (and especially for very heavy ions) the maximum of the dE
1340  // curve occurs for Einc greater than the punch-through energy, therefore it is not always
1341  // true to assume that if the particle does not stop in the detector the required solution
1342  // is that for type=KVIonRangeTable::kEmax. For a range of energies between punch-through
1343  // and dE_max, the required solution is still that for type=KVMaterial::kEmin.
1344  // If the residual energy of the particle is unknown, there is no way to know which is the
1345  // correct solution.
1346  //
1347  // \warning If the given energy loss in the active layer is greater than the maximum theoretical dE
1348  // for given Z & A, (dE > GetMaxDeltaE(Z,A)) then we return a NEGATIVE incident energy
1349  // corresponding to the maximum, GetEIncOfMaxDeltaE(Z,A)
1350 
1351  if (Z < 1) return 0.;
1352 
1353  Double_t DE = (delta_e > 0 ? delta_e : GetEnergyLoss());
1354 
1355  // If the given energy loss in the active layer is greater than the maximum theoretical dE
1356  // for given Z & A, (dE > GetMaxDeltaE(Z,A)) then we return a NEGATIVE incident energy
1357  // corresponding to the maximum, GetEIncOfMaxDeltaE(Z,A)
1358  if (DE > GetMaxDeltaE(Z, A)) return -GetEIncOfMaxDeltaE(Z, A);
1359 
1360  TF1* dE = GetELossFunction(Z, A);
1361  Double_t e1, e2;
1362  dE->GetRange(e1, e2);
1363  switch (type) {
1364  case kEmin:
1365  e2 = GetEIncOfMaxDeltaE(Z, A);
1366  break;
1367  case kEmax:
1368  e1 = GetEIncOfMaxDeltaE(Z, A);
1369  break;
1370  }
1371  KVBase::GetX_status status;
1372  Double_t EINC = ProtectedGetX(dE, DE, status, e1, e2);
1374 // Warning("GetIncidentEnergy",
1375 // "In %s : Called for Z=%d A=%d with dE=%f sol_type %d",
1376 // GetName(), Z, A, DE, type);
1377 // Warning("GetIncidentEnergy",
1378 // "Max DeltaE in this case is %f MeV",
1379 // GetMaxDeltaE(Z, A));
1380 // Warning("GetIncidentEnergy",
1381 // "Between Einc limits [%f,%f] no solution found",
1382 // e1,e2);
1383 // Warning("GetIncidentEnergy",
1384 // "Returned value is -Einc for %s dE, %f",
1385 // (status>0 ? "maximum" : "minimum"), EINC);
1386  return -EINC;
1387  }
1388  return EINC;
1389 }
1390 
1391 
1392 
1398 
1400 {
1401  // Overrides KVMaterial::GetDeltaEFromERes
1402  //
1403  // Calculate energy loss in active layer of detGetAlignedDetector for nucleus (Z,A)
1404  // having a residual kinetic energy Eres (MeV)
1405 
1406  if (Z < 1 || Eres <= 0.) return 0.;
1407  Double_t Einc = GetIncidentEnergyFromERes(Z, A, Eres);
1408  if (Einc <= 0.) return 0.;
1409  return GetELossFunction(Z, A)->Eval(Einc);
1410 }
1411 
1412 
1413 
1420 
1422 {
1423  // Overrides KVMaterial::GetIncidentEnergyFromERes
1424  //
1425  // Calculate incident energy of nucleus from residual energy.
1426  //
1427  // Returns -1 if Eres is out of defined range of values
1428 
1429  if (Z < 1 || Eres <= 0.) return 0.;
1430  //return GetEResFunction(Z, A)->GetX(Eres);
1431  KVBase::GetX_status status;
1432  Double_t einc = KVBase::ProtectedGetX(GetEResFunction(Z, A), Eres, status);
1433  if (status == KVBase::GetX_status::above_maximum || status == KVBase::GetX_status::below_minimum){// problem with inversion - value out of defined range of function
1434  return -1;
1435  }
1436  return einc;
1437 }
1438 
1439 
1440 
1444 
1446 {
1447  // Returns the smallest maximum energy for which range tables are valid
1448  // for all absorbers in the detector, and given ion (Z,A)
1449 
1450  Double_t maxmin = -1.;
1451  TIter next(&fAbsorbers);
1452  KVMaterial* abs;
1453  while ((abs = (KVMaterial*)next())) {
1454  if (maxmin < 0.) maxmin = abs->GetEmaxValid(Z, A);
1455  else {
1456  if (abs->GetEmaxValid(Z, A) < maxmin) maxmin = abs->GetEmaxValid(Z, A);
1457  }
1458  }
1459  return maxmin;
1460 }
1461 
1462 
1463 
1481 
1483 {
1484  // Create detector from text file in 'TEnv' format.
1485  //
1486  // Example:
1487  // ========
1488  //
1489  // Layer: Gold
1490  // Gold.Material: Au
1491  // Gold.AreaDensity: 200.*KVUnits::ug
1492  // +Layer: Gas1
1493  // Gas1.Material: C3F8
1494  // Gas1.Thickness: 5.*KVUnits::cm
1495  // Gas1.Pressure: 50.*KVUnits::mbar
1496  // Gas1.Active: yes
1497  // +Layer: Si1
1498  // Si1.Material: Si
1499  // Si1.Thickness: 300.*KVUnits::um
1500 
1501  TEnv fEnvFile(envrc);
1502 
1503  KVString layers(fEnvFile.GetValue("Layer", ""));
1504  layers.Begin(" ");
1505  while (!layers.End()) {
1506  KVString layer = layers.Next();
1507  KVString mat = fEnvFile.GetValue(Form("%s.Material", layer.Data()), "");
1508  KVString tS = fEnvFile.GetValue(Form("%s.Thickness", layer.Data()), "");
1509  KVString pS = fEnvFile.GetValue(Form("%s.Pressure", layer.Data()), "");
1510  KVString dS = fEnvFile.GetValue(Form("%s.AreaDensity", layer.Data()), "");
1511  Double_t thick, dens, press;
1512  thick = dens = press = 0.;
1513  KVMaterial* M = 0;
1514  if (pS != "" && tS != "") {
1515  press = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", pS.Data()));
1516  press /= 1.e+12;
1517  thick = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", tS.Data()));
1518  thick /= 1.e+12;
1519  M = new KVMaterial(mat.Data(), thick, press);
1520  }
1521  else if (tS != "") {
1522  thick = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", tS.Data()));
1523  thick /= 1.e+12;
1524  M = new KVMaterial(mat.Data(), thick);
1525  }
1526  else if (dS != "") {
1527  dens = (Double_t)gROOT->ProcessLineFast(Form("%s*1.e+12", dS.Data()));
1528  dens /= 1.e+12;
1529  M = new KVMaterial(dens, mat.Data());
1530  }
1531  if (M) {
1532  AddAbsorber(M);
1533  if (fEnvFile.GetValue(Form("%s.Active", layer.Data()), kFALSE)) SetActiveLayer(M);
1534  }
1535  }
1536 }
1537 
1538 
1539 
1543 
1545 {
1546  // WARNING: SAME AS KVDetector::GetLinearRange
1547  // Only linear range in centimetres is calculated for detectors!
1548  return GetLinearRange(Z, A, Einc);
1549 }
1550 
1551 
1552 
1558 
1560 {
1561  // Returns range of ion in centimetres in this detector,
1562  // taking into account all layers.
1563  // Note that for Einc > punch through energy, this range is no longer correct
1564  // (but still > total thickness of detector).
1565  return GetRangeFunction(Z, A)->Eval(Einc);
1566 }
1567 
1568 
1569 
1573 
1575 {
1576  // Returns energy (in MeV) necessary for ion (Z,A) to punch through all
1577  // layers of this detector
1578 
1579  if (fSingleLayer) {
1580  // Optimize calculation time for single-layer detector
1581  return fActiveLayer->GetPunchThroughEnergy(Z, A);
1582  }
1583  //return GetRangeFunction(Z, A)->GetX(GetTotalThicknessInCM());
1584  KVBase::GetX_status status;
1585  return ProtectedGetX(GetRangeFunction(Z, A),GetTotalThicknessInCM(),status);
1586 }
1587 
1588 
1589 
1590 
1595 
1597 {
1598  // Creates and fills a KVDrawable<TGraph> with the punch through energy in MeV vs. Z for the given detector,
1599  // for Z=1-92. The mass of each nucleus is calculated according to the given mass formula
1600  // (see KVNucleus).
1601 
1602  TGraph* punch = new TGraph(92);
1603  punch->SetName(Form("KVDetpunchthrough_%s_mass%d", GetName(), massform));
1604  punch->SetTitle(Form("Simple Punch-through %s (MeV) (mass formula %d)", GetName(), massform));
1605  KVNucleus nuc;
1606  nuc.SetMassFormula(massform);
1607  for (int Z = 1; Z <= 92; Z++) {
1608  nuc.SetZ(Z);
1609  punch->SetPoint(Z - 1, Z, GetPunchThroughEnergy(nuc.GetZ(), nuc.GetA()));
1610  }
1611  return punch;
1612 }
1613 
1614 
1615 
1620 
1622 {
1623  // Creates and fills a KVDrawable<TGraph> with the punch through energy in MeV/nucleon vs. Z for the given detector,
1624  // for Z=1-92. The mass of each nucleus is calculated according to the given mass formula
1625  // (see KVNucleus).
1626 
1627  TGraph* punch = new TGraph(92);
1628  punch->SetName(Form("KVDetpunchthroughEsurA_%s_mass%d", GetName(), massform));
1629  punch->SetTitle(Form("Simple Punch-through %s (AMeV) (mass formula %d)", GetName(), massform));
1630  KVNucleus nuc;
1631  nuc.SetMassFormula(massform);
1632  for (int Z = 1; Z <= 92; Z++) {
1633  nuc.SetZ(Z);
1634  punch->SetPoint(Z - 1, Z, GetPunchThroughEnergy(nuc.GetZ(), nuc.GetA()) / nuc.GetA());
1635  }
1636  return punch;
1637 }
1638 
1639 
1640 
1641 
1643 
1645 {
1646  return (KVGroup*)GetParentStructure("GROUP");
1647 }
1648 
1649 
1650 
1652 
1654 {
1655  return (GetGroup() ? GetGroup()->GetNumber() : 0);
1656 }
1657 
1658 
1659 
1661 
1663 {
1664  fParentStrucList.Add(elem);
1665 }
1666 
1667 
1668 
1670 
1672 {
1673  fParentStrucList.Remove(elem);
1674 }
1675 
1676 
1677 
1681 
1683 {
1684  // Get parent geometry structure element of given type.
1685  // Give unique name of structure if more than one element of same type is possible.
1686  KVGeoStrucElement* el = 0;
1687  if (strcmp(name, "")) {
1689  el = (KVGeoStrucElement*)strucs->FindObject(name);
1690  delete strucs;
1691  }
1692  else
1694  return el;
1695 }
1696 
1697 
1698 
1701 
1703 {
1704  // Set ROOT geometry global matrix transformation to coordinate frame of active layer volume
1705  SetMatrix(m);
1706 }
1707 
1708 
1709 
1712 
1714 {
1715  // Set ROOT geometry shape of active layer volume
1716  SetShape(s);
1717 }
1718 
1719 
1720 
1723 
1725 {
1726  // Set ROOT geometry global matrix transformation to coordinate frame of entrance window
1728 }
1729 
1730 
1731 
1734 
1736 {
1737  // Set ROOT geometry shape of entrance window
1738  fEWPosition.SetShape(s);
1739 }
1740 
1741 
1742 
1753 
1755 {
1756  // Overrides KVMaterial::SetThickness
1757  //
1758  // If ROOT geometry is defined, we modify the DZ thickness of the volume representing
1759  // this detector in accordance with the new thickness.
1760  //
1761  // This is only implemented for single-layer detectors with the following shapes:
1762  // - TGeoBBox (rectangular box)
1763  // - TGeoTube (tube)
1764  // - TGeoArb8 (arbitrary trapezoid with less than 8 vertices standing on two parallel planes perpendicular to Z axis)
1765 
1766  if (ROOTGeo() && fSingleLayer) {
1769  TGeoBBox* shape = (TGeoBBox*)pn->GetShape();
1770  TGeoShape* newshape = nullptr;
1771  // bad kludge - is there no better way to clone a shape and change its dZ?
1772  if (shape->IsA() == TGeoBBox::Class()) {
1773  newshape = new TGeoBBox(shape->GetDX(), shape->GetDY(), 0.5 * thick);
1774  }
1775  else if (shape->IsA() == TGeoTube::Class()) {
1776  TGeoTube* oldtube = static_cast<TGeoTube*>(shape);
1777  newshape = new TGeoTube(oldtube->GetRmin(), oldtube->GetRmax(), 0.5 * thick);
1778  }
1779  else if (shape->IsA() == TGeoArb8::Class()) {
1780  TGeoArb8* oldtube = static_cast<TGeoArb8*>(shape);
1781  auto vert = oldtube->GetVertices();
1782  newshape = new TGeoArb8(0.5 * thick, vert);
1783  }
1784  else {
1785  KVError::Error(this, "SetThickness", "No implementation for %s (%s)", shape->IsA()->GetName(), GetName());
1786  }
1787  if (newshape) {
1788  pn->Align(nullptr, newshape);
1790  }
1791  }
1792  KVMaterial::SetThickness(thick);
1793 }
1794 
1795 
1796 
1802 
1804 {
1805  // Return kTRUE if the two detectors have the same internal structure, i.e.
1806  // - the same number of absorber layers
1807  // - in the same order
1808  // - with the same material & thickness
1809 
1810  int nabs = GetNumberOfAbsorberLayers();
1811  if (other->GetNumberOfAbsorberLayers() != nabs) return kFALSE;
1812  bool same = true;
1813  for (int iabs = 0; iabs < nabs; ++iabs) {
1814  KVMaterial* this_abs = GetAbsorber(iabs);
1815  KVMaterial* other_abs = other->GetAbsorber(iabs);
1816  if (!this_abs->IsType(other_abs->GetType())
1817  || this_abs->GetMass() != other_abs->GetMass()
1818  || this_abs->GetThickness() != other_abs->GetThickness())
1819  same = false;
1820  }
1821  return same;
1822 }
1823 
1824 
1825 
1833 
1835 {
1836  // Add a new signal to the list of detector's signals.
1837  // \param[in] type define the name of the signal to add
1838  // \returns pointer to the new signal object
1839  // \note do not `delete`{.cpp} the signal object: the detector handles deletion
1840  //
1841  // If the type is "SignalTrace", we add a special KVDetectorSignalTrace object
1842 
1843  if(type=="SignalTrace")
1844  return AddDetectorSignalTrace();
1845  auto signal = new KVDetectorSignal(type, this);
1846  fDetSignals.Add(signal);
1847  return signal;
1848 }
1849 
1850 
1851 
1857 
1859 {
1860  // Add a new signal trace (with type "SignalTrace") to the list of detector's signals.
1861  //
1862  // \returns pointer to the new signal object
1863  // \note do not `delete`{.cpp} the signal object: the detector handles deletion
1864 
1865  auto signal = new KVDetectorSignalTrace(this);
1866  fDetSignals.Add(signal);
1867  return signal;
1868 }
1869 
1870 
1871 
1879 
1881 {
1882  // Add a new KVDetectorSignalExpression to this detector
1883  //
1884  // \param[in] type the name/type of the new signal
1885  // \param[in] _expr mathematical expression using any of the known signals of the detector
1886  //
1887  // \note If the expression is not valid, no signal will be created and method returns kFALSE.
1888 
1890  if (!ds->IsValid()) {
1891  delete ds;
1892  ds = nullptr;
1893  }
1894  else
1895  AddDetectorSignal(ds);
1896  return (ds != nullptr);
1897 }
1898 
1899 
1900 
1909 
1911 {
1912  // \param[in] P pressure in [Torr]
1913  //
1914  // For a gaseous detector, set/change the pressure of the active gas layer.
1915  //
1916  // For ROOT geometries, we change the medium/material of the corresponding node in the geometry
1917  // in order to reflect the change in pressure (gases are represented by different media/materials
1918  // for each pressure/temperature) so that it will be taken into account for example when filtering simulated data.
1919 
1921  if (ROOTGeo()) {
1922  // find node in geometry
1925  // use new medium reflecting change in pressure
1927  }
1928 }
1929 
1930 
1931 
1940 
1942 {
1943  // \param[in] T pressure in [deg. C]
1944  //
1945  // For a gaseous detector, set/change the temperature of the active gas layer.
1946  //
1947  // For ROOT geometries, we change the medium/material of the corresponding node in the geometry
1948  // in order to reflect the change in temperature (gases are represented by different media/materials
1949  // for each pressure/temperature) so that it will be taken into account for example when filtering simulated data.
1950 
1952  if (ROOTGeo()) {
1953  // find node in geometry
1956  // use new medium reflecting change in pressure
1958  }
1959 }
1960 
1961 
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
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:177
GetX_status
Definition: KVBase.h:321
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:1622
virtual Bool_t IsType(const Char_t *typ) const
Definition: KVBase.h:185
virtual void SetType(const Char_t *str)
Definition: KVBase.h:173
static TPluginHandler * LoadPlugin(const Char_t *base, const Char_t *uri="0")
Definition: KVBase.cpp:795
UInt_t GetNumber() const
Definition: KVBase.h:220
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:173
static KVDetector * MakeDetector(const Char_t *name, Float_t thick)
void SetThickness(Double_t thick) override
virtual Bool_t IsSimMode() const
Definition: KVDetector.h:647
virtual Bool_t IsOK() const
Definition: KVDetector.h:676
KVPosition fEWPosition
position of entrance window i.e. first volume in detector geometry
Definition: KVDetector.h:176
KVMaterial * GetActiveLayer() const override
Definition: KVDetector.h:322
KVUniqueNameList fParentStrucList
list of geometry structures which directly contain this detector
Definition: KVDetector.h:177
Int_t GetNumberOfAbsorberLayers() const
Definition: KVDetector.h:337
void SetMaterial(const Char_t *type) override
Definition: KVDetector.cpp:169
Double_t ELossActive(Double_t *x, Double_t *par)
Definition: KVDetector.cpp:967
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:267
KVGeoStrucElement * GetParentStructure(const Char_t *type, const Char_t *name="") const
KVGroup * GetGroup() const
void AddDetectorSignal(KVDetectorSignal *ds)
Definition: KVDetector.h:287
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:527
Bool_t fDetecting
=kTRUE if detector is "detecting", =kFALSE if not
Definition: KVDetector.h:283
Bool_t ReplaceCalibrator(const Char_t *type, KVCalibrator *cal, const KVNameValueList &opts="")
Definition: KVDetector.cpp:499
virtual Double_t GetTotalDeltaE(Int_t Z, Int_t A, Double_t Einc)
virtual Double_t GetEnergy() const
Definition: KVDetector.h:374
virtual TF1 * GetEResFunction(Int_t Z, Int_t A)
static Int_t fDetCounter
Definition: KVDetector.h:179
void AddAbsorber(KVMaterial *)
Definition: KVDetector.cpp:592
KVDetectorSignalTrace * AddDetectorSignalTrace()
virtual Double_t GetEResAfterDetector() const
Definition: KVDetector.h:631
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:279
void Print(Option_t *option="") const override
Definition: KVDetector.cpp:338
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:897
TF1 * fELossF
parametric function dE in active layer vs. incident energy
Definition: KVDetector.h:275
Double_t GetLinearRange(Int_t Z, Int_t A, Double_t Einc) override
const KVPosition & GetEntranceWindow() const
Definition: KVDetector.h:693
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:608
@ kIdentifiedParticle
Definition: KVDetector.h:187
@ kUnidentifiedParticle
Definition: KVDetector.h:186
void ClearHits()
Definition: KVDetector.h:442
void SetEnergyLoss(Double_t e) const override
Definition: KVDetector.h:398
void remove_signal_for_calibrator(KVCalibrator *K)
Definition: KVDetector.cpp:662
TF1 * fEResF
parametric function Eres residual energy after all layers of detector
Definition: KVDetector.h:276
Bool_t HasSameStructureAs(const KVDetector *) const
UInt_t GetGroupNumber()
virtual KVDetectorSignal * GetDetectorSignal(const KVString &type) const
Definition: KVDetector.h:543
virtual void ReadDefinitionFromFile(const Char_t *)
Double_t GetEnergyLoss() const override
Definition: KVDetector.h:394
void SetShape(TGeoBBox *s) override
Definition: KVDetector.h:200
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:268
void SetActiveLayer(KVMaterial *actif)
Definition: KVDetector.h:312
KVDetector()
default ctor
Definition: KVDetector.cpp:59
Bool_t BelongsToUnidentifiedParticle() const
Definition: KVDetector.h:571
void DetectParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:200
Double_t RangeDet(Double_t *x, Double_t *par)
Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:301
virtual void RemoveCalibrators()
Definition: KVDetector.cpp:684
virtual Double_t GetEntranceWindowSurfaceArea()
Return surface area of first layer of detector in cm2.
TGeoBBox * GetShape() const override
Definition: KVDetector.h:208
KVUniqueNameList fDetSignals
list of signals associated with detector
Definition: KVDetector.h:233
Double_t get_corrected_energy(AbsorberStack *stack, KVNucleus *nuc, Double_t e, Bool_t transmission)
Definition: KVDetector.h:239
Int_t fUnidentP
temporary counters, determine state of identified/unidentified particle flags
Definition: KVDetector.h:191
TF1 * fRangeF
parametric function range of particles in detector
Definition: KVDetector.h:277
Bool_t AddDetectorSignalExpression(const KVString &type, const KVString &_expr)
virtual void SetEResAfterDetector(Double_t e)
Definition: KVDetector.h:627
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:666
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:823
KVGeoDetectorNode * GetNode()
Definition: KVDetector.h:354
Bool_t fSimMode
=kTRUE when using to simulate detector response, =kFALSE when analysing data
Definition: KVDetector.h:281
Double_t GetDeltaEFromERes(Int_t Z, Int_t A, Double_t Eres) override
void SetMatrix(const TGeoHMatrix *m) override
Definition: KVDetector.h:196
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:180
void AddHit(KVNucleus *part)
Definition: KVDetector.h:424
void RemoveAllAbsorbers()
Definition: KVDetector.cpp:631
Double_t GetEIncOfMaxDeltaE(Int_t Z, Int_t A) override
Double_t GetTotalThicknessInCM() const
Definition: KVDetector.h:343
KVCalibrator * GetCalibrator(const Char_t *name, const Char_t *type) const
Definition: KVDetector.h:869
Int_t fIdentP
temporary counters, determine state of identified/unidentified particle flags
Definition: KVDetector.h:190
void SetPressure(Double_t P) override
Double_t GetELostByParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVDetector.cpp:266
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:282
void SetActiveLayerShape(TGeoBBox *)
Set ROOT geometry shape of active layer volume.
void SetAnalysed(Bool_t b=kTRUE)
Definition: KVDetector.h:457
Bool_t fSingleLayer
=kTRUE if detector has a single absorber layer
Definition: KVDetector.h:285
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:762
void init()
default initialisations
Definition: KVDetector.cpp:32
void Clear(Option_t *opt="") override
Definition: KVDetector.cpp:550
KVList fAbsorbers
list of absorbers making up the detector
Definition: KVDetector.h:269
Bool_t AddCalibrator(KVCalibrator *cal, const KVNameValueList &opts="")
Definition: KVDetector.cpp:421
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)
Double_t GetTotalDeltaE(Int_t Z, Int_t A, Double_t Einc)
void SetIncidenceAngle(double psi)
Double_t GetDeltaE(Int_t Z, Int_t A, Double_t Einc)
Returns energy loss of given nucleus in the active layer of the detector.
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:115
virtual void SetPressure(Double_t)
Definition: KVMaterial.cpp:633
virtual void SetTemperature(Double_t)
Definition: KVMaterial.cpp:699
virtual void SetThickness(Double_t thick)
Definition: KVMaterial.cpp:499
virtual Double_t GetThickness() const
Definition: KVMaterial.cpp:537
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:886
virtual Double_t GetLinearRange(Int_t Z, Int_t A, Double_t Einc)
Definition: KVMaterial.cpp:954
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:92
virtual void SetShape(TGeoBBox *)
Definition: KVPosition.cpp:729
virtual Double_t GetSurfaceArea(int npoints=100000) const
Definition: KVPosition.cpp:902
virtual void SetMatrix(const TGeoHMatrix *)
Set the global transformation matrix for this volume.
Definition: KVPosition.cpp:713
virtual TGeoBBox * GetShape() const
Definition: KVPosition.cpp:759
virtual Double_t GetMaximumMisalignmentAngle() const
Definition: KVPosition.h:282
virtual Bool_t ROOTGeo() const
Definition: KVPosition.h:257
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
Double_t Dot(const TVector3 &) const
TVector3 Unit() const
RVec< PromoteType< T > > abs(const RVec< T > &v)
Double_t x[n]
gr SetName("gr")
void Error(UserClass p, const char *location, const char *va_(fmt),...)
Definition: KVError.h:116
void Warning(UserClass p, const char *location, const char *va_(fmt),...)
Definition: KVError.h:125
double T(double x)
void init()
Double_t ACos(Double_t)
constexpr Double_t K()
constexpr Double_t RadToDeg()
TMarker m
TArc a
ClassImp(TPyArg)