KaliVeda
Toolkit for HIC analysis
KVDetectionSimulator.cpp
1 //Created by KVClassFactory on Sat Oct 10 09:37:42 2015
2 //Author: John Frankland,,,
3 
4 #include "KVDetectionSimulator.h"
5 #include "KVGeoNavigator.h"
6 
8 
9 
10 
17  KVBase(Form("DetectionSimulator_%s", a->GetName()),
18  Form("Simulate detection of particles or events in detector array %s", a->GetTitle())),
19  fArray(a), fCalcTargELoss(kTRUE)
20 {
21  // Initialise a detection simulator
22  //
23  // The detector array is put into simulation mode, and the minimum cut-off energy
24  // for propagation of particles is set (1 keV is default)
25  SetArray(a);
26 }
27 
28 
29 
61 
62 void KVDetectionSimulator::DetectEvent(KVEvent* event, const Char_t* detection_frame)
63 {
64  //Simulate detection of event by multidetector array.
65  //
66  // optional argument detection_frame(="" by default) can be used to give name of
67  // inertial reference frame (defined for all particles of 'event') to be used.
68  // e.g. if the simulated event's default reference frame is the centre of mass frame, before calling this method
69  // you should create the 'laboratory' or 'detector' frame with KVEvent::SetFrame(...), and then give the
70  // name of the 'LAB' or 'DET' frame as 3rd argument here.
71  //
72  //For each particle in the event we calculate first its energy loss in the target (if the target has been defined, see KVMultiDetArray::SetTarget).
73  //By default these energy losses are calculated from a point half-way along the beam-direction through the target (taking into account the orientation
74  //of the target), if you want random depths for each event call GetTarget()->SetRandomized() before using DetectEvent().
75  //
76  //If the particle escapes the target then we look for the group in the array that it will hit. If there is one, then the detection of this particle by the
77  //different members of the group is simulated.
78  //
79  //The detectors concerned have their fEloss members set to the energy lost by the particle when it crosses them.
80  //
81  //Give tags to the simulated particles via KVNucleus::AddGroup() method
82  //Two general tags :
83  // - DETECTED : cross at least one active layer of one detector
84  // - UNDETECTED : go through dead zone or stopped in target
85  //We add also different sub group :
86  // - For UNDETECTED particles : "NO HIT", "NEUTRON", "DEAD ZONE", "STOPPED IN TARGET" and "THRESHOLD", the last one concerns particles
87  // which go through the first detection stage of the multidetector array but stopped in an absorber (ie an inactive layer)
88  // - For DETECTED particles :
89  // * "PUNCH THROUGH" corrresponds to particle which cross all the materials in front of it
90  // (high energy particle punch through)
91  // * "INCOMPLETE" corresponds to particles which stopped in the first detection stage of the multidetector
92  // in a detector which can not give alone a clear identification,
93  //
94 
95  fDetectionFrame = detection_frame;
96 
97  if (get_array_navigator()->IsTracking()) {
98  // clear any tracks created by last event
101  }
102 
103  // Reset detectors in array hit by any previous events
104  ClearHitGroups();
105 
106  // iterate through the particles of the event
107  for (auto& part : EventIterator(event)) {
108  // reference to particle in requested detection frame
109  auto part_to_detect = (KVNucleus*)part.GetFrame(detection_frame, kFALSE);
110 
111  // store initial energy of particle in detection frame
112  part_to_detect->SetE0();
113  part.SetParameter("SIM:Z", part.GetZ());
114  part.SetParameter("SIM:A", part.GetA());
115  part.SetParameter("SIM:ENERGY", part_to_detect->GetE());
116  part.SetParameter("SIM:THETA", part_to_detect->GetTheta());
117  part.SetParameter("SIM:PHI", part_to_detect->GetPhi());
118 
119  // neutral particles & those with less than the cut-off energy are not detected
120  if ((part.GetZ() == 0) && !get_array_navigator()->IsTracking()) {
121  // neutrons are included in tracking, if active
122  part.SetParameter("UNDETECTED", "NEUTRON");
123  }
124  else if (part.GetZ() && !get_array_navigator()->CheckIonForRangeTable(part.GetZ(), part.GetA())) {
125  // ignore charged particles which range table cannot handle
126  part.SetParameter("UNDETECTED", "NOT IN RANGE TABLE");
127  }
128  else if (!fGeoFilter && (part_to_detect->GetEnergy() < GetMinKECutOff())) {
129  part.SetParameter("UNDETECTED", "AT REST");
130  }
131  else {
132  if (IncludeTargetEnergyLoss() && GetTarget() && part.GetZ()) {
133  //simulate passage through target material
134  auto ebef = part_to_detect->GetE();
135  GetTarget()->DetectParticle(part_to_detect);
136  auto eLostInTarget = ebef - part_to_detect->GetE();
137  part.SetParameter("ENERGY LOSS IN TARGET", eLostInTarget);
138  if (part_to_detect->GetE() < GetMinKECutOff())
139  part.SetParameter("UNDETECTED", "STOPPED IN TARGET");
140  }
141 
142  if (fGeoFilter || (part_to_detect->GetE() > GetMinKECutOff())) {
143 
144  auto nvl = PropagateParticle(part_to_detect);
145 
146  if (nvl.IsEmpty()) {
147  if (part.GetZ() == 0) {
148  // tracking
149  part.SetParameter("UNDETECTED", "NEUTRON");
150  }
151  else {
152  if (part.GetParameters()->HasParameter("DEADZONE")) {
153  // deadzone
154  part.SetParameter("UNDETECTED", "DEAD ZONE");
155  }
156  else {
157  // missed all detectors
158  part.SetParameter("UNDETECTED", "NO HIT");
159  }
160  }
161  }
162  else {
163  // check for incomplete stopping of particle
164  // note that energy losses are not calculated in DEADZONE volume; as soon as a particle enters
165  // a DEADZONE volume its propagation stops. therefore particles which lose energy in one or more
166  // active material volumes and then hit a DEADZONE may have residual kinetic energy, but not
167  // because they crossed all detector layers without losing all their energy, which is the meaning of "DETECTED=PUNCH THROUGH"
168  if (part_to_detect->GetE() > GetMinKECutOff()) {
169  part.SetParameter("RESIDUAL ENERGY", part_to_detect->GetE());
170  if (part.GetParameters()->HasParameter("DEADZONE"))
171  part.SetParameter("DETECTED", "DEADZONE");
172  else
173  part.SetParameter("DETECTED", "PUNCH THROUGH");
174  }
175  else
176  part.SetParameter("DETECTED", "OK");
177  }
178 
179  if (!nvl.IsEmpty()) {
180  for (Int_t ii = 0; ii < nvl.GetNpar(); ++ii) {
181  part.SetParameter(nvl.GetNameAt(ii), nvl.GetDoubleValue(ii));
182  }
183  }
184 
185  }
186  }
187 
188  part_to_detect->SetMomentum(*part_to_detect->GetPInitial());
189  }
190 
191 }
192 
193 
194 
195 
206 
208 {
209  // Simulate detection of a single particle
210  //
211  // Propagate particle through the array,
212  // calculating its energy losses in all absorbers, and setting the
213  // energy loss members of the active detectors on the way.
214  //
215  // Returns a list containing the name and energy loss of each
216  // detector hit in array (list is empty if none i.e. particle
217  // in beam pipe or dead zone of the multidetector)
218 
219  auto nparams = part->GetParameters()->GetNpar();
220 
222 
223  // particle missed all detectors
224  if (part->GetParameters()->GetNpar() == nparams ||
225  ((part->GetParameters()->GetNpar() - nparams) == 1 && part->GetParameters()->HasParameter("DEADZONE")))
226  return KVNameValueList();
227 
228  // list of energy losses in active layers of detectors
229  KVNameValueList NVL;
230 
231  // find detectors in array hit by particle
232  KVDetector* last_detector = nullptr;
233  TIter next(part->GetParameters()->GetList());
234  KVNamedParameter* param;
235  while ((param = (KVNamedParameter*)next())) {
236  KVString pname(param->GetName());
237  pname.Begin(":");
238  KVString pn2 = pname.Next();
239  KVString pn3 = pname.Next();
240  if (pn2 == "DE") {
241  pn3.Begin("/");
242  KVString det_name = pn3.Next();
243  if (pn3.End() || pn3.Next().BeginsWith("ACTIVE")) {
244  // energy loss in active layer of detector
245  KVDetector* curDet = fArray->GetDetector(det_name);
246  if (curDet) {
247  last_detector = curDet;
248  Double_t de = param->GetDouble();
249  NVL.SetValue(curDet->GetName(), de);
250  // add detector to name of trajectory followed by particle
251  TString traj;
252  if (part->GetParameters()->HasStringParameter("TRAJECTORY")) {
253  traj = part->GetParameters()->GetStringValue("TRAJECTORY");
254  traj.Prepend(Form("%s/", det_name.Data()));
255  }
256  else {
257  traj = Form("%s/", det_name.Data());
258  }
259  part->SetParameter("TRAJECTORY", traj);
260  // set number of group where detected
261  part->SetParameter("GROUP", (int)curDet->GetGroupNumber());
262  }
263  }
264  }
265  }
266  // add hit group to list if not already in it
267  if (last_detector) {
268  fHitGroups.AddGroup(last_detector->GetGroup());
269  part->SetParameter("STOPPING DETECTOR", last_detector->GetName());
270  }
271 
272  return NVL;
273 }
274 
275 
276 
int Int_t
char Char_t
constexpr Bool_t kFALSE
double Double_t
R__EXTERN TGeoManager * gGeoManager
char * Form(const char *fmt,...)
Class for iterating over nuclei in events accessed through base pointer/reference.
Base class for KaliVeda framework.
Definition: KVBase.h:139
Simulate detection of events in a detector array.
KVTarget * GetTarget() const
void DetectEvent(KVEvent *event, const Char_t *detection_frame="")
Double_t GetMinKECutOff() const
KVNameValueList PropagateParticle(KVNucleus *)
TString fDetectionFrame
when true, only consider geometry, not particle energies
KVRangeTableGeoNavigator * get_array_navigator() const
name of kinematical frame used in last call to DetectEvent()
Bool_t IncludeTargetEnergyLoss() const
KVDetectorEvent fHitGroups
array used for detection
KVMultiDetArray * fArray
Bool_t fGeoFilter
whether to include energy loss in target, if defined
void AddGroup(KVGroup *grp)
Abstract base class container for multi-particle events.
Definition: KVEvent.h:67
Bool_t IsTracking() const
void ResetTrackID(Int_t id=0)
virtual KVDetector * GetDetector(const Char_t *name) const
Return detector in this structure with given name.
Double_t GetZ() const
Definition: KVMaterial.cpp:390
Base class for describing the geometry of a detector array.
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
void SetValue(const Char_t *name, value_type value)
Int_t GetNpar() const
return the number of stored parameters
Bool_t HasStringParameter(const Char_t *name) const
const Char_t * GetStringValue(const Char_t *name) const
Bool_t HasParameter(const Char_t *name) const
KVHashList * GetList() const
A generic named parameter storing values of different types.
Double_t GetDouble() const
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
KVNameValueList * GetParameters() const
Definition: KVParticle.h:818
void SetParameter(const Char_t *name, ValType value) const
Definition: KVParticle.h:822
void PropagateParticle(KVNucleus *, TVector3 *TheOrigin=0) override
We start a new track to represent the particle's trajectory through the array.
Bool_t CheckIonForRangeTable(Int_t Z, Int_t A)
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition: KVString.h:73
void Begin(TString delim) const
Definition: KVString.cpp:565
Bool_t End() const
Definition: KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition: KVString.cpp:695
void DetectParticle(KVNucleus *, TVector3 *norm=0) override
Definition: KVTarget.cpp:486
void ClearTracks()
const char * GetName() const override
const char * Data() const
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
TString & Prepend(char c, Ssiz_t rep=1)
TArc a
ClassImp(TPyArg)