Belle II Software  release-08-01-10
BeamBkgGeneratorModule.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 // Own header.
10 #include <background/modules/BeamBkgGenerator/BeamBkgGeneratorModule.h>
11 
12 // framework - DataStore
13 #include <framework/datastore/StoreArray.h>
14 #include <framework/datastore/StoreObjPtr.h>
15 
16 // framework aux
17 #include <framework/gearbox/Unit.h>
18 #include <framework/gearbox/Const.h>
19 #include <framework/logging/Logger.h>
20 #include <framework/gearbox/GearDir.h>
21 
22 // data objects
23 #include <framework/dataobjects/EventMetaData.h>
24 #include <mdst/dataobjects/MCParticle.h>
25 #include <generators/SAD/dataobjects/SADMetaHit.h>
26 
27 // random generator
28 #include <TRandom.h>
29 
30 #include <Math/VectorUtil.h>
31 
32 // coordinates translation
33 #include <iostream>
34 #include <TGeoMatrix.h>
35 #include <generators/SAD/ReaderSAD.h>
36 
37 using namespace std;
38 using namespace Belle2;
39 
40 //-----------------------------------------------------------------
41 // Register module
42 //-----------------------------------------------------------------
43 
44 REG_MODULE(BeamBkgGenerator);
45 
46 //-----------------------------------------------------------------
47 // Implementation
48 //-----------------------------------------------------------------
49 
50 BeamBkgGeneratorModule::BeamBkgGeneratorModule() : Module()
51 {
52  // set module description
53  setDescription("Beam background generator based on SAD files. "
54  "The generator picks up particles from the SAD file randomly "
55  "according to their rates. "
56  "Number of events is determined from 'realTime' and overall rate, and "
57  "the generator terminates the execution when this number is reached.");
58 
59  // Add parameters
60  addParam("fileName", m_fileName, "name of the SAD file converted to root");
61  addParam("treeName", m_treeName, "name of the TTree in the SAD file", string("sad"));
62  addParam("ringName", m_ringName, "name of the superKEKB ring (LER or HER)");
63  addParam("realTime", m_realTime,
64  "equivalent superKEKB running time to generate sample [ns].");
65 }
66 
68 {
69 }
70 
72 {
73  // register MCParticles
74 
75  StoreArray<MCParticle> mcParticles;
76  mcParticles.registerInDataStore();
77 
78  StoreArray<SADMetaHit> sadHits;
79  sadHits.registerInDataStore();
80 
81 
82  // check steering parameters
83 
84  if (m_ringName != "LER" and m_ringName != "HER") {
85  B2ERROR("ringName can only be LER or HER");
86  }
87  if (m_realTime <= 0) {
88  B2ERROR("realTime must be positive");
89  }
90 
91  // open SAD file and get TTree
92 
93  m_file = TFile::Open(m_fileName.c_str());
94  if (!m_file) {
95  B2ERROR(m_fileName << ": can't open file");
96  return;
97  }
98  m_tree = (TTree*) m_file->Get(m_treeName.c_str());
99  if (!m_tree) {
100  B2ERROR(m_treeName << ": no such TTree in the SAD file");
101  return;
102  }
103 
104  m_tree->SetBranchAddress("s", &m_sad.s);
105  m_tree->SetBranchAddress("x", &m_sad.x);
106  m_tree->SetBranchAddress("px", &m_sad.px);
107  m_tree->SetBranchAddress("y", &m_sad.y);
108  m_tree->SetBranchAddress("py", &m_sad.py);
109  m_tree->SetBranchAddress("E", &m_sad.E);
110  m_tree->SetBranchAddress("rate", &m_sad.rate);
111 
112  // for SADMetaHit
113  m_tree->SetBranchAddress("ss", &m_sad.ss);
114  m_tree->SetBranchAddress("sraw", &m_sad.sraw);
115  m_tree->SetBranchAddress("ssraw", &m_sad.ssraw);
116  m_tree->SetBranchAddress("nturn", &m_sad.nturn);
117  m_tree->SetBranchAddress("xraw", &m_sad.xraw);
118  m_tree->SetBranchAddress("yraw", &m_sad.yraw);
119  m_tree->SetBranchAddress("r", &m_sad.r);
120  m_tree->SetBranchAddress("rr", &m_sad.rr);
121  m_tree->SetBranchAddress("dp_over_p0", &m_sad.dp_over_p0);
122  m_tree->SetBranchAddress("watt", &m_sad.watt);
123 
124  int numEntries = m_tree->GetEntries();
125  if (numEntries <= 0) {
126  B2ERROR("SAD tree is empty");
127  return;
128  }
129 
130  // construct vector of cumulative rates and determine number of events to generate
131 
132  m_rates.push_back(0);
133  for (int i = 0; i < numEntries; i++) {
134  m_tree->GetEntry(i);
135  m_rates.push_back(m_sad.rate + m_rates.back());
136  m_counters.push_back(0);
137  }
138 
139  m_numEvents = gRandom->Poisson(m_rates.back() * m_realTime / Unit::s);
140 
141  // set rotation from SAD to Belle II
142 
143  if (m_ringName == "LER") {
144  GearDir ring("/Detector/SuperKEKB/LER/");
145  m_rotation.SetAngle(ring.getAngle("angle"));
146  m_ring = 2;
147  } else {
148  GearDir ring("/Detector/SuperKEKB/HER/");
149  m_rotation.SetAngle(ring.getAngle("angle"));
150  m_ring = 1;
151  }
152 
153  m_sectionOrdering.insert(m_sectionOrdering.end(), {1, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2});
154 
155  B2RESULT("BG rate: " << m_rates.back() / 1e6 << " MHz, events to generate: "
156  << m_numEvents);
157 
158 }
159 
161 {
162 }
163 
165 {
166 
167  // check event counter
168 
169  if (m_eventCounter >= m_numEvents) {
170  StoreObjPtr<EventMetaData> eventMetaData;
171  eventMetaData->setEndOfData(); // stop event processing
172  return;
173  }
174  m_eventCounter++;
175 
176  // get SAD entry
177 
178  int i = generateEntry();
179  m_tree->GetEntry(i);
180  m_counters[i]++;
181 
182  // make SADMetaHit
183  int ring_section = -1;
184  double ssraw = m_sad.ss;
185  if (m_sad.ss < 0) ssraw += 3016.;
186  int section = (int)(ssraw * 12 / 3016.);
187  if ((unsigned)section < m_sectionOrdering.size()) ring_section = m_sectionOrdering[section];
188 
189  StoreArray<SADMetaHit> SADMetaHits;
191  0., m_sad.nturn,
194  m_sad.watt, m_ring, ring_section));
195 
196 
197  // transform to Belle II (flip sign of y and s, rotate)
198 
199  ROOT::Math::XYZVector position(m_sad.x * Unit::m, -m_sad.y * Unit::m, -m_sad.s * Unit::m);
200  position = m_rotation * position;
201 
202  double pz = sqrt(m_sad.E * m_sad.E - m_sad.px * m_sad.px - m_sad.py * m_sad.py);
203  if (m_ringName == "LER") pz = -pz;
204  ROOT::Math::XYZVector momentum(m_sad.px, -m_sad.py, pz);
205  momentum = m_rotation * momentum;
206 
207  // PDG code and mass
208 
209  int pdgCode = Const::electron.getPDGCode();
210  double mass = Const::electron.getMass();
211  if (m_ringName == "LER") pdgCode = -pdgCode;
212 
213  // append SAD particle to MCParticles
214 
215  StoreArray<MCParticle> MCParticles;
216  MCParticle* part = MCParticles.appendNew();
217  part->setPDG(pdgCode);
218  part->setMass(mass);
219  part->setProductionVertex(position);
220  part->setProductionTime(0);
221  part->setMomentum(momentum);
222  part->setEnergy(sqrt(momentum.Mag2() + mass * mass));
223  part->setValidVertex(true);
224  part->setStatus(MCParticle::c_PrimaryParticle);
225  part->addStatus(MCParticle::c_StableInGenerator);
226 
227  // FarBeamLine region transformation
228  if (abs(m_sad.s * Unit::m) > 4.0 * Unit::m) {
229  // initial coordinates in SAD space
230  double particlePosSADfar[] = {m_sad.x* Unit::m, -m_sad.y* Unit::m, 0.0 * Unit::m};
231  double particleMomSADfar[] = {m_sad.px* Unit::GeV, -m_sad.py* Unit::GeV, pz* Unit::GeV};
232  // final coordinates in Geant4 space
233  double particlePosGeant4[] = {0.0, 0.0, 0.0};
234  double particleMomGeant4[] = {0.0, 0.0, 0.0};
235 
236  // create a transformation matrix for a given ring
237  TGeoHMatrix transMatrix;
238  if (m_ringName == "LER") {
240  } else {
242  }
243 
244  // calculate a new set of coordinates in Geant4 space
245  transMatrix.LocalToMaster(particlePosSADfar, particlePosGeant4); // position
246  transMatrix.LocalToMasterVect(particleMomSADfar, particleMomGeant4); // momentum
247  // apply a new set of coordinates
248  part->setMomentum(ROOT::Math::XYZVector(particleMomGeant4[0], particleMomGeant4[1], particleMomGeant4[2]));
249  part->setProductionVertex(ROOT::Math::XYZVector(particlePosGeant4[0], particlePosGeant4[1], particlePosGeant4[2]));
250  }
251 }
252 
254 {
255 }
256 
258 {
259  // close SAD file
260  m_file->Close();
261 
262  B2RESULT("BG rate: " << m_rates.back() / 1e6 << " MHz, equivalent time: "
263  << m_realTime / Unit::us << " us, "
264  << m_eventCounter << " events generated");
266  B2ERROR("Number of generated events does not match the equivalent running time: "
267  << m_numEvents << " events needed, but "
268  << m_eventCounter << " generated");
269 
270  int imax = 0;
271  double average = 0;
272  for (unsigned i = 0; i < m_counters.size(); i++) {
273  if (m_counters[i] > m_counters[imax]) imax = i;
274  average += m_counters[i];
275  }
276  average /= m_counters.size();
277  B2RESULT("SAD particle usage: on average " << average << " times, max "
278  << m_counters[imax] << " times (entry " << imax << ")");
279 
280 }
281 
282 
284 {
285  double rate = gRandom->Uniform(m_rates.back());
286  int i1 = 0;
287  int i2 = m_rates.size() - 1;
288  while (i2 - i1 > 1) {
289  int i = (i1 + i2) / 2;
290  if (rate > m_rates[i]) {
291  i1 = i;
292  } else {
293  i2 = i;
294  }
295  }
296  return i1;
297 }
std::vector< int > m_counters
counters: how many times SAD particles are used
virtual void initialize() override
Initialize the Module.
virtual ~BeamBkgGeneratorModule()
Destructor.
virtual void event() override
Event processor.
virtual void endRun() override
End-of-run action.
ReaderSAD m_readerSAD
the transformation from SAD to Belle II system for the far beamline
std::vector< double > m_rates
cumulative rates of SAD particles [Hz]
virtual void terminate() override
Termination action.
ROOT::Math::RotationY m_rotation
rotation from SAD to Belle II frame
std::string m_fileName
name of the SAD file converted to root
int generateEntry() const
Pick up particle randomly from the SAD file according to its rate.
int m_ring
ring number, 1-HER, 2-LER
int m_numEvents
number of events to generate
double m_realTime
equivalent SuperKEKB running time in [ns]
virtual void beginRun() override
Called when entering a new run.
std::vector< int > m_sectionOrdering
superKEKB section ordering
std::string m_ringName
name of the superKEKB ring (LER or HER)
std::string m_treeName
name of the TTree in the SAD file
int getPDGCode() const
PDG code.
Definition: Const.h:464
double getMass() const
Particle mass.
Definition: UnitConst.cc:356
static const ChargedStable electron
electron particle
Definition: Const.h:650
GearDir is the basic class used for accessing the parameter store.
Definition: GearDir.h:31
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
@ 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
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
TGeoHMatrix SADtoGeant(ReaderSAD::AcceleratorRings accRing, double s)
Transformation matrix.
Definition: ReaderSAD.cc:416
@ c_HER
High Energy Ring (electrons)
Definition: ReaderSAD.h:47
@ c_LER
Low Energy Ring (positrons)
Definition: ReaderSAD.h:48
ClassSADMetaHit - digitization simulated metahit for the SAD detector.
Definition: SADMetaHit.h:25
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
static const double us
[microsecond]
Definition: Unit.h:97
static const double m
[meters]
Definition: Unit.h:69
static const double s
[second]
Definition: Unit.h:95
static const double GeV
Standard of [energy, momentum, mass].
Definition: Unit.h:51
double getAngle(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard angle unit.
Definition: Interface.h:299
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
int nturn
number of turns from scattered to lost
double E
E at lost position [GeV] (in fact momentum magnitude!)
double sraw
s at lost position [m] before matching G4 beam pipe inner surface
double ss
scattered position (|s|<Ltot/2) [m]
double yraw
y at lost position [m] before matching G4 beam pipe inner surface
double rr
sqrt(xraw*xraw+yraw*yraw) [m]
double dp_over_p0
momentum deviation of the lost particle
double xraw
x at lost position [m] before matching G4 beam pipe inner surface
double s
lost position measured from IP along the ring [m]