CMS 3D CMS Logo

CustomParticleFactory.cc
Go to the documentation of this file.
4 
7 
8 #include "G4ParticleTable.hh"
9 #include "G4DecayTable.hh"
10 #include "G4PhaseSpaceDecayChannel.hh"
11 #include "G4ProcessManager.hh"
12 #include "G4ParticleDefinition.hh"
13 #include "G4SystemOfUnits.hh"
14 
17 
18 #include <iomanip>
19 #include <iostream>
20 #include <sstream>
21 
23 std::vector<G4ParticleDefinition *> CustomParticleFactory::m_particles;
24 
25 #ifdef G4MULTITHREADED
26 G4Mutex CustomParticleFactory::customParticleFactoryMutex = G4MUTEX_INITIALIZER;
27 #endif
28 
30 
32  if (loaded) {
33  return;
34  }
35 #ifdef G4MULTITHREADED
36  G4MUTEXLOCK(&customParticleFactoryMutex);
37  if (loaded) {
38  return;
39  }
40 #endif
41 
42  // loading once
43  loaded = true;
44  std::ifstream configFile(filePath.c_str());
45 
47  edm::LogVerbatim("SimG4CoreCustomPhysics")
48  << "CustomParticleFactory: Reading Custom Particle and G4DecayTable from \n"
49  << filePath;
50  // This should be compatible IMO to SLHA
51  G4ParticleTable *theParticleTable = G4ParticleTable::GetParticleTable();
52  while (getline(configFile, line)) {
53  line.erase(0, line.find_first_not_of(" \t")); // Remove leading whitespace.
54  if (line.length() == 0 || line.at(0) == '#') {
55  continue;
56  } // Skip blank lines and comments.
57  // The mass table begins with a line containing "BLOCK MASS"
58  if (ToLower(line).find("block") < line.npos && ToLower(line).find("mass") < line.npos) {
59  edm::LogVerbatim("SimG4CoreCustomPhysics") << "CustomParticleFactory: Retrieving mass table.";
61  }
62  if (line.find("DECAY") < line.npos) {
63  int pdgId;
64  double width;
65  std::string tmpString;
66  std::stringstream lineStream(line);
67  lineStream >> tmpString >> pdgId >> width;
68  // assume SLHA format, e.g.: DECAY 1000021 5.50675438E+00 # gluino decays
69  edm::LogVerbatim("SimG4CoreCustomPhysics")
70  << "CustomParticleFactory: entry to G4DecayTable: pdgID, width " << pdgId << ", " << width;
71  G4ParticleDefinition *aParticle = theParticleTable->FindParticle(pdgId);
72  if (nullptr == aParticle || width == 0.0) {
73  continue;
74  }
75  G4DecayTable *aDecayTable = getDecayTable(&configFile, pdgId);
76  aParticle->SetDecayTable(aDecayTable);
77  aParticle->SetPDGStable(false);
78  aParticle->SetPDGLifeTime(1.0 / (width * CLHEP::GeV) * 6.582122e-22 * CLHEP::MeV * CLHEP::s);
79  G4ParticleDefinition *aAntiParticle = theParticleTable->FindAntiParticle(pdgId);
80  if (nullptr != aAntiParticle && aAntiParticle->GetPDGEncoding() != pdgId) {
81  aAntiParticle->SetDecayTable(getAntiDecayTable(pdgId, aDecayTable));
82  aAntiParticle->SetPDGStable(false);
83  aAntiParticle->SetPDGLifeTime(1.0 / (width * CLHEP::GeV) * 6.582122e-22 * CLHEP::MeV * CLHEP::s);
84  }
85  }
86  }
87 #ifdef G4MULTITHREADED
88  G4MUTEXUNLOCK(&customParticleFactoryMutex);
89 #endif
90 }
91 
93  if (std::abs(pdgCode) % 100 < 14 && std::abs(pdgCode) / 1000000 == 0) {
94  edm::LogError("CustomParticleFactory::addCustomParticle")
95  << "Pdg code too low " << pdgCode << " " << std::abs(pdgCode) / 1000000;
96  return;
97  }
98 
99  if (CustomPDGParser::s_isSIMP(pdgCode)) {
100  CMSSIMP *simp = CMSSIMP::Definition(mass * GeV);
101  CMSAntiSIMP *antisimp = CMSAntiSIMP::Definition(mass * GeV);
102  m_particles.push_back(simp);
103  m_particles.push_back(antisimp);
104  return;
105  }
106 
108  G4String pType = "custom";
109  G4String pSubType = "";
110  G4double spectatormass = 0.0;
111  G4ParticleDefinition *spectator = nullptr;
113  if (CustomPDGParser::s_isgluinoHadron(pdgCode)) {
114  pType = "rhadron";
115  }
116  if (CustomPDGParser::s_isSLepton(pdgCode)) {
117  pType = "sLepton";
118  }
119  if (CustomPDGParser::s_isMesonino(pdgCode)) {
120  pType = "mesonino";
121  }
122  if (CustomPDGParser::s_isSbaryon(pdgCode)) {
123  pType = "sbaryon";
124  }
125 
126  double massGeV = mass * CLHEP::GeV;
127  double width = 0.0;
128  double charge = CLHEP::eplus * CustomPDGParser::s_charge(pdgCode);
129  if (name.compare(0, 4, "~HIP") == 0) {
130  if ((name.compare(0, 7, "~HIPbar") == 0)) {
131  std::string str = name.substr(7);
132  charge = CLHEP::eplus * atoi(str.c_str()) / 3.;
133  } else {
134  std::string str = name.substr(4);
135  charge = -CLHEP::eplus * atoi(str.c_str()) / 3.;
136  }
137  }
138  if (name.compare(0, 9, "anti_~HIP") == 0) {
139  if ((name.compare(0, 12, "anti_~HIPbar") == 0)) {
140  std::string str = name.substr(12);
141  charge = -CLHEP::eplus * atoi(str.c_str()) / 3.;
142  } else {
143  std::string str = name.substr(9);
144  charge = CLHEP::eplus * atoi(str.c_str()) / 3.;
145  }
146  }
147  int spin = (int)CustomPDGParser::s_spin(pdgCode) - 1;
148  int parity = +1;
149  int conjugation = 0;
150  int isospin = 0;
151  int isospinZ = 0;
152  int gParity = 0;
153  int lepton = 0; //FIXME:
154  int baryon = 1; //FIXME:
155  bool stable = true;
156  double lifetime = -1;
157 
158  if (CustomPDGParser::s_isDphoton(pdgCode)) {
159  pType = "darkpho";
160  spin = 2;
161  parity = -1;
162  conjugation = -1;
163  isospin = 0;
164  isospinZ = 0;
165  gParity = 0;
166  lepton = 0;
167  baryon = 0;
168  stable = true;
169  lifetime = -1;
170  }
171 
172  G4DecayTable *decaytable = nullptr;
173  G4ParticleTable *theParticleTable = G4ParticleTable::GetParticleTable();
174 
175  CustomParticle *particle = new CustomParticle(name,
176  massGeV,
177  width,
178  charge,
179  spin,
180  parity,
181  conjugation,
182  isospin,
183  isospinZ,
184  gParity,
185  pType,
186  lepton,
187  baryon,
188  pdgCode,
189  stable,
190  lifetime,
191  decaytable);
192 
193  if (pType == "rhadron" && name != "~g") {
194  G4String cloudname = name + "cloud";
195  G4String cloudtype = pType + "cloud";
196  spectator = theParticleTable->FindParticle(1000021);
197  spectatormass = spectator->GetPDGMass();
198  G4double cloudmass = massGeV - spectatormass;
199  CustomParticle *tmpParticle =
200  new CustomParticle(cloudname, cloudmass, 0.0, 0, 0, +1, 0, 0, 0, 0, cloudtype, 0, +1, 0, true, -1.0, nullptr);
201  particle->SetCloud(tmpParticle);
202  particle->SetSpectator(spectator);
203 
204  edm::LogVerbatim("SimG4CoreCustomPhysics")
205  << "CustomParticleFactory: " << name << " being assigned spectator" << spectator->GetParticleName()
206  << " and cloud " << cloudname << "\n"
207  << " Masses: " << mass << " Gev, " << spectatormass / CLHEP::GeV << " GeV and "
208  << cloudmass / CLHEP::GeV << " GeV.";
209  } else if (pType == "mesonino" || pType == "sbaryon") {
210  int sign = 1;
211  if (pdgCode < 0)
212  sign = -1;
213 
214  G4String cloudname = name + "cloud";
215  G4String cloudtype = pType + "cloud";
216  if (CustomPDGParser::s_isstopHadron(pdgCode)) {
217  spectator = theParticleTable->FindParticle(1000006 * sign);
218  } else {
219  if (CustomPDGParser::s_issbottomHadron(pdgCode)) {
220  spectator = theParticleTable->FindParticle(1000005 * sign);
221  } else {
222  spectator = nullptr;
223  edm::LogError("SimG4CoreCustomPhysics") << "CustomParticleFactory: Cannot find spectator parton";
224  }
225  }
226  if (nullptr != spectator) {
227  spectatormass = spectator->GetPDGMass();
228  }
229  G4double cloudmass = massGeV - spectatormass;
230  CustomParticle *tmpParticle =
231  new CustomParticle(cloudname, cloudmass, 0.0, 0, 0, +1, 0, 0, 0, 0, cloudtype, 0, +1, 0, true, -1.0, nullptr);
232  particle->SetCloud(tmpParticle);
233  particle->SetSpectator(spectator);
234 
235  if (nullptr != spectator)
236  edm::LogVerbatim("SimG4CoreCustomPhysics")
237  << "CustomParticleFactory: " << name << " being assigned spectator" << spectator->GetParticleName()
238  << " and cloud " << cloudname << "\n"
239  << " Masses: " << mass << " Gev, " << spectatormass / CLHEP::GeV << " GeV and "
240  << cloudmass / CLHEP::GeV << " GeV.";
241  } else {
242  particle->SetCloud(nullptr);
243  particle->SetSpectator(nullptr);
244  }
245  m_particles.push_back(particle);
246 }
247 
249  int pdgId;
250  double mass;
253  G4ParticleTable *theParticleTable = G4ParticleTable::GetParticleTable();
254 
255  // This should be compatible IMO to SLHA
256  while (getline(*configFile, line)) {
257  line.erase(0, line.find_first_not_of(" \t")); // remove leading whitespace
258  if (line.length() == 0 || line.at(0) == '#')
259  continue; // skip blank lines and comments
260  if (ToLower(line).find("block") < line.npos) {
261  edm::LogInfo("SimG4CoreCustomPhysics") << "CustomParticleFactory: Finished the Mass Table ";
262  break;
263  }
264  std::stringstream sstr(line);
265  sstr >> pdgId >> mass >> tmp >> name; // Assume SLHA format, e.g.: 1000001 5.68441109E+02 # ~d_L
266 
267  mass = std::max(mass, 0.0);
268  if (theParticleTable->FindParticle(pdgId)) {
269  continue;
270  }
271 
272  edm::LogVerbatim("SimG4CoreCustomPhysics")
273  << "CustomParticleFactory: Calling addCustomParticle for pdgId: " << pdgId << ", mass " << mass << " GeV "
274  << name << ", isgluinoHadron: " << CustomPDGParser::s_isgluinoHadron(pdgId)
275  << ", isstopHadron: " << CustomPDGParser::s_isstopHadron(pdgId)
276  << ", isSIMP: " << CustomPDGParser::s_isSIMP(pdgId);
278 
280  int pdgIdPartner = pdgId % 100;
281  G4ParticleDefinition *aParticle = theParticleTable->FindParticle(pdgIdPartner);
282  //Add antiparticles for SUSY particles only, not for rHadrons.
283  if (nullptr != aParticle) {
284  edm::LogVerbatim("SimG4CoreCustomPhysics")
285  << "CustomParticleFactory: Found partner particle for "
286  << " pdgId= " << pdgId << ", pdgIdPartner= " << pdgIdPartner << " " << aParticle->GetParticleName();
287  }
288 
290  !CustomPDGParser::s_isSIMP(pdgId) && pdgId != 1000006 && pdgId != -1000006 && pdgId != 25 && pdgId != 35 &&
291  pdgId != 36 && pdgId != 37) {
292  int sign = aParticle->GetAntiPDGEncoding() / pdgIdPartner;
293  edm::LogVerbatim("SimG4CoreCustomPhysics")
294  << "CustomParticleFactory: For " << aParticle->GetParticleName() << " pdg= " << pdgIdPartner
295  << ", GetAntiPDGEncoding() " << aParticle->GetAntiPDGEncoding() << " sign= " << sign;
296 
297  if (std::abs(sign) != 1) {
298  edm::LogVerbatim("SimG4CoreCustomPhysics")
299  << "CustomParticleFactory: sign= " << sign << " a: " << aParticle->GetAntiPDGEncoding()
300  << " b: " << pdgIdPartner;
301  aParticle->DumpTable();
302  }
303  if (sign == -1 && pdgId != 25 && pdgId != 35 && pdgId != 36 && pdgId != 37 && pdgId != 1000039) {
304  tmp = "anti_" + name;
305  if (theParticleTable->FindParticle(-pdgId) == nullptr) {
306  edm::LogVerbatim("SimG4CoreCustomPhysics")
307  << "CustomParticleFactory: Calling addCustomParticle for antiparticle with pdgId: " << -pdgId << ", mass "
308  << mass << " GeV, name " << tmp;
310  theParticleTable->FindParticle(pdgId)->SetAntiPDGEncoding(-pdgId);
311  }
312  } else
313  theParticleTable->FindParticle(pdgId)->SetAntiPDGEncoding(pdgId);
314  }
315 
316  if (pdgId == 1000039)
317  theParticleTable->FindParticle(pdgId)->SetAntiPDGEncoding(pdgId); // gravitino
318  if (pdgId == 1000024 || pdgId == 1000037 || pdgId == 37) {
319  tmp = "anti_" + name;
320  if (!theParticleTable->FindParticle(-pdgId)) {
321  edm::LogVerbatim("SimG4CoreCustomPhysics")
322  << "CustomParticleFactory: Calling addCustomParticle for antiparticle (2) with pdgId: " << -pdgId
323  << ", mass " << mass << " GeV, name " << tmp;
325  theParticleTable->FindParticle(pdgId)->SetAntiPDGEncoding(-pdgId);
326  }
327  }
328  if (pdgId == 9000006) {
329  tmp = name + "bar";
330  edm::LogVerbatim("CustomPhysics") << "Calling addCustomParticle for antiparticle with pdgId: " << -pdgId
331  << ", mass " << mass << ", name " << tmp;
333  theParticleTable->FindParticle(pdgId)->SetAntiPDGEncoding(-pdgId);
334  }
335  }
336 }
337 
338 G4DecayTable *CustomParticleFactory::getDecayTable(std::ifstream *configFile, int pdgId) {
339  double br;
340  int nDaughters;
341  int pdg[4] = {0};
343 
344  G4ParticleTable *theParticleTable = G4ParticleTable::GetParticleTable();
345 
346  std::string parentName = theParticleTable->FindParticle(pdgId)->GetParticleName();
347  G4DecayTable *decaytable = new G4DecayTable();
348 
349  while (getline(*configFile, line)) {
350  line.erase(0, line.find_first_not_of(" \t")); // remove leading whitespace
351  if (line.length() == 0)
352  continue; // skip blank lines
353  if (line.at(0) == '#' && ToLower(line).find("br") < line.npos && ToLower(line).find("nda") < line.npos)
354  continue; // skip a comment of the form: # BR NDA ID1 ID2
355  if (line.at(0) == '#' || ToLower(line).find("block") < line.npos) {
356  edm::LogInfo("SimG4CoreCustomPhysics") << "CustomParticleFactory: Finished the Decay Table ";
357  break;
358  }
359 
360  std::stringstream sstr(line);
361  sstr >> br >> nDaughters; // assume SLHA format, e.g.: 1.49435135E-01 2 -15 16 # BR(H+ -> tau+ nu_tau)
362  LogDebug("SimG4CoreCustomPhysics") << "CustomParticleFactory: Branching Ratio: " << br
363  << ", Number of Daughters: " << nDaughters;
364  if (nDaughters > 4) {
365  edm::LogError("SimG4CoreCustomPhysics")
366  << "CustomParticleFactory: Number of daughters is too large (max = 4): " << nDaughters
367  << " for pdgId: " << pdgId;
368  break;
369  }
370  if (br <= 0.0) {
371  edm::LogError("SimG4CoreCustomPhysics")
372  << "CustomParticleFactory: Branching ratio is " << br << " for pdgId: " << pdgId;
373  break;
374  }
375  std::string name[4] = {""};
376  for (int i = 0; i < nDaughters; ++i) {
377  sstr >> pdg[i];
378  LogDebug("SimG4CoreCustomPhysics") << "CustomParticleFactory: Daughter ID " << pdg[i];
379  const G4ParticleDefinition *part = theParticleTable->FindParticle(pdg[i]);
380  if (!part) {
381  edm::LogWarning("SimG4CoreCustomPhysics")
382  << "CustomParticleFactory: particle with PDG code" << pdg[i] << " not found!";
383  continue;
384  }
385  name[i] = part->GetParticleName();
386  }
388  G4PhaseSpaceDecayChannel *aDecayChannel =
389  new G4PhaseSpaceDecayChannel(parentName, br, nDaughters, name[0], name[1], name[2], name[3]);
390  decaytable->Insert(aDecayChannel);
391  edm::LogVerbatim("SimG4CoreCustomPhysics")
392  << "CustomParticleFactory: inserted decay channel "
393  << " for pdgID= " << pdgId << " " << parentName << " BR= " << br << " Daughters: " << name[0] << " "
394  << name[1] << " " << name[2] << " " << name[3];
395  }
396  return decaytable;
397 }
398 
399 G4DecayTable *CustomParticleFactory::getAntiDecayTable(int pdgId, G4DecayTable *theDecayTable) {
400  std::string name[4] = {""};
401  G4ParticleTable *theParticleTable = G4ParticleTable::GetParticleTable();
402 
403  std::string parentName = theParticleTable->FindParticle(-pdgId)->GetParticleName();
404  G4DecayTable *decaytable = new G4DecayTable();
405 
406  for (int i = 0; i < theDecayTable->entries(); ++i) {
407  G4VDecayChannel *theDecayChannel = theDecayTable->GetDecayChannel(i);
408  int nd = std::min(4, theDecayChannel->GetNumberOfDaughters());
409  for (int j = 0; j < nd; ++j) {
410  int id = theDecayChannel->GetDaughter(j)->GetAntiPDGEncoding();
411  G4ParticleDefinition *part = theParticleTable->FindParticle(id);
412  if (nullptr == part) {
413  edm::LogWarning("SimG4CoreCustomPhysics")
414  << "CustomParticleFactory: antiparticle with PDG code" << id << " not found!";
415  continue;
416  }
417  name[j] = part->GetParticleName();
418  }
419  G4PhaseSpaceDecayChannel *aDecayChannel =
420  new G4PhaseSpaceDecayChannel(parentName, theDecayChannel->GetBR(), nd, name[0], name[1], name[2], name[3]);
421  decaytable->Insert(aDecayChannel);
422  edm::LogVerbatim("SimG4CoreCustomPhysics")
423  << "CustomParticleFactory: inserted decay channel "
424  << " for pdgID= " << -pdgId << " " << parentName << " BR= " << theDecayChannel->GetBR()
425  << " Daughters: " << name[0] << " " << name[1] << " " << name[2] << " " << name[3];
426  }
427  return decaytable;
428 }
429 
431  std::locale loc;
432  for (std::string::size_type i = 0; i < str.length(); ++i)
433  str.at(i) = std::tolower(str.at(i), loc);
434  return str;
435 }
436 
437 const std::vector<G4ParticleDefinition *> &CustomParticleFactory::getCustomParticles() { return m_particles; }
Log< level::Info, true > LogVerbatim
static bool s_isDphoton(int pdg)
static double s_charge(int pdg)
static const int stable
Definition: TopGenEvent.h:10
static bool s_isSbaryon(int pdg)
static bool s_isgluinoHadron(int pdg)
void SetCloud(G4ParticleDefinition *theCloud)
Log< level::Error, false > LogError
uint16_t size_type
void loadCustomParticles(const std::string &filePath)
static std::vector< G4ParticleDefinition * > m_particles
Definition: CMSSIMP.h:8
static bool s_isMesonino(int pdg)
static bool s_isSIMP(int pdg)
static bool s_isSLepton(int pdg)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::string ToLower(std::string str)
void SetSpectator(G4ParticleDefinition *theSpectator)
static double s_spin(int pdg)
static CMSAntiSIMP * Definition(double mass)
Definition: CMSAntiSIMP.cc:12
Log< level::Info, false > LogInfo
void getMassTable(std::ifstream *configFile)
G4DecayTable * getDecayTable(std::ifstream *configFile, int pdgId)
void addCustomParticle(int pdgCode, double mass, const std::string &name)
part
Definition: HCALResponse.h:20
G4DecayTable * getAntiDecayTable(int pdgId, G4DecayTable *theDecayTable)
const std::vector< G4ParticleDefinition * > & getCustomParticles()
static bool s_issbottomHadron(int pdg)
static bool s_isstopHadron(int pdg)
Log< level::Warning, false > LogWarning
#define str(s)
tmp
align.sh
Definition: createJobs.py:716
#define LogDebug(id)
static CMSSIMP * Definition(double mass)
Definition: CMSSIMP.cc:12