KaliVeda  1.12/06
Heavy-Ion Analysis Toolkit
KVTarget.cpp
Go to the documentation of this file.
1 #include "KVTarget.h"
2 #include "KVEvent.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 
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 
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 = new KVNucleus(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 
704  //delete clone
705  delete clone_part;
706 
707  return Eloss;
708 }
709 
710 
711 
712 
720 
722 {
723  //Simulate passage of particles from some simulation through the target material.
724  //The particles will be slowed down according to their calculated energy losses.
725  //First we SetOutgoing(): for a simulated event, energy losses are only calculated from some
726  //interaction point inside the target to the outside. This interaction point will be taken half-way
727  //through the target (by default) or at some random depth in the target if SetRandomized() is
728  //called first.
729 
730  SetOutgoing();
731  KVNucleus* part;
732  while ((part = (KVNucleus*) event->GetNextParticle())) { // loop over particles
734  }
735 }
736 
737 
738 
739 
741 
742 void KVTarget::Print(Option_t* opt) const
743 {
744  cout << "Target " << GetName() << ", " << GetTitle() << endl;
745  fTargets->Print(opt);
746 }
747 
748 
749 
750 
752 
754 {
755  KVMaterial::Clear(opt);
756  fTargets->Execute("Clear", Form("%s", opt));
757 }
758 
759 
760 
761 
772 
774 {
775  //Returns last known interaction point (if part=0) or generates a new one if part!=0.
776  //
777  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
778  //direction 'of the incident particle's trajectory through target.
779  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction.
780  //
781  //If no interaction point is set by the user (i.e. GetInteractionPoint never called with
782  //the address of a KVParticle), the default is to generate an interaction point using the
783  //beam (+ve Z-)direction.
784 
785  TVector3 dir;
786  if (!part) {
787  //check fIntPoint is valid
788  if (fIntPoint.Mag() > 0)
789  return fIntPoint;
790  //set default direction - beam direction
791  dir.SetXYZ(0, 0, 1);
792  }
793  else {
794  dir = part->GetMomentum();
795  }
797  Double_t depth;
798  depth = (IsRandomized() ? gRandom->Uniform(e_eff) : 0.5 * e_eff);
799  fIntPoint = depth * (dir.Unit());
800  return fIntPoint;
801 }
802 
803 
804 
805 
814 
816 {
817  //Sets the interaction point inside the layer with index 'ilayer'
818  //
819  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
820  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
821  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
822  //inside the layer
823 
824  //total effective thickness (along 'dir') of all layers before 'ilayer'
825  Double_t e_eff =
826  (ilayer > 1 ? GetTotalEffectiveThickness(dir, 1, ilayer - 1) : 0.0);
827 #ifdef DBG_TRGT
828  cout <<
829  "total effective thickness (along 'dir') of all layers before 'ilayer'="
830  << e_eff << endl;
831 #endif
832  //effective depth inside layer (along 'dir')
833  Double_t e_eff_ilayer = GetEffectiveThickness(dir, ilayer);
834  Double_t depth =
835  (IsRandomized() ? gRandom->Uniform(e_eff_ilayer) : 0.5 *
836  e_eff_ilayer);
837 #ifdef DBG_TRGT
838  cout << "dpeth inside interaction layer=" << depth << endl;
839 #endif
840  fIntPoint = (e_eff + depth) * (dir.Unit());
841 #ifdef DBG_TRGT
842  cout << "generated IP vector:" << endl;
843  fIntPoint.Print();
844 #endif
845 }
846 
847 
848 
849 
857 
859 {
860  //Sets the interaction point inside the layer made of absorber type 'name'
861  //
862  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
863  //direction 'dir' inside layer (e.g. incident particle's trajectory through layer).
864  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction 'dir'
865  //inside the layer
866 
867  Int_t ilayer = GetLayerIndex(name);
868  if (!ilayer) {
869  Error("SetInteractionLayer",
870  "No layer in target with material type %s", name);
871  }
872  SetInteractionLayer(ilayer, dir);
873 }
874 
875 
876 
877 
885 
887 {
888  //Sets the interaction point inside the layer made of absorber type 'name'
889  //
890  //if IsRandomized()=kTRUE the generated interaction point is at a random distance along the
891  //direction along the incident particle's trajectory through layer.
892  //if IsRandomized()=kFALSE the generated interaction point is half way along the direction
893  //inside the layer
894 
895  TVector3 dir = part->GetMomentum();
896  SetInteractionLayer(name, dir);
897 }
898 
899 
900 
901 
904 
905 void KVTarget::SetMaterial(const Char_t* type)
906 {
907  // Set material of first layer
908  if (GetLayerByIndex(1))
910 }
911 
912 
913 
914 
917 
919 {
920  // Set 'thickness' in mg/cm**2 of a layer, by default this is the first layer
921  if (GetLayerByIndex(ilayer))
922  GetLayerByIndex(ilayer)->SetAreaDensity(thick * KVUnits::mg);
923 }
924 
925 
926 
927 
931 
933 {
934  //Calculates total number of atoms per square centimetre of the target.
935  //For a multilayer target, the area densities for each layer are summed up.
936  Double_t atom_cib = 0;
937  for (int i = 1; i <= NumberOfLayers(); i++) {
938  //N_atoms = N_Avogadro * target_thickness (mg/cm**2) * 1.e-3 / atomic_mass_of_target
939  atom_cib +=
940  TMath::Na() * GetThickness(i) * 1.e-3 /
941  GetLayerByIndex(i)->GetMass();
942  }
943  return atom_cib;
944 }
945 
946 
947 
948 
962 
964 {
965  // Calculate initial energy of particle from its current (residual) energy, assumed
966  // to correspond to the state of the particle after passage through all or some part
967  // of the target, taking into account the particle's direction of motion and an arbitrary
968  // orientation of the target.
969  //
970  // The 'TVector3*' argument is not used.
971  //
972  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
973  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
974  // we calculate energy of particle before entering target
975  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
976  // we calculate energy of particle at interactio point
977 
978  Double_t ERes = 0.0;
979 
980  //make 'clone' of nucleus to simulate energy losses
981  KVNucleus* clone_part = new KVNucleus(kvp->GetZ(), kvp->GetA());
982  clone_part->SetMomentum(kvp->GetMomentum());
983 
984  if (!IsIncoming() && !IsOutgoing()) {
985 
986  //correct for losses in all layers
987  for (int i = NumberOfLayers(); i > 0; i--) {
988  ERes = GetLayerByIndex(i)->GetParticleEIncFromERes(clone_part, &fNormal);
989  clone_part->SetKE(ERes);
990  }
991  delete clone_part;
992  return ERes;
993 
994  }
995  else {
996 
997  //find starting or ending layer (where is I.P. ?)
998  Int_t iplay_index = GetLayerIndex(GetInteractionPoint());
999  //particle going forwards or backwards ?
1000  TVector3 p = clone_part->GetMomentum();
1001  Bool_t backwards = (p * GetNormal() < 0.0);
1002 
1003  if (iplay_index) {
1004 
1005  KVMaterial* iplay = GetLayerByIndex(iplay_index);
1006 
1007  //effective thickness of I.P. layer is reduced because we start/stop from inside it
1008  //the effective thickness (measured along the normal) after the I.P. is given by the
1009  //sum of all thicknesses up to and including this layer minus the scalar product of
1010  //'depth' with the normal (i.e. the projection of 'depth' along the normal)
1011 
1012  Double_t e_thick_iplay = GetTotalThickness(1,
1013  iplay_index) -
1015  e_thick_iplay =
1016  (IsIncoming() ? iplay->GetAreaDensity() / KVUnits::mg -
1017  e_thick_iplay : e_thick_iplay);
1018 
1019  if (backwards)
1020  e_thick_iplay = iplay->GetAreaDensity() / KVUnits::mg - e_thick_iplay;
1021  //modify effective physical thickness of layer
1022  Double_t thick_iplay = iplay->GetAreaDensity();
1023  iplay->SetAreaDensity(e_thick_iplay * KVUnits::mg);
1024 
1025  //first and last indices of layers to pass through
1026  Int_t ilay1 =
1027  (IsIncoming() ? (backwards ? NumberOfLayers() : 1) :
1028  iplay_index);
1029  Int_t ilay2 =
1030  (IsIncoming() ? iplay_index
1031  : (backwards ? 1 : NumberOfLayers()));
1032 
1033  //correct for losses in different layers
1034  if (backwards) {
1035 
1036  for (int i = ilay2;
1037  i <= ilay1; i++) {
1038  ERes =
1040  &fNormal);
1041  clone_part->SetKE(ERes);
1042  }
1043 
1044  }
1045  else {
1046 
1047  for (int i = ilay2;
1048  i >= ilay1 ; i--) {
1049  ERes =
1051  &fNormal);
1052  clone_part->SetKE(ERes);
1053  }
1054 
1055  }
1056 
1057  //reset original thickness of IP layer
1058  iplay->SetAreaDensity(thick_iplay);
1059 
1060  }
1061  else {
1062  Error("GetParticleEIncFromERes", "Interaction point is outside of target");
1063  }
1064  }
1065 
1066  //delete clone
1067  delete clone_part;
1068 
1069  return ERes;
1070 }
1071 
1072 
1073 
1074 
1093 
1095 {
1096  // Calculate initial energy of nucleus (Z,A) from given residual energy Eres, assumed
1097  // to correspond to the state of the particle after passage through all or some part
1098  // of the target, taking into account an arbitrary orientation of the target.
1099  //
1100  // *** WARNING ***
1101  // Obviously we cannot know the particle's direction of motion,
1102  // therefore we assume it to be travelling in the beam direction (0,0,1)
1103  // Normally you should use GetParticleEIncFromERes
1104  //
1105  // The' 'TVector3*' argument is not used.
1106  //
1107  // If IsIncoming()=kFALSE & IsOutgoing()=kFALSE, we assume the particle passed through the whole of the target.
1108  // If IsIncoming()=kTRUE, assume current energy is energy on reaching interaction point;
1109  // we calculate energy of particle before entering target
1110  // If IsOutgoing()=kTRUE, assume current energy is energy on exiting from target;
1111  // we calculate energy of particle at interactio point
1112 
1113  //Fake nucleus
1114  KVNucleus dummy(Z, A);
1115  dummy.SetKE(Eres);
1116  return GetParticleEIncFromERes(&dummy);
1117 }
1118 
1119 
1120 
int Int_t
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,...)
Base class container for multi-particle events.
Definition: KVEvent.h:176
Extended TList class which owns its objects by default.
Definition: KVList.h:27
Description of physical materials used to construct detectors; interface to range tables.
Definition: KVMaterial.h:41
virtual void Copy(TObject &obj) const
Copy this to obj.
Definition: KVMaterial.cpp:891
Double_t GetEffectiveAreaDensity(TVector3 &norm, TVector3 &direction)
Definition: KVMaterial.cpp:553
void SetAreaDensity(Double_t dens)
Definition: KVMaterial.cpp:406
Double_t GetAreaDensity() const
Return area density of material in g/cm**2.
Definition: KVMaterial.cpp:427
virtual void SetMaterial(const Char_t *type)
Definition: KVMaterial.cpp:191
virtual Double_t GetELostByParticle(KVNucleus *, TVector3 *norm=0)
Definition: KVMaterial.cpp:597
virtual void Clear(Option_t *opt="")
Reset absorber - set energy lost by particles to zero.
Definition: KVMaterial.cpp:879
KVMaterial()
default ctor
Definition: KVMaterial.cpp:70
virtual void DetectParticle(KVNucleus *, TVector3 *norm=0)
Definition: KVMaterial.cpp:844
virtual Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0)
Definition: KVMaterial.cpp:632
Double_t GetMass() const
Returns atomic mass of material. Will be isotopic mass if set.
Definition: KVMaterial.cpp:252
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:565
void SetMomentum(const TVector3 &v)
Definition: KVParticle.h:535
void SetKE(Double_t ecin)
Definition: KVParticle.cpp:230
Double_t GetKE() const
Definition: KVParticle.h:575
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:742
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:594
Int_t NumberOfLayers() const
Definition: KVTarget.h:165
virtual Double_t GetParticleEIncFromERes(KVNucleus *, TVector3 *norm=0)
Definition: KVTarget.cpp:963
KVList * fTargets
list of layers
Definition: KVTarget.h:138
Bool_t IsOutgoing() const
Definition: KVTarget.h:225
virtual Double_t GetIncidentEnergyFromERes(Int_t Z, Int_t A, Double_t Eres)
Definition: KVTarget.cpp:1094
void Clear(Option_t *opt="")
Reset absorber - set energy lost by particles to zero.
Definition: KVTarget.cpp:753
TVector3 & GetInteractionPoint(KVParticle *part=0)
Definition: KVTarget.cpp:773
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:815
void DetectEvent(KVEvent *)
Definition: KVTarget.cpp:721
virtual void SetMaterial(const Char_t *type)
Set material of first layer.
Definition: KVTarget.cpp:905
TVector3 fNormal
normal to target - (0,0,1) by default
Definition: KVTarget.h:140
Bool_t IsRandomized() const
Definition: KVTarget.h:247
KVList * GetLayers() const
Definition: KVTarget.h:169
const TVector3 & GetNormal()
Definition: KVTarget.h:153
void SetOutgoing(Bool_t r=kTRUE)
Definition: KVTarget.h:237
Double_t GetTotalThickness()
Definition: KVTarget.cpp:138
Double_t GetAtomsPerCM2() const
virtual UInt_t GetUnits() const;
Definition: KVTarget.cpp:932
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:918
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