KaliVeda
Toolkit for HIC analysis
KVTarget.cpp
1 #include "KVTarget.h"
2 #include "KVNucleusEvent.h"
3 #include "KVUnits.h"
4 #include "TMath.h"
5 #include "Riostream.h"
6 #include "TRandom.h"
7 
8 using namespace std;
9 
11 
12 
13 
16 void KVTarget::init()
17 {
18  //Default initialisations
19  SetRandomized(kFALSE);
20  SetIncoming(kFALSE);
21  SetOutgoing(kFALSE);
22  fTargets = new KVList;
23  SetName("KVTarget");
24  SetTitle("Target for experiment");
25  fNLayers = 0;
26 
27  fNormal.SetXYZ(0, 0, 1);
28  fIntPoint.SetXYZ(0, 0, 0);
29 }
30 
31 
32 
35 
37 {
38  //Default costructor
39  init();
40 }
41 
42 
43 
44 
48 
49 KVTarget::KVTarget(const Char_t* material, const Double_t thick)
50 {
51  // Just give the type & "thickness" of material for target
52  // The "thickness" is the area density of the target in mg/cm**2.
53 
54  init();
55  AddLayer(material, thick);
56 }
57 
58 
59 //
60 
63 
65 {
66  //Copy ctor
67  init();
68 #if ROOT_VERSION_CODE >= ROOT_VERSION(3,4,0)
69  obj.Copy(*this);
70 #else
71  ((KVTarget&) obj).Copy(*this);
72 #endif
73 }
74 
75 
76 
77 #if ROOT_VERSION_CODE >= ROOT_VERSION(3,4,0)
78 
81 
82 void KVTarget::Copy(TObject& obj) const
83 #else
84 void KVTarget::Copy(TObject& obj)
85 #endif
86 {
87  //Copy this to obj
88  ((KVTarget&)obj).fTargets->Clear();// delete any existing layers
89  ((KVTarget&) obj).fNLayers = 0;
90  KVMaterial::Copy(obj);
91  ((KVTarget&) obj).SetRandomized(IsRandomized());
92  ((KVTarget&) obj).SetIncoming(IsIncoming());
93  ((KVTarget&) obj).SetOutgoing(IsOutgoing());
94 
95  ((KVTarget&) obj).fNormal = fNormal;
96 
97  TIter next(GetLayers());
98  KVMaterial* mat;
99  while ((mat = (KVMaterial*) next())) {
100  ((KVTarget&) obj).AddLayer(mat->GetName(), mat->GetAreaDensity() / KVUnits::mg);
101  }
102 }
103 
104 
105 
111 
112 void KVTarget::AddLayer(const Char_t* material, Double_t thick)
113 {
114  // Add a layer to a target, with 'thickness' in mg/cm**2 (area density).
115  // Sets/updates name of target with name of material.
116  // In case of multi-layer target the name is
117  // material1/material2/material3/...
118 
119  fTargets->Add(new KVMaterial(thick * KVUnits::mg, material));
120  fNLayers++;
121  if (fNLayers == 1) {
122  SetName(material);
123  }
124  else {
125  TString _name(GetName());
126  _name += "/";
127  _name += material;
128  SetName(_name.Data());
129  }
130 }
131 
132 
133 
134 
138 
140 {
141  // return sum of 'thicknesses' (area densities in mg/cm**2)
142  // of all layers in target
143 
144  Float_t thick = 0.;
145  TIter next(fTargets);
146  KVMaterial* mat = 0;
147  while ((mat = (KVMaterial*) next())) {
148  thick += mat->GetAreaDensity();
149  }
150  return thick / KVUnits::mg;
151 }
152 
153 
154 
155 
159 
161 {
162  //return sum of 'thicknesses' (area densities in mg/cm**2)
163  // of layers lay1 to lay2 in target
164 
165  Double_t thick = 0.;
166  for (int i = lay1; i <= lay2; i++) {
167  thick += GetThickness(i);
168  }
169  return thick;
170 }
171 
172 
173 
174 
178 
180 {
181  //Sets angle of target to incident beam direction by rotating about the +x axis (12 o'clock)
182  //Angle 'a' is given in degrees.
183 
184  fNormal.SetXYZ(0, 0, 1);
186 }
187 
188 
189 
190 
193 
195 {
196  //Gives angle of target to incident beam direction in degrees
197 
198  return TMath::RadToDeg() * fNormal.Angle(TVector3(0, 0, 1));
199 }
200 
201 
202 
203 
214 
216 {
217  //Return effective 'thickness' (in mg/cm**2) of layer ilayer (ilayer=1, 2, ...)
218  //By default ilayer=1 (i.e. for single layer target)
219  //The effective thickness depends on the angle of the target (rotation about
220  //x-axis => theta wrt z- (beam)-axis).
221  //It also depends on the direction of motion of the incident particle.
222  //If no particle is given, effective thicknesses are calculated as for
223  //particles travelling in the beam direction.
224 
225  //get (or make) vector in particle direction of motion (z-direction if no particle)
226  //Info("KVTarget::GetEffectiveThickness","(KVParticle * part, Int_t ilayer)");
227 
228  TVector3 p;
229  if (part)
230  p = part->GetMomentum();
231  else
232  p = TVector3(0, 0, 1);
233 
234  return GetEffectiveThickness(p, ilayer);
235 }
236 
237 
238 
239 
246 
248  Int_t ilayer)
249 {
250  //Return effective 'thickness' (in mg/cm**2) of layer ilayer (ilayer=1, 2, ...)
251  //By default ilayer=1 (i.e. for single layer target)
252  //The effective thickness depends on the orientation of the target (given by
253  //the direction of the normal to its surface) and on the direction (e.g. direction of a particle)
254  // Info("KVTarget::GetEffectiveThickness","TVector3 & direction,Int_t ilayer");
255  if (ilayer < 1 || ilayer > NumberOfLayers()) {
256  Error("GetEffectiveThickness(Int_t ilayer, TVector3& direction)",
257  "Layer number %d is illegal. Valid values are between 1 and %d.",
258  ilayer, NumberOfLayers());
259  return 0.0;
260  }
261  return GetLayerByIndex(ilayer)->GetEffectiveAreaDensity(fNormal, direction) / KVUnits::mg;
262 }
263 
264 
265 
266 
272 
274 {
275  //Returns absorber corresponding to 'depth' inside target, starting from the 'entrance'
276  //layer and following the direction of 'depth'. Note: 'depth' is measured in the same
277  //'thickness' units as the thickness of the different layers of the target (mg/cm2)
278  //WARNING : returns 0 if no layer is found (depth is outside of target)
279 
280  return GetLayerByIndex(GetLayerIndex(depth));
281 }
282 
283 
284 
285 
292 
294 {
295  //Returns absorber index corresponding to 'depth' inside target, starting from the 'entrance'
296  //layer and following the direction of 'depth'. Note: 'depth' is measured in the same
297  //'thickness' units as the thickness of the different layers of the target (mg/cm2)
298  //WARNING : user should check returned index is >0
299  //If not, this means that the given depth does not correspond to a layer inside the target
300 
301  Double_t thick = 0.0;
302  Double_t D = depth.Mag();
303  Int_t i = 0;
304 
305  while (thick < D && i < NumberOfLayers()) {
306  //increase total thickness by effective thickness 'seen' in direction of 'depth' vector
307  thick += GetEffectiveThickness(depth, ++i);
308  }
309 
310  return (thick < D ? 0 : i);
311 }
312 
313 
314 
315 
321 
323 {
324  //Returns absorber corresponding to 'depth' inside target, starting from the 'entrance'
325  //layer and following the normal direction. Note: 'depth' is measured in the same
326  //'thickness' units as the thickness of the different layers of the target (mg/cm2, um, etc.)
327  //WARNING : returns 0 if no layer is found (depth is outside of target)
328 
329  return GetLayerByIndex(GetLayerIndex(depth));
330 }
331 
332 
333 
334 
339 
341 {
342  //Returns layer index corresponding to absorber of type 'name'.
343  //WARNING : user should check returned index is >0
344  //If not, this means that the given material name does not correspond to a layer inside the target
345  KVMaterial* mat = GetLayer(name);
346  return (mat ? GetLayers()->IndexOf(mat) + 1 : 0);
347 }
348 
349 
350 
351 
354 
356 {
357  //Returns layer corresponding to absorber of type 'name'.
359 }
360 
361 
362 
363 
366 
368 {
369  //'Thickness' in mg/cm**2 of layer 'ilayer' in target
370  KVMaterial* lay = GetLayerByIndex(ilayer);
371  return (lay ? lay->GetAreaDensity() / KVUnits::mg : 0.0);
372 }
373 
374 
375 
376 
383 
385 {
386  //Returns absorber index corresponding to 'depth' inside target, starting from the 'entrance'
387  //layer and following the normal direction. Note: 'depth' is measured in the same
388  //'thickness' units as the thickness of the different layers of the target (mg/cm2)
389  //WARNING : user should check returned index is >0
390  //If not, this means that the given depth does not correspond to a layer inside the target
391 
392  Double_t thick = 0.0;
393  Int_t i = 0;
394 
395  while (thick < depth && i < NumberOfLayers()) {
396  //increase total thickness by thickness of layer
397  thick += GetThickness(++i);
398  }
399 
400  return (thick < depth ? 0 : i);
401 }
402 
403 
404 
405 
412 
414 {
415  //return sum of effective 'thicknesses' (mg/cm**2) of all layers in target
416  //taking into account the angle of the target to the beam
417  //and the direction of motion of the incident particle.
418  //If no particle is given, effective thicknesses are calculated as for
419  //particles travelling in the beam direction.
420 
421  TVector3 p = (part ? part->GetMomentum() : TVector3(0, 0, 1));
423 }
424 
425 
426 
427 
436 
438  Int_t ilay2)
439 {
440  //return sum of effective 'thicknesses' (mg/cm**2) of layers ilay1 to ilay2 in target
441  //taking into account the angle of the target to the beam
442  //and the given direction.
443  //
444  //GetTotalEffectiveThickness(dir) --> thickness of all layers
445  //GetTotalEffectiveThickness(dir,ilay1) --> thickness of layers ilay1 to last
446  //GetTotalEffectiveThickness(dir,ilay1,ilay2) --> thickness of layers ilay1 to ilay2
447 
448  Double_t thick = 0.0;
449  ilay2 =
450  (ilay2
451  ? (ilay2 <=
452  NumberOfLayers() ? (ilay2 >=
453  ilay1 ? ilay2 : ilay1) : NumberOfLayers()) :
454  NumberOfLayers());
455  for (Int_t i = ilay1; i <= ilay2; i++) {
456  thick += GetEffectiveThickness(dir, i);
457  }
458  return thick;
459 }
460 
461 
462 
463 
465 
466 KVTarget::~KVTarget()
467 {
468  delete fTargets;
469  fTargets = 0;
470 }
471 
472 
473 //#define DBG_TRGT
474 
485 
487 {
488  //Simulate passage of a particle through a target.
489  //Energy losses are calculated and the particle is slowed down.
490  //We take into account the direction of motion of the particle and an arbitrary orientation of the target.
491  //
492  //The' 'TVector3* dummy'argument is not used.
493  //
494  //If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, the particle will pass through the whole of the target.
495  //If IsIncoming()=kTRUE, calculate energy loss up to interaction point
496  //If IsOutgoing()=kTRUE, calculate energy loss from interaction point onwards (outwards)
497  if (kvp->GetKE() <= 0.)
498  return;
499 
500  if (!IsIncoming() && !IsOutgoing()) {
501  //calculate losses in all layers
502  for (int i = 1;
503  i <= NumberOfLayers() && kvp->GetKE() > 0.;
504  i++) {
506  }
507  }
508  else {
509 
510  //find starting or ending layer (where is I.P. ?)
511  Int_t iplay_index = GetLayerIndex(GetInteractionPoint());
512 #ifdef DBG_TRGT
513  cout << "IP is in layer " << iplay_index << endl;
514 #endif
515  //particle going forwards or backwards ?
516  TVector3 p = kvp->GetMomentum();
517  Bool_t backwards = (p * GetNormal() < 0.0);
518 #ifdef DBG_TRGT
519  cout << "Particle is going ";
520  backwards ? cout << "backwards" : cout << "forwards";
521  cout << endl;
522 #endif
523 
524  if (iplay_index) {
525 
526  KVMaterial* iplay = GetLayerByIndex(iplay_index);
527 
528  //effective thickness of I.P. layer is reduced because we start/stop from inside it
529  //the effective thickness (measured along the normal) after the I.P. is given by the
530  //sum of all thicknesses up to and including this layer minus the scalar product of
531  //'depth' with the normal (i.e. the projection of 'depth' along the normal)
532 
533  Double_t e_thick_iplay = GetTotalThickness(1,
534  iplay_index) -
536  e_thick_iplay =
537  (IsIncoming() ? iplay->GetAreaDensity() / KVUnits::mg -
538  e_thick_iplay : e_thick_iplay);
539 
540  if (backwards)
541  e_thick_iplay = iplay->GetAreaDensity() / KVUnits::mg - e_thick_iplay;
542 #ifdef DBG_TRGT
543  cout << "Effective thickness of IP layer is " << e_thick_iplay <<
544  " (real:" << iplay->GetAreaDensity() / KVUnits::mg << ")" << endl;
545 #endif
546  //modify effective physical thickness of layer
547  Double_t thick_iplay = iplay->GetAreaDensity();// in g/cm**2
548  iplay->SetAreaDensity(e_thick_iplay * KVUnits::mg);
549 
550  //first and last indices of layers to pass through
551  Int_t ilay1 =
552  (IsIncoming() ? (backwards ? NumberOfLayers() : 1) :
553  iplay_index);
554  Int_t ilay2 =
555  (IsIncoming() ? iplay_index
556  : (backwards ? 1 : NumberOfLayers()));
557 
558  if (backwards) {
559  for (int i = ilay1;
560  i >= ilay2 && kvp->GetKE() > 0.; i--)
562  }
563  else {
564  for (int i = ilay1;
565  i <= ilay2 && kvp->GetKE() > 0.; i++)
567  }
568 
569  //reset original thickness of IP layer
570  iplay->SetAreaDensity(thick_iplay);
571 
572  }
573  else {
574  Error("DetectParticle", "Interaction point is outside of target");
575  }
576  }
577 }
578 
579 
580 
581 
593 
595 {
596  //Simulate passage of a particle through a target.
597  //Energy losses are calculated but the particle's energy is not modified.
598  //We take into account the direction of motion of the particle and an arbitrary
599  //orientation of the target.
600  //
601  //The' 'TVector3* dummy'argument is not used.
602  //
603  //If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, the particle will pass through the whole of the target.
604  //If IsIncoming()=kTRUE, calculate energy loss up to interaction point
605  //If IsOutgoing()=kTRUE, calculate energy loss from interaction point onwards (outwards)
606 
607  Double_t Eloss = 0.0, E0 = kvp->GetKE();
608 
609  if (E0 <= 0.)
610  return E0;
611 
612  //make 'clone' of nucleus to simulate energy losses
613  KVNucleus clone_part(kvp->GetZ(), kvp->GetA());
614  clone_part.SetMomentum(kvp->GetMomentum());
615 
616  if (!IsIncoming() && !IsOutgoing()) {
617  //calculate losses in all layers
618  for (int i = 1;
619  i <= NumberOfLayers() && clone_part.GetKE() > 0.;
620  i++) {
621  Eloss +=
622  GetLayerByIndex(i)->GetELostByParticle(&clone_part, &fNormal);
623  clone_part.SetKE(E0 - Eloss);
624  }
625  }
626  else {
627 
628  //find starting or ending layer (where is I.P. ?)
629  Int_t iplay_index = GetLayerIndex(GetInteractionPoint());
630 #ifdef DBG_TRGT
631  cout << "IP is in layer " << iplay_index << endl;
632 #endif
633  //particle going forwards or backwards ?
634  TVector3 p = clone_part.GetMomentum();
635  Bool_t backwards = (p * GetNormal() < 0.0);
636 #ifdef DBG_TRGT
637  cout << "Particle is going ";
638  backwards ? cout << "backwards" : cout << "forwards";
639  cout << endl;
640 #endif
641 
642  if (iplay_index) {
643 
644  KVMaterial* iplay = GetLayerByIndex(iplay_index);
645 
646  //effective thickness of I.P. layer is reduced because we start/stop from inside it
647  //the effective thickness (measured along the normal) after the I.P. is given by the
648  //sum of all thicknesses up to and including this layer minus the scalar product of
649  //'depth' with the normal (i.e. the projection of 'depth' along the normal)
650 
651  Double_t e_thick_iplay = GetTotalThickness(1,
652  iplay_index) -
654  e_thick_iplay =
655  (IsIncoming() ? iplay->GetAreaDensity() / KVUnits::mg -
656  e_thick_iplay : e_thick_iplay);
657 
658  if (backwards)
659  e_thick_iplay = iplay->GetAreaDensity() / KVUnits::mg - e_thick_iplay;
660 #ifdef DBG_TRGT
661  cout << "Effective thickness of IP layer is " << e_thick_iplay <<
662  " (real:" << iplay->GetAreaDensity() / KVUnits::mg << ")" << endl;
663 #endif
664  //modify effective physical thickness of layer
665  Double_t thick_iplay = iplay->GetAreaDensity(); // g/cm**2
666  iplay->SetAreaDensity(e_thick_iplay * KVUnits::mg);
667 
668  //first and last indices of layers to pass through
669  Int_t ilay1 =
670  (IsIncoming() ? (backwards ? NumberOfLayers() : 1) :
671  iplay_index);
672  Int_t ilay2 =
673  (IsIncoming() ? iplay_index
674  : (backwards ? 1 : NumberOfLayers()));
675 
676  if (backwards) {
677  for (int i = ilay1;
678  i >= ilay2 && clone_part.GetKE() > 0.; i--) {
679  Eloss +=
680  GetLayerByIndex(i)->GetELostByParticle(&clone_part,
681  &fNormal);
682  clone_part.SetKE(E0 - Eloss);
683  }
684  }
685  else {
686  for (int i = ilay1;
687  i <= ilay2 && clone_part.GetKE() > 0.; i++) {
688  Eloss +=
689  GetLayerByIndex(i)->GetELostByParticle(&clone_part,
690  &fNormal);
691  clone_part.SetKE(E0 - Eloss);
692  }
693  }
694 
695  //reset original thickness of IP layer
696  iplay->SetAreaDensity(thick_iplay);
697 
698  }
699  else {
700  Error("DetectParticle", "Interaction point is outside of target");
701  }
702  }
703  return Eloss;
704 }
705 
706 
707 
708 
716 
718 {
719  //Simulate passage of particles from some simulation through the target material.
720  //The particles will be slowed down according to their calculated energy losses.
721  //First we SetOutgoing(): for a simulated event, energy losses are only calculated from some
722  //interaction point inside the target to the outside. This interaction point will be taken half-way
723  //through the target (by default) or at some random depth in the target if SetRandomized() is
724  //called first.
725 
726  SetOutgoing();
727  for (auto& part : EventIterator(event)) { // loop over particles
729  }
730 }
731 
732 
733 
734 
736 
737 void KVTarget::Print(Option_t* opt) const
738 {
739  cout << "Target " << GetName() << ", " << GetTitle() << endl;
740  fTargets->Print(opt);
741 }
742 
743 
744 
745 
747 
749 {
750  KVMaterial::Clear(opt);
751  fTargets->Execute("Clear", Form("%s", opt));
752 }
753 
754 
755 
756 
767 
769 {
770  //Returns last known interaction point (if part=0) or generates a new one if part!=0.
771  //
772  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
773  //direction 'of the incident particle's trajectory through target.
774  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction.
775  //
776  //If no interaction point is set by the user (i.e. GetInteractionPoint never called with
777  //the address of a KVParticle), the default is to generate an interaction point using the
778  //beam (+ve Z-)direction.
779 
780  TVector3 dir;
781  if (!part) {
782  //check fIntPoint is valid
783  if (fIntPoint.Mag() > 0)
784  return fIntPoint;
785  //set default direction - beam direction
786  dir.SetXYZ(0, 0, 1);
787  }
788  else {
789  dir = part->GetMomentum();
790  }
791  return GetInteractionPoint(dir);
792 }
793 
794 
795 
797 
799 {
801  Double_t depth;
802  depth = (IsRandomized() ? gRandom->Uniform(e_eff) : 0.5 * e_eff);
803  fIntPoint = depth * (dir.Unit());
804  return fIntPoint;
805 }
806 
807 
808 
809 
819 
821 {
822  //Sets the interaction point inside the layer with index 'ilayer'
823  //
824  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
825  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
826  //
827  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
828  //inside the layer
829 
830  //total effective thickness (along 'dir') of all layers before 'ilayer'
831  Double_t e_eff =
832  (ilayer > 1 ? GetTotalEffectiveThickness(dir, 1, ilayer - 1) : 0.0);
833 #ifdef DBG_TRGT
834  cout <<
835  "total effective thickness (along 'dir') of all layers before 'ilayer'="
836  << e_eff << endl;
837 #endif
838  //effective depth inside layer (along 'dir')
839  Double_t e_eff_ilayer = GetEffectiveThickness(dir, ilayer);
840  Double_t depth =
841  (IsRandomized() ? gRandom->Uniform(e_eff_ilayer) : 0.5 *
842  e_eff_ilayer);
843 #ifdef DBG_TRGT
844  cout << "dpeth inside interaction layer=" << depth << endl;
845 #endif
846  fIntPoint = (e_eff + depth) * (dir.Unit());
847 #ifdef DBG_TRGT
848  cout << "generated IP vector:" << endl;
849  fIntPoint.Print();
850 #endif
851 }
852 
853 
854 
855 
863 
865 {
866  //Sets the interaction point inside the layer made of absorber type 'name'
867  //
868  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
869  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
870  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
871  //inside the layer
872 
873  Int_t ilayer = GetLayerIndex(name);
874  if (!ilayer) {
875  Error("SetInteractionLayer",
876  "No layer in target with material type %s", name);
877  }
878  SetInteractionLayer(ilayer, dir);
879 }
880 
881 
882 
883 
891 
893 {
894  //Sets the interaction point inside the layer made of absorber type 'name'
895  //
896  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
897  //direction along the incident particle's trajectory through layer.
898  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction
899  //inside the layer
900 
901  TVector3 dir = part->GetMomentum();
903 }
904 
905 
906 
907 
910 
911 void KVTarget::SetMaterial(const Char_t* type)
912 {
913  // Set material of first layer
914  if (GetLayerByIndex(1))
916 }
917 
918 
919 
920 
923 
925 {
926  // Set 'thickness' in mg/cm**2 of a layer, by default this is the first layer
927  if (GetLayerByIndex(ilayer))
928  GetLayerByIndex(ilayer)->SetAreaDensity(thick * KVUnits::mg);
929 }
930 
931 
932 
933 
937 
939 {
940  //Calculates total number of atoms per square centimetre of the target.
941  //For a multilayer target, the area densities for each layer are summed up.
942  Double_t atom_cib = 0;
943  for (int i = 1; i <= NumberOfLayers(); i++) {
944  //N_atoms = N_Avogadro * target_thickness (mg/cm**2) * 1.e-3 / atomic_mass_of_target
945  atom_cib +=
946  TMath::Na() * GetThickness(i) * 1.e-3 /
947  GetLayerByIndex(i)->GetMass();
948  }
949  return atom_cib;
950 }
951 
952 
953 
954 
968 
970 {
971  // Calculate initial energy of particle from its current (residual) energy, assumed
972  // to correspond to the state of the particle after passage through all or some part
973  // of the target, taking into account the particle's direction of motion and an arbitrary
974  // orientation of the target.
975  //
976  // The 'TVector3*' argument is not used.
977  //
978  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
979  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
980  // we calculate energy of particle before entering target
981  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
982  // we calculate energy of particle at interactio point
983 
984  Double_t ERes = 0.0;
985 
986  //make 'clone' of nucleus to simulate energy losses
987  KVNucleus clone_part(kvp->GetZ(), kvp->GetA());
988  clone_part.SetMomentum(kvp->GetMomentum());
989 
990  if (!IsIncoming() && !IsOutgoing()) {
991 
992  //correct for losses in all layers
993  for (int i = NumberOfLayers(); i > 0; i--) {
994  ERes = GetLayerByIndex(i)->GetParticleEIncFromERes(&clone_part, &fNormal);
995  clone_part.SetKE(ERes);
996  }
997  return ERes;
998 
999  }
1000  else {
1001 
1002  //find starting or ending layer (where is I.P. ?)
1003  Int_t iplay_index = GetLayerIndex(GetInteractionPoint());
1004 #ifdef DBG_TRGT
1005  cout << "IP is in layer " << iplay_index << endl;
1006 #endif
1007  //particle going forwards or backwards ?
1008  TVector3 p = clone_part.GetMomentum();
1009  Bool_t backwards = (p * GetNormal() < 0.0);
1010 #ifdef DBG_TRGT
1011  cout << "Particle is going ";
1012  backwards ? cout << "backwards" : cout << "forwards";
1013  cout << endl;
1014 #endif
1015 
1016  if (iplay_index) {
1017 
1018  KVMaterial* iplay = GetLayerByIndex(iplay_index);
1019 
1020  //effective thickness of I.P. layer is reduced because we start/stop from inside it
1021  //the effective thickness (measured along the normal) after the I.P. is given by the
1022  //sum of all thicknesses up to and including this layer minus the scalar product of
1023  //'depth' with the normal (i.e. the projection of 'depth' along the normal)
1024 
1025  Double_t e_thick_iplay = GetTotalThickness(1,
1026  iplay_index) -
1028  e_thick_iplay =
1029  (IsIncoming() ? iplay->GetAreaDensity() / KVUnits::mg -
1030  e_thick_iplay : e_thick_iplay);
1031 
1032  if (backwards)
1033  e_thick_iplay = iplay->GetAreaDensity() / KVUnits::mg - e_thick_iplay;
1034 #ifdef DBG_TRGT
1035  cout << "Effective thickness of IP layer is " << e_thick_iplay <<
1036  " (real:" << iplay->GetAreaDensity() / KVUnits::mg << ")" << endl;
1037 #endif
1038  //modify effective physical thickness of layer
1039  Double_t thick_iplay = iplay->GetAreaDensity();
1040  iplay->SetAreaDensity(e_thick_iplay * KVUnits::mg);
1041 
1042  //first and last indices of layers to pass through
1043  Int_t ilay1 =
1044  (IsIncoming() ? (backwards ? NumberOfLayers() : 1) :
1045  iplay_index);
1046  Int_t ilay2 =
1047  (IsIncoming() ? iplay_index
1048  : (backwards ? 1 : NumberOfLayers()));
1049 
1050  //correct for losses in different layers
1051  if (backwards) {
1052 
1053  for (int i = ilay2;
1054  i <= ilay1; i++) {
1055  ERes =
1056  GetLayerByIndex(i)->GetParticleEIncFromERes(&clone_part,
1057  &fNormal);
1058  clone_part.SetKE(ERes);
1059  }
1060 
1061  }
1062  else {
1063 
1064  for (int i = ilay2;
1065  i >= ilay1 ; i--) {
1066  ERes =
1067  GetLayerByIndex(i)->GetParticleEIncFromERes(&clone_part,
1068  &fNormal);
1069  clone_part.SetKE(ERes);
1070  }
1071 
1072  }
1073 
1074  //reset original thickness of IP layer
1075  iplay->SetAreaDensity(thick_iplay);
1076 
1077  }
1078  else {
1079  Error("GetParticleEIncFromERes", "Interaction point is outside of target");
1080  }
1081  }
1082  return ERes;
1083 }
1084 
1085 
1086 
1087 
1106 
1108 {
1109  // Calculate initial energy of nucleus (Z,A) from given residual energy Eres, assumed
1110  // to correspond to the state of the particle after passage through all or some part
1111  // of the target, taking into account an arbitrary orientation of the target.
1112  //
1113  // *** WARNING ***
1114  // Obviously we cannot know the particle's direction of motion,
1115  // therefore we assume it to be travelling in the beam direction (0,0,1)
1116  // Normally you should use GetParticleEIncFromERes
1117  //
1118  // The' 'TVector3*' argument is not used.
1119  //
1120  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
1121  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
1122  // we calculate energy of particle before entering target
1123  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
1124  // we calculate energy of particle at interactio point
1125 
1126  //Fake nucleus
1127  KVNucleus dummy(Z, A);
1128  dummy.SetKE(Eres);
1129  return GetParticleEIncFromERes(&dummy);
1130 }
1131 
1132 
1133 
int Int_t
bool Bool_t
char Char_t
float Float_t
constexpr Bool_t kFALSE
double Double_t
const char Option_t
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t 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 TRandom * gRandom
char * Form(const char *fmt,...)
Class for iterating over nuclei in events accessed through base pointer/reference.
void Error(const char *method, const char *msgfmt,...) const override
Definition: KVBase.cpp:1709
Abstract base class container for multi-particle events.
Definition: KVEvent.h:67
Extended TList class which owns its objects by default.
Definition: KVList.h:22
Description of physical materials used to construct detectors & targets; interface to range tables.
Definition: KVMaterial.h:90
Double_t GetEffectiveAreaDensity(const TVector3 &norm, const TVector3 &direction)
Definition: KVMaterial.cpp:720
void Clear(Option_t *opt="") override
Reset absorber - set stored energy lost by particles in absorber to zero.
void SetAreaDensity(Double_t dens)
Definition: KVMaterial.cpp:520
Double_t GetAreaDensity() const
Definition: KVMaterial.cpp:553
virtual Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=nullptr)
Definition: KVMaterial.cpp:801
virtual void DetectParticle(KVNucleus *, TVector3 *norm=nullptr)
virtual void SetMaterial(const Char_t *type)
Definition: KVMaterial.cpp:217
virtual Double_t GetELostByParticle(KVNucleus *, TVector3 *norm=nullptr)
Definition: KVMaterial.cpp:766
KVMaterial()
default ctor
Definition: KVMaterial.cpp:73
void Copy(TObject &obj) const override
Make a copy of this material object.
Double_t GetMass() const
Definition: KVMaterial.cpp:302
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
Int_t GetA() const
Definition: KVNucleus.cpp:796
Int_t GetZ() const
Return the number of proton / atomic number.
Definition: KVNucleus.cpp:767
Base class for relativistic kinematics of massive particles.
Definition: KVParticle.h:396
TVector3 GetMomentum() const
Definition: KVParticle.h:607
void SetKE(Double_t ecin)
Definition: KVParticle.cpp:246
void SetMomentum(const TVector3 *v)
Definition: KVParticle.h:545
Double_t GetKE() const
Definition: KVParticle.h:617
void Execute(const char *method, const char *params, Int_t *error=0) override
void Add(TObject *obj) override
virtual TObject * FindObjectByType(const Char_t *) const
Calculation/correction of energy losses of particles through an experimental target.
Definition: KVTarget.h:128
void DetectParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVTarget.cpp:486
Bool_t IsIncoming() const
Definition: KVTarget.h:208
Double_t GetThickness() const override
Definition: KVTarget.h:191
KVTarget()
Default costructor.
Definition: KVTarget.cpp:36
void Print(Option_t *opt="") const override
Definition: KVTarget.cpp:737
void SetAngleToBeam(Double_t a)
Definition: KVTarget.cpp:179
void Copy(TObject &obj) const override
Copy this to obj.
Definition: KVTarget.cpp:82
void init()
Default initialisations.
Definition: KVTarget.cpp:16
Double_t GetELostByParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVTarget.cpp:594
Int_t NumberOfLayers() const
Definition: KVTarget.h:167
KVList * fTargets
list of layers
Definition: KVTarget.h:140
Bool_t IsOutgoing() const
Definition: KVTarget.h:228
TVector3 & GetInteractionPoint(KVParticle *part=0)
Definition: KVTarget.cpp:768
Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0) override
Definition: KVTarget.cpp:969
Int_t fNLayers
number of layers
Definition: KVTarget.h:141
Double_t GetEffectiveThickness(KVParticle *part=0, Int_t ilayer=1)
Definition: KVTarget.cpp:215
void SetMaterial(const Char_t *type) override
Set material of first layer.
Definition: KVTarget.cpp:911
KVMaterial * GetLayer(TVector3 &depth)
Definition: KVTarget.cpp:273
KVMaterial * GetLayerByDepth(Double_t depth)
Definition: KVTarget.cpp:322
void AddLayer(const Char_t *material, Double_t thick)
Definition: KVTarget.cpp:112
Double_t GetTotalEffectiveThickness(KVParticle *part=0)
Definition: KVTarget.cpp:413
void SetInteractionLayer(Int_t ilayer, TVector3 &dir)
Definition: KVTarget.cpp:820
void DetectEvent(KVEvent *)
Definition: KVTarget.cpp:717
TVector3 fNormal
normal to target - (0,0,1) by default
Definition: KVTarget.h:142
Bool_t IsRandomized() const
Definition: KVTarget.h:250
KVList * GetLayers() const
Definition: KVTarget.h:171
const TVector3 & GetNormal()
Definition: KVTarget.h:155
void SetOutgoing(Bool_t r=kTRUE)
Definition: KVTarget.h:240
Double_t GetTotalThickness()
Definition: KVTarget.cpp:139
Double_t GetAtomsPerCM2() const
virtual UInt_t GetUnits() const;
Definition: KVTarget.cpp:938
Double_t GetAngleToBeam()
Gives angle of target to incident beam direction in degrees.
Definition: KVTarget.cpp:194
void SetLayerThickness(Float_t thick, Int_t ilayer=1)
Set 'thickness' in mg/cm**2 of a layer, by default this is the first layer.
Definition: KVTarget.cpp:924
Int_t GetLayerIndex(TVector3 &depth)
Definition: KVTarget.cpp:293
TVector3 fIntPoint
last randomly generated interaction point
Definition: KVTarget.h:143
virtual Double_t GetIncidentEnergyFromERes(Int_t Z, Int_t A, Double_t Eres) override
Definition: KVTarget.cpp:1107
KVMaterial * GetLayerByIndex(Int_t ilayer) const
Definition: KVTarget.h:175
void Clear(Option_t *opt="") override
Definition: KVTarget.cpp:748
virtual void Print(Option_t *option, const char *wildcard, Int_t recurse=1) const
const char * GetName() const override
const char * GetTitle() const override
virtual void SetName(const char *name)
virtual Double_t Uniform(Double_t x1, Double_t x2)
const char * Data() const
void SetXYZ(Double_t x, Double_t y, Double_t z)
void Print(Option_t *option="") const override
TVector3 Unit() const
void RotateX(Double_t)
Double_t Angle(const TVector3 &) const
Double_t Mag() const
gr SetName("gr")
void init()
constexpr Double_t DegToRad()
constexpr Double_t Na()
constexpr Double_t RadToDeg()
TArc a
ClassImp(TPyArg)