21 #include <CLHEP/Units/SystemOfUnits.h>
22 #include <CLHEP/Units/PhysicalConstants.h>
26 #include <G4PrimaryVertex.hh>
27 #include <G4PrimaryParticle.hh>
28 #include <G4ParticleDefinition.hh>
29 #include <G4VPhysicalVolume.hh>
30 #include <G4LogicalVolume.hh>
31 #include <G4VSolid.hh>
47 v->time = g4->GetT0();
55 const G4PrimaryParticle* g4p)
60 p->
pdgID = g4p->GetPDGcode();
61 p->
psx = g4p->GetPx();
62 p->
psy = g4p->GetPy();
63 p->
psz = g4p->GetPz();
64 p->
time = g4p->GetProperTime();
79 p->
mass = g4p->GetMass();
80 p->
charge = int(3.0 * g4p->GetCharge());
90 G4PrimaryParticle* gp)
97 int pid = int(interaction->
particles.size());
99 G4PrimaryParticle* dau = gp->GetDaughter();
101 int mask = interaction->
mask;
106 particle_origine->
out.insert(p->
id);
116 dv->
in.insert(p->
id);
118 interaction->
vertices[mask].emplace_back(dv) ;
120 for(; dau; dau = dau->GetNext())
121 collectPrimaries(pm, interaction, dv, dau);
129 std::set<G4PrimaryVertex*>
const& primaries)
132 interaction->
locked =
true;
133 interaction->
mask = mask;
134 for (
auto const& gv: primaries) {
137 interaction->
vertices[mask].emplace_back(
v);
138 for (G4PrimaryParticle *gp = gv->GetPrimary(); gp; gp = gp->GetNext()) {
139 collectPrimaries(pm, interaction,
v, gp);
178 static void appendInteraction(
const Geant4Action* caller,
182 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
187 Geant4PrimaryInteraction::VertexMap::iterator ivfnd, iv, ivend;
188 for( iv=input->
vertices.begin(), ivend=input->
vertices.end(); iv != ivend; ++iv ) {
189 int theMask = input->
mask;
190 ivfnd = output->
vertices.find(theMask);
191 if ( ivfnd != output->
vertices.end() ) {
192 caller->
abortRun(
"Duplicate primary interaction identifier!",
193 "Cannot handle 2 interactions with identical identifiers!");
201 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
204 for( ip=particles.begin(), ipend=particles.end(); ip != ipend; ++ip ) {
207 mx_id = p->
id+1 > mx_id ? p->
id+1 : mx_id;
213 Geant4PrimaryInteraction::VertexMap::iterator iv, ivend;
214 std::set<int> in, out;
215 std::set<int>::iterator i;
217 for(iv=vertices.begin(), ivend=vertices.end(); iv != ivend; ++iv) {
221 for(in=
v->in, i=in.begin(),
v->in.clear(); i != in.end(); ++i)
222 v->in.insert((*i)+part_offset);
223 for(out=
v->out, i=out.begin(),
v->out.clear(); i != out.end(); ++i)
224 v->out.insert((*i)+part_offset);
233 typedef std::vector<Interaction*> Interactions;
236 Interaction* output =
event.
extension<Interaction>();
238 int particle_offset = 0;
240 for(Interactions::const_iterator i=inter.begin(); i != inter.end(); ++i) {
241 Interaction* interaction = *i;
242 int vertex_offset = particle_offset;
243 if ( !interaction->applyMask() ) {
244 caller->
abortRun(
"Found single interaction with multiple primary vertices!",
245 "Cannot merge individual interactions with more than one primary!");
247 rebaseParticles(interaction->particles,particle_offset);
248 rebaseVertices(interaction->vertices,vertex_offset);
249 appendInteraction(caller,output,interaction);
251 output->setNextPID(particle_offset);
252 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
253 caller->
debug(
"+++ Merging MC input record from %d interactions:",(
int)inter.size());
254 for( ip=output->particles.begin(), ipend=output->particles.end(); ip != ipend; ++ip )
265 Geant4PrimaryEvent::Interaction::VertexMap::iterator iv;
266 Geant4PrimaryEvent::Interaction::ParticleMap::iterator ip;
267 double gamma = std::sqrt(1 +
SQR(tan(alpha)));
268 double betagamma = std::tan(alpha);
271 caller->
abortRun(
"Locked interactions may not be boosted!",
272 "Cannot boost interactions with a native G4 primary record!");
274 else if ( alpha != 0.0 ) {
278 double t = gamma *
v->time + betagamma *
v->x / CLHEP::c_light;
279 double x = gamma *
v->x + betagamma * CLHEP::c_light *
v->time;
291 double t = gamma * p->
time + betagamma * p->
vsx / CLHEP::c_light;
292 double x = gamma * p->
vsx + betagamma * CLHEP::c_light * p->
time;
298 double px = betagamma * std::sqrt(e2) + gamma * p->
psx;
318 double dx,
double dy,
double dz,
double dt)
320 Geant4PrimaryEvent::Interaction::VertexMap::iterator iv;
321 Geant4PrimaryEvent::Interaction::ParticleMap::iterator ip;
324 caller->
abortRun(
"Locked interactions may not be smeared!",
325 "Cannot smear interactions with a native G4 primary record!");
352 G4PrimaryParticle* g4 = 0;
353 const G4ParticleDefinition* def = p.
definition();
355 double energy = p.
energy();
357 double mass2 = energy*energy - mom2;
360 mass2 = def->GetPDGMass() * def->GetPDGMass();
362 energy = std::sqrt(mom2 + mass2);
363 if ( std::fabs(p.
energy()-energy) > 0e0 ) {
364 dd4hep::printout(dd4hep::INFO,
"createG4Primary",
365 "Change particle %s energy from %10.5f MeV by %g ppm to avoid negative Energy^2",
366 (def) ? def->GetParticleName().c_str() :
"???", p.
energy(), std::fabs(p.
energy()-energy)*1e6);
369 if ( 0 != p->
pdgID ) {
372 g4 =
new G4PrimaryParticle(pdgID, p->
psx, p->
psy, p->
psz, energy);
375 g4 =
new G4PrimaryParticle(def, p->
psx, p->
psy, p->
psz, energy);
376 g4->SetCharge(
double(p.
charge())/3.0);
381 if ( p->
spin[0] != 0.0 || p->
spin[1] != 0.0 || p->
spin[2] != 0.0 ) {
382 g4->SetPolarization(p->
spin[0], p->
spin[1], p->
spin[2]);
387 static std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> >
388 getRelevant(std::set<int>& visited,
389 std::map<int,G4PrimaryParticle*>& prim,
394 typedef std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> > Primaries;
395 using dd4hep::printout;
398 visited.insert(p->
id);
401 bool rejectParticle =
false
404 printout(dd4hep::DEBUG,
"Input",
405 "Checking rejection of stable: PDG(%-10d), Definition(%s), reject(%s)",
408 rejectParticle ?
"true" :
"false");
409 if (not rejectParticle and prim.find(p->
id) == prim.end() ) {
410 G4PrimaryParticle* p4 = createG4Primary(p);
412 res.emplace_back(p,p4);
417 int first_daughter = *(dau.begin());
422 double proper_time = fabs(dp->
time-p->
time) * me;
423 double proper_time_Precision = pow(10.,-DBL_DIG)*fabs(me)*fmax(fabs(p->
time),fabs(dp->
time));
424 bool isProperTimeZero = (fabs(proper_time) <= fabs(proper_time_Precision));
429 or (isProperTimeZero and p.definition()->GetPDGStable() )
430 or (isProperTimeZero and primaryConfig.m_zeroTimePDGs.count(abs(p->pdgID)) != 0 )
434 printout(
dd4hep::DEBUG, "Input",
435 "Checking rejection: PDG(%-10d), Definition(%s), isProperTimeZero(%s, %3.15f), stable(%s), doc(%s), reject(%s)",
437 p.definition() ? "true" : "false",
438 isProperTimeZero ? "true" : "false", proper_time,
439 (
bool(p.definition()) ? p.definition()->GetPDGStable() : false) ? "true" : "false",
441 rejectParticle ? "true" : "false");
443 bool failStableWithChildren = (not rejectParticle and p.definition()->GetPDGStable());
444 if (failStableWithChildren) {
445 printout(dd4hep::FATAL,
"Input",
446 "+++ Stable particle (PDG: %-10d) with daughters! check your MC record, adapt particle.tbl file...",
448 throw std::runtime_error(
"Cannot Simmulate this MC Record");
450 if (not rejectParticle) {
451 std::map<int, G4PrimaryParticle*>::iterator ip4 = prim.find(p->
id);
452 G4PrimaryParticle* p4 = (ip4 == prim.end()) ? 0 : (*ip4).second;
454 p4 = createG4Primary(p);
459 p4->SetProperTime(-1);
461 p4->SetProperTime(proper_time);
465 for(Geant4Particle::Particles::const_iterator i=dau.begin(); i!=dau.end(); ++i) {
466 if ( visited.find(*i) == visited.end() ) {
467 Primaries tmp = getRelevant(visited,prim,pm,primaryConfig,pm[*i]);
468 daughters.insert(daughters.end(), tmp.begin(),tmp.end());
471 for(Primaries::iterator i=daughters.begin(); i!=daughters.end(); ++i)
472 p4->SetDaughter((*i).second);
474 res.emplace_back(p,p4);
477 for(Geant4Particle::Particles::const_iterator i=dau.begin(); i!=dau.end(); ++i) {
478 if ( visited.find(*i) == visited.end() ) {
479 Primaries tmp = getRelevant(visited,prim,pm,primaryConfig,pm[*i]);
480 res.insert(res.end(), tmp.begin(),tmp.end());
491 bool insideWorldVolume(
const G4VPhysicalVolume* world,
const G4ThreeVector& point) {
492 auto* logical = world ? world->GetLogicalVolume() :
nullptr;
493 G4VSolid* solid = logical ? logical->GetSolid() :
nullptr;
494 return solid ? (solid->Inside(point) != kOutside) :
true;
503 typedef std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> > Primaries;
506 Interaction* interaction = context->
event().
extension<Interaction>();
507 Interaction::ParticleMap& pm = interaction->particles;
508 Interaction::VertexMap& vm = interaction->vertices;
509 std::map<int,G4PrimaryParticle*> prim;
510 std::set<int> visited;
513 auto const& primaryConfig = primHandler ? primHandler->m_primaryConfig :
Geant4PrimaryConfig();
515 caller->
debug(
"PrimaryConfiguration:%s", primaryConfig.
toString().c_str());
517 if ( interaction->locked ) {
518 caller->
abortRun(
"Locked interactions may not be used to generate primaries!",
519 "Cannot handle a native G4 primary record!");
523 Geant4PrimaryInteraction::VertexMap::iterator ivfnd, iv, ivend;
524 for(Interaction::VertexMap::const_iterator iend=vm.end(),i=vm.begin(); i!=iend; ++i) {
528 if ( !insideWorldVolume(context->
world(), G4ThreeVector(
v->x,
v->y,
v->z)) ) {
530 caller->
warning(
"+++ Dropping primary vertex at (%+.2e,%+.2e,%+.2e) [mm]: outside the world volume",
531 v->x/CLHEP::mm,
v->y/CLHEP::mm,
v->z/CLHEP::mm);
534 caller->
except(
"Primary vertex at (%+.2e,%+.2e,%+.2e) [mm] is outside the world volume. "
535 "Geant4 cannot track particles starting there. Enlarge the world volume, or set "
536 "SkipParticlesOutsideWorldVolume=True to drop such vertices instead.",
537 v->x/CLHEP::mm,
v->y/CLHEP::mm,
v->z/CLHEP::mm);
539 G4PrimaryVertex* v4 =
new G4PrimaryVertex(
v->x,
v->y,
v->z,
v->time);
540 event->AddPrimaryVertex(v4);
541 caller->
print(
"+++++ G4PrimaryVertex at (%+.2e,%+.2e,%+.2e) [mm] %+.2e [ns]",
542 v->x/CLHEP::mm,
v->y/CLHEP::mm,
v->z/CLHEP::mm,
v->time/CLHEP::ns);
543 for(Geant4Vertex::Particles::const_iterator ip=
v->out.begin(); ip!=
v->out.end(); ++ip) {
549 if ( p->
parents.size() == 0 ) {
550 Primaries relevant = getRelevant(visited,prim,pm,primaryConfig,p);
551 for(Primaries::const_iterator j=relevant.begin(); j!= relevant.end(); ++j) {
553 G4PrimaryParticle* p4 = (*j).second;
559 ::snprintf(text,
sizeof(text),
"-> G4Primary[%3d]",num_part);
570 for(
const auto& vtx : prim ) {
572 primaries->
insert(vtx.second, p);