Print

Print


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