Author: [log in to unmask] Date: Thu Oct 1 11:25:51 2015 New Revision: 3665 Log: [SLIC-251] Preliminary rewrite of MCParticle event generation to correctly handle displaced vertices. Modified: projects/slic/trunk/include/MCParticleManager.hh projects/slic/trunk/src/MCParticleManager.cc Modified: projects/slic/trunk/include/MCParticleManager.hh ============================================================================= --- projects/slic/trunk/include/MCParticleManager.hh (original) +++ projects/slic/trunk/include/MCParticleManager.hh Thu Oct 1 11:25:51 2015 @@ -32,6 +32,7 @@ typedef map<G4int, MCParticle*> TrackIDMap; typedef map<MCParticle*, G4PrimaryParticle*> PrimaryParticleMap; +typedef map<G4PrimaryParticle*, MCParticle*> MCParticleMap; typedef PrimaryParticleMap::iterator PrimaryParticleMapIterator; typedef set<MCParticle*> MCParticleSet; @@ -102,7 +103,7 @@ void reset() { _trackIDMap.clear(); _primaryMap.clear(); - _visitedParticles.clear(); + _mcpMap.clear(); _mcpVec = 0; } @@ -116,7 +117,7 @@ } /** - * Generate a G4Event from a collection of MCParticles. + * Generate an event from a collection of MCParticles. * @param[in] mcparticles The MCParticle collection. * @param[in] event The output G4Event. */ @@ -136,14 +137,27 @@ */ G4double smearZPosition(const G4double rms); -private: + /** + * Create a primary particle from an MCParticle and recursively create primaries for all its daughters. + * @param[in] mcp the input MCParticle + * @return the primary particle converted from the MCParticle + */ + std::set<G4PrimaryParticle*> createPrimary(G4PrimaryParticle* parent, MCParticle* mcp); /** - * Get the relevant G4ParticleParticle objects from an MCParticle. - * @param[in] p The MCParticle. - * @return The set of relevant G4PrimaryParticle objects. + * Create a primary vertex from an MCParticle. + * @param[in] mcp the input MCParticle + * @return the primary vertex converted from the MCParticle */ - std::set<G4PrimaryParticle*> getRelevantParticles(MCParticle* p); + G4PrimaryVertex* createVertex(MCParticle* mcp); + + /** + * Return true if particle is a daughter of another primary. + * @return true if particle is a daughter + */ + bool isDaughter(G4PrimaryParticle* particle, const std::set<G4PrimaryParticle*>& primaries); + +private: /** * Set the MCParticle collection. @@ -161,9 +175,9 @@ PrimaryParticleMap _primaryMap; /** - * Set keeping track of which MCParticles have been processed in generator. + * Reverse map of G4PrimaryParticle to MCParticle. */ - MCParticleSet _visitedParticles; + MCParticleMap _mcpMap; /** * Map of MCParticle to track ID. Modified: projects/slic/trunk/src/MCParticleManager.cc ============================================================================= --- projects/slic/trunk/src/MCParticleManager.cc (original) +++ projects/slic/trunk/src/MCParticleManager.cc Thu Oct 1 11:25:51 2015 @@ -5,181 +5,199 @@ // Geant4 #include "G4SystemOfUnits.hh" +#include "globals.hh" #include "Randomize.hh" namespace slic { void MCParticleManager::generateEvent(LCCollectionVec* particles, G4Event* event) { - /* Apply Z smearing to input particles. */ +#if SLIC_LOG + log() << LOG::head << LOG::debug << "generating event " << event->GetEventID() << " from " << particles->size() << " MCParticles" << LOG::done; +#endif + + // Apply Z smearing to input particles. +#if SLIC_LOG + log() << LOG::debug << "applying Z smearing: " << EventSourceManager::instance()->getZSmearing() << LOG::done; +#endif G4double z = smearZPosition(EventSourceManager::instance()->getZSmearing()); - /* Apply the Lorentz Transformation to input particles. */ + /// Apply the Lorentz Transformation to input particles. +#if SLIC_LOG + log() << LOG::debug << "applying Lorentz transform: " << EventSourceManager::instance()->getLorentzTransformationAngle() << LOG::done; +#endif applyLorentzTransformation(particles, EventSourceManager::instance()->getLorentzTransformationAngle()); - /* - * Process particles and add them to the primary vertex of the event. - */ - G4ThreeVector particlePosition(0, 0, z); - G4double particleTime; - G4PrimaryVertex* vertex = new G4PrimaryVertex(particlePosition, particleTime); - for(size_t i=0; i < particles->size(); i++) { - MCParticle* mcp = (MCParticle*)(*particles)[i]; - if (mcp->getParents().size()==0) { - //std::cout << "construct tree of relevant G4PrimaryParticles for initial MCParticle " << i << " " << std::flush; - std::set<G4PrimaryParticle*> primaries = getRelevantParticles(mcp); - //std::cout << "... finished" << std::endl; - std::set<G4PrimaryParticle*>::iterator primaryIt; - for (primaryIt = primaries.begin(); primaryIt != primaries.end(); primaryIt++) { - vertex->SetPrimary(*primaryIt); - //std::cout << "G4PrimaryParticle ("<< (*primaryIt)->GetPDGcode() << ") added to G4PrimaryVertex." << std::endl; + log() << LOG::endl; + + // Loop over MCParticle input list. + for (size_t i = 0; i < particles->size(); i++) { + + // Get the next MCParticle. + MCParticle* mcp = (MCParticle*) (*particles)[i]; + + // Debug print information about the particle. +#ifdef SLIC_LOG + log() << LOG::debug << "processing MCParticle " << i << LOG::done; + log() << LOG::debug + << "PDG: " << mcp->getPDG() << LOG::endl + << "gen status: " << mcp->getGeneratorStatus() << LOG::endl + << "sim status: " << mcp->getSimulatorStatus() << LOG::endl + << "energy: " << mcp->getEnergy() << LOG::endl + << "time: " << mcp->getTime() << LOG::endl + << "daughters: " << mcp->getDaughters().size() << LOG::endl + << "vertex: ( " << mcp->getVertex()[0] << " " << mcp->getVertex()[1] << " " << mcp->getVertex()[2] << " )" << LOG::endl + << "p: ( " << mcp->getMomentum()[0] << ", " << mcp->getMomentum()[1] << ", " << mcp->getMomentum()[2] << " )" << LOG::endl + << "charge: " << mcp->getCharge() << LOG::endl + << "mass: " << mcp->getMass() << LOG::endl + << "daughters: " << mcp->getDaughters().size() << LOG::endl + << "parents: " << mcp->getParents().size() + << LOG::done; + log() << LOG::endl; +#endif + + // Only make vertices for particles without parents. + if (mcp->getParents().size() == 0) { + +#ifdef SLIC_LOG + log() << LOG::debug << "creating new vertex for MCParticle " << i << LOG::done; +#endif + + // Create a new primary vertex. + G4PrimaryVertex* vertex = 0; + + if (mcp->getGeneratorStatus() == 1 || mcp->getGeneratorStatus() == 2) { + vertex = createVertex(mcp); } - } - } - - /* Add the primary vertex to Geant4. */ - event->AddPrimaryVertex(vertex); - - /* Register the collection of MCParticles that was created. */ - setMCParticleCollection(particles); -} - - -std::set<G4PrimaryParticle*> MCParticleManager::getRelevantParticles(MCParticle* p) { - - //log each particle which has been called, to avoid double counting and increase efficiency - _visitedParticles.insert(p); - PrimaryParticleMap::iterator mcpIT; - std::set<G4PrimaryParticle*> relevantParticlesSet; //holds all relevant decay particles of p - - /* - * Case #1: - * - * If p is a stable particle: search for it in LCIO2Geant4Map - * - * If exists in map: get the G4PrimaryParticle version of p from LCIO2Geant4Map - * Else: create G4PrimaryParticle version write it to LCIO2Geant4Map - * - * Finally: insert the G4PrimaryParticle verion of p into the relevant particle list - * and return the list. - */ - if (p->getGeneratorStatus() == 1) { - G4PrimaryParticle* g4p; - mcpIT = _primaryMap.find(p); - if (mcpIT != _primaryMap.end()) { - g4p = mcpIT->second; - } else { - G4int IDHEP = p->getPDG(); - G4double PHEP1 = p->getMomentum()[0]; - G4double PHEP2 = p->getMomentum()[1]; - G4double PHEP3 = p->getMomentum()[2]; - G4double PHEP5 = p->getMass(); - // create G4PrimaryParticle object - g4p = new G4PrimaryParticle(IDHEP, PHEP1 * GeV, PHEP2 * GeV, PHEP3 * GeV); - g4p->SetMass(PHEP5 * GeV); - _primaryMap[p] = g4p; - //std::cout << "*" << std::flush; - } - //std::cout << g4p->GetPDGcode() << std::flush; - relevantParticlesSet.insert(g4p); - return relevantParticlesSet; - } - - /* - * CASE #2: - * - * If p is not stable: get first decay daughter and calculate the proper time of p. - * - * If proper time is not zero: particle is "relevant", since it carries vertex information. - * - * If p is already in LCIO2Geant4Map: take it. - * Else: create G4PrimaryParticle version of p and write it to LCIO2Geant4Map - * - * Collect all relevant particles of all daughters and setup "relevant mother- - * daughter-relations" between relevant decay particles and G4PrimaryParticle version of p - * - * Finally: insert only the G4PrimaryParticle version of p to the relevant particle list and return this "list". - * The added particle has now the correct pre-assigned decay products and (hopefully) the right lifetime. - */ - else if (p->getDaughters().size() > 0) { //fg: require that there is at least one daughter - otherwise forget the particle - // calculate proper time - MCParticle* dp = p->getDaughters()[0]; - - double proper_time = fabs((dp->getTime() - p->getTime()) * p->getMass()) / p->getEnergy(); - // fix by S.Morozov for real != 0 - double aPrecision = dp->getTime() * p->getMass() / p->getEnergy(); - double bPrecision = p->getTime() * p->getMass() / p->getEnergy(); - - double proper_time_Precision = pow(10, -DBL_DIG)*fmax(fabs(aPrecision),fabs(bPrecision)); - - bool isProperTimeZero = (proper_time <= proper_time_Precision); - - // -- remove original --- if (proper_time != 0) { - if (isProperTimeZero == false) { - - G4PrimaryParticle* g4p; - mcpIT = _primaryMap.find(p); - if (mcpIT != _primaryMap.end()) { - g4p = mcpIT->second; - } else { - G4int IDHEP = p->getPDG(); - G4double PHEP1 = p->getMomentum()[0]; - G4double PHEP2 = p->getMomentum()[1]; - G4double PHEP3 = p->getMomentum()[2]; - G4double PHEP5 = p->getMass(); - // create G4PrimaryParticle object - g4p = new G4PrimaryParticle(IDHEP, PHEP1 * GeV, PHEP2 * GeV, PHEP3 * GeV); - g4p->SetMass(PHEP5 * GeV); - g4p->SetProperTime(proper_time * ns); - _primaryMap[p] = g4p; - std::set<G4PrimaryParticle*> vec3; - for (size_t i = 0; i < p->getDaughters().size(); i++) { - if (_visitedParticles.count(p->getDaughters()[i]) == 0) { - std::set<G4PrimaryParticle*> vec2 = getRelevantParticles(p->getDaughters()[i]); - std::set<G4PrimaryParticle*>::iterator setit; - for (setit = vec2.begin(); setit != vec2.end(); setit++) { - vec3.insert(*setit); - } + +#ifdef SLIC_LOG + log() << LOG::debug << "creating primary for MCParticle " << i << LOG::done; +#endif + + // Create a primary particle and recursively create its daughters. + const std::set<G4PrimaryParticle*> primaries = createPrimary(0, mcp); + + // Loop over returned set of primary particles. + for (std::set<G4PrimaryParticle*>::const_iterator it = primaries.begin(); it != primaries.end(); it++) { + + // Is this a top-level particle with no daughters? + if (!MCParticleManager::isDaughter((*it), primaries)) { + + // Create a new vertex if necessary. + if (vertex == 0) { + // Create vertex by looking up MCParticle from the primary. + vertex = createVertex(_mcpMap[(*it)]); } - } - std::set<G4PrimaryParticle*>::iterator setit; - for (setit = vec3.begin(); setit != vec3.end(); setit++) { - g4p->SetDaughter(*setit); - } - //std::cout << "*" << std::flush; - } - //std::cout << g4p->GetPDGcode() << std::flush; - relevantParticlesSet.insert(g4p); - return relevantParticlesSet; - } - /* CASE #3: - * - * If p is not stable AND has zero lifetime: forget about p and retrieve all relevant - * decay particles of all daughters of p. - * - * In this case this step of recursion is just there for collecting all relevant decay - * products of daughters and returning them. - */ - else { - for (size_t i = 0; i < p->getDaughters().size(); i++) { - if (_visitedParticles.count(p->getDaughters()[i]) == 0) { - std::set<G4PrimaryParticle*> vec2 = getRelevantParticles(p->getDaughters()[i]); - std::set<G4PrimaryParticle*>::iterator setit; - for (setit = vec2.begin(); setit != vec2.end(); setit++) { - relevantParticlesSet.insert(*setit); - } + + // Add the primary particle to the vertex. + vertex->SetPrimary(*it); } } - return relevantParticlesSet; - } - } - return relevantParticlesSet; + + // Add the vertex to the event. + event->AddPrimaryVertex(vertex); + } +#ifdef SLIC_LOG + log() << "-------------------------------------------------" << LOG::endl; +#endif + } + + // Register the collection of MCParticles that was created. + setMCParticleCollection(particles); +} + +std::set<G4PrimaryParticle*> MCParticleManager::createPrimary(G4PrimaryParticle* parent, MCParticle* mcp) { + + // The MCParticle argument should not be null. + if (mcp == 0) { + G4Exception("", "", FatalException, "MCParticle is null."); + } + + // Set of primaries that will be returned. + std::set<G4PrimaryParticle*> primaries; + + G4PrimaryParticle* primary = 0; + + // Is this primary not created yet and does it have a valid generator status? + if (_primaryMap.count(mcp) == 0 && (mcp->getGeneratorStatus() == 1 || mcp->getGeneratorStatus() == 2)) { + + // Create the primary particle from the MCParticle's information. + primary = new G4PrimaryParticle(); + primary->SetPDGcode(mcp->getPDG()); + primary->SetCharge(mcp->getCharge()); + primary->SetMass(mcp->getMass() * GeV); + const double* p = mcp->getMomentum(); + primary->SetMomentum(p[0] * GeV, p[1] * GeV, p[2] * GeV); + + // Set the proper time by subtracting from daughter's time. + if (mcp->getDaughters().size() > 0) { + MCParticle* dp = mcp->getDaughters()[0]; + double properTime = fabs((dp->getTime() - mcp->getTime()) * mcp->getMass()) / mcp->getEnergy(); +#ifdef SLIC_LOG + log() << LOG::debug << "proper time set to " << properTime << LOG::done; +#endif + primary->SetProperTime(mcp->getTime() * ns); + } + + // Map primary to MCParticle. +#ifdef SLIC_LOG + log() << LOG::debug << "mapping MCParticle " << mcp << " to primary " << primary << LOG::done; +#endif + _primaryMap[mcp] = primary; + + // Map MCParticle to primary. + _mcpMap[primary] = mcp; + + if (parent != 0) { +#ifdef SLIC_LOG + log() << LOG::debug << "setting parent primary on daughter" << LOG::done; +#endif + parent->SetDaughter(primary); + } + + primaries.insert(primary); + } + + for (int i = 0; i < mcp->getDaughters().size(); i++) { +#ifdef SLIC_LOG + log() << LOG::debug << "creating primary for dau particle " << i << LOG::done; +#endif + std::set<G4PrimaryParticle*> daughters = createPrimary(primary, mcp->getDaughters()[i]); +#ifdef SLIC_LOG + log() << LOG::debug << "created " << daughters.size() << " daughter primaries" << LOG::done; +#endif + + primaries.insert(daughters.begin(), daughters.end()); + } +#ifdef SLIC_LOG + log().getOutputStream().flush(); +#endif + return primaries; +} + +G4PrimaryVertex* MCParticleManager::createVertex(MCParticle* mcp) { + + // Get the particle's origin. + const double* particleVertex = mcp->getVertex(); + G4ThreeVector particlePosition(particleVertex[0], particleVertex[1], particleVertex[2]); + + // Get the particle's time. + G4double particleTime = mcp->getTime(); + + // Create a new vertex for this particle. +#ifdef SLIC_LOG + log() << LOG::debug << "creating vertex at position " << particlePosition << " with time " << particleTime << LOG::done; +#endif + G4PrimaryVertex* vertex = new G4PrimaryVertex(particlePosition, particleTime); + + return vertex; } void MCParticleManager::applyLorentzTransformation(LCCollection* particles, const G4double alpha) { - if (alpha == 0) + if (alpha == 0) { return; // nothing to do + } //G4cout << "Applying Lorentz Transformation angle: " << alpha << G4endl; @@ -206,7 +224,6 @@ // after the transformation (boost in x-direction) pPrime[0] = betagamma * sqrt(sqr(p[0]) + sqr(p[1]) + sqr(p[2]) + sqr(m)) + gamma * p[0]; - pPrime[1] = p[1]; pPrime[2] = p[2]; @@ -223,9 +240,23 @@ if (rms != 0) { // Generate smeared Z position. z = G4RandGauss::shoot(0, rms/mm); - G4cout << "Smeared Z position: " << z << G4endl; + //G4cout << "Smeared Z position: " << z << G4endl; } return z; } -}; +bool MCParticleManager::isDaughter(G4PrimaryParticle* particle, const std::set<G4PrimaryParticle*>& primaries) { + for (std::set<G4PrimaryParticle*>::iterator it = primaries.begin(); it != primaries.end(); it++) { + G4PrimaryParticle* dau = (*it)->GetDaughter(); + while (dau != 0) { + if (dau == particle) { + return true; + } + dau = dau->GetNext(); + } + } + return false; +} + +} +; ######################################################################## Use REPLY-ALL to reply to list To unsubscribe from the LCDET-SVN list, click the following link: https://listserv.slac.stanford.edu/cgi-bin/wa?SUBED1=LCDET-SVN&A=1