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  // 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
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, but not
172  // because they crossed all detector layers without losing all their energy, which is the meaning of "DETECTED=PUNCH THROUGH"
173  if (part_to_detect->GetE() > GetMinKECutOff()) {
174  part.SetParameter("RESIDUAL ENERGY", part_to_detect->GetE());
175  if (part.GetParameters()->HasParameter("DEADZONE"))
176  part.SetParameter("DETECTED", "DEADZONE");
177  else
178  part.SetParameter("DETECTED", "PUNCH THROUGH");
179  }
180  else
181  part.SetParameter("DETECTED", "OK");
182  }
183 
184  if (!nvl.IsEmpty()) {
185  for (Int_t ii = 0; ii < nvl.GetNpar(); ++ii) {
186  part.SetParameter(nvl.GetNameAt(ii), nvl.GetDoubleValue(ii));
187  }
188  }
189 
190  if(part.GetParameters()->HasParameter("MULTIGROUP"))
191  multi_group_parts.Add(&part);
192 
193  }
194  }
195 
196  part_to_detect->SetMomentum(*part_to_detect->GetPInitial());
197  }
198 
199  if(!multi_group_parts.IsEmpty())
200  {
201  // for each particle with parameter MULTIGROUP we make copies of the particle
202  // (1 for each extra group) and add them to the event
203  for(auto _p : multi_group_parts)
204  {
205  auto part = dynamic_cast<KVNucleus*>(_p);
206  part->GetParameters()->SetValue("DETECTED","OK");
207  auto multigroup = part->GetParameters()->GetIntValue("MULTIGROUP");
208  for(int mgrp = 1; mgrp<multigroup; ++mgrp)
209  {
210  KVNucleus* nuc;
211  part->Copy(*(nuc = event->AddNucleus()));
212  // now remove/rename parameters in each particle:
213  // - in nuc, GROUP_mgrp -> GROUP, TRAJECTORY_mgrp -> TRAJECTORY, etc.
214  nuc->GetParameters()->SetValue("GROUP", nuc->GetParameters()->GetIntValue(Form("GROUP_%d",mgrp)));
215  nuc->GetParameters()->SetValue("TRAJECTORY", nuc->GetParameters()->GetStringValue(Form("TRAJECTORY_%d",mgrp)));
216  nuc->GetParameters()->SetValue("STOPPING DETECTOR", nuc->GetParameters()->GetStringValue(Form("STOPPING DETECTOR_%d",mgrp)));
217  nuc->GetParameters()->RemoveParameter(Form("GROUP_%d",mgrp));
218  nuc->GetParameters()->RemoveParameter(Form("TRAJECTORY_%d",mgrp));
219  nuc->GetParameters()->RemoveParameter(Form("STOPPING DETECTOR_%d",mgrp));
220  part->GetParameters()->RemoveParameter(Form("GROUP_%d",mgrp));
221  part->GetParameters()->RemoveParameter(Form("TRAJECTORY_%d",mgrp));
222  part->GetParameters()->RemoveParameter(Form("STOPPING DETECTOR_%d",mgrp));
223  // parse trajectory into list of detectors
224  KVString traj(nuc->GetParameters()->GetStringValue("TRAJECTORY"));
225  traj.Begin("/");
226  while(!traj.End())
227  {
228  auto ddet = traj.Next();
229  // any parameters in 'part's list which contain the name of this detector are removed
230  KVUnownedList to_remove;
231  TIter it_par(part->GetParameters()->GetList());
233  while( (np = (KVNamedParameter*)it_par()) )
234  {
235  if(TString(np->GetName()).Contains(ddet))
236  to_remove.Add(np);
237  }
238  if(!to_remove.IsEmpty())
239  {
240  for(auto rp : to_remove)
241  {
242  part->GetParameters()->RemoveParameter(rp->GetName());
243  }
244  }
245  }
246  // now do the same for 'nuc's list of parameters
247  traj = part->GetParameters()->GetStringValue("TRAJECTORY");
248  traj.Begin("/");
249  while(!traj.End())
250  {
251  auto ddet = traj.Next();
252  // any parameters in 'nuc's list which contain the name of this detector are removed
253  KVUnownedList to_remove;
254  TIter it_par(nuc->GetParameters()->GetList());
256  while( (np = (KVNamedParameter*)it_par()) )
257  {
258  if(TString(np->GetName()).Contains(ddet))
259  to_remove.Add(np);
260  }
261  if(!to_remove.IsEmpty())
262  {
263  for(auto rp : to_remove)
264  {
265  nuc->GetParameters()->RemoveParameter(rp->GetName());
266  }
267  }
268  }
269  }
270  }
271  }
272 
273 }
274 
275 
276 
277 
288 
290 {
291  // Simulate detection of a single particle
292  //
293  // Propagate particle through the array,
294  // calculating its energy losses in all absorbers, and setting the
295  // energy loss members of the active detectors on the way.
296  //
297  // Returns a list containing the name and energy loss of each
298  // detector hit in array (list is empty if none i.e. particle
299  // in beam pipe or dead zone of the multidetector)
300 
301  auto nparams = part->GetParameters()->GetNpar();
302 
304 
305  // particle missed all detectors
306  if (part->GetParameters()->GetNpar() == nparams ||
307  ((part->GetParameters()->GetNpar() - nparams) == 1 && part->GetParameters()->HasParameter("DEADZONE")))
308  return KVNameValueList();
309 
310  // list of energy losses in active layers of detectors
311  KVNameValueList NVL;
312 
313  // trajectories followed in each group crossed by particle
314  // (taking into account possibility that particle may traverse more than 1 group)
315  std::unordered_map<unsigned int,TString> traj_group_map;
316  // find detectors in array hit by particle
317  KVDetector* last_detector = nullptr;
318  TIter next(part->GetParameters()->GetList());
319  KVNamedParameter* param;
320  while ((param = (KVNamedParameter*)next())) {
321  KVString pname(param->GetName());
322  pname.Begin(":");
323  KVString pn2 = pname.Next();
324  KVString pn3 = pname.Next();
325  if (pn2 == "DE") {
326  pn3.Begin("/");
327  KVString det_name = pn3.Next();
328  if (pn3.End() || pn3.Next().BeginsWith("ACTIVE")) {
329  // energy loss in active layer of detector
330  KVDetector* curDet = fArray->GetDetector(det_name);
331  if (curDet) {
332  last_detector = curDet;
333  Double_t de = param->GetDouble();
334  NVL.SetValue(curDet->GetName(), de);
335  // add detector to name of trajectory followed by particle
336  TString traj;
337  if (part->GetParameters()->HasStringParameter("TRAJECTORY")) {
338  traj = part->GetParameters()->GetStringValue("TRAJECTORY");
339  traj.Prepend(Form("%s/", det_name.Data()));
340  }
341  else {
342  traj = Form("%s/", det_name.Data());
343  }
344  part->SetParameter("TRAJECTORY", traj);
345  // set number of group where detected
346  part->SetParameter("GROUP", (int)curDet->GetGroupNumber());
347  auto group_num = curDet->GetGroupNumber();
348  auto& traj_string = traj_group_map[group_num];
349  if(traj_string.IsNull()) // begin new trajectory?
350  traj_string.Form("%s/", det_name.Data());
351  else
352  traj_string.Prepend(Form("%s/", det_name.Data()));
353  }
354  }
355  }
356  }
357  // analyse resulting map of groups & trajectories
358  if(traj_group_map.size() > 1)
359  {
360  // multiple groups hit: need to add copy of particle for each group
361  int itraj{0};
362  for(auto& tgp : traj_group_map)
363  {
364  fHitGroups.AddGroup(fArray->GetGroup(tgp.first));
365  KVString traj(tgp.second);
366  traj.Begin("/"); // first detector in trajectory is stopping detector (for this trajectory)
367  if(itraj)
368  {
369  part->SetParameter(Form("TRAJECTORY_%d",itraj), tgp.second);
370  part->SetParameter(Form("GROUP_%d",itraj), (int)tgp.first);
371  part->SetParameter(Form("STOPPING DETECTOR_%d",itraj), traj.Next());
372  }
373  else
374  {
375  part->SetParameter("TRAJECTORY", tgp.second);
376  part->SetParameter("GROUP", (int)tgp.first);
377  part->SetParameter("STOPPING DETECTOR", traj.Next());
378  }
379  ++itraj;
380  }
381  if(itraj>1) part->SetParameter("MULTIGROUP",itraj);
382  }
383  else
384  {
385  // add hit group to list if not already in it
386  if (last_detector) {
387  fHitGroups.AddGroup(last_detector->GetGroup());
388  part->SetParameter("STOPPING DETECTOR", last_detector->GetName());
389  }
390  }
391  return NVL;
392 }
393 
394 
395 
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: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
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)
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:159
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:123
void Copy(TObject &) const override
Copy this KVNucleus into the KVNucleus object referenced by "obj".
Definition: KVNucleus.cpp:827
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)