Belle II Software development
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
32namespace 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) {
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
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:695
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
G4VPhysicalVolume * getTopVolume()
Return a pointer to the top volume.
static GeometryManager & getInstance()
Return a reference to the instance.
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
void term()
Terminates the generator.
Definition: CRY.cc:200
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
GraphParticle & addParticle()
Add new particle to the graph.
Abstract base class for different kinds of events.