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
100  get_array_navigator()->ResetTrackID();
101  }
102 
103  // Reset detectors in array hit by any previous events
104  ClearHitGroups();
105 
106  // if any particle traverses >1 group of the array, we need to add copies of the particle
107  // to the simulated event, 1 for each group crossed (with the corresponding informations
108  // for reconstruction procedures)
109  KVUnownedList multi_group_parts;
110 
111  // iterate through the particles of the event
112  for (auto& part : EventIterator(event)) {
113  // reference to particle in requested detection frame
114  auto part_to_detect = (KVNucleus*)part.GetFrame(detection_frame, kFALSE);
115 
116  // store initial energy of particle in detection frame
117  part_to_detect->SetE0();
118  part.SetParameter("SIM:Z", part.GetZ());
119  part.SetParameter("SIM:A", part.GetA());
120  part.SetParameter("SIM:ENERGY", part_to_detect->GetE());
121  part.SetParameter("SIM:THETA", part_to_detect->GetTheta());
122  part.SetParameter("SIM:PHI", part_to_detect->GetPhi());
123 
124  // neutral particles & those with less than the cut-off energy are not detected
125  if ((part.GetZ() == 0) && !get_array_navigator()->IsTracking()) {
126  // neutrons are included in tracking, if active
127  part.SetParameter("UNDETECTED", "NEUTRON");
128  }
129  else if (part.GetZ() && !get_array_navigator()->CheckIonForRangeTable(part.GetZ(), part.GetA())) {
130  // ignore charged particles which range table cannot handle
131  part.SetParameter("UNDETECTED", "NOT IN RANGE TABLE");
132  }
133  else if (!fGeoFilter && (part_to_detect->GetEnergy() < GetMinKECutOff())) {
134  part.SetParameter("UNDETECTED", "AT REST");
135  }
136  else {
137  if (IncludeTargetEnergyLoss() && GetTarget() && part.GetZ()) {
138  //simulate passage through target material
139  auto ebef = part_to_detect->GetE();
140  GetTarget()->DetectParticle(part_to_detect);
141  auto eLostInTarget = ebef - part_to_detect->GetE();
142  part.SetParameter("ENERGY LOSS IN TARGET", eLostInTarget);
143  if (part_to_detect->GetE() < GetMinKECutOff())
144  part.SetParameter("UNDETECTED", "STOPPED IN TARGET");
145  }
146 
147  if (fGeoFilter || (part_to_detect->GetE() > GetMinKECutOff())) {
148 
149  auto nvl = PropagateParticle(part_to_detect);
150 
151  if (nvl.IsEmpty()) {
152  if (part.GetZ() == 0) {
153  // tracking
154  part.SetParameter("UNDETECTED", "NEUTRON");
155  }
156  else {
157  if (part.GetParameters()->HasParameter("DEADZONE")) {
158  // deadzone
159  part.SetParameter("UNDETECTED", "DEAD ZONE");
160  }
161  else {
162  // missed all detectors
163  part.SetParameter("UNDETECTED", "NO HIT");
164  }
165  }
166  }
167  else {
168  // check for incomplete stopping of particle => PUNCH THROUGH
169  // note that energy losses are not calculated in DEADZONE volume; as soon as a particle enters
170  // a DEADZONE volume its propagation stops. therefore particles which lose energy in one or more
171  // active material volumes and then hit a DEADZONE may have residual kinetic energy also
172  if (part_to_detect->GetE() > GetMinKECutOff()) {
173  part.SetParameter("RESIDUAL ENERGY", part_to_detect->GetE());
174  part.SetParameter("DETECTED", "PUNCH THROUGH");
175  }
176  else
177  part.SetParameter("DETECTED", "OK");
178  }
179 
180  if (!nvl.IsEmpty()) {
181  for (Int_t ii = 0; ii < nvl.GetNpar(); ++ii) {
182  part.SetParameter(nvl.GetNameAt(ii), nvl.GetDoubleValue(ii));
183  }
184  }
185 
186  if(part.GetParameters()->HasParameter("MULTIGROUP"))
187  multi_group_parts.Add(&part);
188 
189  }
190  }
191 
192  part_to_detect->SetMomentum(*part_to_detect->GetPInitial());
193  }
194 
195  if(!multi_group_parts.IsEmpty())
196  {
197  // for each particle with parameter MULTIGROUP we make copies of the particle
198  // (1 for each extra group) and add them to the event
199  for(auto _p : multi_group_parts)
200  {
201  auto part = dynamic_cast<KVNucleus*>(_p);
202  part->GetParameters()->SetValue("DETECTED","OK");
203  auto multigroup = part->GetParameters()->GetIntValue("MULTIGROUP");
204  for(int mgrp = 1; mgrp<multigroup; ++mgrp)
205  {
206  KVNucleus* nuc;
207  part->Copy(*(nuc = event->AddNucleus()));
208  // now remove/rename parameters in each particle:
209  // - in nuc, GROUP_mgrp -> GROUP, TRAJECTORY_mgrp -> TRAJECTORY, etc.
210  nuc->GetParameters()->SetValue("GROUP", nuc->GetParameters()->GetIntValue(Form("GROUP_%d",mgrp)));
211  nuc->GetParameters()->SetValue("TRAJECTORY", nuc->GetParameters()->GetStringValue(Form("TRAJECTORY_%d",mgrp)));
212  nuc->GetParameters()->SetValue("STOPPING DETECTOR", nuc->GetParameters()->GetStringValue(Form("STOPPING DETECTOR_%d",mgrp)));
213  nuc->GetParameters()->RemoveParameter(Form("GROUP_%d",mgrp));
214  nuc->GetParameters()->RemoveParameter(Form("TRAJECTORY_%d",mgrp));
215  nuc->GetParameters()->RemoveParameter(Form("STOPPING DETECTOR_%d",mgrp));
216  part->GetParameters()->RemoveParameter(Form("GROUP_%d",mgrp));
217  part->GetParameters()->RemoveParameter(Form("TRAJECTORY_%d",mgrp));
218  part->GetParameters()->RemoveParameter(Form("STOPPING DETECTOR_%d",mgrp));
219  // parse trajectory into list of detectors
220  KVString traj(nuc->GetParameters()->GetStringValue("TRAJECTORY"));
221  traj.Begin("/");
222  while(!traj.End())
223  {
224  auto ddet = traj.Next();
225  // any parameters in 'part's list which contain the name of this detector are removed
226  KVUnownedList to_remove;
227  TIter it_par(part->GetParameters()->GetList());
229  while( (np = (KVNamedParameter*)it_par()) )
230  {
231  if(TString(np->GetName()).Contains(ddet))
232  to_remove.Add(np);
233  }
234  if(!to_remove.IsEmpty())
235  {
236  for(auto rp : to_remove)
237  {
238  part->GetParameters()->RemoveParameter(rp->GetName());
239  }
240  }
241  }
242  // now do the same for 'nuc's list of parameters
243  traj = part->GetParameters()->GetStringValue("TRAJECTORY");
244  traj.Begin("/");
245  while(!traj.End())
246  {
247  auto ddet = traj.Next();
248  // any parameters in 'nuc's list which contain the name of this detector are removed
249  KVUnownedList to_remove;
250  TIter it_par(nuc->GetParameters()->GetList());
252  while( (np = (KVNamedParameter*)it_par()) )
253  {
254  if(TString(np->GetName()).Contains(ddet))
255  to_remove.Add(np);
256  }
257  if(!to_remove.IsEmpty())
258  {
259  for(auto rp : to_remove)
260  {
261  nuc->GetParameters()->RemoveParameter(rp->GetName());
262  }
263  }
264  }
265  }
266  }
267  }
268 
269 }
270 
271 
272 
273 
284 
285 KVNameValueList KVDetectionSimulator::PropagateParticle(KVNucleus* part)
286 {
287  // Simulate detection of a single particle
288  //
289  // Propagate particle through the array,
290  // calculating its energy losses in all absorbers, and setting the
291  // energy loss members of the active detectors on the way.
292  //
293  // Returns a list containing the name and energy loss of each
294  // detector hit in array (list is empty if none i.e. particle
295  // in beam pipe or dead zone of the multidetector)
296 
297  auto nparams = part->GetParameters()->GetNpar();
298 
299  get_array_navigator()->PropagateParticle(part);
300 
301  // particle missed all detectors
302  if (part->GetParameters()->GetNpar() == nparams ||
303  ((part->GetParameters()->GetNpar() - nparams) == 1 && part->GetParameters()->HasParameter("DEADZONE")))
304  return KVNameValueList();
305 
306  // list of energy losses in active layers of detectors
307  KVNameValueList NVL;
308 
309  // trajectories followed in each group crossed by particle
310  // (taking into account possibility that particle may traverse more than 1 group)
311  std::unordered_map<unsigned int,TString> traj_group_map;
312  // find detectors in array hit by particle
313  KVDetector* last_detector = nullptr;
314  TIter next(part->GetParameters()->GetList());
315  KVNamedParameter* param;
316  while ((param = (KVNamedParameter*)next())) {
317  KVString pname(param->GetName());
318  pname.Begin(":");
319  KVString pn2 = pname.Next();
320  KVString pn3 = pname.Next();
321  if (pn2 == "DE") {
322  pn3.Begin("/");
323  KVString det_name = pn3.Next();
324  if (pn3.End() || pn3.Next().BeginsWith("ACTIVE")) {
325  // energy loss in active layer of detector
326  KVDetector* curDet = fArray->GetDetector(det_name);
327  if (curDet) {
328  last_detector = curDet;
329  Double_t de = param->GetDouble();
330  NVL.SetValue(curDet->GetName(), de);
331  // add detector to name of trajectory followed by particle
332  TString traj;
333  if (part->GetParameters()->HasStringParameter("TRAJECTORY")) {
334  traj = part->GetParameters()->GetStringValue("TRAJECTORY");
335  traj.Prepend(Form("%s/", det_name.Data()));
336  }
337  else {
338  traj = Form("%s/", det_name.Data());
339  }
340  part->SetParameter("TRAJECTORY", traj);
341  // set number of group where detected
342  part->SetParameter("GROUP", (int)curDet->GetGroupNumber());
343  auto group_num = curDet->GetGroupNumber();
344  auto& traj_string = traj_group_map[group_num];
345  if(traj_string.IsNull()) // begin new trajectory?
346  traj_string.Form("%s/", det_name.Data());
347  else
348  traj_string.Prepend(Form("%s/", det_name.Data()));
349  }
350  }
351  }
352  }
353  // analyse resulting map of groups & trajectories
354  if(traj_group_map.size() > 1)
355  {
356  // multiple groups hit: need to add copy of particle for each group
357  int itraj{0};
358  for(auto& tgp : traj_group_map)
359  {
360  fHitGroups.AddGroup(fArray->GetGroup(tgp.first));
361  KVString traj(tgp.second);
362  traj.Begin("/"); // first detector in trajectory is stopping detector (for this trajectory)
363  if(itraj)
364  {
365  part->SetParameter(Form("TRAJECTORY_%d",itraj), tgp.second);
366  part->SetParameter(Form("GROUP_%d",itraj), (int)tgp.first);
367  part->SetParameter(Form("STOPPING DETECTOR_%d",itraj), traj.Next());
368  }
369  else
370  {
371  part->SetParameter("TRAJECTORY", tgp.second);
372  part->SetParameter("GROUP", (int)tgp.first);
373  part->SetParameter("STOPPING DETECTOR", traj.Next());
374  }
375  ++itraj;
376  }
377  if(itraj>1) part->SetParameter("MULTIGROUP",itraj);
378  }
379  else
380  {
381  // add hit group to list if not already in it
382  if (last_detector) {
383  fHitGroups.AddGroup(last_detector->GetGroup());
384  part->SetParameter("STOPPING DETECTOR", last_detector->GetName());
385  }
386  }
387  return NVL;
388 }
389 
390 
391 
int Int_t
char Char_t
constexpr Bool_t kFALSE
double Double_t
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 np
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:140
Simulate detection of events in a detector array.
KVTarget * GetTarget() const
void DetectEvent(KVEvent *event, const Char_t *detection_frame="")
Double_t GetMinKECutOff() const
Bool_t IncludeTargetEnergyLoss() const
void AddGroup(KVGroup *grp)
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:173
KVGroup * GetGroup() const
UInt_t GetGroupNumber()
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.
KVGroup * GetGroup(const Char_t *name) const
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
Int_t GetIntValue(const Char_t *name) const
void SetValue(const Char_t *name, value_type value)
void RemoveParameter(const Char_t *name)
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:108
void Copy(TObject &) const override
Copy this KVNucleus into the KVNucleus object referenced by "obj".
Definition: KVNucleus.cpp:839
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)
void Add(TObject *obj) override
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
Extended TList class which does not own its objects by default.
Definition: KVUnownedList.h:20
virtual Bool_t IsEmpty() const
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)