Commit in projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util on MAIN
MergeEventTools.java+311added 2901
MergeEventsDriver.java+119added 2901
+430
2 added files
import Driver for event merging

projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util
MergeEventTools.java added at 2901
--- projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util/MergeEventTools.java	                        (rev 0)
+++ projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util/MergeEventTools.java	2014-01-23 17:10:40 UTC (rev 2901)
@@ -0,0 +1,311 @@
+package org.lcsim.util;
+
+import hep.physics.particle.properties.ParticleType;
+import hep.physics.vec.BasicHep3Vector;
+import hep.physics.vec.BasicHepLorentzVector;
+import hep.physics.vec.Hep3Vector;
+import hep.physics.vec.HepLorentzVector;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.lcsim.detector.IDetectorElement;
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.MCParticle;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.event.SimTrackerHit;
+import org.lcsim.event.EventHeader.LCMetaData;
+import org.lcsim.event.base.BaseMCParticle;
+import org.lcsim.event.base.BaseSimCalorimeterHit;
+import org.lcsim.event.base.BaseSimTrackerHit;
+import org.lcsim.lcio.LCIOConstants;
+import org.lcsim.lcio.LCIOUtil;
+
+
+/**
+ * Class with helper methods for event merging.
+ * 
+ * @author <a href="mailto:[log in to unmask]">Christian Grefe</a>
+ */
+public class MergeEventTools {
+
+	/**
+	 * Merge two events. The first event will contain both events afterwards.
+	 * @param event the event which have the other event added
+	 * @param mergeEvent the event to be merged with the first event
+	 */
+	static public void mergeEvents(EventHeader event, EventHeader mergeEvent) {
+		mergeEvents(event, mergeEvent, new ArrayList<String>(), new HashMap<String, Map<Long,SimCalorimeterHit>>());
+	}
+	
+	/**
+	 * Merge two events. The first event will contain both events afterwards. Collections can be ignored.
+	 * @param event the event which have the other event added
+	 * @param mergeEvent the event to be merged with the first event
+	 * @param ignoreCollections list of collection names that will not be merged
+	 */
+	static public void mergeEvents(EventHeader event, EventHeader mergeEvent, Collection<String> ignoreCollections) {
+		mergeEvents(event, mergeEvent, ignoreCollections, new HashMap<String, Map<Long,SimCalorimeterHit>>());
+	}
+	
+	/**
+	 * Merge two events. The first event will contain both events afterwards. Collections can be ignored. A map holding maps of cell IDs to sim calorimeter hits is used to avoid
+	 * that this information has to be obtained again if this method is called multiple times on the same event.
+	 * @param event the event which have the other event added
+	 * @param mergeEvent the event to be merged with the first event
+	 * @param ignoreCollections list of collection names that will not be merged
+	 * @param caloHitMaps map of collection names to maps of cell IDs to SimCalorimeterHits used to identify which cells require merging
+	 */
+	static public void mergeEvents(EventHeader event, EventHeader mergeEvent, Collection<String> ignoreCollections, Map<String, Map<Long, SimCalorimeterHit>> caloHitMaps) {
+		Collection<LCMetaData> mergeMetaDataList = mergeEvent.getMetaData();
+		// we need to have a single map of mc particles to their copies to ensure that all MCParticle references point to the same instance
+		Map<MCParticle, MCParticle> mcParticleMap = new HashMap<MCParticle, MCParticle>();
+		for (LCMetaData mergeMetaData : mergeMetaDataList) {
+			String collectionName = mergeMetaData.getName();
+			if (ignoreCollections.contains(collectionName)) {
+				continue;
+			}
+			Class collectionType = mergeMetaData.getType();
+			if (mergeEvent.get(collectionType, collectionName).isEmpty()) {
+				continue;
+			}
+			LCMetaData metaData = event.getMetaData((List) event.get(collectionName));
+			if (collectionType.isAssignableFrom(MCParticle.class)) {
+				mergeMCParticleCollections(metaData, mergeMetaData, mcParticleMap);
+			} else if (collectionType.isAssignableFrom(SimTrackerHit.class)) {
+				mergeSimTrackerHitCollections(metaData, mergeMetaData, mcParticleMap);
+			} else if (collectionType.isAssignableFrom(SimCalorimeterHit.class)) {
+				if (!caloHitMaps.containsKey(collectionName)) {
+					Map<Long, SimCalorimeterHit> hitMap = new HashMap<Long, SimCalorimeterHit>();
+					for (SimCalorimeterHit hit : event.get(SimCalorimeterHit.class, collectionName)) {
+						hitMap.put(hit.getCellID(), hit);
+					}
+					caloHitMaps.put(metaData.getName(), hitMap);
+				}
+				mergeSimCalorimeterHitCollections(metaData, mergeMetaData, mcParticleMap, caloHitMaps.get(collectionName));
+			}
+		}
+	}
+	
+	/**
+	 * Merge two MCParticle collections. The first one will contain both collections afterwards. All MCParticles are deep copied
+	 * to allow for garbage collection.
+	 * @param metaData meta data of the first collection
+	 * @param mergeMetaData meta data of the second collection
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 */
+	static public void mergeMCParticleCollections(LCMetaData metaData, LCMetaData mergeMetaData, Map<MCParticle, MCParticle> mcParticleMap) {
+		String collectionName = mergeMetaData.getName();
+		List<MCParticle> mcParticles = metaData.getEvent().get(MCParticle.class, collectionName);
+		List<MCParticle> mergeMcParticles = mergeMetaData.getEvent().get(MCParticle.class, collectionName);
+		for (MCParticle mcParticle : mergeMcParticles) {
+			mcParticles.add(getMcParticleCopy(mcParticle, mcParticleMap));
+		}
+	}
+	
+	/**
+	 * Merge two SimTrackerHit collections. The first one will contain both collections afterwards. All SimTrackerHits are deep copied
+	 * to allow for garbage collection. Similarly, the MCParticles referenced by the SimTrackerHits are copied.
+	 * @param metaData meta data of the first collection
+	 * @param mergeMetaData meta data of the second collection
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 */
+	static public void mergeSimTrackerHitCollections(LCMetaData metaData, LCMetaData mergeMetaData, Map<MCParticle, MCParticle> mcParticleMap) {
+		String collectionName = mergeMetaData.getName();
+		List<SimTrackerHit> trackerHits = metaData.getEvent().get(SimTrackerHit.class, collectionName);
+		List<SimTrackerHit> mergeTrackerHits = mergeMetaData.getEvent().get(SimTrackerHit.class, collectionName);
+		for (SimTrackerHit hit : mergeTrackerHits) {
+			trackerHits.add(copySimTrackerHit(hit, metaData, mcParticleMap));
+		}
+	}
+	
+	/**
+	 * Merge two SimCalorimeterHit collections. The first one will contain both collections afterwards. All SimCalorimeterHits are deep copied
+	 * to allow for garbage collection. Similarly, the MCParticles referenced by the SimCalorimeterHits are copied.
+	 * @param metaData meta data of the first collection
+	 * @param mergeMetaData meta data of the second collection
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 */
+	static public void mergeSimCalorimeterHitCollections(LCMetaData metaData, LCMetaData mergeMetaData, Map<MCParticle, MCParticle> mcParticleMap, Map<Long, SimCalorimeterHit> caloHitMap) {
+		String collectionName = mergeMetaData.getName();
+		List<SimCalorimeterHit> caloHits = metaData.getEvent().get(SimCalorimeterHit.class, collectionName);
+		List<SimCalorimeterHit> mergeCaloHits = mergeMetaData.getEvent().get(SimCalorimeterHit.class, collectionName);
+		for (SimCalorimeterHit caloHit : mergeCaloHits) {
+			long cellID = caloHit.getCellID();
+			if (caloHitMap.containsKey(cellID)) {
+				SimCalorimeterHit hit = caloHitMap.get(cellID);
+				caloHit = copySimCalorimeterHit(caloHit, metaData, mcParticleMap);
+				SimCalorimeterHit mergedHit = mergeSimCalorimeterHits(hit, caloHit);
+				caloHits.remove(hit);
+				caloHitMap.put(cellID, mergedHit);
+				caloHits.add(mergedHit);
+			} else {
+				SimCalorimeterHit caloHitCopy = copySimCalorimeterHit(caloHit, metaData, mcParticleMap); 
+				caloHitMap.put(cellID, caloHitCopy);
+				caloHits.add(caloHitCopy);
+			}
+		}
+	}
+
+	/**
+	 * Creates a deep copy of an MCParticle.
+	 * @param mcParticle the particle to be copied
+	 * @return the copied MCParticle
+	 */
+	static public MCParticle copyMcParticle(MCParticle mcParticle) {
+		Hep3Vector origin = new BasicHep3Vector(mcParticle.getOriginX(), mcParticle.getOriginY(), mcParticle.getOriginZ());
+		HepLorentzVector p = new BasicHepLorentzVector(mcParticle.getEnergy(), new double[] {mcParticle.getPX(), mcParticle.getPY(), mcParticle.getPZ()});
+		ParticleType ptype = mcParticle.getType().getParticlePropertyProvider().get(mcParticle.getPDGID());
+		int status = mcParticle.getGeneratorStatus();
+		double time = mcParticle.getProductionTime();
+		BaseMCParticle copyMcP = new BaseMCParticle(origin, p, ptype, status, time);
+		// override the mass and charge from the particle type to prevent unknown particle exceptions
+		copyMcP.setMass(mcParticle.getMass());
+		copyMcP.setCharge(mcParticle.getCharge());
+		copyMcP.setSimulatorStatus(mcParticle.getSimulatorStatus().getValue());
+		return copyMcP;
+	}
+	
+	/**
+	 * Helper method to make a proper deep copy of an MCParticle and all its ancestors. A map between the original
+	 * particle and can be used to ensure that all references to the original particle use the same copy.
+	 * @param mcParticle the particle to be cpoied
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 * @return the copied MCParticle
+	 */
+	static public MCParticle getMcParticleCopy(MCParticle mcParticle, Map<MCParticle, MCParticle> mcParticleMap) {
+		if (!mcParticleMap.containsKey(mcParticle)) {
+			MCParticle mcParticleCopy = copyMcParticle(mcParticle);
+			mcParticleMap.put(mcParticle, mcParticleCopy);
+			for (MCParticle parent : mcParticle.getParents()) {
+				MCParticle parentCopy = getMcParticleCopy(parent, mcParticleMap);
+				((BaseMCParticle) parentCopy).addDaughter(mcParticleCopy);
+			}
+		}
+		return mcParticleMap.get(mcParticle);
+	}
+	
+	/**
+	 * Creates a deep copy of a SimTrackerHit and assigns the given meta data. The corresponding MCParticles are also copied if they are not present in the map,
+	 * otherwise the reference is updated to use the copy provided by the map.
+	 * @param hit the original hit
+	 * @param metaData the new meta data
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 * @return the copied hit
+	 */
+	static public SimTrackerHit copySimTrackerHit(SimTrackerHit hit, LCMetaData metaData, Map<MCParticle, MCParticle> mcParticleMap) {
+    	double[] position = new double[3];
+    	double[] momentum = new double[3];
+    	double[] hitp = hit.getPosition();
+    	double[] hitm = hit.getMomentum();
+    	for (int i = 0; i != 3; i++ ) {
+    		position[i] = hitp[i];
+    		momentum[i] = hitm[i];
+    	}
+    	double dEdx = hit.getdEdx();
+    	double pathLength = hit.getPathLength();
+    	double time = hit.getTime();
+    	int cellID = hit.getCellID();
+    	MCParticle mcParticle = getMcParticleCopy(hit.getMCParticle(), mcParticleMap);
+    	IDetectorElement de = hit.getDetectorElement();
+    	
+		return new BaseSimTrackerHit(position, dEdx, momentum, pathLength, time, cellID, mcParticle, metaData, de);
+	}
+	
+	/**
+	 * Creates a deep copy of a SimCalorimeterHit and assigns the given meta data. The corresponding MCParticles are also copied if they are not present in the map,
+	 * otherwise the reference is updated to use the copy provided by the map.
+	 * @param hit the original hit
+	 * @param metaData the new meta data
+	 * @param mcParticleMap map to store relation between the original MCParticles and their copies required to ensure consistency in relations to that MCParticle
+	 * @return the copied hit
+	 */
+	static public SimCalorimeterHit copySimCalorimeterHit(SimCalorimeterHit hit, LCMetaData metaData, Map<MCParticle, MCParticle> mcParticleMap) {
+		long id = hit.getCellID();
+		double rawEnergy = hit.getRawEnergy();
+		double time = hit.getTime();
+		int nMCP = hit.getMCParticleCount();
+		Object[] mcparts = new Object[nMCP];
+		float[] energies = new float[nMCP];
+		float[] times = new float[nMCP];
+		int[] pdgs = null;
+		List<float[]> steps = new ArrayList<float[]>();
+		boolean hasPDG = LCIOUtil.bitTest(metaData.getFlags(),LCIOConstants.CHBIT_PDG);
+		if (hasPDG) {
+			pdgs = new int[nMCP];
+		}
+		// fill arrays with values from hit
+		for (int i = 0; i != nMCP; i++) {
+			mcparts[i] = getMcParticleCopy(hit.getMCParticle(i), mcParticleMap);
+			energies[i] = (float)hit.getContributedEnergy(i);
+			times[i] = (float)hit.getContributedTime(i);
+			if (hasPDG){
+				pdgs[i] = hit.getPDG(i);
+				steps.add(hit.getStepPosition(i));
+			}
+		}
+		
+		BaseSimCalorimeterHit copyHit = new BaseSimCalorimeterHit(id, rawEnergy, time, mcparts, energies, times, pdgs, steps);
+		//copyHit.setDetectorElement(hit.getDetectorElement());
+		copyHit.setMetaData(metaData);
+		
+		return copyHit;
+	}
+	
+	/**
+	 * Merges two SimCalorimeterHits that occupy the same cell
+	 * @param hit the first hit to be merged
+	 * @param mergeHit the second hit to be merged
+	 * @return the combined calorimeter hit
+	 */
+	static public SimCalorimeterHit mergeSimCalorimeterHits(SimCalorimeterHit hit, SimCalorimeterHit mergeHit) {
+		int nMcpHit = hit.getMCParticleCount();
+		int nMcpMergeHit = mergeHit.getMCParticleCount();
+		int nMcp = nMcpHit + nMcpMergeHit;
+		// arrays of mc particle contributions to the hit
+		Object[] mcpList = new Object[nMcp];
+		float[] eneList = new float[nMcp];
+		float[] timeList = new float[nMcp];
+		int[] pdgList = null;
+		LCMetaData metaData = hit.getMetaData();
+		boolean hasPDG = LCIOUtil.bitTest(metaData.getFlags(),LCIOConstants.CHBIT_PDG);
+		if (hasPDG) {
+			pdgList = new int[nMcp];
+		}
+		List<float[]> steps = new ArrayList<float[]>();
+		double rawEnergy = 0.;
+		// fill arrays with values from hit
+		for (int i = 0; i != nMcpHit; i++) {
+			mcpList[i] = hit.getMCParticle(i);
+			eneList[i] = (float) hit.getContributedEnergy(i);
+			timeList[i] = (float) hit.getContributedTime(i);
+			if (hasPDG) {
+				pdgList[i] = hit.getPDG(i);
+				steps.add(hit.getStepPosition(i));
+			}
+			rawEnergy += eneList[i];
+		}
+		// add values of overlay hit
+		for (int i = 0; i != nMcpMergeHit; i++) {
+			int j = nMcpHit + i;
+	    	mcpList[j] = mergeHit.getMCParticle(i);
+			eneList[j] = (float) mergeHit.getContributedEnergy(i);
+			timeList[j] = (float) mergeHit.getContributedTime(i);
+			if (hasPDG) {
+				pdgList[j] = mergeHit.getPDG(i);
+				steps.add(mergeHit.getStepPosition(i));
+			}
+			rawEnergy += eneList[j];
+		}
+		// need to set time to 0 so it is recalculated from the timeList
+		SimCalorimeterHit mergedHit = new BaseSimCalorimeterHit(hit.getCellID(),
+				rawEnergy, 0., mcpList, eneList, timeList, pdgList, steps);
+		//mergedHit.setDetectorElement(oldHit.getDetectorElement());
+		mergedHit.setMetaData(metaData);
+		return mergedHit;
+	}
+	
+}

projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util
MergeEventsDriver.java added at 2901
--- projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util/MergeEventsDriver.java	                        (rev 0)
+++ projects/lcsim/trunk/recon-drivers/src/main/java/org/lcsim/util/MergeEventsDriver.java	2014-01-23 17:10:40 UTC (rev 2901)
@@ -0,0 +1,119 @@
+package org.lcsim.util;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.lcsim.event.EventHeader;
+import org.lcsim.event.SimCalorimeterHit;
+import org.lcsim.lcio.LCIOWriter;
+
+/**
+ * Driver to merge multiple consecutive events into a single event.
+ * No Driver should be run after this one, since it will be seeing partially merged events.
+ *
+ * @author <a href="mailto:[log in to unmask]">Christian Grefe</a>
+ */
+public class MergeEventsDriver extends Driver {
+	
+	protected int nEvts;
+	protected String outputFile;
+	protected EventHeader currentEvent;
+	protected int currentEventNumber;
+	protected LCIOWriter writer;
+	protected Collection<String> ignoreCollections;
+	protected boolean writeOnlyFullEvents;
+	protected Map<String, Map<Long, SimCalorimeterHit>> caloHitMaps;
+	
+	public MergeEventsDriver() {
+		nEvts = 1;
+		ignoreCollections = new ArrayList<String>();
+		writeOnlyFullEvents = false;
+	}
+	
+	/**
+	 * Number of events merged into one event. A negative number will merge all events
+	 * into a single event.
+	 * @param nEvts number of events
+	 */
+	public void setNumberOfEvents(int nEvts) {
+		this.nEvts = nEvts;
+	}
+	
+	/**
+	 * Decides if an event at the end of the sample which has less than the desired number
+	 * of events is written to the output file
+	 * @param writeOnlyFullEvents
+	 */
+	public void setWriteOnlyFullEvents(boolean writeOnlyFullEvents) {
+		this.writeOnlyFullEvents = writeOnlyFullEvents;
+	}
+	
+	/**
+	 * Defines the output file
+	 * @param outputFile
+	 */
+	public void setOutputFile(String outputFile) {
+		this.outputFile = outputFile;
+	}
+	
+	public void setIgnoreCollection(String collectionName) {
+		this.ignoreCollections.add(collectionName);
+	}
+	
+	public void setIgnoreCollections(String[] collectionNames) {
+		this.ignoreCollections.addAll(Arrays.asList(collectionNames));
+	}
+	
+	@Override
+	protected void startOfData() {
+		try {
+			writer = new LCIOWriter(outputFile);
+		} catch (IOException e) {
+			throw new RuntimeException(e.getMessage());
+		}
+		writer.addAllIgnore(ignoreCollections);
+		// map to store the cell IDs of all calorimeter hits to decide which hits have to be merged.
+		caloHitMaps = new HashMap<String, Map<Long,SimCalorimeterHit>>();
+		currentEventNumber = 0;
+	};
+	
+	@Override
+	protected void process(EventHeader event) {
+		if (currentEventNumber == 0 && nEvts != 1) {
+			currentEvent = event;
+		} else if (nEvts > 0 && currentEventNumber % nEvts == 0) {
+			writeCurrentEvent();
+			currentEvent = event;
+			caloHitMaps.clear();
+		} else {
+			MergeEventTools.mergeEvents(currentEvent, event, ignoreCollections, caloHitMaps);
+		}
+		currentEventNumber++;
+	}
+	
+	@Override
+	protected void endOfData() {
+		if (!writeOnlyFullEvents || (nEvts > 0 && currentEventNumber % nEvts == 0)) {
+			writeCurrentEvent();
+		}
+		try {
+			writer.close();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	protected void writeCurrentEvent() {
+		if (currentEvent != null) {
+			try {
+				writer.write(currentEvent);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+}
SVNspam 0.1


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