GENIEGenerator
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
HNLVertexGenerator.cxx
Go to the documentation of this file.
1 //____________________________________________________________________________
2 /*
3  Copyright (c) 2003-2024, The GENIE Collaboration
4  For the full text of the license visit http://copyright.genie-mc.org
5 
6  Author: John Plows <komninos-john.plows \at physics.ox.ac.uk>
7  University of Oxford
8 */
9 //____________________________________________________________________________
10 
12 
13 using namespace genie;
14 using namespace genie::hnl;
15 using namespace genie::units;
16 
17 //____________________________________________________________________________
19  GeomRecordVisitorI("genie::hnl::VertexGenerator")
20 {
21 
22 }
23 //____________________________________________________________________________
25  GeomRecordVisitorI(name)
26 {
27 
28 }
29 //____________________________________________________________________________
30 VertexGenerator::VertexGenerator(string name, string config) :
31  GeomRecordVisitorI(name, config)
32 {
33 
34 }
35 //____________________________________________________________________________
37 {
38 
39 }
40 //____________________________________________________________________________
42 {
43  /*!
44  * Uses ROOT's TGeoManager to find out where the intersections with the detector volume live
45  * Label them as entry and exit point. Then use them to determine:
46  * 1) A decay vertex within the detector
47  * 2) A time-of-decay (== delay of HNL to reach the decay vertex wrt a massless SM v)
48  * 3) Geom weight: Survival to detector * decay within detector.
49  */
50 
51  // before anything else: find the geometry!
52  if( !fGeoManager ){
53  LOG( "HNL", pINFO )
54  << "Getting geometry information from " << fGeomFile;
55 
56  fGeoManager = TGeoManager::Import(fGeomFile.c_str());
57 
58  TGeoVolume * top_volume = fGeoManager->GetTopVolume();
59  assert( top_volume );
60  TGeoShape * ts = top_volume->GetShape();
61  TGeoBBox * box = (TGeoBBox *) ts;
62 
63  this->ImportBoundingBox(box);
64  }
65 
66  this->SetStartingParameters( event_rec );
67 
68  double weight = 1.0; // pure geom weight
69 
70  TVector3 startPoint, momentum, entryPoint, exitPoint;
71  startPoint.SetXYZ( fSx, fSy, fSz );
72  momentum.SetXYZ( fPx, fPy, fPz );
73 
74  bool didIntersectDet = this->VolumeEntryAndExitPoints( startPoint, momentum, entryPoint, exitPoint, fGeoManager, fGeoVolume );
75 
76  if( isUsingDk2nu ) assert( didIntersectDet ); // forced to hit detector somewhere!
77  else {
78  std::vector< double > * newProdVtx = new std::vector< double >();
79  newProdVtx->emplace_back( startPoint.X() );
80  newProdVtx->emplace_back( startPoint.Y() );
81  newProdVtx->emplace_back( startPoint.Z() );
82 
83  }
84  if( !didIntersectDet ){ // bail
85  LOG( "HNL", pERROR )
86  << "Bailing...";
87  TLorentzVector v4dummy( -999.9, -999.9, -999.9, -999.9 );
88  event_rec->SetVertex( v4dummy );
89  return;
90  }
91 
92  this->EnforceUnits( "mm", "rad", "ns" );
93 
94  // move fCoMLifetime to ns from GeV^{-1}
95  fCoMLifetime *= 1.0 / ( units::ns * units::GeV );
96 
97  double maxDx = exitPoint.X() - entryPoint.X();
98  double maxDy = exitPoint.Y() - entryPoint.Y();
99  double maxDz = exitPoint.Z() - entryPoint.Z();
100 
101  double maxLength = std::sqrt( std::pow( maxDx , 2.0 ) +
102  std::pow( maxDy , 2.0 ) +
103  std::pow( maxDz , 2.0 ) );
104 
105  TLorentzVector * p4HNL = event_rec->Particle(0)->GetP4();
106  double betaMag = p4HNL->P() / p4HNL->E();
107  double gamma = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
108 
109  double elapsed_length = this->CalcTravelLength( betaMag, fCoMLifetime, maxLength ); //mm
110  __attribute__((unused)) double ratio_length = elapsed_length / maxLength;
111 
112  // from these we can also make the weight. It's P( survival ) * P( decay in detector | survival )
113  double distanceBeforeDet = std::sqrt( std::pow( (entryPoint.X() - startPoint.X()), 2.0 ) +
114  std::pow( (entryPoint.Y() - startPoint.Y()), 2.0 ) +
115  std::pow( (entryPoint.Y() - startPoint.Z()), 2.0 ) ); // mm
116 
117  double timeBeforeDet = distanceBeforeDet / ( betaMag * kNewSpeedOfLight ); // ns lab
118  double timeInsideDet = maxLength / ( betaMag * kNewSpeedOfLight ); // ns lab
119 
120  double LabToRestTime = 1.0 / ( gamma );
121  timeBeforeDet *= LabToRestTime; // ns rest
122  timeInsideDet *= LabToRestTime; // ns rest
123 
124  double survProb = std::exp( - timeBeforeDet / fCoMLifetime );
125  weight *= 1.0 / survProb;
126  double decayProb = 1.0 - std::exp( - timeInsideDet / fCoMLifetime );
127  weight *= 1.0 / decayProb;
128 
129  // save the survival and decay probabilities
130  if( event_rec->Particle(1) && event_rec->Particle(2) ){
131  event_rec->Particle(1)->SetPosition( 0.0, 0.0, 0.0, survProb );
132  event_rec->Particle(2)->SetPosition( 0.0, 0.0, 0.0, decayProb );
133  }
134 
135  // update the weight
136  event_rec->SetWeight( event_rec->Weight() * weight );
137 
138  TVector3 decayPoint = this->GetDecayPoint( elapsed_length, entryPoint, momentum ); // USER, mm
139 
140  // write out vtx in [m, ns]
141  TLorentzVector x4( decayPoint.X() * units::mm / units::m,
142  decayPoint.Y() * units::mm / units::m,
143  decayPoint.Z() * units::mm / units::m,
144  event_rec->Vertex()->T() );
145 
146  event_rec->SetVertex(x4);
147 
148  // the validation app doesn't run the Decayer. So we will insert two neutrinos (not a valid
149  // decay mode), to store entry and exit point
150  if( !isUsingDk2nu ){
151  assert( !event_rec->Particle(1) );
152 
153  TLorentzVector tmpp4( 0.0, 0.0, 0.0, 0.5 );
154  TLorentzVector ex4( 0.0, 0.0, 0.0, 0.0 );
155  ex4.SetXYZT( entryPoint.X(), entryPoint.Y(), entryPoint.Z(), 0.0 );
156  TLorentzVector xx4( 0.0, 0.0, 0.0, 0.0 );
157  xx4.SetXYZT( exitPoint.X(), exitPoint.Y(), exitPoint.Z(), 0.0 );
158 
159  GHepParticle nu1( genie::kPdgNuMu, kIStStableFinalState, -1, -1, -1, -1, tmpp4, ex4 );
160  GHepParticle nu2( genie::kPdgAntiNuMu, kIStStableFinalState, -1, -1, -1, -1, tmpp4, xx4 );
161 
162  event_rec->AddParticle( nu1 ); event_rec->AddParticle( nu2 );
163 
164  // save the survival and decay probabilities
165  // event_rec->Particle(1)->SetPolarization( survProb, decayProb );
166  event_rec->Particle(1)->SetPosition( 0.0, 0.0, 0.0, survProb );
167  event_rec->Particle(2)->SetPosition( 0.0, 0.0, 0.0, decayProb );
168  event_rec->SetWeight(weight);
169  }
170 
171  // also set entry and exit points. Do this in x4 of Particles(1,2)
172  if( event_rec->Particle(1) && event_rec->Particle(2) ){
173  (event_rec->Particle(1))->SetPosition( entryPoint.X(), entryPoint.Y(), entryPoint.Z(), event_rec->Particle(1)->Vt() );
174  (event_rec->Particle(2))->SetPosition( exitPoint.X(), exitPoint.Y(), exitPoint.Z(), event_rec->Particle(2)->Vt() );
175  }
176 
177 }
178 //____________________________________________________________________________
179 void VertexGenerator::EnforceUnits( std::string length_units, std::string angle_units, std::string time_units ) const{
180 
181  LOG( "HNL", pWARN )
182  << "Switching units to " << length_units.c_str() << " , " << angle_units.c_str() << " , " << time_units.c_str();
183 
184  double old_lunits = lunits;
185  __attribute__((unused)) double old_aunits = aunits;
186  double old_tunits = tunits;
187 
188  lunits = utils::units::UnitFromString( length_units ); lunitString = length_units;
189  aunits = utils::units::UnitFromString( angle_units );
190  tunits = utils::units::UnitFromString( time_units ); tunitString = time_units;
191 
192  // convert to new units
193  fSx /= lunits/old_lunits; fSy /= lunits/old_lunits; fSz /= lunits/old_lunits;
194  fPx /= lunits/old_lunits; fPy /= lunits/old_lunits; fPz /= lunits/old_lunits;
195  fEx /= lunits/old_lunits; fEy /= lunits/old_lunits; fEz /= lunits/old_lunits;
196  fXx /= lunits/old_lunits; fXy /= lunits/old_lunits; fXz /= lunits/old_lunits;
197  fLx /= lunits/old_lunits; fLy /= lunits/old_lunits; fLz /= lunits/old_lunits;
198 
199  fDx /= lunits/old_lunits; fDy /= lunits/old_lunits; fDz /= lunits/old_lunits;
200  fOx /= lunits/old_lunits; fOy /= lunits/old_lunits; fOz /= lunits/old_lunits;
201 
202  kNewSpeedOfLight /= (lunits / old_lunits) / (tunits / old_tunits);
203 
204  LOG( "HNL", pDEBUG )
205  << "kNewSpeedOfLight = " << kNewSpeedOfLight << " [" << lunitString.c_str() << "/"
206  << tunitString.c_str() << "]";
207 }
208 //____________________________________________________________________________
209 double VertexGenerator::CalcTravelLength( double betaMag, double CoMLifetime, double maxLength ) const
210 {
211  // decay probability P0(t) = 1 - exp( -t/tau ) where:
212  // t = time-of-flight (in rest frame)
213  // tau = CoMLifetime
214 
215  assert( betaMag > 0.0 && betaMag < 1.0 ); // massive moving particle
216  double maxLabTime = maxLength / ( betaMag * kNewSpeedOfLight );
217  double gamma = std::sqrt( 1.0 / ( 1.0 - betaMag * betaMag ) );
218  double maxRestTime = maxLabTime / gamma ; // this is how "wide" the detector looks like
219 
220  // if P(DL=0) = 1, P(DL = LMax) = exp( - LMax / c * 1/( beta * gamma ) * 1 / CoMLifetime )
221  double PExit = std::exp( - maxRestTime / CoMLifetime );
222 
223  // from [0,1] we'd reroll anything in [0, PExit] and keep (PExit, 1]. That's expensive.
224  // Instead, let 1 ==> maxRestTime, 0 ==> 0, exponential decay
225 
226  RandomGen * rnd = RandomGen::Instance();
227  double ranthrow = rnd->RndGen().Uniform();
228 
229  double S0 = (1.0 - PExit) * ranthrow + PExit;
230  double rest_time = CoMLifetime * std::log( 1.0 / S0 );
231  double elapsed_time = rest_time * gamma;
232  double elapsed_length = elapsed_time * betaMag * kNewSpeedOfLight;
233 
234  /*
235  LOG( "HNL", pDEBUG )
236  << "betaMag, maxLength, CoMLifetime = " << betaMag << ", " << maxLength << ", " << CoMLifetime
237  << "\nbetaMag = " << betaMag << " ==> gamma = " << gamma
238  << "\n==> maxLength [" << tunitString.c_str()
239  << "] = " << maxRestTime << " (rest frame) = " << maxLabTime << " (lab frame)"
240  << "\nranthrow = " << ranthrow << ", PExit = " << PExit
241  << "\n==> S0 = " << S0 << " ==> rest_time [" << lunitString.c_str() << "] = " << rest_time
242  << " ==> elapsed_time [" << tunitString.c_str()
243  << "] = " << elapsed_time << " ==> elapsed_length [" << lunitString.c_str()
244  << "] = " << elapsed_length;
245  */
246 
247  return elapsed_length;
248 }
249 //____________________________________________________________________________
250 TVector3 VertexGenerator::GetDecayPoint( double travelLength, TVector3 & entryPoint, TVector3 & momentum ) const
251 {
252  double ex = entryPoint.X(); double ey = entryPoint.Y(); double ez = entryPoint.Z();
253  double px = momentum.X(); double py = momentum.Y(); double pz = momentum.Z();
254  double p2 = px*px + py*py + pz*pz; double p = std::sqrt(p2);
255  px *= 1./p; py *= 1./p; pz *= 1./p;
256 
257  double dx = ex + travelLength * px; fDx = dx;
258  double dy = ey + travelLength * py; fDy = dy;
259  double dz = ez + travelLength * pz; fDz = dz;
260 
261  fDxROOT = fDx * lunits / units::cm;
262  fDyROOT = fDy * lunits / units::cm;
263  fDzROOT = fDz * lunits / units::cm;
264 
265  TVector3 decayPoint( dx, dy, dz );
266  return decayPoint;
267 }
268 //____________________________________________________________________________
269 double VertexGenerator::GetMaxLength( TVector3 & entryPoint, TVector3 & exitPoint ) const
270 {
271  double ex = entryPoint.X(); double ey = entryPoint.Y(); double ez = entryPoint.Z();
272  double xx = exitPoint.X(); double xy = exitPoint.Y(); double xz = exitPoint.Z();
273 
274  return std::sqrt( (ex-xx)*(ex-xx) + (ey-xy)*(ey-xy) + (ez-xz)*(ez-xz) );
275 }
276 //____________________________________________________________________________
278 {
279  fOx = 0.0; fOy = 0.0; fOz = 0.0;
280  fLx = 1.0; fLy = 1.0; fLz = 1.0; // m
281 
285 
287  * (genie::units::m / lunits)
288  / (genie::units::s / tunits);
289 
290  LOG("HNL", pDEBUG)
291  << "Setting simple decay volume with unit-m side."
292  << "\nSetting units to \"mm\", \"rad\", \"ns\"";
293 
294  EnforceUnits("mm","rad","ns");
295 }
296 //____________________________________________________________________________
297 // if entry and exit points, populate TVector3's with their coords. If not, return false
298 bool VertexGenerator::SDVEntryAndExitPoints( TVector3 & startPoint, TVector3 momentum,
299  TVector3 & entryPoint, TVector3 & exitPoint ) const
300 {
301  assert( fOx == 0.0 && fOy == 0.0 && fOz == 0.0 &&
302  fLx == 1000.0 && fLy == 1000.0 && fLz == 1000.0 ); // SDV, mm
303  fSx = startPoint.X(); fSy = startPoint.Y(); fSz = startPoint.Z(); // mm
304  fPx = momentum.X(); fPy = momentum.Y(); fPz = momentum.Z(); // GeV
305  double fP2 = fPx*fPx + fPy*fPy + fPz*fPz; double fP = std::sqrt(fP2); // GeV
306  fPx *= 1.0/fP; fPy *= 1.0/fP; fPz *= 1.0/fP; // GeV / GeV
307 
308  // calc parameter for line at each face [mm]
309  double txP = ( fLx - fSx ) / fPx;
310  double txM = ( -fLx - fSx ) / fPx;
311  double tyP = ( fLy - fSy ) / fPy;
312  double tyM = ( -fLy - fSy ) / fPy;
313  double tzP = ( fLz - fSz ) / fPz;
314  double tzM = ( -fLz - fSz ) / fPz;
315 
316  // do we have an entry or exit anywhere?
317  // entry from face Q = const <==> { pr(momentum, Q) points to origin && within bounding square }
318  // exit from face Q = const <==> { -pr(momentum, Q) points to origin && within bounding square }
319  double q1t = 0.0, q2t = 0.0;
320  bool pointsOnX = false, pointsOnY = false, pointsOnZ = false;
321 
322  // case x = +fLx
323  q1t = fSy + txP * fPy; q2t = fSz + txP * fPz;
324  if( std::abs( q1t ) <= fLy && std::abs( q2t ) <= fLz ){ // within bounding square
325  pointsOnX = true;
326  if( fSx * fPx < 0 ){ // pointing towards origin
327  fEx = fLx; fEy = q1t; fEz = q2t;
328  } else if( fSx * fPx > 0 ){ // pointing away from origin
329  fXx = fLx; fXy = q1t; fXz = q2t;
330  } else return false; // treat tangent as no entry
331  }
332  // case x = -fLx
333  q1t = fSy + txM * fPy; q2t = fSz + txM * fPz;
334  if( std::abs( q1t ) <= fLy && std::abs( q2t ) <= fLz ){ // within bounding square
335  pointsOnX = true;
336  if( fSx * fPx < 0 ){ // pointing towards origin
337  fEx = -fLx; fEy = q1t; fEz = q2t;
338  } else if( fSx * fPx > 0 ){ // pointing away from origin
339  fXx = -fLx; fXy = q1t; fXz = q2t;
340  } else return false; // treat tangent as no entry
341  }
342 
343  // case y = +fLy
344  q1t = fSz + tyP * fPz; q2t = fSx + tyP * fPx;
345  if( std::abs( q1t ) <= fLz && std::abs( q2t ) <= fLx ){ // within bounding square
346  pointsOnY = true;
347  if( fSy * fPy < 0 ){ // pointing towards origin
348  fEx = q2t; fEy = fLy; fEz = q1t;
349  } else if( fSy * fPy > 0 ){ // pointing away from origin
350  fXx = q2t; fXy = fLy; fXz = q1t;
351  } else return false; // treat tangent as no entry
352  }
353  // case y = -fLy
354  q1t = fSz + tyM * fPz; q2t = fSx + tyM * fPx;
355  if( std::abs( q1t ) <= fLz && std::abs( q2t ) <= fLx ){ // within bounding square
356  pointsOnY = true;
357  if( fSy * fPy < 0 ){ // pointing towards origin
358  fEx = q2t; fEy = -fLy; fEz = q1t;
359  } else if( fSy * fPy > 0 ){ // pointing away from origin
360  fXx = q2t; fXy = -fLy; fXz = q1t;
361  } else return false; // treat tangent as no entry
362  }
363 
364  // case z = +fLz
365  q1t = fSx + tzP * fPx; q2t = fSy + tzP * fPy;
366  if( std::abs( q1t ) <= fLx && std::abs( q2t ) <= fLy ){ // within bounding square
367  pointsOnZ = true;
368  if( fSz * fPz < 0 ){ // pointing towards origin
369  fEx = q1t; fEy = q2t; fEz = fLz;
370  } else if( fSz * fPz > 0 ){ // pointing away from origin
371  fXx = q1t; fXy = q2t; fXz = fLz;
372  } else return false; // treat tangent as no entry
373  }
374  // case z = -fLz
375  q1t = fSx + tzM * fPx; q2t = fSy + tzM * fPy;
376  if( std::abs( q1t ) <= fLx && std::abs( q2t ) <= fLy ){ // within bounding square
377  pointsOnZ = true;
378  if( fSz * fPz < 0 ){ // pointing towards origin
379  fEx = q1t; fEy = q2t; fEz = -fLz;
380  } else if( fSz * fPz > 0 ){ // pointing away from origin
381  fXx = q1t; fXy = q2t; fXz = -fLz;
382  } else return false; // treat tangent as no entry
383  }
384 
385  bool finalPoints = ( pointsOnX || pointsOnY || pointsOnZ );
386  if( finalPoints ){
387  entryPoint.SetXYZ( fEx, fEy, fEz );
388  exitPoint.SetXYZ( fXx, fXy, fXz );
389  return true;
390  }
391 
392  // missed detector
393  return false;
394 }
395 //____________________________________________________________________________
396 #ifdef __GENIE_GEOM_DRIVERS_ENABLED__
397 void VertexGenerator::ImportBoundingBox( TGeoBBox * box ) const
398 {
399  fLx = box->GetDX() * units::cm / lunits;
400  fLy = box->GetDY() * units::cm / lunits;
401  fLz = box->GetDZ() * units::cm / lunits;
402  fOx = (box->GetOrigin())[0] * units::cm / lunits;
403  fOy = (box->GetOrigin())[1] * units::cm / lunits;
404  fOz = (box->GetOrigin())[2] * units::cm / lunits;
405 
406  fLxROOT = box->GetDX();
407  fLyROOT = box->GetDY();
408  fLzROOT = box->GetDZ();
409 
410  fOxROOT = (box->GetOrigin())[0];
411  fOyROOT = (box->GetOrigin())[1];
412  fOzROOT = (box->GetOrigin())[2];
413 }
414 //____________________________________________________________________________
415 void VertexGenerator::SetStartingParameters( GHepRecord * event_rec ) const
416 {
417  isUsingDk2nu = (event_rec->Particle(1) != NULL); // validation App doesn't run Decayer
418  isUsingRootGeom = true;
419 
421  xMult = ( isUsingDk2nu ) ? units::cm / units::mm : 1.0;
422 
423  fCoMLifetime = event_rec->Probability();
424 
425  assert( event_rec->Particle(0) );
426 
427  TVector3 dumori(0.0, 0.0, 0.0); // tgt-hall frame origin is 0
428  TVector3 detori( (fCx + fDetTranslation.at(0)) * units::m / units::cm,
429  (fCy + fDetTranslation.at(1)) * units::m / units::cm,
430  (fCz + fDetTranslation.at(2)) * units::m / units::cm ); // for rotations of the detector
431 
432  TLorentzVector * x4HNL = event_rec->Particle(0)->GetX4(); // NEAR, cm ns
433  TVector3 xHNL_near = x4HNL->Vect();
434  TVector3 xHNL_user = this->ApplyUserRotation( xHNL_near, detori, fDetRotation, false ); // tgt-hall --> user
435  TLorentzVector * x4HNL_user = new TLorentzVector();
436  x4HNL_user->SetXYZT( xHNL_user.X() - (fCx + fDetTranslation.at(0)) * units::m / units::cm,
437  xHNL_user.Y() - (fCy + fDetTranslation.at(1)) * units::m / units::cm,
438  xHNL_user.Z() - (fCz + fDetTranslation.at(2)) * units::m / units::cm,
439  x4HNL->T() ); // USER, cm ns
440 
441  TVector3 startPoint( xMult * x4HNL_user->X(), xMult * x4HNL_user->Y(), xMult * x4HNL_user->Z() ); // USER mm
442  double mtomm = units::m / units::mm;
443 
444  TLorentzVector * p4HNL = event_rec->Particle(0)->GetP4();
445  TVector3 momentum( p4HNL->Px(), p4HNL->Py(), p4HNL->Pz() );
446 
447 
448  fSx = startPoint.X(); fSy = startPoint.Y(); fSz = startPoint.Z();
449  fSxROOT = fSx * units::mm / units::cm;
452  fPx = momentum.X(); fPy = momentum.Y(); fPz = momentum.Z();
453 }
454 //____________________________________________________________________________
455 bool VertexGenerator::VolumeEntryAndExitPoints( TVector3 & startPoint, TVector3 & momentum,
456  TVector3 & entryPoint, TVector3 & exitPoint,
457  TGeoManager * /* gm */, TGeoVolume * /* vol */ ) const
458 {
459  const double mmtolunits = units::mm / lunits;
460 
461  double sx = startPoint.X(); double sy = startPoint.Y(); double sz = startPoint.Z();
462  sx *= mmtolunits; sy *= mmtolunits; sz *= mmtolunits;
463  double px = momentum.X(); double py = momentum.Y(); double pz = momentum.Z();
464  double p2 = px*px + py*py + pz*pz; double p = std::sqrt(p2);
465  px *= 1./p; py *= 1./p; pz *= 1./p;
466 
467  fSx = sx; fSy = sy; fSz = sz;
469  fPx = px; fPy = py; fPz = pz;
470 
471  // put first point slightly inside the bounding box
472  double firstZOffset = -0.1; // cm
473  firstZOffset *= units::cm / lunits;
474 
475  double firstZ = fOz - (fLz/2.0 - firstZOffset);
476 
477  // now find which point the line would hit this z at
478  double dz = firstZ - sz;
479  double tz = dz / pz;
480  double dx = tz * px;
481  double dy = tz * py;
482  double firstX = sx + dx;
483  double firstY = sy + dy;
484 
485  // now we gotta return everything to cm for ROOT to work its magic.
486  double firstXROOT = firstX * lunits / units::cm,
487  firstYROOT = firstY * lunits / units::cm, firstZROOT = firstZ * lunits / units::cm;
488 
489  if( !gGeoManager )
490  TGeoManager * gm = TGeoManager::Import(fGeomFile.c_str());
491  gGeoManager->SetCurrentPoint( firstXROOT, firstYROOT, firstZROOT );
492  gGeoManager->SetCurrentDirection( px, py, pz );
493 
494  /*
495  LOG( "HNL", pINFO )
496  << "\nCurrent point is: ( " << firstX << ", " << firstY << ", " << firstZ << " ) [" << lunitString.c_str() << "]"
497  << "\nFrom start point : ( " << sx << ", " << sy << ", " << sz << " ) [" << lunitString.c_str() << "]"
498  << "\nIn ROOT, current is : ( " << firstXROOT << ", " << firstYROOT << ", " << firstZROOT << " ) [cm]"
499  << "\nIn ROOT, start is : ( " << fSxROOT << ", " << fSyROOT << ", " << fSzROOT << " ) [cm]"
500  << "\nCurrent direction is: ( " << px << ", " << py << ", " << pz << " ) [GeV/GeV]";
501  */
502 
503  std::string pathString = this->CheckGeomPoint( firstXROOT, firstYROOT, firstZROOT );
504 
505  assert( pathString.find("/", 1) == string::npos ); // need to be in TOP volume but outside any other volume so we can enter this.
506 
507  double stepmax = 1.0e+6; // cm
508  stepmax *= genie::units::cm / lunits;
509 
510  LOG( "HNL", pDEBUG )
511  << "Starting to search for intersections...";
512 
513  // enter the volume.
514  TGeoNode * nextNode = gGeoManager->FindNextBoundaryAndStep( stepmax );
515 
516  if( (gGeoManager->GetCurrentPoint())[0] == firstXROOT &&
517  (gGeoManager->GetCurrentPoint())[1] == firstYROOT &&
518  (gGeoManager->GetCurrentPoint())[2] == firstZROOT )
519  nextNode = gGeoManager->FindNextBoundaryAndStep();
520 
521  pathString = this->CheckGeomPoint( (gGeoManager->GetCurrentPoint())[0],
522  (gGeoManager->GetCurrentPoint())[1],
523  (gGeoManager->GetCurrentPoint())[2] );
524 
525  if( nextNode == NULL )
526  return false;
527 
528  TVector3 dumori(0.0, 0.0, 0.0);
529 
530  // entered the detector, let's save this point
531  fEx = ( gGeoManager->GetCurrentPoint() )[0] * genie::units::cm / lunits;
532  fEy = ( gGeoManager->GetCurrentPoint() )[1] * genie::units::cm / lunits;
533  fEz = ( gGeoManager->GetCurrentPoint() )[2] * genie::units::cm / lunits;
534  entryPoint.SetXYZ( fEx, fEy, fEz );
535 
536  fExROOT = ( gGeoManager->GetCurrentPoint() )[0];
537  fEyROOT = ( gGeoManager->GetCurrentPoint() )[1];
538  fEzROOT = ( gGeoManager->GetCurrentPoint() )[2];
539 
540  TVector3 entryPoint_user( fExROOT * units::cm / units::m,
542  fEzROOT * units::cm / units::m ); // USER, m
543  TVector3 entryPoint_near = this->ApplyUserRotation( entryPoint_user, dumori, fDetRotation, true );
544  entryPoint_near.SetXYZ( entryPoint_near.X() + (fCx + fDetTranslation.at(0)),
545  entryPoint_near.Y() + (fCy + fDetTranslation.at(1)),
546  entryPoint_near.Z() + (fCz + fDetTranslation.at(2)) );
547 
548  /*
549  LOG( "HNL", pDEBUG )
550  << "\nEntry point found at ( " << fEx << ", " << fEy << ", " << fEz << " ) [" << lunitString.c_str() << "]"
551  << "\nIn ROOT, entry at ( " << fExROOT << ", " << fEyROOT << ", " << fEzROOT << " ) [cm]";
552  */
553 
554  // now propagate until we exit again
555 
556  int bdIdx = 0;
557  const int bdIdxMax = 1e+4;
558 
559  double sfx = 0.0, sfy = 0.0, sfz = 0.0; // coords of the "safe" points in user units
560  double sfxROOT = 0.0, sfyROOT = 0.0, sfzROOT = 0.0; // same, in cm
561 
562  // do one big step first
563  // then if not outside yet, step by ever smaller steps until some threshold
564  Double_t sNext = std::min( std::max( fLx, std::max( fLy, fLz ) ), 10.0 * lunits / units::cm ) / 2.0;
565  Double_t sNextROOT = sNext * lunits / units::cm;
566  gGeoManager->SetStep( sNextROOT );
567  gGeoManager->Step();
568 
569  // FindNextBoundaryAndStep() sets step size to distance to next boundary and executes that step
570  // so one "step" here is actually one big step + one small step
571  while( gGeoManager->FindNextBoundaryAndStep() && bdIdx < bdIdxMax ){
572  const Double_t * currPoint = gGeoManager->GetCurrentPoint();
573 
574  sfxROOT = currPoint[0]; sfyROOT = currPoint[1]; sfzROOT = currPoint[2];
575  if( sNextROOT >= 2.0 * lunits / units::cm ) sNextROOT *= 0.5;
576  gGeoManager->SetStep( sNextROOT );
577  gGeoManager->Step();
578  bdIdx++;
579  }
580  if( bdIdx == bdIdxMax ){
581  LOG( "HNL", pWARN )
582  << "Failed to exit this volume. Dropping this trajectory.";
583  return false;
584  }
585 
586  // guard against small detectors
587  if( ( sfxROOT == 0.0 && sfyROOT == 0.0 && sfzROOT == 0.0 ) ||
588  ( sfxROOT == fExROOT && sfyROOT == fEyROOT && sfzROOT == fEzROOT ) ){
589  // set this to go 5 cm after the start.
590  LOG( "HNL", pWARN )
591  << "This section is smaller than 5 cm. Are you sure you want this decay volume? Proceeding anyway.";
592  gGeoManager->SetCurrentPoint( fExROOT, fEyROOT, fEzROOT );
593  gGeoManager->SetStep( 5.0 ); // ROOT units are cm!
594  gGeoManager->Step();
595  const Double_t * currPoint = gGeoManager->GetCurrentPoint();
596  sfxROOT = currPoint[0]; sfyROOT = currPoint[1]; sfzROOT = currPoint[2];
597  }
598 
599  sfx = sfxROOT * units::cm / lunits; sfy = sfyROOT * units::cm / lunits; sfz = sfzROOT * units::cm / lunits;
600 
601  // exited the detector, let's save this point
602  fXx = sfx; fXxROOT = sfxROOT;
603  fXy = sfy; fXyROOT = sfyROOT;
604  fXz = sfz; fXzROOT = sfzROOT;
605  exitPoint.SetXYZ( fXx, fXy, fXz );
606 
607  TVector3 exitPoint_user( fXxROOT * units::cm / units::m,
609  fXzROOT * units::cm / units::m ); // USER, m
610  TVector3 exitPoint_near = this->ApplyUserRotation( exitPoint_user, dumori, fDetRotation, true );
611  exitPoint_near.SetXYZ( exitPoint_near.X() + (fCx + fDetTranslation.at(0)),
612  exitPoint_near.Y() + (fCy + fDetTranslation.at(1)),
613  exitPoint_near.Z() + (fCz + fDetTranslation.at(2)) );
614 
615  /*
616  LOG( "HNL", pINFO )
617  << "\nExit point found at ( " << fXx << ", " << fXy << ", " << fXz << " ) ["
618  << lunitString.c_str() << "]"
619  << "\nIn ROOT, exit at ( " << fXxROOT << ", " << fXyROOT << ", " << fXzROOT << " ) [cm]";
620  */
621 
622  return true;
623 
624 }
625 #endif // #ifdef __GENIE_GEOM_DRIVERS_ENABLED__
626 //____________________________________________________________________________
628 {
629  Algorithm::Configure(config);
630  this->LoadConfig();
631 }
632 //____________________________________________________________________________
633 void VertexGenerator::Configure(string config)
634 {
635  Algorithm::Configure(config);
636  this->LoadConfig();
637 }
638 //____________________________________________________________________________
640 {
641  if( fIsConfigLoaded ) return;
642 
643  LOG( "HNL", pDEBUG )
644  << "Loading geometry parameters from file. . .";
645 
646  this->GetParamVect( "Near2User_T", fB2UTranslation );
647  this->GetParamVect( "Near2User_R", fDetRotation );
648  this->GetParamVect( "Near2Beam_R", fB2URotation );
649  this->GetParamVect( "DetCentre_User", fDetTranslation );
650  fCx = fB2UTranslation.at(0); fCy = fB2UTranslation.at(1); fCz = fB2UTranslation.at(2);
651  fUx = fDetTranslation.at(0); fUy = fDetTranslation.at(1); fUz = fDetTranslation.at(2);
652  fAx1 = fB2URotation.at(0); fAz = fB2URotation.at(1); fAx2 = fB2URotation.at(2);
653  fBx1 = fDetRotation.at(0); fBz = fDetRotation.at(1); fBx2 = fDetRotation.at(2);
654 
655  fIsConfigLoaded = true;
656 }
657 //____________________________________________________________________________
658 void VertexGenerator::GetInterestingPoints( TVector3 & entryPoint, TVector3 & exitPoint, TVector3 & decayPoint ) const
659 {
660  entryPoint.SetXYZ( fEx, fEy, fEz );
661  exitPoint.SetXYZ( fXx, fXy, fXz );
662  decayPoint.SetXYZ( fDx, fDy, fDz );
663 }
664 //____________________________________________________________________________
665 TVector3 VertexGenerator::ApplyUserRotation( TVector3 vec, bool doBackwards ) const
666 {
667  double vx = vec.X(), vy = vec.Y(), vz = vec.Z();
668 
669  double Ax2 = ( doBackwards ) ? -fAx2 : fAx2;
670  double Az = ( doBackwards ) ? -fAz : fAz;
671  double Ax1 = ( doBackwards ) ? -fAx1 : fAx1;
672 
673  // Ax2 first
674  double x = vx, y = vy, z = vz;
675  vy = y * std::cos( Ax2 ) - z * std::sin( Ax2 );
676  vz = y * std::sin( Ax2 ) + z * std::cos( Ax2 );
677  y = vy; z = vz;
678  // then Az
679  vx = x * std::cos( Az ) - y * std::sin( Az );
680  vy = x * std::sin( Az ) + y * std::cos( Az );
681  x = vx; y = vy;
682  // Ax1 last
683  vy = y * std::cos( Ax1 ) - z * std::sin( Ax1 );
684  vz = y * std::sin( Ax1 ) + z * std::cos( Ax1 );
685 
686  TVector3 nvec( vx, vy, vz );
687  return nvec;
688 }
689 //____________________________________________________________________________
690 TVector3 VertexGenerator::ApplyUserRotation( TVector3 vec, TVector3 oriVec, std::vector<double> rotVec, bool doBackwards ) const
691 {
692  double vx = vec.X(), vy = vec.Y(), vz = vec.Z();
693  double ox = oriVec.X(), oy = oriVec.Y(), oz = oriVec.Z();
694 
695  vx -= ox; vy -= oy; vz -= oz; // make this rotation about detector origin
696 
697  assert( rotVec.size() == 3 ); // want 3 Euler angles, otherwise this is unphysical.
698  double Ax2 = ( doBackwards ) ? -rotVec.at(2) : rotVec.at(2);
699  double Az = ( doBackwards ) ? -rotVec.at(1) : rotVec.at(1);
700  double Ax1 = ( doBackwards ) ? -rotVec.at(0) : rotVec.at(0);
701 
702  // Ax2 first
703  double x = vx, y = vy, z = vz;
704  vy = y * std::cos( Ax2 ) - z * std::sin( Ax2 );
705  vz = y * std::sin( Ax2 ) + z * std::cos( Ax2 );
706  y = vy; z = vz;
707  // then Az
708  vx = x * std::cos( Az ) - y * std::sin( Az );
709  vy = x * std::sin( Az ) + y * std::cos( Az );
710  x = vx; y = vy;
711  // Ax1 last
712  vy = y * std::cos( Ax1 ) - z * std::sin( Ax1 );
713  vz = y * std::sin( Ax1 ) + z * std::cos( Ax1 );
714 
715  // back to beam frame
716  vx += ox; vy += oy; vz += oz;
717  TVector3 nvec( vx, vy, vz );
718  return nvec;
719 }
720 //____________________________________________________________________________
721 void VertexGenerator::SetGeomFile( string geomfile ) const
722 {
723  fGeomFile = geomfile;
724 }
725 //____________________________________________________________________________
726 std::string VertexGenerator::CheckGeomPoint( Double_t x, Double_t y, Double_t z ) const
727 {
728  Double_t point[3];
729  Double_t local[3];
730  point[0] = x;
731  point[1] = y;
732  point[2] = z;
733  TGeoVolume *vol = gGeoManager->GetTopVolume();
734  TGeoNode *node = gGeoManager->FindNode(point[0], point[1], point[2]);
735  gGeoManager->MasterToLocal(point, local);
736  return gGeoManager->GetPath();
737 }
static constexpr double cm
Definition: Units.h:68
bool SDVEntryAndExitPoints(TVector3 &startPoint, TVector3 momentum, TVector3 &entryPoint, TVector3 &exitPoint) const
double CoMLifetime
virtual GHepParticle * Particle(int position) const
Definition: GHepRecord.cxx:104
virtual void SetWeight(double wght)
Definition: GHepRecord.h:130
TLorentzVector * GetX4(void) const
std::vector< double > fDetRotation
#define pERROR
Definition: Messenger.h:59
static RandomGen * Instance()
Access instance.
Definition: RandomGen.cxx:71
const int kPdgNuMu
Definition: PDGCodes.h:30
int GetParamVect(const std::string &comm_name, std::vector< T > &v, bool is_top_call=true) const
Handle to load vectors of parameters.
static constexpr double s
Definition: Units.h:95
virtual double Weight(void) const
Definition: GHepRecord.h:124
static constexpr double ns
Definition: Units.h:98
A singleton holding random number generator classes. All random number generation in GENIE should tak...
Definition: RandomGen.h:29
std::string CheckGeomPoint(Double_t x, Double_t y, Double_t z) const
virtual TLorentzVector * Vertex(void) const
Definition: GHepRecord.h:140
void Configure(const Registry &config)
double Vt(void) const
Get production time.
Definition: GHepParticle.h:97
Expands the EventRecordVisitorI interface to include public interfaces for the HNL VertexGenerator mo...
void SetPosition(const TLorentzVector &v4)
const double e
#define LOG(stream, priority)
A macro that returns the requested log4cpp::Category appending a string (using the FILE...
Definition: Messenger.h:96
void ProcessEventRecord(GHepRecord *event_rec) const
std::vector< double > fDetTranslation
static constexpr double GeV
Definition: Units.h:28
TVector3 ApplyUserRotation(TVector3 vec, bool doBackwards) const
TLorentzVector * GetP4(void) const
double UnitFromString(string u)
Definition: UnitUtils.cxx:18
virtual void Configure(const Registry &config)
Definition: Algorithm.cxx:62
#define pINFO
Definition: Messenger.h:62
double CalcTravelLength(double betaMag, double CoMLifetime, double maxLength) const
const int kPdgAntiNuMu
Definition: PDGCodes.h:31
#define pWARN
Definition: Messenger.h:60
virtual double Probability(void) const
Definition: GHepRecord.h:125
void SetStartingParameters(GHepRecord *event_rec) const
double GetMaxLength(TVector3 &entryPoint, TVector3 &exitPoint) const
std::vector< double > fB2URotation
static __attribute__((unused)) double fDecayGammas[]
A registry. Provides the container for algorithm configuration parameters.
Definition: Registry.h:65
std::vector< double > fB2UTranslation
virtual void SetVertex(double x, double y, double z, double t)
Definition: GHepRecord.cxx:827
TRandom3 & RndGen(void) const
rnd number generator for generic usage
Definition: RandomGen.h:80
static constexpr double mm
Definition: Units.h:65
virtual void AddParticle(const GHepParticle &p)
Definition: GHepRecord.cxx:499
void GetInterestingPoints(TVector3 &entryPoint, TVector3 &exitPoint, TVector3 &decayPoint) const
void EnforceUnits(std::string length_units, std::string angle_units, std::string time_units) const
void SetGeomFile(std::string geomfile) const
static constexpr double kSpeedOfLight
Definition: Units.h:32
GENIE&#39;s GHEP MC event record.
Definition: GHepRecord.h:45
static constexpr double m
Definition: Units.h:71
STDHEP-like event record entry that can fit a particle or a nucleus.
Definition: GHepParticle.h:39
TVector3 GetDecayPoint(double travelLength, TVector3 &entryPoint, TVector3 &momentum) const
#define pDEBUG
Definition: Messenger.h:63