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  }
792  Double_t depth;
793  depth = (IsRandomized() ? gRandom->Uniform(e_eff) : 0.5 * e_eff);
794  fIntPoint = depth * (dir.Unit());
795  return fIntPoint;
796 }
797 
798 
799 
800 
809 
811 {
812  //Sets the interaction point inside the layer with index 'ilayer'
813  //
814  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
815  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
816  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
817  //inside the layer
818 
819  //total effective thickness (along 'dir') of all layers before 'ilayer'
820  Double_t e_eff =
821  (ilayer > 1 ? GetTotalEffectiveThickness(dir, 1, ilayer - 1) : 0.0);
822 #ifdef DBG_TRGT
823  cout <<
824  "total effective thickness (along 'dir') of all layers before 'ilayer'="
825  << e_eff << endl;
826 #endif
827  //effective depth inside layer (along 'dir')
828  Double_t e_eff_ilayer = GetEffectiveThickness(dir, ilayer);
829  Double_t depth =
830  (IsRandomized() ? gRandom->Uniform(e_eff_ilayer) : 0.5 *
831  e_eff_ilayer);
832 #ifdef DBG_TRGT
833  cout << "dpeth inside interaction layer=" << depth << endl;
834 #endif
835  fIntPoint = (e_eff + depth) * (dir.Unit());
836 #ifdef DBG_TRGT
837  cout << "generated IP vector:" << endl;
838  fIntPoint.Print();
839 #endif
840 }
841 
842 
843 
844 
852 
854 {
855  //Sets the interaction point inside the layer made of absorber type 'name'
856  //
857  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
858  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
859  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
860  //inside the layer
861 
862  Int_t ilayer = GetLayerIndex(name);
863  if (!ilayer) {
864  Error("SetInteractionLayer",
865  "No layer in target with material type %s", name);
866  }
867  SetInteractionLayer(ilayer, dir);
868 }
869 
870 
871 
872 
880 
882 {
883  //Sets the interaction point inside the layer made of absorber type 'name'
884  //
885  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
886  //direction along the incident particle's trajectory through layer.
887  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction
888  //inside the layer
889 
890  TVector3 dir = part->GetMomentum();
892 }
893 
894 
895 
896 
899 
900 void KVTarget::SetMaterial(const Char_t* type)
901 {
902  // Set material of first layer
903  if (GetLayerByIndex(1))
905 }
906 
907 
908 
909 
912 
914 {
915  // Set 'thickness' in mg/cm**2 of a layer, by default this is the first layer
916  if (GetLayerByIndex(ilayer))
917  GetLayerByIndex(ilayer)->SetAreaDensity(thick * KVUnits::mg);
918 }
919 
920 
921 
922 
926 
928 {
929  //Calculates total number of atoms per square centimetre of the target.
930  //For a multilayer target, the area densities for each layer are summed up.
931  Double_t atom_cib = 0;
932  for (int i = 1; i <= NumberOfLayers(); i++) {
933  //N_atoms = N_Avogadro * target_thickness (mg/cm**2) * 1.e-3 / atomic_mass_of_target
934  atom_cib +=
935  TMath::Na() * GetThickness(i) * 1.e-3 /
936  GetLayerByIndex(i)->GetMass();
937  }
938  return atom_cib;
939 }
940 
941 
942 
943 
957 
959 {
960  // Calculate initial energy of particle from its current (residual) energy, assumed
961  // to correspond to the state of the particle after passage through all or some part
962  // of the target, taking into account the particle's direction of motion and an arbitrary
963  // orientation of the target.
964  //
965  // The 'TVector3*' argument is not used.
966  //
967  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
968  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
969  // we calculate energy of particle before entering target
970  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
971  // we calculate energy of particle at interactio point
972 
973  Double_t ERes = 0.0;
974 
975  //make 'clone' of nucleus to simulate energy losses
976  KVNucleus clone_part(kvp->GetZ(), kvp->GetA());
977  clone_part.SetMomentum(kvp->GetMomentum());
978 
979  if (!IsIncoming() && !IsOutgoing()) {
980 
981  //correct for losses in all layers
982  for (int i = NumberOfLayers(); i > 0; i--) {
983  ERes = GetLayerByIndex(i)->GetParticleEIncFromERes(&clone_part, &fNormal);
984  clone_part.SetKE(ERes);
985  }
986  return ERes;
987 
988  }
989  else {
990 
991  //find starting or ending layer (where is I.P. ?)
992  Int_t iplay_index = GetLayerIndex(GetInteractionPoint());
993 #ifdef DBG_TRGT
994  cout << "IP is in layer " << iplay_index << endl;
995 #endif
996  //particle going forwards or backwards ?
997  TVector3 p = clone_part.GetMomentum();
998  Bool_t backwards = (p * GetNormal() < 0.0);
999 #ifdef DBG_TRGT
1000  cout << "Particle is going ";
1001  backwards ? cout << "backwards" : cout << "forwards";
1002  cout << endl;
1003 #endif
1004 
1005  if (iplay_index) {
1006 
1007  KVMaterial* iplay = GetLayerByIndex(iplay_index);
1008 
1009  //effective thickness of I.P. layer is reduced because we start/stop from inside it
1010  //the effective thickness (measured along the normal) after the I.P. is given by the
1011  //sum of all thicknesses up to and including this layer minus the scalar product of
1012  //'depth' with the normal (i.e. the projection of 'depth' along the normal)
1013 
1014  Double_t e_thick_iplay = GetTotalThickness(1,
1015  iplay_index) -
1017  e_thick_iplay =
1018  (IsIncoming() ? iplay->GetAreaDensity() / KVUnits::mg -
1019  e_thick_iplay : e_thick_iplay);
1020 
1021  if (backwards)
1022  e_thick_iplay = iplay->GetAreaDensity() / KVUnits::mg - e_thick_iplay;
1023 #ifdef DBG_TRGT
1024  cout << "Effective thickness of IP layer is " << e_thick_iplay <<
1025  " (real:" << iplay->GetAreaDensity() / KVUnits::mg << ")" << endl;
1026 #endif
1027  //modify effective physical thickness of layer
1028  Double_t thick_iplay = iplay->GetAreaDensity();
1029  iplay->SetAreaDensity(e_thick_iplay * KVUnits::mg);
1030 
1031  //first and last indices of layers to pass through
1032  Int_t ilay1 =
1033  (IsIncoming() ? (backwards ? NumberOfLayers() : 1) :
1034  iplay_index);
1035  Int_t ilay2 =
1036  (IsIncoming() ? iplay_index
1037  : (backwards ? 1 : NumberOfLayers()));
1038 
1039  //correct for losses in different layers
1040  if (backwards) {
1041 
1042  for (int i = ilay2;
1043  i <= ilay1; i++) {
1044  ERes =
1045  GetLayerByIndex(i)->GetParticleEIncFromERes(&clone_part,
1046  &fNormal);
1047  clone_part.SetKE(ERes);
1048  }
1049 
1050  }
1051  else {
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 
1063  //reset original thickness of IP layer
1064  iplay->SetAreaDensity(thick_iplay);
1065 
1066  }
1067  else {
1068  Error("GetParticleEIncFromERes", "Interaction point is outside of target");
1069  }
1070  }
1071  return ERes;
1072 }
1073 
1074 
1075 
1076 
1095 
1097 {
1098  // Calculate initial energy of nucleus (Z,A) from given residual energy Eres, assumed
1099  // to correspond to the state of the particle after passage through all or some part
1100  // of the target, taking into account an arbitrary orientation of the target.
1101  //
1102  // *** WARNING ***
1103  // Obviously we cannot know the particle's direction of motion,
1104  // therefore we assume it to be travelling in the beam direction (0,0,1)
1105  // Normally you should use GetParticleEIncFromERes
1106  //
1107  // The' 'TVector3*' argument is not used.
1108  //
1109  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
1110  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
1111  // we calculate energy of particle before entering target
1112  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
1113  // we calculate energy of particle at interactio point
1114 
1115  //Fake nucleus
1116  KVNucleus dummy(Z, A);
1117  dummy.SetKE(Eres);
1118  return GetParticleEIncFromERes(&dummy);
1119 }
1120 
1121 
1122 
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.
Abstract base class container for multi-particle events.
Definition: KVEvent.h:67
Extended TList class which owns its objects by default.
Definition: KVList.h:28
Description of physical materials used to construct detectors & targets; interface to range tables.
Definition: KVMaterial.h:89
Double_t GetEffectiveAreaDensity(TVector3 &norm, 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:792
Int_t GetZ() const
Return the number of proton / atomic number.
Definition: KVNucleus.cpp:763
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:207
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:227
TVector3 & GetInteractionPoint(KVParticle *part=0)
Definition: KVTarget.cpp:768
Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0) override
Definition: KVTarget.cpp:958
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:900
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:810
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:249
KVList * GetLayers() const
Definition: KVTarget.h:171
const TVector3 & GetNormal()
Definition: KVTarget.h:155
void SetOutgoing(Bool_t r=kTRUE)
Definition: KVTarget.h:239
Double_t GetTotalThickness()
Definition: KVTarget.cpp:139
Double_t GetAtomsPerCM2() const
virtual UInt_t GetUnits() const;
Definition: KVTarget.cpp:927
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:913
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:1096
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 void Error(const char *method, const char *msgfmt,...) const
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")
const long double mg
Definition: KVUnits.h:74
void init()
constexpr Double_t DegToRad()
constexpr Double_t Na()
constexpr Double_t RadToDeg()
TArc a
ClassImp(TPyArg)