Belle II Software  release-08-01-10
CRY.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <generators/cry/CRY.h>
10 
11 #include <framework/gearbox/Unit.h>
12 #include <framework/logging/Logger.h>
13 #include <framework/utilities/IOIntercept.h>
14 #include <mdst/dataobjects/MCParticleGraph.h>
15 
16 #include <TDatabasePDG.h>
17 #include <TRandom3.h>
18 
19 #include <VecGeom/volumes/UnplacedBox.h>
20 #include <VecGeom/volumes/UnplacedOrb.h>
21 #include <VecGeom/volumes/UnplacedTube.h>
22 #include <VecGeom/base/LorentzVector.h>
23 #include <geometry/GeometryManager.h>
24 #include "G4VPhysicalVolume.hh"
25 #include "G4LogicalVolume.hh"
26 #include "G4Box.hh"
27 
28 #include <string>
29 #include <vector>
30 #include <sstream>
31 
32 namespace Belle2 {
37  void CRY::init()
38  {
39  std::stringstream setupString;
40  setupString << " returnGammas " << m_returnGammas << std::endl;
41  setupString << " returnKaons " << m_returnKaons << std::endl;
42  setupString << " returnPions " << m_returnPions << std::endl;
43  setupString << " returnProtons " << m_returnProtons << std::endl;
44  setupString << " returnNeutrons " << m_returnNeutrons << std::endl;
45  setupString << " returnElectrons " << m_returnElectrons << std::endl;
46  setupString << " returnMuons " << m_returnMuons << std::endl;
47  setupString << " date " << m_date << std::endl;
48  setupString << " latitude " << 36.0 << std::endl;
49  setupString << " altitude " << 0 << std::endl;
50  setupString << " subboxLength " << m_subboxLength << std::endl;
51 
53  initLogCapture.start();
54 
55  // CRY setup
56  m_crySetup.reset(new CRYSetup(setupString.str(), m_cosmicDataDir));
57  // Set the random generator to the setup
58  m_crySetup->setRandomFunction([]()->double { return gRandom->Rndm(); });
59  // Set up the generator
60  m_cryGenerator.reset(new CRYGenerator(m_crySetup.get()));
61 
62  initLogCapture.finish();
63 
64  // set up the acceptance box
65  const auto coords = m_acceptSize.size();
66  if (coords == 1) {
67  m_acceptance.reset(new vecgeom::UnplacedOrb(m_acceptSize[0]));
68  } else if (coords == 2) {
69  m_acceptance.reset(new vecgeom::SUnplacedTube<vecgeom::TubeTypes::NonHollowTube>(0, m_acceptSize[0], m_acceptSize[1], 0, 2 * M_PI));
70  } else if (coords == 3) {
71  m_acceptance.reset(new vecgeom::UnplacedBox(m_acceptSize[0], m_acceptSize[1], m_acceptSize[2]));
72  } else {
73  B2FATAL("Acceptance volume needs to have one, two or three values for sphere, cylinder and box respectively");
74  }
75  //get information from geometry and create the world box
76  G4VPhysicalVolume* volume = geometry::GeometryManager::getInstance().getTopVolume();
77  if (!volume) {
78  B2FATAL("No geometry found -> Add the Geometry module to the path before the CRY module.");
79  }
80  G4Box* topbox = (G4Box*) volume->GetLogicalVolume()->GetSolid();
81  if (!topbox) {
82  B2FATAL("No G4Box found -> Check the logical volume of the geometry.");
83  }
84 
85  // Wrap the world coordinates (G4 coordinates are mm, Belle 2 units are currently cm)
86  double halfLength_x = topbox->GetXHalfLength() * Belle2::Unit::mm;
87  double halfLength_y = topbox->GetYHalfLength() * Belle2::Unit::mm;
88  double halfLength_z = topbox->GetZHalfLength() * Belle2::Unit::mm;
89 
90  // m_world.reset(new vecgeom::UnplacedBox(m_subboxLength / 2. * Unit::m, m_subboxLength / 2. * Unit::m,
91  // m_subboxLength / 2. * Unit::m));
92  m_world.reset(new vecgeom::UnplacedBox(halfLength_x / Unit::cm, halfLength_y / Unit::cm,
93  halfLength_z / Unit::cm));
94  B2INFO("World size [" << halfLength_x / Unit::cm << ", " << halfLength_x / Unit::cm << ", " << halfLength_x / Unit::cm << "]");
95 
96  const double maxSize = *std::max_element(m_acceptSize.begin(), m_acceptSize.end());
97  const double minWorld = std::min({halfLength_x, halfLength_y, halfLength_z, });
98  if (maxSize > (minWorld / Unit::cm)) {
99  B2FATAL("Acceptance bigger than world volume " << LogVar("acceptance", maxSize)
100  << LogVar("World size", minWorld / Unit::cm));
101  }
102 
103  }
104 
106  {
107  bool eventInAcceptance = 0;
108  static std::vector<CRYParticle*> ev;
109 
110  //force at least particle in acceptance box
111  for (int iTrial = 0; iTrial < m_maxTrials; ++iTrial) {
112  m_totalTrials++;
113  // Generate one event
114  ev.clear();
115  m_cryGenerator->genEvent(&ev);
116  // check all particles
117  for (auto* p : ev) {
118  const int pdg = p->PDGid();
119  const double kineticEnergy = p->ke() * Unit::MeV;
120  if (kineticEnergy < m_kineticEnergyThreshold) continue;
121 
122  const double mass = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
123  const double etot = kineticEnergy + mass;
124  // since etot is at least mass this cannot be negative
125  const double ptot = sqrt(etot * etot - mass * mass);
126 
127  // Momentum
128  // We have x horizontal, y up and z along the beam. So uvw -> zxy, xc yc zc -> zxy
129  const double px = ptot * p->v();
130  const double py = ptot * p->w();
131  const double pz = ptot * p->u();
132  // Vertex
133  const double vx = p->y() * Unit::m;
134  const double vy = p->z() * Unit::m;
135  const double vz = p->x() * Unit::m;
136 
137  // Time
138  /* In basf2, it is assumed that t = 0 when an event was produced,
139  For the cosmic case, we set t = 0 when particle cross y=0 plane;
140  The output time from CRY (p->t()) is too large (order of second) and also
141  increase as simulated time, so it is impossible to handle in basf2.
142  For event which has more then one particle, the difference between their production
143  times is also too large (> micro-second) to keep in basf2, so the time relation
144  between particles in each event is also reset. Production of each particle in event is set t=0 at y=0.
145  if one need production from CRY for a special study, you have to find a way to handle it...*/
146  double time = 0;
147 
148  vecgeom::Vector3D<double> pos(vx, vy, vz);
149  vecgeom::LorentzVector<double> mom(px, py, pz, etot);
150  const double speed = (mass == 0 ? 1 : mom.Beta()) * Const::speedOfLight;
151 
152  // Project on the boundary of the world box
153  auto inside = m_world->Inside(pos);
154  if (inside == vecgeom::kInside) {
155  // inside the world volume, go backwards in time to the world box
156  const auto dir = -mom.vect().Unit();
157  double dist = m_world->DistanceToOut(pos, dir);
158  pos += dist * dir;
159  time -= dist / speed;
160  } else if (inside == vecgeom::kOutside) {
161  // outside the world volume, go forwards in time to the world box
162  // this should not happen but better safe then sorry ...
163  const auto dir = mom.vect().Unit();
164  double dist = m_world->DistanceToIn(pos, dir);
165  if (dist == vecgeom::InfinityLength<double>()) continue;
166  pos += dist * dir;
167  time += dist / speed;
168  }
169  // Intersect with the acceptance box
170  double dist = m_acceptance->DistanceToIn(pos, mom.vect().Unit());
171  if (dist == vecgeom::InfinityLength<double>()) continue;
172 
173  // We want to keep this one
174  auto& particle = mcGraph.addParticle();
175  // all particle of a generator are primary
176  particle.addStatus(MCParticle::c_PrimaryParticle);
177  // all particle of CRY are stable
178  particle.addStatus(MCParticle::c_StableInGenerator);
179  particle.setPDG(pdg);
180  particle.setFirstDaughter(0);
181  particle.setLastDaughter(0);
182  particle.setMomentum(ROOT::Math::XYZVector(mom.x(), mom.y(), mom.z()));
183  particle.setMass(mass);
184  particle.setEnergy(mom.e());
185  particle.setProductionVertex(ROOT::Math::XYZVector(pos.x(), pos.y(), pos.z()));
186  particle.setProductionTime(time);
187  eventInAcceptance = true;
188  }
189  // clean up CRY event
190  for (auto* p : ev) delete p;
191  // and if we have something in the acceptance then we're done
192  if (eventInAcceptance) {
193  return;
194  }
195 
196  }
197  B2ERROR("Number of trials exceeds maxTrials increase number of maxTrials" << LogVar("maxTrials", m_maxTrials));
198  }
199 
200  void CRY::term()
201  {
202  B2RESULT("Total time simulated: " << m_cryGenerator->timeSimulated() << " seconds");
203  B2RESULT("Total number of events simulated: " << m_totalTrials);
204  }
205 
206 
208 }
bool m_returnElectrons
Whether or not CRY should return electrons.
Definition: CRY.h:154
std::string m_cosmicDataDir
directory that holds cosmic data files.
Definition: CRY.h:141
std::unique_ptr< vecgeom::VUnplacedVolume > m_acceptance
acceptance shape
Definition: CRY.h:160
bool m_returnKaons
Whether or not CRY should return kaons.
Definition: CRY.h:150
bool m_returnMuons
Whether or not CRY should return muons.
Definition: CRY.h:155
int m_subboxLength
length of the square n-n plane in Cry in meters
Definition: CRY.h:142
bool m_returnGammas
Whether or not CRY should return gammas.
Definition: CRY.h:149
std::vector< double > m_acceptSize
Shape parameters for the acceptance shape.
Definition: CRY.h:143
std::string m_date
date used for generation (month-day-year).
Definition: CRY.h:146
std::unique_ptr< vecgeom::VUnplacedVolume > m_world
world box shape
Definition: CRY.h:159
double m_kineticEnergyThreshold
kinetic energy threshold.
Definition: CRY.h:145
std::unique_ptr< CRYGenerator > m_cryGenerator
The CRY generator.
Definition: CRY.h:158
std::unique_ptr< CRYSetup > m_crySetup
The CRY generator setup.
Definition: CRY.h:157
bool m_returnProtons
Whether or not CRY should return protons.
Definition: CRY.h:152
bool m_returnNeutrons
Whether or not CRY should return neutrons.
Definition: CRY.h:153
int m_totalTrials
total number of thrown events.
Definition: CRY.h:148
bool m_returnPions
Whether or not CRY should return pions.
Definition: CRY.h:151
int m_maxTrials
number of trials per event.
Definition: CRY.h:147
static const double speedOfLight
[cm/ns]
Definition: Const.h:686
bool start()
Start intercepting the output.
Definition: IOIntercept.h:155
Capture stdout and stderr and convert into log messages.
Definition: IOIntercept.h:226
bool finish()
Finish the capture and emit the message if output has appeard on stdout or stderr.
Definition: IOIntercept.cc:236
@ c_Debug
Debug: for code development.
Definition: LogConfig.h:26
@ c_Warning
Warning: for potential problems that the user should pay attention to.
Definition: LogConfig.h:29
Class to build, validate and sort a particle decay chain.
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
@ c_StableInGenerator
bit 1: Particle is stable, i.e., not decaying in the generator.
Definition: MCParticle.h:49
static const double mm
[millimeters]
Definition: Unit.h:70
static const double m
[meters]
Definition: Unit.h:69
static const double MeV
[megaelectronvolt]
Definition: Unit.h:114
static const double cm
Standard units with the value = 1.
Definition: Unit.h:47
static GeometryManager & getInstance()
Return a reference to the instance.
G4VPhysicalVolume * getTopVolume()
Return a pointer to the top volume.
Class to store variables with their name which were sent to the logging service.
void init()
Initializes the generator.
Definition: CRY.cc:37
void generateEvent(MCParticleGraph &mcGraph)
Generates one single event.
Definition: CRY.cc:105
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
void term()
Terminates the generator.
Definition: CRY.cc:200
GraphParticle & addParticle()
Add new particle to the graph.
Abstract base class for different kinds of events.