File indexing completed on 2025-01-18 09:14:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/Printout.h>
0016 #include <DDG4/Geant4InputHandling.h>
0017 #include <DDG4/Geant4Primary.h>
0018 #include <DDG4/Geant4Context.h>
0019 #include <DDG4/Geant4Action.h>
0020 #include <DDG4/Geant4PrimaryHandler.h>
0021 #include <CLHEP/Units/SystemOfUnits.h>
0022 #include <CLHEP/Units/PhysicalConstants.h>
0023
0024
0025 #include <G4Event.hh>
0026 #include <G4PrimaryVertex.hh>
0027 #include <G4PrimaryParticle.hh>
0028 #include <G4ParticleDefinition.hh>
0029
0030
0031 #include <stdexcept>
0032 #include <limits>
0033 #include <cmath>
0034
0035 using namespace dd4hep::sim;
0036 using PropertyMask = dd4hep::detail::ReferenceBitMask<int>;
0037
0038
0039 Geant4Vertex* dd4hep::sim::createPrimary(const G4PrimaryVertex* g4) {
0040 Geant4Vertex* v = new Geant4Vertex();
0041 v->x = g4->GetX0();
0042 v->y = g4->GetY0();
0043 v->z = g4->GetZ0();
0044 v->time = g4->GetT0();
0045 return v;
0046 }
0047
0048
0049 Geant4Particle*
0050 dd4hep::sim::createPrimary(int particle_id,
0051 const Geant4Vertex* v,
0052 const G4PrimaryParticle* g4p)
0053 {
0054 Geant4ParticleHandle p = new Geant4Particle();
0055 p->id = particle_id;
0056 p->reason = 0;
0057 p->pdgID = g4p->GetPDGcode();
0058 p->psx = g4p->GetPx();
0059 p->psy = g4p->GetPy();
0060 p->psz = g4p->GetPz();
0061 p->time = g4p->GetProperTime();
0062 p->properTime = g4p->GetProperTime();
0063 p->vsx = v->x;
0064 p->vsy = v->y;
0065 p->vsz = v->z;
0066 p->vex = v->x;
0067 p->vey = v->y;
0068 p->vez = v->z;
0069
0070
0071 p->spin[0] = 0;
0072 p->spin[1] = 0;
0073 p->spin[2] = 0;
0074 p->colorFlow[0] = 0;
0075 p->colorFlow[0] = 0;
0076 p->mass = g4p->GetMass();
0077 p->charge = int(3.0 * g4p->GetCharge());
0078 PropertyMask status(p->status);
0079 status.set(G4PARTICLE_GEN_STABLE);
0080 return p;
0081 }
0082
0083
0084 static void collectPrimaries(Geant4PrimaryMap* pm,
0085 Geant4PrimaryInteraction* interaction,
0086 Geant4Vertex* particle_origine,
0087 G4PrimaryParticle* gp)
0088 {
0089
0090 if ( pm->get(gp) ) {
0091 return;
0092 }
0093
0094 int pid = int(interaction->particles.size());
0095 Geant4Particle* p = createPrimary(pid,particle_origine,gp);
0096 G4PrimaryParticle* dau = gp->GetDaughter();
0097 PropertyMask status(p->status);
0098 int mask = interaction->mask;
0099
0100 interaction->particles.emplace(p->id,p);
0101 status.set(G4PARTICLE_PRIMARY);
0102 p->mask = mask;
0103 particle_origine->out.insert(p->id);
0104
0105 pm->insert(gp,p);
0106
0107 if ( dau ) {
0108 Geant4Vertex* dv = new Geant4Vertex(*particle_origine);
0109 PropertyMask reason(p->reason);
0110 reason.set(G4PARTICLE_HAS_SECONDARIES);
0111
0112 dv->mask = mask;
0113 dv->in.insert(p->id);
0114
0115 interaction->vertices[mask].emplace_back(dv) ;
0116
0117 for(; dau; dau = dau->GetNext())
0118 collectPrimaries(pm, interaction, dv, dau);
0119 }
0120 }
0121
0122
0123 Geant4PrimaryInteraction*
0124 dd4hep::sim::createPrimary(int mask,
0125 Geant4PrimaryMap* pm,
0126 std::set<G4PrimaryVertex*>const& primaries)
0127 {
0128 Geant4PrimaryInteraction* interaction = new Geant4PrimaryInteraction();
0129 interaction->locked = true;
0130 interaction->mask = mask;
0131 for (auto const& gv: primaries) {
0132 Geant4Vertex* v = createPrimary(gv);
0133 v->mask = mask;
0134 interaction->vertices[mask].emplace_back(v);
0135 for (G4PrimaryParticle *gp = gv->GetPrimary(); gp; gp = gp->GetNext()) {
0136 collectPrimaries(pm, interaction, v, gp);
0137 }
0138 }
0139 return interaction;
0140 }
0141
0142
0143 int dd4hep::sim::generationInitialization(const Geant4Action* ,
0144 const Geant4Context* context)
0145 {
0146
0147
0148
0149
0150
0151 context->event().addExtension(new Geant4PrimaryMap());
0152
0153
0154 context->event().addExtension(new Geant4ParticleMap());
0155
0156
0157
0158
0159
0160
0161
0162
0163 Geant4PrimaryEvent* evt = new Geant4PrimaryEvent();
0164 context->event().addExtension(evt);
0165
0166
0167
0168 Geant4PrimaryInteraction* inter = new Geant4PrimaryInteraction();
0169 inter->setNextPID(-1);
0170 context->event().addExtension(inter);
0171 return 1;
0172 }
0173
0174
0175 static void appendInteraction(const Geant4Action* caller,
0176 Geant4PrimaryInteraction* output,
0177 Geant4PrimaryInteraction* input)
0178 {
0179 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
0180 for( ip=input->particles.begin(), ipend=input->particles.end(); ip != ipend; ++ip ) {
0181 Geant4Particle* p = (*ip).second;
0182 output->particles.emplace(p->id,p->addRef());
0183 }
0184 Geant4PrimaryInteraction::VertexMap::iterator ivfnd, iv, ivend;
0185 for( iv=input->vertices.begin(), ivend=input->vertices.end(); iv != ivend; ++iv ) {
0186 int theMask = input->mask;
0187 ivfnd = output->vertices.find(theMask);
0188 if ( ivfnd != output->vertices.end() ) {
0189 caller->abortRun("Duplicate primary interaction identifier!",
0190 "Cannot handle 2 interactions with identical identifiers!");
0191 }
0192 for(Geant4Vertex* vtx : (*iv).second )
0193 output->vertices[theMask].emplace_back( vtx->addRef() );
0194 }
0195 }
0196
0197 static void rebaseParticles(Geant4PrimaryInteraction::ParticleMap& particles, int &offset) {
0198 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
0199 int mx_id = offset;
0200
0201 for( ip=particles.begin(), ipend=particles.end(); ip != ipend; ++ip ) {
0202 Geant4ParticleHandle p((*ip).second);
0203 p.offset(offset);
0204 mx_id = p->id+1 > mx_id ? p->id+1 : mx_id;
0205 }
0206 offset = mx_id;
0207 }
0208
0209 static void rebaseVertices(Geant4PrimaryInteraction::VertexMap& vertices, int part_offset) {
0210 Geant4PrimaryInteraction::VertexMap::iterator iv, ivend;
0211 std::set<int> in, out;
0212 std::set<int>::iterator i;
0213
0214 for(iv=vertices.begin(), ivend=vertices.end(); iv != ivend; ++iv) {
0215 for( Geant4Vertex* v : (*iv).second ){
0216 in = v->in;
0217 out = v->out;
0218 for(in=v->in, i=in.begin(), v->in.clear(); i != in.end(); ++i)
0219 v->in.insert((*i)+part_offset);
0220 for(out=v->out, i=out.begin(), v->out.clear(); i != out.end(); ++i)
0221 v->out.insert((*i)+part_offset);
0222 }
0223 }
0224 }
0225
0226 int dd4hep::sim::mergeInteractions(const Geant4Action* caller,
0227 const Geant4Context* context)
0228 {
0229 typedef Geant4PrimaryEvent::Interaction Interaction;
0230 typedef std::vector<Interaction*> Interactions;
0231 Geant4Event& event = context->event();
0232 Geant4PrimaryEvent* evt = event.extension<Geant4PrimaryEvent>();
0233 Interaction* output = event.extension<Interaction>();
0234 Interactions inter = evt->interactions();
0235 int particle_offset = 0;
0236
0237 for(Interactions::const_iterator i=inter.begin(); i != inter.end(); ++i) {
0238 Interaction* interaction = *i;
0239 int vertex_offset = particle_offset;
0240 if ( !interaction->applyMask() ) {
0241 caller->abortRun("Found single interaction with multiple primary vertices!",
0242 "Cannot merge individual interactions with more than one primary!");
0243 }
0244 rebaseParticles(interaction->particles,particle_offset);
0245 rebaseVertices(interaction->vertices,vertex_offset);
0246 appendInteraction(caller,output,interaction);
0247 }
0248 output->setNextPID(particle_offset);
0249 Geant4PrimaryInteraction::ParticleMap::iterator ip, ipend;
0250 caller->debug("+++ Merging MC input record from %d interactions:",(int)inter.size());
0251 for( ip=output->particles.begin(), ipend=output->particles.end(); ip != ipend; ++ip )
0252 Geant4ParticleHandle((*ip).second).dump1(DEBUG,caller->name(),"Merged particles");
0253 return 1;
0254 }
0255
0256
0257 int dd4hep::sim::boostInteraction(const Geant4Action* caller,
0258 Geant4PrimaryEvent::Interaction* inter,
0259 double alpha)
0260 {
0261 #define SQR(x) (x*x)
0262 Geant4PrimaryEvent::Interaction::VertexMap::iterator iv;
0263 Geant4PrimaryEvent::Interaction::ParticleMap::iterator ip;
0264 double gamma = std::sqrt(1 + SQR(tan(alpha)));
0265 double betagamma = std::tan(alpha);
0266
0267 if ( inter->locked ) {
0268 caller->abortRun("Locked interactions may not be boosted!",
0269 "Cannot boost interactions with a native G4 primary record!");
0270 }
0271 else if ( alpha != 0.0 ) {
0272
0273 for(iv=inter->vertices.begin(); iv != inter->vertices.end(); ++iv){
0274 for( Geant4Vertex* v : (*iv).second ) {
0275 double t = gamma * v->time + betagamma * v->x / CLHEP::c_light;
0276 double x = gamma * v->x + betagamma * CLHEP::c_light * v->time;
0277 double y = v->y;
0278 double z = v->z;
0279 v->x = x;
0280 v->y = y;
0281 v->z = z;
0282 v->time = t;
0283 }
0284 }
0285
0286 for(ip=inter->particles.begin(); ip != inter->particles.end(); ++ip) {
0287 Geant4ParticleHandle p = (*ip).second;
0288 double t = gamma * p->time + betagamma * p->vsx / CLHEP::c_light;
0289 double x = gamma * p->vsx + betagamma * CLHEP::c_light * p->time;
0290 double y = p->vsy;
0291 double z = p->vsz;
0292
0293 double m = p->mass;
0294 double e2 = SQR(p->psx)+SQR(p->psy)+SQR(p->psz)+SQR(m);
0295 double px = betagamma * std::sqrt(e2) + gamma * p->psx;
0296 double py = p->psy;
0297 double pz = p->psz;
0298
0299 p->vsx = x;
0300 p->vsy = y;
0301 p->vsz = z;
0302 p->time = t;
0303
0304 p->psx = px;
0305 p->psy = py;
0306 p->psz = pz;
0307 }
0308 }
0309 return 1;
0310 }
0311
0312
0313 int dd4hep::sim::smearInteraction(const Geant4Action* caller,
0314 Geant4PrimaryEvent::Interaction* inter,
0315 double dx, double dy, double dz, double dt)
0316 {
0317 Geant4PrimaryEvent::Interaction::VertexMap::iterator iv;
0318 Geant4PrimaryEvent::Interaction::ParticleMap::iterator ip;
0319
0320 if ( inter->locked ) {
0321 caller->abortRun("Locked interactions may not be smeared!",
0322 "Cannot smear interactions with a native G4 primary record!");
0323 }
0324
0325
0326 for(iv=inter->vertices.begin(); iv != inter->vertices.end(); ++iv) {
0327 for( Geant4Vertex* v : (*iv).second ){
0328 v->x += dx;
0329 v->y += dy;
0330 v->z += dz;
0331 v->time += dt;
0332 }
0333 }
0334
0335 for(ip=inter->particles.begin(); ip != inter->particles.end(); ++ip) {
0336 Geant4Particle* p = (*ip).second;
0337 p->vsx += dx;
0338 p->vsy += dy;
0339 p->vsz += dz;
0340 p->vex += dx;
0341 p->vey += dy;
0342 p->vez += dz;
0343 p->time += dt;
0344 }
0345 return 1;
0346 }
0347
0348 static G4PrimaryParticle* createG4Primary(const Geant4ParticleHandle p) {
0349 G4PrimaryParticle* g4 = 0;
0350 const G4ParticleDefinition* def = p.definition();
0351
0352 double energy = p.energy();
0353 double mom2 = (p->psx*p->psx) + (p->psy*p->psy) + (p->psz*p->psz);
0354 double mass2 = energy*energy - mom2;
0355 if ( mass2 < 0e0 ) {
0356 if ( def ) {
0357 mass2 = def->GetPDGMass() * def->GetPDGMass();
0358 }
0359 energy = std::sqrt(mom2 + mass2);
0360 if ( std::fabs(p.energy()-energy) > 0e0 ) {
0361 dd4hep::printout(dd4hep::INFO,"createG4Primary",
0362 "Change particle %s energy from %10.5f MeV by %g ppm to avoid negative Energy^2",
0363 (def) ? def->GetParticleName().c_str() : "???", p.energy(), std::fabs(p.energy()-energy)*1e6);
0364 }
0365 }
0366 if ( 0 != p->pdgID ) {
0367
0368 const int pdgID = p->pdgID < 1000000000 ? p->pdgID : p.definition()->GetPDGEncoding();
0369 g4 = new G4PrimaryParticle(pdgID, p->psx, p->psy, p->psz, energy);
0370 }
0371 else {
0372 g4 = new G4PrimaryParticle(def, p->psx, p->psy, p->psz, energy);
0373 g4->SetCharge(double(p.charge())/3.0);
0374 }
0375
0376
0377
0378 return g4;
0379 }
0380
0381 static std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> >
0382 getRelevant(std::set<int>& visited,
0383 std::map<int,G4PrimaryParticle*>& prim,
0384 Geant4PrimaryInteraction::ParticleMap& pm,
0385 const Geant4PrimaryConfig& primaryConfig,
0386 const Geant4ParticleHandle p)
0387 {
0388 typedef std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> > Primaries;
0389 using dd4hep::printout;
0390
0391 Primaries res;
0392 visited.insert(p->id);
0393 PropertyMask status(p->status);
0394 if ( status.isSet(G4PARTICLE_GEN_STABLE) ) {
0395 bool rejectParticle = false
0396 or (primaryConfig.m_rejectPDGs.count(abs(p->pdgID)) != 0)
0397 ;
0398 printout(dd4hep::DEBUG, "Input",
0399 "Checking rejection of stable: PDG(%-10d), Definition(%s), reject(%s)",
0400 p->pdgID,
0401 p.definition() ? "true" : "false",
0402 rejectParticle ? "true" : "false");
0403 if (not rejectParticle and prim.find(p->id) == prim.end() ) {
0404 G4PrimaryParticle* p4 = createG4Primary(p);
0405 prim[p->id] = p4;
0406 res.emplace_back(p,p4);
0407 }
0408 }
0409 else if ( p->daughters.size() > 0 ) {
0410 const Geant4Particle::Particles& dau = p->daughters;
0411 int first_daughter = *(dau.begin());
0412 Geant4ParticleHandle dp = pm[first_daughter];
0413 double en = p.energy();
0414 double me = en > std::numeric_limits<double>::epsilon() ? p->mass / en : 0.0;
0415
0416 double proper_time = fabs(dp->time-p->time) * me;
0417 double proper_time_Precision = pow(10.,-DBL_DIG)*fabs(me)*fmax(fabs(p->time),fabs(dp->time));
0418 bool isProperTimeZero = (fabs(proper_time) <= fabs(proper_time_Precision));
0419
0420
0421 bool rejectParticle = not p.definition()
0422 or (primaryConfig.m_rejectPDGs.count(abs(p->pdgID)) != 0)
0423 or (isProperTimeZero and p.definition()->GetPDGStable() )
0424 or (isProperTimeZero and primaryConfig.m_zeroTimePDGs.count(abs(p->pdgID)) != 0 )
0425 or (status.isSet(G4PARTICLE_GEN_DOCUMENTATION) || status.isSet(G4PARTICLE_GEN_BEAM) || status.isSet(G4PARTICLE_GEN_OTHER))
0426 or false;
0427
0428 printout(dd4hep::DEBUG, "Input",
0429 "Checking rejection: PDG(%-10d), Definition(%s), isProperTimeZero(%s, %3.15f), stable(%s), doc(%s), reject(%s)",
0430 p->pdgID,
0431 p.definition() ? "true" : "false",
0432 isProperTimeZero ? "true" : "false", proper_time,
0433 (bool(p.definition()) ? p.definition()->GetPDGStable() : false) ? "true" : "false",
0434 status.isSet(G4PARTICLE_GEN_DOCUMENTATION) || status.isSet(G4PARTICLE_GEN_BEAM) || status.isSet(G4PARTICLE_GEN_OTHER) ? "true" : "false",
0435 rejectParticle ? "true" : "false");
0436
0437 bool failStableWithChildren = (not rejectParticle and p.definition()->GetPDGStable());
0438 if (failStableWithChildren) {
0439 printout(dd4hep::FATAL,"Input",
0440 "+++ Stable particle (PDG: %-10d) with daughters! check your MC record, adapt particle.tbl file...",
0441 p->pdgID);
0442 throw std::runtime_error("Cannot Simmulate this MC Record");
0443 }
0444 if (not rejectParticle) {
0445 std::map<int, G4PrimaryParticle*>::iterator ip4 = prim.find(p->id);
0446 G4PrimaryParticle* p4 = (ip4 == prim.end()) ? 0 : (*ip4).second;
0447 if ( !p4 ) {
0448 p4 = createG4Primary(p);
0449 p4->SetProperTime(proper_time);
0450 prim[p->id] = p4;
0451 Primaries daughters;
0452 for(Geant4Particle::Particles::const_iterator i=dau.begin(); i!=dau.end(); ++i) {
0453 if ( visited.find(*i) == visited.end() ) {
0454 Primaries tmp = getRelevant(visited,prim,pm,primaryConfig,pm[*i]);
0455 daughters.insert(daughters.end(), tmp.begin(),tmp.end());
0456 }
0457 }
0458 for(Primaries::iterator i=daughters.begin(); i!=daughters.end(); ++i)
0459 p4->SetDaughter((*i).second);
0460 }
0461 res.emplace_back(p,p4);
0462 }
0463 else {
0464 for(Geant4Particle::Particles::const_iterator i=dau.begin(); i!=dau.end(); ++i) {
0465 if ( visited.find(*i) == visited.end() ) {
0466 Primaries tmp = getRelevant(visited,prim,pm,primaryConfig,pm[*i]);
0467 res.insert(res.end(), tmp.begin(),tmp.end());
0468 }
0469 }
0470 }
0471 }
0472 return res;
0473 }
0474
0475
0476 int dd4hep::sim::generatePrimaries(const Geant4Action* caller,
0477 const Geant4Context* context,
0478 G4Event* event)
0479 {
0480 typedef std::vector< std::pair<Geant4Particle*,G4PrimaryParticle*> > Primaries;
0481 typedef Geant4PrimaryInteraction Interaction;
0482 Geant4PrimaryMap* primaries = context->event().extension<Geant4PrimaryMap>();
0483 Interaction* interaction = context->event().extension<Interaction>();
0484 Interaction::ParticleMap& pm = interaction->particles;
0485 Interaction::VertexMap& vm = interaction->vertices;
0486 std::map<int,G4PrimaryParticle*> prim;
0487 std::set<int> visited;
0488
0489 auto const* primHandler = dynamic_cast<const Geant4PrimaryHandler*>(caller);
0490 auto const& primaryConfig = primHandler ? primHandler->m_primaryConfig : Geant4PrimaryConfig();
0491
0492 caller->debug("PrimaryConfiguration:%s", primaryConfig.toString().c_str());
0493
0494 if ( interaction->locked ) {
0495 caller->abortRun("Locked interactions may not be used to generate primaries!",
0496 "Cannot handle a native G4 primary record!");
0497 return 0;
0498 }
0499 else {
0500 Geant4PrimaryInteraction::VertexMap::iterator ivfnd, iv, ivend;
0501 for(Interaction::VertexMap::const_iterator iend=vm.end(),i=vm.begin(); i!=iend; ++i) {
0502 for( Geant4Vertex* v : (*i).second ){
0503
0504 int num_part = 0;
0505 G4PrimaryVertex* v4 = new G4PrimaryVertex(v->x,v->y,v->z,v->time);
0506 event->AddPrimaryVertex(v4);
0507 caller->print("+++++ G4PrimaryVertex at (%+.2e,%+.2e,%+.2e) [mm] %+.2e [ns]",
0508 v->x/CLHEP::mm,v->y/CLHEP::mm,v->z/CLHEP::mm,v->time/CLHEP::ns);
0509 for(Geant4Vertex::Particles::const_iterator ip=v->out.begin(); ip!=v->out.end(); ++ip) {
0510 Geant4ParticleHandle p = pm[*ip];
0511 if ( p->daughters.size() > 0 ) {
0512 PropertyMask mask(p->reason);
0513 mask.set(G4PARTICLE_HAS_SECONDARIES);
0514 }
0515 if ( p->parents.size() == 0 ) {
0516 Primaries relevant = getRelevant(visited,prim,pm,primaryConfig,p);
0517 for(Primaries::const_iterator j=relevant.begin(); j!= relevant.end(); ++j) {
0518 Geant4ParticleHandle r = (*j).first;
0519 G4PrimaryParticle* p4 = (*j).second;
0520 PropertyMask reason(r->reason);
0521 char text[64];
0522
0523 reason.set(G4PARTICLE_PRIMARY);
0524 v4->SetPrimary(p4);
0525 ::snprintf(text,sizeof(text),"-> G4Primary[%3d]",num_part);
0526 r.dumpWithMomentum(caller->outputLevel()-1,caller->name(),text);
0527 ++num_part;
0528 }
0529 }
0530 }
0531 if(caller->outputLevel() <= VERBOSE){
0532 v4->Print();
0533 }
0534 }
0535 }
0536 for( const auto& vtx : prim ) {
0537 Geant4ParticleHandle p = pm[vtx.first];
0538 primaries->insert(vtx.second, p);
0539 }
0540 }
0541 return 1;
0542 }