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