KaliVeda
Toolkit for HIC analysis
KVElasticScatter.cpp
1 /*
2 $Id: KVElasticScatter.cpp,v 1.9 2007/04/04 10:39:17 ebonnet Exp $
3 $Revision: 1.9 $
4 $Date: 2007/04/04 10:39:17 $
5 */
6 
7 //Created by KVClassFactory on Thu Oct 19 22:31:02 2006
8 //Author: John Frankland
9 
10 #include "KVElasticScatter.h"
11 #include "KVMultiDetArray.h"
12 #include "TH1F.h"
13 #include "KVDetector.h"
14 #include "KVGroup.h"
15 #include "KVTarget.h"
16 #include "KV2Body.h"
17 #include "TObjArray.h"
18 #include "KVExpDB.h"
19 #include "TRandom.h"
20 using namespace std;
21 
23 
24 
25 
29 {
30  //Default constructor
31  if (!gMultiDetArray)
32  Error("KVElasticScatter", "First define the multidetector array for the simulation");
33  SetRun(run);
34  gMultiDetArray->SetSimMode(kTRUE);
35 }
36 
37 
38 
39 
42 
43 KVElasticScatter::~KVElasticScatter()
44 {
45  //Destructor
46  if (fDepth)
47  delete fDepth;
48  if (fTheta)
49  delete fTheta;
50  gMultiDetArray->SetSimMode(kFALSE);
51 }
52 
53 
54 
55 
62 
64 {
65  //Set beam, detector parameters, target, etc. for run
66  //
67  // The default reaction kinematics is that of the KVDBSystem associated to the run.
68  //
69  // The default scattering position in the target is random.
70  gMultiDetArray->SetParameters(run);
71  fTarget = gMultiDetArray->GetTarget();
72  fTarget->SetRandomized();
73  fAtomicDensity = fTarget->GetAtomsPerCM2() * 1.e-24; //in barn^-1 units
74  fIntLayer = 0;
75  fMultiLayer = (fTarget->NumberOfLayers() > 1);
76  // get reaction propoerties from system
77  auto sys = gExpDB->GetDBRun(run)->GetSystem();
78  fKinematics = sys->GetKinematics();
79 }
80 
81 
82 
83 
90 
92 {
93  // Give name of detector towards which elastic scattering will occur.
94  //
95  // \note this does not necessarily mean that the particle will actually
96  // arrive in the given detector (it may stop before it), but the aim is to
97  // define the trajectory of the particle in the array.
98 
99  fDetector = gMultiDetArray->GetDetector(det);
100  if (!fDetector) {
101  Error("SetDetector", "Detector %s is unknown!", det);
102  return;
103  }
104  // get trajectory for detector
105  if (fDetector->GetNode()->GetNTraj() > 1) {
106  Warning("SetDetector", "Ambiguous trajectory choice: detector %s has %d trajectories", det, fDetector->GetNode()->GetNTraj());
107  }
108  auto traj = (KVGeoDNTrajectory*)fDetector->GetNode()->GetTrajectories()->First();
109  Info("SetDetector", "Using trajectory: %s", traj->GetName());
110 
111  //we store the association between detector type and index in list
112  fDetInd.Clear();
113  fAlignedDetectors.Clear();
114 
115  traj->IterateBackFrom();
116 
117  Int_t i = 0;
118  KVGeoDetectorNode* gdn = nullptr;
119  while ((gdn = traj->GetNextNode())) {
120  KVDetector* d = gdn->GetDetector();
121  fAlignedDetectors.Add(d);
122  fDetInd.SetValue(d->GetLabel(), i);
123  ++i;
124  }
125  //store number of aligned detectors
126  fNDets = i;
127  fHistos.Expand(fNDets);
128  fHistos.SetOwner(); //will delete histos it stores
129 }
130 
131 
132 
133 
140 
142 {
143  //For multilayer targets, use this method to choose in which
144  //layer the scattering will take place.
145  //
146  //If name="", reset any previous choice so that scattering
147  //can take place in any layer
148  if (!fTarget) {
149  cout <<
150  "<KVElasticScatter::SetTargetScatteringLayer> : No target set. Set run first."
151  << endl;
152  return;
153  }
154  fIntLayer = fTarget->GetLayerIndex(name);
155  if (fIntLayer)
156  fTarget->SetInteractionLayer(fIntLayer, fBeamDirection);
157 }
158 
159 
160 
161 
165 
167 {
168  //Set binning of the GetEnergy histogram
169  // Default value is 500
170  fBinE = nbins;
171 }
172 
173 
174 
176 
178 {
179  if (!fDetector) {
180  cout <<
181  "<KVElasticScatter::CalculateScattering> : Set detector first" <<
182  endl;
183  return false;
184  }
185  fHistos.Clear(); //delete any previous histograms
186 
187  KVDetector* d;
188  TIter n(&fAlignedDetectors);
189  while ((d = (KVDetector*) n()))
190  fHistos.Add(new TH1F(Form("hEloss_%s", d->GetName()), "Eloss (MeV)", fBinE, 0., 0.));
191 
192  return true;
193 }
194 
195 
196 
198 
199 std::pair<double, double> KVElasticScatter::get_random_angles_for_scattering(const KV2Body& scattering_kinematics)
200 {
201  auto max_scattering_angle = scattering_kinematics.GetMaxAngleLab(fNucleusOfInterest);
202  if (fDetector->GetEntranceWindow().GetThetaMin() > max_scattering_angle) {
203  Warning("CalculateScattering",
204  "Detector %s has minimum theta %f deg. > max scattering angle of %s, %f deg.: abandon calculation",
205  fDetector->GetName(), fDetector->GetEntranceWindow().GetThetaMin(), scattering_kinematics.GetNucleus(fNucleusOfInterest)->GetSymbol(),
206  max_scattering_angle);
207  return {-1., -1.};
208  }
209  //set random direction of outgoing projectile
210  double th, ph;
211  th = ph = 0.;
212  do {
213  fDetector->GetRandomAngles(th, ph);
214  }
215  while (th > max_scattering_angle);
216 
217  return {th, ph};
218 }
219 
220 
221 
223 
224 void KVElasticScatter::detect_particle_fill_histograms(KVNucleus* ejectile, double theta, double phi, double xsec)
225 {
226  int j = 0;
227  TIter n(&fAlignedDetectors);
228  KVDetector* d;
229  while ((d = (KVDetector*) n())) {
230  auto cew = d->GetCentreOfEntranceWindow();
231  d->DetectParticle(ejectile, &cew);
232  //fill histograms
233  if(fFWHM) // take into account detector resolution
234  {
235  auto E = d->GetEnergy();
236  ((TH1F*)fHistos[j++])->Fill(gRandom->Gaus(E, get_det_resolution(E)/2.35), xsec * sin(theta * TMath::DegToRad()));
237  }
238  else
239  ((TH1F*)fHistos[j++])->Fill(d->GetEnergy(), xsec * sin(theta * TMath::DegToRad()));
240  //prepare for next round: set energy loss to zero
241  d->Clear();
242  }
243 }
244 
245 
246 
249 
251 {
252  // Perform scattering 'N' times
253 
254  if (!initial_checks_and_reset())
255  return;
256 
257  fNtirages = N;
258 
259  //set up histograms
260  // -- histograms for debugging: depth in target and angular distribution
261  if (fDepth)
262  delete fDepth;
263  if (fTheta)
264  delete fTheta;
265  fDepth =
266  new TH1F("hDepth", "Depth (mg/cm2)", 500, 0., fTarget->GetTotalEffectiveThickness());
267  fTheta = new TH1F("hTheta", "Theta (deg.)", 500, 0., 0.);
268 
269  //set random interaction point for scattering
270  TVector3 IP;
271  if (fIntLayer) {
272  fTarget->SetInteractionLayer(fIntLayer, fBeamDirection);
273  IP = fTarget->GetInteractionPoint();
274  }
275  else {
276  IP = fTarget->GetInteractionPoint(fBeamDirection);
277  }
278 
279  /* -------------------------------------------------------------------------------------------------------------------------- */
280 
281  if (fGetTargFromLay) {
282  // get target nucleus properties from scattering layer ?
283  KVMaterial* targ_mat = fTarget->GetLayer(IP);
284  auto zt = targ_mat->GetZ();
285  auto at = targ_mat->GetMass();
286  // check for fractional Z or A - compound material!
287  if ((zt != int(zt)) || at != int(at)) {
288  Error("CalculateScattering", "Target has non-elemental layer with effective Z=%f and A=%f. Cannot use.",
289  zt, at);
290  fGetTargFromLay = false;
291  }
292  else
293  fKinematics->SetTarget({int(zt), int(at)});
294  }
295 
296  for (int i = 0; i < N; i++) {
297 
298  reset_before_new_scattering();
299 
300  auto Projectile = *(fKinematics->GetNucleus(KV2Body::projectile));
301  auto Target = *(fKinematics->GetNucleus(KV2Body::target));
302 
303  //calculate slowing of incoming projectile
304  fTarget->SetIncoming();
305  fTarget->DetectParticle(&Projectile);
306 
307  KV2Body scattering{Projectile, Target, fExx};
308  if (fOutgoingPL)
309  scattering.SetOutgoing(*fOutgoingPL);
310 
311  if (fExx > 0)
312  scattering.SetEDiss(fExx);
313 
314  scattering.CalculateKinematics();
315 
316  auto theta_phi = get_random_angles_for_scattering(scattering);
317 
318  //set energy of scattered nucleus
319  auto elab = scattering.GetELab(fNucleusOfInterest, theta_phi.first);
320  auto ejectile = scattering.GetNucleus(fNucleusOfInterest);
321 
322  auto kine_branch = fKineSol;
323  if (fKineSol == KV2Body::low_E_branch) {
324  if (!elab->second()) {
325  Warning("CalculateScattering", "Low energy branch requested, but only high energy kinematics for theta = %f deg.",
326  theta_phi.first);
327  ejectile->SetEnergy(*elab->first());
328  kine_branch = KV2Body::high_E_branch;
329  }
330  else {
331  ejectile->SetEnergy(*elab->second());
332  }
333  }
334  else if (fKineSol == KV2Body::both_branches) {
335  if (!elab->second()) {
336  Warning("CalculateScattering", "Both branches requested, but only high energy kinematics for theta = %f deg.",
337  theta_phi.first);
338  ejectile->SetEnergy(*elab->first());
339  kine_branch = KV2Body::high_E_branch;
340  }
341  else {
342  ejectile->SetEnergy(1.0);
343  ejectile->SetTheta(theta_phi.first);
344  auto angle_with_beam = TMath::RadToDeg() * ejectile->Angle(fBeamDirection);
345  auto xsec_hi = TMath::Abs(scattering.GetXSecRuthLab(angle_with_beam, fNucleusOfInterest, KV2Body::high_E_branch));
346  auto xsec_lo = TMath::Abs(scattering.GetXSecRuthLab(angle_with_beam, fNucleusOfInterest, KV2Body::low_E_branch));
347  if (gRandom->Uniform() < xsec_hi / (xsec_hi + xsec_lo)) {
348  // high
349  ejectile->SetEnergy(*elab->first());
350  kine_branch = KV2Body::high_E_branch;
351  }
352  else {
353  // low
354  ejectile->SetEnergy(*elab->second());
355  kine_branch = KV2Body::low_E_branch;
356  }
357  }
358  }
359  else
360  ejectile->SetEnergy(*elab->first());
361 
362  ejectile->SetTheta(theta_phi.first);
363  ejectile->SetPhi(theta_phi.second);
364 
365  // get Rutherford Xsec for projectile scattered to theta degrees in lab
366  // taking into account the initial direction of the beam (if beam direction = (0,0,1) this is just the same as theta)
367  double angle_with_beam = TMath::RadToDeg() * ejectile->Angle(fBeamDirection);
368  auto xsec = TMath::Abs(scattering.GetXSecRuthLab(angle_with_beam, fNucleusOfInterest, kine_branch));
369 
370  // fill angular distribution
371  fTheta->Fill(theta_phi.first, xsec);
372 
373  //slowing of outgoing ejectile in target
374  fTarget->SetOutgoing();
375 
376  fTarget->DetectParticle(ejectile);
377  fDepth->Fill(IP.z());
378 
379  //now detect particle in detector(s)
380  detect_particle_fill_histograms(ejectile, theta_phi.first, theta_phi.second, xsec);
381 
382  //set random interaction point for scattering
383  if (fIntLayer) {
384  fTarget->SetInteractionLayer(fIntLayer, fBeamDirection);
385  IP = fTarget->GetInteractionPoint();
386  }
387  else {
388  IP = fTarget->GetInteractionPoint(fBeamDirection);
389  }
390  if (fGetTargFromLay) {
391  // get target nucleus properties from scattering layer ?
392  KVMaterial* targ_mat = fTarget->GetLayer(IP);
393  auto zt = targ_mat->GetZ();
394  auto at = targ_mat->GetMass();
395  // check for fractional Z or A - compound material!
396  if ((zt != int(zt)) || at != int(at)) {
397  Error("CalculateScattering", "Target has non-elemental layer with effective Z=%f and A=%f. Cannot use.",
398  zt, at);
399  fGetTargFromLay = false;
400  }
401  else
402  fKinematics->SetTarget({int(zt), int(at)});
403  }
404  }
405  end_of_run();
406 }
407 
408 
409 
410 
411 
414 
416 {
417  //Energy loss in detector with given 'label' through which scattered particle passes.
418 
419  return (fDetInd.HasParameter(label) ? GetEnergy(fDetInd.GetIntValue(label)) : 0);
420 }
421 
422 
423 
424 
431 
433 {
434  //Energy loss in any detector through which scattered particle passes.
435  //
436  //The index corresponds to the order in which detectors are crossed by the
437  //particle, beginning with 0 for the first detector, and ending with
438  //(GetNDets()-1)
439  return (TH1F*)fHistos[index];
440 }
441 
442 
443 
446 
448 {
449  // Print details of calculation to be performed
450 
451  Info("Print", "CALCULATION DETAILS:");
452  if (fGetTargFromLay)
453  Info("Print", "Projectile is %s %.1f MeV/u; target nucleus depends on scattering layer.",
454  fKinematics->GetNucleus(KV2Body::projectile)->GetSymbol(),
455  fKinematics->GetNucleus(KV2Body::projectile)->GetAMeV());
456  else
457  Info("Print", "Entrance channel is: %s", fKinematics->GetTitle());
458  if (fExx > 0) {
459  Info("Print", "Inelastic scattering: outgoing Ex=%f", fExx);
460  }
461  Info("Print", "Target used is:");
462  fTarget->Print();
463  Info("Print", "Scattering will be calculated for outgoing %s",
464  fNucleusOfInterest == KV2Body::projectile_like ? "PROJECTILE_LIKE" : "TARGET_LIKE");
465  Info("Print", "We will use %s kinematic solutions",
466  fKineSol == KV2Body::both_branches ? "BOTH" : (fKineSol == KV2Body::high_E_branch ? "the HIGH ENERGY" : "the LOW ENERGY"));
467  if (fDetector) {
468  Info("Print", "Particles scattered towards %s: theta:[%f,%f] phi:[%f,%f]", fDetector->GetName(),
469  fDetector->GetThetaMin(), fDetector->GetThetaMax(), fDetector->GetPhiMin(), fDetector->GetPhiMax());
470  }
471 }
472 
473 
474 //__________________________________________________________________//
475 
int Int_t
#define d(i)
char Char_t
constexpr Bool_t kTRUE
#define N
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
char name[80]
R__EXTERN TRandom * gRandom
char * Form(const char *fmt,...)
Relativistic binary kinematics calculator.
Definition: KV2Body.h:178
Double_t GetMaxAngleLab(nucleus_of_interest i) const
Definition: KV2Body.cpp:546
void SetOutgoing(const KVNucleus &proj_out)
Definition: KV2Body.cpp:411
@ target
Definition: KV2Body.h:265
@ projectile_like
Definition: KV2Body.h:266
@ projectile
Definition: KV2Body.h:264
@ low_E_branch
Definition: KV2Body.h:271
@ both_branches
Definition: KV2Body.h:272
@ high_E_branch
Definition: KV2Body.h:270
KVNucleus * GetNucleus(nucleus_of_interest i) const
Definition: KV2Body.cpp:468
KVDBSystem * GetSystem() const
Definition: KVDBRun.cpp:240
KV2Body * GetKinematics()
Definition: KVDBSystem.cpp:103
Base class for detector geometry description, interface to energy-loss calculations.
Definition: KVDetector.h:160
Calculate elastic scattering spectra in specific detectors of a multidetector array ,...
virtual std::pair< double, double > get_random_angles_for_scattering(const KV2Body &scattering_kinematics)
void SetDetector(const Char_t *det)
virtual bool initial_checks_and_reset()
TH1F * GetEnergy()
Return pointer to energy loss histogram for chosen detector (in MeV)
void CalculateScattering(Int_t N)
Perform scattering 'N' times.
void Print() const
Print details of calculation to be performed.
void SetRun(Int_t run)
void SetTargetScatteringLayer(const Char_t *name)
virtual void detect_particle_fill_histograms(KVNucleus *ejectile, double theta, double phi, double xsec)
void SetEbinning(Int_t nbins)
KVDBRun * GetDBRun(Int_t number) const
Definition: KVExpDB.h:144
Path taken by particles through multidetector geometry.
Information on relative positions of detectors & particle trajectories.
KVDetector * GetDetector() const
virtual KVDetector * GetDetector(const Char_t *name) const
Return detector in this structure with given name.
Description of physical materials used to construct detectors & targets; interface to range tables.
Definition: KVMaterial.h:90
Double_t GetZ() const
Definition: KVMaterial.cpp:390
Double_t GetMass() const
Definition: KVMaterial.cpp:302
KVTarget * GetTarget()
virtual void SetParameters(UInt_t n, Bool_t physics_parameters_only=kFALSE)
virtual void SetSimMode(Bool_t on=kTRUE)
Description of properties and kinematics of atomic nuclei.
Definition: KVNucleus.h:123
const Char_t * GetSymbol(Option_t *opt="") const
Definition: KVNucleus.cpp:71
void SetRandomized(Bool_t r=kTRUE)
Definition: KVTarget.h:254
virtual Double_t Gaus(Double_t mean=0, Double_t sigma=1)
virtual Double_t Uniform(Double_t x1, Double_t x2)
Double_t z() const
RVec< PromoteType< T > > sin(const RVec< T > &v)
const Int_t n
void Error(const char *location, const char *fmt,...)
void Info(const char *location, const char *fmt,...)
void Warning(const char *location, const char *fmt,...)
constexpr Double_t E()
constexpr Double_t DegToRad()
Double_t Abs(Double_t d)
constexpr Double_t RadToDeg()
ClassImp(TPyArg)