Author: [log in to unmask]
Date: Wed Jan 7 17:03:40 2015
New Revision: 3479
Log:
Overhaul of BaseCluster class and related changes.
Modified:
projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/Cluster.java
projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/AbstractClusterPropertyCalculator.java
projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/BaseCluster.java
projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/ClusterPropertyCalculator.java
projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/TensorClusterPropertyCalculator.java
Modified: projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/Cluster.java
=============================================================================
--- projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/Cluster.java (original)
+++ projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/Cluster.java Wed Jan 7 17:03:40 2015
@@ -1,10 +1,8 @@
package org.lcsim.event;
import java.util.List;
-/** The LCIO cluster.
- *
- * @author gaede
- * @version $Id: Cluster.java,v 1.6 2011/11/09 22:50:28 jeremy Exp $
+/**
+ * The LCIO cluster interface.
*/
public interface Cluster
@@ -14,6 +12,8 @@
* elsewhere, e.g. in the run header. Bits 16-31 are used internally.
*/
public int getType();
+
+ public int getParticleId();
/** Energy of the cluster.
*/
Modified: projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/AbstractClusterPropertyCalculator.java
=============================================================================
--- projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/AbstractClusterPropertyCalculator.java (original)
+++ projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/AbstractClusterPropertyCalculator.java Wed Jan 7 17:03:40 2015
@@ -3,6 +3,7 @@
import java.util.List;
import org.lcsim.event.CalorimeterHit;
+import org.lcsim.event.Cluster;
/**
* An abstract implementation of {@link ClusterPropertyCalculator}.
@@ -11,15 +12,30 @@
*/
public abstract class AbstractClusterPropertyCalculator implements ClusterPropertyCalculator {
- protected double[] position;
- protected double[] positionError;
+ protected double[] position = new double[3];
+ protected double[] positionError = new double[6];
protected double iphi;
protected double itheta;
- protected double[] directionError;
- protected double[] shapeParameters;
+ protected double[] directionError = new double[6];
+ protected double[] shapeParameters = new double[6];
+
+ @Override
+ public void calculateProperties(List<CalorimeterHit> hits) {
+ }
@Override
- public abstract void calculateProperties(List<CalorimeterHit> hits);
+ public void calculateProperties(Cluster cluster) {
+ calculateProperties(cluster.getCalorimeterHits());
+ }
+
+ protected void reset() {
+ position = new double[3];
+ positionError = new double[6];
+ iphi = 0;
+ itheta = 0;
+ directionError = new double[6];
+ shapeParameters = new double[6];
+ }
@Override
public double[] getPosition() {
@@ -42,7 +58,7 @@
}
@Override
- public double[] getDirectionError() {
+ public double[] getDirectionError() {
return directionError;
}
Modified: projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/BaseCluster.java
=============================================================================
--- projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/BaseCluster.java (original)
+++ projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/BaseCluster.java Wed Jan 7 17:03:40 2015
@@ -7,385 +7,525 @@
import org.lcsim.event.CalorimeterHit;
import org.lcsim.event.Cluster;
-import org.lcsim.event.MCParticle;
-import org.lcsim.event.SimCalorimeterHit;
-import org.lcsim.geometry.IDDecoder;
-import org.lcsim.geometry.compact.Subdetector;
-
/**
- * Default implementation of Cluster Interface for Simulation
- *
- * @author cassell
+ * <p>
+ * This is a concrete implementation of the {@link org.lcsim.event.Cluster} LCIO interface.
+ * <p>
+ * This version is an overhaul of the previous base class, with the following changes:
+ * <ul>
+ * <li>Added several constructors with argument lists, including one that is fully qualified and another
+ * that takes a list of hits only.</li>
+ * <li>Removed the prior implementation of subdetector energies in favor of a simple set method.
+ * (This part of the API is basically unused anyways.)</li>
+ * <li>Added set methods for all class variables, where they were missing.</li>
+ * <li>Added access to particle ID based on the official API.</li>
+ * <li>Added a few utility methods for adding lists of hits and clusters.</li>
+ * <li>Added a method for setting a hit contribution that is different from the corrected energy.</li>
+ * <li>Simplified the {@link #calculateProperties()} method so it doesn't do a bunch of array copies.</li>
+ * </ul>
+ *
+ * @see org.lcsim.event.Cluster
+ * @see org.lcsim.event.CalorimeterHit
+ * @see org.lcsim.event.base.ClusterPropertyCalculator
+ * @see org.lcsim.event.base.TensorClusterPropertyCalculator
+ *
+ * @author Jeremy McCormick <[log in to unmask]>
+ * @author Norman Graf <[log in to unmask]>
+ *
*/
-public class BaseCluster implements Cluster
-{
+public class BaseCluster implements Cluster {
+
protected List<CalorimeterHit> hits = new ArrayList<CalorimeterHit>();
+ protected List<Double> hitContributions = new ArrayList<Double>();
protected List<Cluster> clusters = new ArrayList<Cluster>();
- protected List<Subdetector> detectors = new ArrayList<Subdetector>();
-// protected double raw_energy;
- protected double corrected_energy;
+
+ protected double energy;
protected double energyError;
- protected double[] subdetector_raw_energies = new double[10];
- protected double[] subdetector_corrected_energies = new double[10];
- protected List<Double> hit_energies = new ArrayList<Double>();
- protected ClusterPropertyCalculator cluster_property_calculator = new TensorClusterPropertyCalculator();
- protected boolean needsPropertyCalculation = true;
- protected double[] position;
- protected double[] positionError;
+
+ protected double[] position = new double[3];
+ protected double[] positionError = new double[6];
+
protected double iphi;
protected double itheta;
- protected double[] directionError;
+
+ protected double[] directionError = new double[6];
protected double[] shapeParameters;
-
- public BaseCluster()
- {
-// raw_energy = 0.;
- corrected_energy = 0.;
- for(int i=0;i<10;i++)
- {
- subdetector_raw_energies[i] = 0.;
- subdetector_corrected_energies[i] = 0.;
- }
- position = new double[3];
- positionError = new double[6];
- directionError = new double[6];
- }
-
- /**
- * Add a CalorimeterHit to the cluster
- */
- public void addHit(CalorimeterHit hit)
- {
- hits.add(hit);
- double hre = hit.getRawEnergy();
-// raw_energy += hre;
- double hce = hit.getCorrectedEnergy();
- IDDecoder idc = hit.getIDDecoder();
- idc.setID(hit.getCellID());
- // Replace call to getValue("system").
- // -- 2007-04-12 Jeremy McCormick
- int detector_index = idc.getSystemID();
- if((detector_index > 9 )|(detector_index < 0))detector_index = 0;
- corrected_energy += hce;
- hit_energies.add(hce);
- subdetector_raw_energies[detector_index] += hre;
- subdetector_corrected_energies[detector_index] += hce;
+
+ protected double[] subdetectorEnergies = new double[0];
+
+ protected int type;
+ protected int pid;
+
+ protected ClusterPropertyCalculator calc = new TensorClusterPropertyCalculator();
+ protected boolean needsPropertyCalculation = true;
+
+ /**
+ * The no argument constructor.
+ */
+ public BaseCluster() {
+ }
+
+ /**
+ * Almost fully qualified constructor, if the cluster's properties are already calculated.
+ * The energy given here will override the value calculated from the hits. If this is not
+ * desired, then another constructor should be used instead. This constructor does not
+ * allow setting hit contributions that are different from the hit energies.
+ * @param hits The list of hits.
+ * @param energy The total energy.
+ * @param energyError The energy error.
+ * @param position The position.
+ * @param positionError The position error.
+ * @param iphi The intrinsic phi.
+ * @param itheta The intrinsic theta.
+ * @param directionError The direction error.
+ * @param shapeParameters The shape parameters.
+ */
+ public BaseCluster(
+ List<CalorimeterHit> hits,
+ double energy,
+ double energyError,
+ double[] position,
+ double[] positionError,
+ double iphi,
+ double itheta,
+ double[] directionError,
+ double[] shapeParameters,
+ int type,
+ int pid) {
+
+ addHits(hits);
+
+ // This will override the energy calculated from the hits, by design!
+ this.energy = energy;
+ this.energyError = energyError;
+
+ this.position = position;
+ this.positionError = positionError;
+
+ this.iphi = iphi;
+ this.itheta = itheta;
+
+ this.directionError = directionError;
+ this.shapeParameters = shapeParameters;
+
+ this.type = type;
+ this.pid = pid;
+
+ this.needsPropertyCalculation = false;
+ }
+
+ /**
+ * Basic constructor that takes a list of hits.
+ * It will apply the default energy calculation.
+ * @param hits The list of CalorimeterHits.
+ */
+ public BaseCluster(List<CalorimeterHit> hits) {
+ addHits(hits);
+ }
+
+ /**
+ *****************************************************
+ * Implementation of get methods from the interface. *
+ *****************************************************
+ */
+
+ /**
+ * Get the list of CalorimeterHits of this cluster.
+ * The hits are not necessarily unique in the list.
+ * @return The hits comprising the cluster.
+ */
+ public List<CalorimeterHit> getCalorimeterHits() {
+ return hits;
+ }
+
+ /**
+ * Get the clusters that are part of this cluster.
+ * @return The clusters comprising the cluster.
+ */
+ public List<Cluster> getClusters() {
+ return clusters;
+ }
+
+ /**
+ * Get the energy of the cluster, which by default will be the
+ * sum of the CalorimeterHit corrected energy values.
+ * @return The energy of the cluster.
+ */
+ public double getEnergy() {
+ return energy;
+ }
+
+ /**
+ * Get the energy error.
+ * @return The energy error.
+ */
+ public double getEnergyError() {
+ return energyError;
+ }
+
+ /**
+ * Get the individual hit contribution energies.
+ * This should be an array of the same size as the hit list.
+ * By default this array contains the hit's corrected energies,
+ * but the contributions may be set to different values
+ * on a per hit basis using the {@link #addHit(CalorimeterHit, double)}
+ * method.
+ * @return The individual hit contribution energies.
+ */
+ public double[] getHitContributions() {
+ double[] arrayCopy = new double[hitContributions.size()];
+ for (int i = 0; i < hitContributions.size(); i++) {
+ arrayCopy[i] = hitContributions.get(i);
+ }
+ return arrayCopy;
+ }
+
+ /**
+ * Get the list of subdetector energy contributions.
+ * The ordering and meaning of this array is unspecified by this class.
+ * @return The list of subdetector energy contributions.
+ */
+ public double[] getSubdetectorEnergies() {
+ return subdetectorEnergies;
+ }
+
+ /**
+ * Get a value defining the type of this cluster.
+ * @return The type of this cluster.
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Get the number of hits in the cluster, including hits in sub-clusters.
+ * Hits belonging to more than one cluster are counted once.
+ * @return The size of the cluster.
+ */
+ public int getSize() {
+ Set<CalorimeterHit> hitSet = new HashSet<CalorimeterHit>(this.hits);
+ for (Cluster cluster : clusters) {
+ hitSet.addAll(cluster.getCalorimeterHits());
+ }
+ int size = hitSet.size();
+ hitSet.clear();
+ return size;
+ }
+
+ /**
+ * Get the intrinsic phi direction of the cluster.
+ * @return The intrinsic phi direction of the cluster.
+ */
+ public double getIPhi() {
+ checkCalculateProperties();
+ return iphi;
+ }
+
+ /**
+ * Get the intrinsic theta direction of the cluster.
+ * @return The intrinsic theta direction of the cluster.
+ */
+ public double getITheta() {
+ checkCalculateProperties();
+ return itheta;
+ }
+
+ /**
+ * Get the direction error of the cluster as a double array of size 6.
+ * @return The direction error of the cluster.
+ */
+ public double[] getDirectionError() {
+ checkCalculateProperties();
+ return directionError;
+ }
+
+ /**
+ * Get the position of the cluster as a double array of size 3.
+ * @return The position of the cluster.
+ */
+ public double[] getPosition() {
+ checkCalculateProperties();
+ return position;
+ }
+
+ /**
+ * Get the position error of the cluster as a double array of size 6.
+ * @return The position error of the cluster.
+ */
+ public double[] getPositionError() {
+ checkCalculateProperties();
+ return positionError;
+ }
+
+ /**
+ * Get the shape parameters of the cluster as a double array of unspecified size.
+ * @return The shape parameters of the cluster.
+ */
+ public double[] getShape() {
+ checkCalculateProperties();
+ return shapeParameters;
+ }
+
+ /**
+ * Get the PDG ID of the particle hypothesis.
+ * @return The PID.
+ */
+ public int getParticleId() {
+ return pid;
+ }
+
+ /**
+ **********************************
+ * Implementation of set methods. *
+ **********************************
+ */
+
+ /**
+ * Set the position of the cluster.
+ * @param position The position of the cluster.
+ * @throws IllegalArgumentException if array is wrong size.
+ */
+ public void setPosition(double[] position) {
+ if (position.length != 3) {
+ throw new IllegalArgumentException("The position array argument has the wrong length: " + position.length);
+ }
+ this.position = position;
+ }
+
+ /**
+ * Set the position error of the cluster.
+ * @param positionError The position error of the cluster.
+ * @throws IllegalArgumentException if array is wrong size.
+ */
+ public void setPositionError(double[] positionError) {
+ if (positionError.length != 6) {
+ throw new IllegalArgumentException("The positionError array argument has the wrong length: " + position.length);
+ }
+ this.positionError = positionError;
+ }
+
+ /**
+ * Set the intrinsic phi of the cluster.
+ * @param iphi The intrinsic phi of the cluster.
+ */
+ public void setIPhi(double iphi) {
+ this.iphi = iphi;
+ }
+
+ /**
+ * Set the intrinsic theta of the cluster.
+ * @param iphi The intrinsic theta of the cluster.
+ */
+ public void setITheta(double itheta) {
+ this.itheta = itheta;
+ }
+
+ /**
+ * Set the direction error of the cluster.
+ * @param directionError The direction error of the cluster.
+ * @throws IllegalArgumentException if array is wrong size.
+ */
+ public void setDirectionError(double[] directionError) {
+ if (directionError.length != 6) {
+ throw new IllegalArgumentException("The directionError array argument has the wrong length: " + position.length);
+ }
+ this.directionError = directionError;
+ }
+
+ /**
+ * Set the shape parameters of the cluster.
+ * @param shapeParameters The shape parameters.
+ */
+ public void setShapeParameters(double[] shapeParameters) {
+ this.shapeParameters = shapeParameters;
+ }
+
+ /**
+ * Set the type of the cluster.
+ * @param type The type of the cluster.
+ */
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ /**
+ * Get the PDG ID of the particle hypothesis.
+ * @return The PID.
+ */
+ public void setParticleId(int pid) {
+ this.pid = pid;
+ }
+
+ /**
+ * Set a total energy of this cluster, overriding any energy
+ * value that may have been automatically calculated from
+ * hit energies.
+ * @param energy The total energy of this cluster.
+ */
+ public void setEnergy(double energy) {
+ this.energy = energy;
+ }
+
+ /**
+ * Set the error on the energy measurement.
+ * @param energyError The error on the energ measurement.
+ */
+ public void setEnergyError(double energyError) {
+ this.energyError = energyError;
+ }
+
+ /**
+ * Set the subdetector energies.
+ * @param subdetectorEnergies The subdetector energies.
+ */
+ public void setSubdetectorEnergies(double[] subdetectorEnergies) {
+ this.subdetectorEnergies = subdetectorEnergies;
+ }
+
+ /**
+ ****************************************************
+ * Convenience methods for adding hits and clusters *
+ ****************************************************
+ */
+
+ /**
+ * Add a list of hits to the cluster.
+ * @param The list of hits to add.
+ */
+ public void addHits(List<CalorimeterHit> hits) {
+ for (CalorimeterHit hit : hits) {
+ addHit(hit);
+ }
+ }
+
+ /**
+ * Add a list of sub-clusters to the cluster.
+ * @param The list of clusters to add.
+ */
+ public void addClusters(List<Cluster> clusters) {
+ for (Cluster cluster : clusters) {
+ addCluster(cluster);
+ }
+ }
+
+ /**
+ * Add a sub-cluster to the cluster.
+ * @param cluster The cluster to add.
+ */
+ public void addCluster(Cluster cluster) {
+ clusters.add(cluster);
+ List<CalorimeterHit> clusterHits = cluster.getCalorimeterHits();
+ for (int i = 0; i < clusterHits.size(); i++) {
+ hits.add(clusterHits.get(i));
+ hitContributions.add(clusterHits.get(i).getCorrectedEnergy());
+ }
+ energy += cluster.getEnergy();
needsPropertyCalculation = true;
- }
-
- /**
- * Add a CalorimeterHit to the cluster from a cluster
- */
- public void addHitFromCluster(CalorimeterHit hit)
- {
- hits.add(hit);
- double hce = hit.getCorrectedEnergy();
- hit_energies.add(hce);
+ }
+
+ /**
+ * Add a hit to the cluster with default energy contribution.
+ * @param hit The hit to add.
+ */
+ public void addHit(CalorimeterHit hit) {
+ addHit(hit, hit.getCorrectedEnergy());
needsPropertyCalculation = true;
}
-
- /**
- * Remove a CalorimeterHit from the cluster
- */
- public void removeHit(CalorimeterHit hit)
- {
- int indx = hits.indexOf(hit);
+
+ /**
+ * Add a hit to the cluster with specified energy contribution.
+ * @param hit The hit to add.
+ * @param contribution The energy contribution of the hit [GeV].
+ */
+ public void addHit(CalorimeterHit hit, double contribution) {
+ hits.add(hit);
+ hitContributions.add(contribution);
+ energy += contribution;
+ needsPropertyCalculation = true;
+ }
+
+ /**
+ * Remove a hit from the cluster.
+ * @param hit The hit to remove.
+ */
+ public void removeHit(CalorimeterHit hit) {
+ int index = hits.indexOf(hit);
hits.remove(hit);
- double hre = hit.getRawEnergy();
-// raw_energy -= hre;
- double hce = hit.getCorrectedEnergy();
- IDDecoder idc = hit.getIDDecoder();
- idc.setID(hit.getCellID());
- int detector_index = idc.getSystemID();
- if((detector_index > 9 )|(detector_index < 0))detector_index = 0;
- corrected_energy -= hce;
- hit_energies.remove(indx);
- subdetector_raw_energies[detector_index] -= hre;
- subdetector_corrected_energies[detector_index] -= hce;
+ double hitEnergy = hit.getCorrectedEnergy();
+ energy -= hitEnergy;
+ hitContributions.remove(index);
needsPropertyCalculation = true;
}
- /**
- * Add a Cluster to the cluster
- */
- public void addCluster(Cluster cluster)
- {
- clusters.add(cluster);
- List<CalorimeterHit> chits = cluster.getCalorimeterHits();
- if(chits.size() > 0)
- {
- for(int i=0;i<chits.size();i++)
- {
- addHitFromCluster(chits.get(i));
- }
- needsPropertyCalculation = true;
- }
- corrected_energy += cluster.getEnergy();
- if(cluster instanceof BaseCluster)
- {
- BaseCluster bcl = (BaseCluster) cluster;
-// raw_energy += bcl.getRawEnergy();
- }
- double[] sde = cluster.getSubdetectorEnergies();
- for(int i=0;i<sde.length;i++)
- {
- subdetector_corrected_energies[i] += sde[i];
- subdetector_raw_energies[i] += sde[i];
- }
- }
-
- /**
- * Do an external calculation of Energy and set it
- */
- public void setEnergy(double Energy)
- {
- corrected_energy = Energy;
- }
-
- /**
- * Return the hits comprising the cluster as per interface
- */
- public List<CalorimeterHit> getCalorimeterHits()
- {
- return hits;
- }
-
- /**
- * Return the clusters comprising the cluster as per interface
- */
- public List<Cluster> getClusters()
- {
- return clusters;
- }
-
- /**
- * Return the corrected Energy of the cluster as per interface
- */
- public double getEnergy()
- {
- return corrected_energy;
- }
-
- public double getEnergyError()
- {
- return energyError;
- }
-
- public void setEnergyError(double energyError)
- {
- this.energyError = energyError;
- }
-
- /**
- * Return the corrected energy contribution of each hit
- * comprising the cluster as per interface
- */
- public double[] getHitContributions()
- {
- double[] earray = new double[hit_energies.size()];
- for(int i=0;i<hit_energies.size();i++)
- {
- earray[i] = hit_energies.get(i);
- }
- return earray;
- }
-
- /**
- * Return the phi direction of the cluster as per interface
- */
- public double getIPhi()
- {
- if(needsPropertyCalculation)
- {
+
+ /**
+ **************************************
+ * ClusterPropertyCalculator methods. *
+ **************************************
+ */
+
+ /**
+ * Calculate properties if needs property calculation.
+ */
+ void checkCalculateProperties() {
+ if (needsPropertyCalculation()) {
calculateProperties();
}
- return iphi;
- }
-
- /**
- * Return the theta direction of the cluster as per interface
- */
- public double getITheta()
- {
- if(needsPropertyCalculation)
- {
- calculateProperties();
- }
- return itheta;
- }
-
- /**
- * Return the direction error of the cluster as per interface
- */
- public double[] getDirectionError()
- {
- if(needsPropertyCalculation)
- {
- calculateProperties();
- }
- return directionError;
- }
-
- /**
- * Return the position of the cluster as per interface
- */
- public double[] getPosition()
- {
- if(needsPropertyCalculation)
- {
- calculateProperties();
- }
- return position;
- }
-
- /**
- * Return the position error of the cluster as per interface
- */
- public double[] getPositionError()
- {
- if(needsPropertyCalculation)
- {
- calculateProperties();
- }
- return positionError;
- }
-
- /**
- * Return the shape parameters of the cluster as per interface
- */
- public double[] getShape()
- {
- if(needsPropertyCalculation)
- {
- calculateProperties();
- }
- return shapeParameters;
- }
-
- /**
- * Return the subdetector energy contributions
- * of the cluster as per interface
- */
- public double[] getSubdetectorEnergies()
- {
- return subdetector_corrected_energies;
- }
-
- /**
- * Return a bit mask defining the type of cluster as per interface
- */
- public int getType()
- {
- return 0;
- }
-
-// /**
-// * Return the sum of the raw energies from the hits in the cluster
-// */
-// public double getRawEnergy()
-// {
-// return raw_energy;
-// }
-
- /**
- * Allow for recalculation of cluster properties, or
- * prevent recalculation after adding to cluster
- */
- public void setNeedsPropertyCalculation(boolean tf)
- {
- needsPropertyCalculation = tf;
- }
-
- /**
- * Override the default ClusterPropertyCalculator
- */
- public void setPropertyCalculator(ClusterPropertyCalculator cpc)
- {
- cluster_property_calculator = cpc;
- needsPropertyCalculation = true;
- }
-
- /**
- * Calculate the cluster properties from the hits
- */
- public void calculateProperties()
- {
- cluster_property_calculator.calculateProperties(hits);
- iphi = cluster_property_calculator.getIPhi();
- itheta = cluster_property_calculator.getITheta();
-
- // important: store info locally, not a reference to info in calculator
- double[] tmp = cluster_property_calculator.getPosition();
- for(int i=0; i<3; ++i) position[i] = tmp[i];
-
- double[] posErr = cluster_property_calculator.getPositionError();
- double[] dirErr = cluster_property_calculator.getDirectionError();
- for(int i=0; i<6; ++i) {
- positionError[i] = posErr[i];
- directionError[i] = dirErr[i];
- }
-
- // In general, assume any number of parameters needed
- double[] shapePar = cluster_property_calculator.getShapeParameters();
- shapeParameters = new double[ shapePar.length ];
- for(int i=0; i<shapePar.length; ++i) {
- shapeParameters[i] = shapePar[i];
- }
-
- needsPropertyCalculation = false;
- }
-
- /** Return the hits comprising the cluster, including hits in
- * subclusters, as per interface. Hits belonging to more than one
- * cluster/subcluster should be counted only once.
- */
- public int getSize()
- {
- Set<CalorimeterHit> hitSet = new HashSet<CalorimeterHit>(this.hits);
- for( Cluster clus : clusters )
- {
- hitSet.addAll( clus.getCalorimeterHits() );
- }
-
- // cleanup and return
- int size = hitSet.size();
- hitSet.clear();
- return size;
- }
-
- /**
- * String representation of this object.
- * @return A String representation of this object
- */
- public String toString()
- {
- double[] pos = this.getPosition();
- double rho = Math.sqrt(pos[0]*pos[0]+pos[1]*pos[1]);
- double theta = Math.atan2( rho, pos[2]);
- double phi = Math.atan2( pos[1], pos[0] );
- if(phi<0) phi += 2*Math.PI;
- return "BaseCluster w/ "+this.getSize()+" hits at theta="+theta*180/Math.PI+", phi="+phi*180/Math.PI;
- }
-
- /**
- * Create and return a set of MCParticles from the hits of the cluster.
- * Only looks at SimCalorimeterHits, as CalorimeterHits don't have MC information.
- * @return The set of unique MCParticles associated with this cluster.
- */
- public Set<MCParticle> findUniqueMCParticlesFromHits()
- {
- Set<MCParticle> mcps = new HashSet<MCParticle>();
- for (CalorimeterHit hit : getCalorimeterHits())
- {
- if (hit instanceof SimCalorimeterHit)
- {
- SimCalorimeterHit simhit = (SimCalorimeterHit)hit;
- for (int i=0; i<simhit.getMCParticleCount(); i++)
- {
- mcps.add(simhit.getMCParticle(i));
- }
- }
- }
- return mcps;
+ }
+
+ /**
+ * Set a property calculator for computing position, etc.
+ * @param calc The property calculator.
+ */
+ public void setPropertyCalculator(ClusterPropertyCalculator calc) {
+ this.calc = calc;
+ }
+
+ /**
+ * True if property calculator is set.
+ * @return True if property calculator is set.
+ */
+ public boolean hasPropertyCalculator() {
+ return calc != null;
+ }
+
+ /**
+ * True if cluster is flagged as needed a property calculation.
+ * @return True if cluster needs property calculation.
+ */
+ public boolean needsPropertyCalculation() {
+ return needsPropertyCalculation;
+ }
+
+ /**
+ * Manually set whether the cluster needs property calculation.
+ * @param needsPropertyCalculation Whether the cluster needs property calculation.
+ */
+ public void setNeedsPropertyCalculation(boolean needsPropertyCalculation) {
+ this.needsPropertyCalculation = needsPropertyCalculation;
+ }
+
+ /**
+ *
+ * Calculate the properties of this cluster using the current
+ * <code>ClusterPropertyCalculator</code>. The calculated properties will be
+ * set on the following class variables:<br/>
+ * {@link #position}, {@link #positionError},
+ * {@link #iphi}, {@link #itheta}, {@link #directionError},
+ * and {@link #shapeParameters}. The cluster will then be flagged
+ * as not needing a property calculation in its current state.
+ */
+ public void calculateProperties() {
+ if (!hasPropertyCalculator()) {
+ throw new RuntimeException("No ClusterPropertyCalculator is set on this object.");
+ }
+ calc.calculateProperties(this);
+ setPosition(calc.getPosition());
+ setPositionError(calc.getPositionError());
+ setIPhi(calc.getIPhi());
+ setITheta(calc.getITheta());
+ setDirectionError(calc.getDirectionError());
+ setShapeParameters(calc.getShapeParameters());
+ setNeedsPropertyCalculation(false);
}
}
Modified: projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/ClusterPropertyCalculator.java
=============================================================================
--- projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/ClusterPropertyCalculator.java (original)
+++ projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/ClusterPropertyCalculator.java Wed Jan 7 17:03:40 2015
@@ -1,8 +1,7 @@
package org.lcsim.event.base;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+
import org.lcsim.event.CalorimeterHit;
import org.lcsim.event.Cluster;
@@ -11,41 +10,45 @@
*
* @author cassell
*/
-public interface ClusterPropertyCalculator
-{
+public interface ClusterPropertyCalculator {
- /**
- * Calculate properties from a CalorimeterHit list
- */
- public void calculateProperties(List<CalorimeterHit> hits);
+ /**
+ * Calculate properties from a CalorimeterHit list.
+ */
+ public void calculateProperties(List<CalorimeterHit> hits);
+
+ /**
+ * Calculate properties from a cluster.
+ */
+ public void calculateProperties(Cluster cluster);
- /**
- * Return position
- */
- public double[] getPosition();
-
- /**
- * Return position error
- */
- public double[] getPositionError();
-
- /**
- * Return phi direction
- */
- public double getIPhi();
-
- /**
- * Return theta direction
- */
- public double getITheta();
-
- /**
- * Return direction error
- */
- public double[] getDirectionError();
-
- /**
- * Return shape parameters
- */
- public double[] getShapeParameters();
+ /**
+ * Return position
+ */
+ public double[] getPosition();
+
+ /**
+ * Return position error
+ */
+ public double[] getPositionError();
+
+ /**
+ * Return phi direction
+ */
+ public double getIPhi();
+
+ /**
+ * Return theta direction
+ */
+ public double getITheta();
+
+ /**
+ * Return direction error
+ */
+ public double[] getDirectionError();
+
+ /**
+ * Return shape parameters
+ */
+ public double[] getShapeParameters();
}
Modified: projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/TensorClusterPropertyCalculator.java
=============================================================================
--- projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/TensorClusterPropertyCalculator.java (original)
+++ projects/lcsim/trunk/event-model/src/main/java/org/lcsim/event/base/TensorClusterPropertyCalculator.java Wed Jan 7 17:03:40 2015
@@ -1,26 +1,19 @@
package org.lcsim.event.base;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+
import org.lcsim.event.CalorimeterHit;
import org.lcsim.event.Cluster;
-// import org.lcsim.geometry.CalorimeterIDDecoder;
+
/**
- * Implementation of ClusterPropertyCalculator Interface using
- * inertia Tensor calculation to derive parameters
- *
+ * Implementation of ClusterPropertyCalculator Interface using inertia Tensor calculation
+ * to derive parameters.
+ *
* @author cassell
*/
-public class TensorClusterPropertyCalculator implements ClusterPropertyCalculator
-{
- protected double[] position;
- protected double[] positionError;
- protected double iphi;
- protected double itheta;
- protected double[] directionError;
- protected double[] shapeParameters;
+public class TensorClusterPropertyCalculator extends AbstractClusterPropertyCalculator {
+
protected double[] mm_NE;
protected double[] mm_CE;
protected double[][] mm_PA;
@@ -28,26 +21,30 @@
/**
* Calculate the cluster properties from the hits
*/
- public TensorClusterPropertyCalculator()
- {
- position = new double[3];
- positionError = new double[6];
- iphi = 0.;
- itheta = 0.;
- directionError = new double[6];
- shapeParameters = new double[6];
- }
- public void calculateProperties(List<CalorimeterHit> hits)
- {
+ public TensorClusterPropertyCalculator() {
+ }
+
+ protected void reset() {
+ super.reset();
mm_NE = new double[3];
mm_CE = new double[3];
mm_PA = new double[3][3];
- for(int i=0;i<3;++i)
- {
+ }
+
+ public void calculateProperties(Cluster cluster) {
+ calculateProperties(cluster.getCalorimeterHits());
+ }
+
+ public void calculateProperties(List<CalorimeterHit> hits) {
+
+ reset();
+
+ for (int i = 0; i < 3; ++i) {
mm_NE[i] = 0.;
mm_CE[i] = 0.;
- for(int j=0;j<3;++j)
- {mm_PA[i][j]= 0.;}
+ for (int j = 0; j < 3; ++j) {
+ mm_PA[i][j] = 0.;
+ }
}
double Etot = 0.0;
double Exx = 0.0;
@@ -70,53 +67,51 @@
double M = 0.0;
double Det = 0.0;
int nhits = hits.size();
- for(int i=0;i<hits.size();i++)
- {
+ for (int i = 0; i < hits.size(); i++) {
CalorimeterHit hit = hits.get(i);
- // CalorimeterIDDecoder decoder = hit.getDecoder();
- // decoder.setID(hit.getCellID());
- // double[] pos = new double[3];
- // pos[0] = decoder.getX();
- // pos[1] = decoder.getY();
- // pos[2] = decoder.getZ();
+ // CalorimeterIDDecoder decoder = hit.getDecoder();
+ // decoder.setID(hit.getCellID());
+ // double[] pos = new double[3];
+ // pos[0] = decoder.getX();
+ // pos[1] = decoder.getY();
+ // pos[2] = decoder.getZ();
double[] pos = hit.getPosition();
double E = hit.getCorrectedEnergy();
Etot += E;
- CEx += E*pos[0];
- CEy += E*pos[1];
- CEz += E*pos[2];
- Exx += E*(pos[1]*pos[1] + pos[2]*pos[2]);
- Eyy += E*(pos[0]*pos[0] + pos[2]*pos[2]);
- Ezz += E*(pos[1]*pos[1] + pos[0]*pos[0]);
- Exy -= E*pos[0]*pos[1];
- Eyz -= E*pos[1]*pos[2];
- Exz -= E*pos[0]*pos[2];
- }
- CEx = CEx/Etot;
- CEy = CEy/Etot;
- CEz = CEz/Etot;
- double CErSq = CEx*CEx + CEy*CEy + CEz*CEz;
+ CEx += E * pos[0];
+ CEy += E * pos[1];
+ CEz += E * pos[2];
+ Exx += E * (pos[1] * pos[1] + pos[2] * pos[2]);
+ Eyy += E * (pos[0] * pos[0] + pos[2] * pos[2]);
+ Ezz += E * (pos[1] * pos[1] + pos[0] * pos[0]);
+ Exy -= E * pos[0] * pos[1];
+ Eyz -= E * pos[1] * pos[2];
+ Exz -= E * pos[0] * pos[2];
+ }
+ CEx = CEx / Etot;
+ CEy = CEy / Etot;
+ CEz = CEz / Etot;
+ double CErSq = CEx * CEx + CEy * CEy + CEz * CEz;
CEr = Math.sqrt(CErSq);
// now go to center of energy coords.
- if (nhits > 3 )
- {
- Exx = Exx - Etot*(CErSq - CEx*CEx);
- Eyy = Eyy - Etot*(CErSq - CEy*CEy);
- Ezz = Ezz - Etot*(CErSq - CEz*CEz);
- Exy = Exy + Etot*CEx*CEy;
- Eyz = Eyz + Etot*CEy*CEz;
- Exz = Exz + Etot*CEz*CEx;
+ if (nhits > 3) {
+ Exx = Exx - Etot * (CErSq - CEx * CEx);
+ Eyy = Eyy - Etot * (CErSq - CEy * CEy);
+ Ezz = Ezz - Etot * (CErSq - CEz * CEz);
+ Exy = Exy + Etot * CEx * CEy;
+ Eyz = Eyz + Etot * CEy * CEz;
+ Exz = Exz + Etot * CEz * CEx;
//
Tr = Exx + Eyy + Ezz;
- double Dxx = Eyy*Ezz - Eyz*Eyz;
- double Dyy = Ezz*Exx - Exz*Exz;
- double Dzz = Exx*Eyy - Exy*Exy;
+ double Dxx = Eyy * Ezz - Eyz * Eyz;
+ double Dyy = Ezz * Exx - Exz * Exz;
+ double Dzz = Exx * Eyy - Exy * Exy;
M = Dxx + Dyy + Dzz;
- double Dxy = Exy*Ezz - Exz*Eyz;
- double Dxz = Exy*Eyz - Exz*Eyy;
- Det = Exx*Dxx - Exy*Dxy + Exz*Dxz;
- double xt = Tr*Tr - 3*M;
+ double Dxy = Exy * Ezz - Exz * Eyz;
+ double Dxz = Exy * Eyz - Exz * Eyy;
+ Det = Exx * Dxx - Exy * Dxy + Exz * Dxz;
+ double xt = Tr * Tr - 3 * M;
double sqrtxt = Math.sqrt(xt);
// eqn to solve for eigenvalues is x**3 - x**2*Tr + x*M - Det = 0
// crosses y axis at -Det and inflection points are
@@ -124,180 +119,163 @@
double mE1 = 0.;
double mE2 = 0.;
double mE3 = 0.;
- double a = (3*M - Tr*Tr)/3.;
- double b = (-2*Tr*Tr*Tr + 9*Tr*M -27*Det)/27.;
- double test = b*b/4. + a*a*a/27.;
- if(test >= 0.01)
- {
- //System.out.println("AbstractCluster: Only 1 real root!!!");
- //System.out.println(" nhits = " + nhits + "\n");
- //System.out.println(" a,b,test = " + a + " " + b + " " + test + "\n");
+ double a = (3 * M - Tr * Tr) / 3.;
+ double b = (-2 * Tr * Tr * Tr + 9 * Tr * M - 27 * Det) / 27.;
+ double test = b * b / 4. + a * a * a / 27.;
+ if (test >= 0.01) {
+ // System.out.println("AbstractCluster: Only 1 real root!!!");
+ // System.out.println(" nhits = " + nhits + "\n");
+ // System.out.println(" a,b,test = " + a + " " + b + " " + test + "\n");
+ } else {
+ double temp;
+ if (test >= 0.)
+ temp = 1.;
+ else
+ temp = Math.sqrt(b * b * 27. / (-a * a * a * 4.));
+ if (b > 0.)
+ temp = -temp;
+ double phi = Math.acos(temp);
+ double temp1 = 2. * Math.sqrt(-a / 3.);
+ mE1 = Tr / 3. + 2. * Math.sqrt(-a / 3.) * Math.cos(phi / 3.);
+ mE2 = Tr / 3. + 2. * Math.sqrt(-a / 3.) * Math.cos(phi / 3. + 2. * Math.PI / 3.);
+ mE3 = Tr / 3. + 2. * Math.sqrt(-a / 3.) * Math.cos(phi / 3. + 4. * Math.PI / 3.);
}
- else
- {
- double temp;
- if(test >= 0.)temp = 1.;
- else temp = Math.sqrt(b*b*27./(-a*a*a*4.));
- if(b > 0.)temp = -temp;
- double phi = Math.acos(temp);
- double temp1 = 2.*Math.sqrt(-a/3.);
- mE1 = Tr/3. + 2.*Math.sqrt(-a/3.)*Math.cos(phi/3.);
- mE2 = Tr/3. + 2.*Math.sqrt(-a/3.)*Math.cos(phi/3. + 2.*Math.PI/3.);
- mE3 = Tr/3. + 2.*Math.sqrt(-a/3.)*Math.cos(phi/3. + 4.*Math.PI/3.);
- }
- if(mE1 < mE2)
- {
- if(mE1 < mE3)
- {
+ if (mE1 < mE2) {
+ if (mE1 < mE3) {
E1 = mE1;
- if(mE2 < mE3)
- {
+ if (mE2 < mE3) {
E2 = mE2;
E3 = mE3;
- }
- else
- {
+ } else {
E2 = mE3;
E3 = mE2;
}
- }
- else
- {
+ } else {
E1 = mE3;
E2 = mE1;
E3 = mE2;
}
- }
- else
- {
- if(mE2 < mE3)
- {
+ } else {
+ if (mE2 < mE3) {
E1 = mE2;
- if(mE1 < mE3)
- {
+ if (mE1 < mE3) {
E2 = mE1;
E3 = mE3;
- }
- else
- {
+ } else {
E2 = mE3;
E3 = mE1;
}
- }
- else
- {
+ } else {
E1 = mE3;
E2 = mE2;
E3 = mE1;
}
}
- NE1 = E1/Etot;
- NE2 = E2/Etot;
- NE3 = E3/Etot;
+ NE1 = E1 / Etot;
+ NE2 = E2 / Etot;
+ NE3 = E3 / Etot;
double[] EV = new double[3];
EV[0] = E1;
EV[1] = E2;
EV[2] = E3;
// Now calculate principal axes
- // For eigenvalue EV, the axis is (nx, ny, nz) where:
- // (Exx - EV)nx + (Exy)ny + (Exz)nz = 0
- // (Eyx)nx + (Eyy - EV)ny + (Eyz)nz = 0
- // (Ezx)nx + (Ezy)ny + (Ezz - EV)nz = 0
- // Setting nx = 1, we have:
- // (Exx - EV) + (Exy)ny + (Exz)nz = 0
- // (Eyx) + (Eyy - EV)ny + (Eyz)nz = 0
- // (Ezx) + (Ezy)ny + (Ezz - EV)nz = 0
- // and so
- // (Exy)ny = EV - Exx - (Exz)nz => ny = (EV - Exx - Exz*nz)/Exy
- // What if Exy = 0? Then provided Eyz is non-zero we can write:
- // (Ezx) + (Ezy)ny + (Ezz - EV)nz = 0
- // ny = (Exz - (Ezz-EV)*nz)/Eyz
- // What if Exy = 0 and Eyz = 0 but (Eyy - EV) is non-zero?
- // (Eyy - EV)ny + (Eyz)nz = 0
- // ny = -(Eyz*nz)/(Eyy-EV)
-
- // In the pathological case where Exz = Eyz = Ezz = 0:
- // (Exx - EV)nx + (Exy)ny = 0 => ny/nx = -(Exx-EV)/Exy
- // (Eyx)nx + (Eyy - EV)ny = 0 => ny/nx = -Eyx/(Eyy-EV)
- // (EV)nz = 0
- // so
- // -ny/nx = (EV-Exx)/Exy = Eyx/(EV-Eyy)
- // But watch out for order! Recalculate eigenvalues for this pathological case.
- // (EV-Exx)(EV-Eyy) = Eyx*Exy
- // EV^2 - EV(Exx+Eyy) + Exx*Eyy - Eyx*Exy = 0
- //
- // In another pathological case, Exz = Exy = 0:
- // (Exx - EV)nx = 0
- // (Eyy - EV)ny + (Eyz)nz = 0 => ny/nz = -(Eyz)/(Eyy-EV)
- // (Ezy)ny + (Ezz - EV)nz = 0 => ny/nz = -(Ezz-EV)/(Ezy)
- // so we cannot set nx = 1. Instead, write:
- // -ny/nz = (Eyz)/(Eyy-EV) = (Ezz-EV)/(Ezy)
- // Then
- // (Eyz)(Ezy) = (Eyy-EV)(Ezz-EV)
- // (Eyz)^2 = (Eyy)(Ezz) - (Eyy)(EV) - (Ezz)(EV) + (EV)^2
- // EV^2 - EV(Eyy+Ezz) + Eyy*Ezz - Eyz*Eyz = 0
-
- // Handle pathological case
- if (Exz == 0.0 && Eyz == 0.0) {
- // Recompute eigenvectors.
- EV[0] = 0.5*(Exx+Eyy) + 0.5*Math.sqrt((Exx+Eyy)*(Exx+Eyy) + 4.0*Exy*Exy);
- EV[1] = 0.5*(Exx+Eyy) - 0.5*Math.sqrt((Exx+Eyy)*(Exx+Eyy) + 4.0*Exy*Exy);
- EV[2] = 0.0;
- for( int i = 0 ; i < 2 ; i++ ) {
- double nx_over_ny = Exy / (Exx-EV[i]);
- double nx_unnormalized = nx_over_ny;
- double ny_unnormalized = 1.0;
- double norm = Math.sqrt(nx_unnormalized*nx_unnormalized + ny_unnormalized*ny_unnormalized);
- mm_PA[i][0] = ny_unnormalized/norm;
- mm_PA[i][1] = nx_unnormalized/norm;
- mm_PA[i][2] = 0.0;
- }
- // ... and now set third eigenvector to the z direction:
- mm_PA[2][0] = 0.0;
- mm_PA[2][1] = 0.0;
- mm_PA[2][2] = 1.0;
- } else if (Exz == 0.0 && Exy == 0.0) {
- // Another pathological case
- EV[0] = 0.5*(Eyy+Ezz) + 0.5*Math.sqrt((Eyy+Ezz)*(Eyy+Ezz) + 4.0*Eyz*Eyz);
- EV[1] = 0.5*(Eyy+Ezz) - 0.5*Math.sqrt((Eyy+Ezz)*(Eyy+Ezz) + 4.0*Eyz*Eyz);
- EV[2] = 0.0;
- for( int i = 0 ; i < 2 ; i++ ) {
- double ny_over_nz = Eyz / (Eyy-EV[i]);
- double ny_unnormalized = ny_over_nz;
- double nz_unnormalized = 1.0;
- double norm = Math.sqrt(ny_unnormalized*ny_unnormalized + nz_unnormalized*nz_unnormalized);
- mm_PA[i][0] = nz_unnormalized/norm;
- mm_PA[i][1] = ny_unnormalized/norm;
- mm_PA[i][2] = 0.0;
- }
- mm_PA[2][0] = 0.0;
- mm_PA[2][1] = 0.0;
- mm_PA[2][2] = 1.0;
- } else {
- for( int i = 0 ; i < 3 ; i++ )
- {
- double[] C = new double[3];
- C[0] = 1.0;
- C[2] = (Exy*Exy + (Eyy - EV[i])*(EV[i] - Exx))/
- ((Eyy - EV[i])*Exz - Eyz*Exy);
- C[1] = (EV[i] - Exx - Exz*C[2])/Exy;
- if (Exy == 0.0) {
- // Recompute
- if (Eyz != 0.0) {
- // ny = (Exz - (Ezz-EV)*nz)/Eyz
- C[1] = (Exz - (Ezz-EV[i])*C[2])/Eyz;
- } else {
- // ny = -(Eyz*nz)/(Eyy-EV)
- C[1] = -(Eyz*C[2])/(Eyy-EV[i]);
- }
- }
- double norm = Math.sqrt(C[0]*C[0] + C[1]*C[1] + C[2]*C[2]);
- mm_PA[i][0] = C[0]/norm;
- mm_PA[i][1] = C[1]/norm;
- mm_PA[i][2] = C[2]/norm;
- }
- }
+ // For eigenvalue EV, the axis is (nx, ny, nz) where:
+ // (Exx - EV)nx + (Exy)ny + (Exz)nz = 0
+ // (Eyx)nx + (Eyy - EV)ny + (Eyz)nz = 0
+ // (Ezx)nx + (Ezy)ny + (Ezz - EV)nz = 0
+ // Setting nx = 1, we have:
+ // (Exx - EV) + (Exy)ny + (Exz)nz = 0
+ // (Eyx) + (Eyy - EV)ny + (Eyz)nz = 0
+ // (Ezx) + (Ezy)ny + (Ezz - EV)nz = 0
+ // and so
+ // (Exy)ny = EV - Exx - (Exz)nz => ny = (EV - Exx - Exz*nz)/Exy
+ // What if Exy = 0? Then provided Eyz is non-zero we can write:
+ // (Ezx) + (Ezy)ny + (Ezz - EV)nz = 0
+ // ny = (Exz - (Ezz-EV)*nz)/Eyz
+ // What if Exy = 0 and Eyz = 0 but (Eyy - EV) is non-zero?
+ // (Eyy - EV)ny + (Eyz)nz = 0
+ // ny = -(Eyz*nz)/(Eyy-EV)
+
+ // In the pathological case where Exz = Eyz = Ezz = 0:
+ // (Exx - EV)nx + (Exy)ny = 0 => ny/nx = -(Exx-EV)/Exy
+ // (Eyx)nx + (Eyy - EV)ny = 0 => ny/nx = -Eyx/(Eyy-EV)
+ // (EV)nz = 0
+ // so
+ // -ny/nx = (EV-Exx)/Exy = Eyx/(EV-Eyy)
+ // But watch out for order! Recalculate eigenvalues for this pathological case.
+ // (EV-Exx)(EV-Eyy) = Eyx*Exy
+ // EV^2 - EV(Exx+Eyy) + Exx*Eyy - Eyx*Exy = 0
+ //
+ // In another pathological case, Exz = Exy = 0:
+ // (Exx - EV)nx = 0
+ // (Eyy - EV)ny + (Eyz)nz = 0 => ny/nz = -(Eyz)/(Eyy-EV)
+ // (Ezy)ny + (Ezz - EV)nz = 0 => ny/nz = -(Ezz-EV)/(Ezy)
+ // so we cannot set nx = 1. Instead, write:
+ // -ny/nz = (Eyz)/(Eyy-EV) = (Ezz-EV)/(Ezy)
+ // Then
+ // (Eyz)(Ezy) = (Eyy-EV)(Ezz-EV)
+ // (Eyz)^2 = (Eyy)(Ezz) - (Eyy)(EV) - (Ezz)(EV) + (EV)^2
+ // EV^2 - EV(Eyy+Ezz) + Eyy*Ezz - Eyz*Eyz = 0
+
+ // Handle pathological case
+ if (Exz == 0.0 && Eyz == 0.0) {
+ // Recompute eigenvectors.
+ EV[0] = 0.5 * (Exx + Eyy) + 0.5 * Math.sqrt((Exx + Eyy) * (Exx + Eyy) + 4.0 * Exy * Exy);
+ EV[1] = 0.5 * (Exx + Eyy) - 0.5 * Math.sqrt((Exx + Eyy) * (Exx + Eyy) + 4.0 * Exy * Exy);
+ EV[2] = 0.0;
+ for (int i = 0; i < 2; i++) {
+ double nx_over_ny = Exy / (Exx - EV[i]);
+ double nx_unnormalized = nx_over_ny;
+ double ny_unnormalized = 1.0;
+ double norm = Math.sqrt(nx_unnormalized * nx_unnormalized + ny_unnormalized * ny_unnormalized);
+ mm_PA[i][0] = ny_unnormalized / norm;
+ mm_PA[i][1] = nx_unnormalized / norm;
+ mm_PA[i][2] = 0.0;
+ }
+ // ... and now set third eigenvector to the z direction:
+ mm_PA[2][0] = 0.0;
+ mm_PA[2][1] = 0.0;
+ mm_PA[2][2] = 1.0;
+ } else if (Exz == 0.0 && Exy == 0.0) {
+ // Another pathological case
+ EV[0] = 0.5 * (Eyy + Ezz) + 0.5 * Math.sqrt((Eyy + Ezz) * (Eyy + Ezz) + 4.0 * Eyz * Eyz);
+ EV[1] = 0.5 * (Eyy + Ezz) - 0.5 * Math.sqrt((Eyy + Ezz) * (Eyy + Ezz) + 4.0 * Eyz * Eyz);
+ EV[2] = 0.0;
+ for (int i = 0; i < 2; i++) {
+ double ny_over_nz = Eyz / (Eyy - EV[i]);
+ double ny_unnormalized = ny_over_nz;
+ double nz_unnormalized = 1.0;
+ double norm = Math.sqrt(ny_unnormalized * ny_unnormalized + nz_unnormalized * nz_unnormalized);
+ mm_PA[i][0] = nz_unnormalized / norm;
+ mm_PA[i][1] = ny_unnormalized / norm;
+ mm_PA[i][2] = 0.0;
+ }
+ mm_PA[2][0] = 0.0;
+ mm_PA[2][1] = 0.0;
+ mm_PA[2][2] = 1.0;
+ } else {
+ for (int i = 0; i < 3; i++) {
+ double[] C = new double[3];
+ C[0] = 1.0;
+ C[2] = (Exy * Exy + (Eyy - EV[i]) * (EV[i] - Exx)) / ((Eyy - EV[i]) * Exz - Eyz * Exy);
+ C[1] = (EV[i] - Exx - Exz * C[2]) / Exy;
+ if (Exy == 0.0) {
+ // Recompute
+ if (Eyz != 0.0) {
+ // ny = (Exz - (Ezz-EV)*nz)/Eyz
+ C[1] = (Exz - (Ezz - EV[i]) * C[2]) / Eyz;
+ } else {
+ // ny = -(Eyz*nz)/(Eyy-EV)
+ C[1] = -(Eyz * C[2]) / (Eyy - EV[i]);
+ }
+ }
+ double norm = Math.sqrt(C[0] * C[0] + C[1] * C[1] + C[2] * C[2]);
+ mm_PA[i][0] = C[0] / norm;
+ mm_PA[i][1] = C[1] / norm;
+ mm_PA[i][2] = C[2] / norm;
+ }
+ }
}
mm_NE[0] = NE1;
mm_NE[1] = NE2;
@@ -305,66 +283,57 @@
mm_CE[0] = CEx;
mm_CE[1] = CEy;
mm_CE[2] = CEz;
- for(int i=0;i<6;i++)
- {
+ for (int i = 0; i < 6; i++) {
positionError[i] = 0.;
directionError[i] = 0.;
shapeParameters[i] = 0.;
}
- for(int i=0;i<3;i++)
- {
+ for (int i = 0; i < 3; i++) {
position[i] = mm_CE[i];
shapeParameters[i] = mm_NE[i];
}
- if(nhits > 3)
- {
- double dr = Math.sqrt( (position[0]+mm_PA[0][0])*(position[0]+mm_PA[0][0]) +
- (position[1]+mm_PA[0][1])*(position[1]+mm_PA[0][1]) +
- (position[2]+mm_PA[0][2])*(position[2]+mm_PA[0][2]) ) -
- Math.sqrt( (position[0])*(position[0]) +
- (position[1])*(position[1]) +
- (position[2])*(position[2]) ) ;
+ if (nhits > 3) {
+ double dr = Math.sqrt((position[0] + mm_PA[0][0]) * (position[0] + mm_PA[0][0]) + (position[1] + mm_PA[0][1]) * (position[1] + mm_PA[0][1]) + (position[2] + mm_PA[0][2]) * (position[2] + mm_PA[0][2])) - Math.sqrt((position[0]) * (position[0]) + (position[1]) * (position[1]) + (position[2]) * (position[2]));
double sign = 1.;
- if(dr < 0.)sign = -1.;
- itheta = Math.acos(sign*mm_PA[0][2]);
- iphi = Math.atan2(sign*mm_PA[0][1],sign*mm_PA[0][0]);
- }
- else
- {
+ if (dr < 0.)
+ sign = -1.;
+ itheta = Math.acos(sign * mm_PA[0][2]);
+ iphi = Math.atan2(sign * mm_PA[0][1], sign * mm_PA[0][0]);
+ } else {
itheta = 999.;
iphi = 999.;
}
}
- public double[] getPosition()
- {
+
+ public double[] getPosition() {
return position;
}
- public double[] getPositionError()
- {
+
+ public double[] getPositionError() {
return positionError;
}
- public double getIPhi()
- {
+
+ public double getIPhi() {
return iphi;
}
- public double getITheta()
- {
+
+ public double getITheta() {
return itheta;
}
- public double[] getDirectionError()
- {
+
+ public double[] getDirectionError() {
return directionError;
}
- public double[] getShapeParameters()
- {
+
+ public double[] getShapeParameters() {
return shapeParameters;
}
- public double[] getNormalizedEigenvalues()
- {
+
+ public double[] getNormalizedEigenvalues() {
return mm_NE;
}
- public double[][] getPrincipleAxis()
- {
+
+ public double[][] getPrincipleAxis() {
return mm_PA;
}
########################################################################
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
|