This page outlines a proposal for an interface to access CalorimeterHit data along with information from the associated detector description.
A single interface was used for the purpose of discussion, though multiple interfaces might be a better (at least more traditionally OO) approach.
Comments welcome as either additions to this page or using the usual comment box.
package org.lcsim.geometry; import hep.physics.vec.Hep3Vector; /** * * A preliminary proposal of an interface to Calorimeter hit data * based on methods from @IDDecoder, @Subdetector, @Calorimeter, @CalorimeterType, * @CalorimeterHit, @Segmentation, @SegmentationBase (and its 4 subclasses), and * @BarrelEndcapFlag. For convenience, CalorimeterCell would combine functionality * from these classes into a single "flattened" API so that users can avoid * lots of subcasting and/or method chaining in order to access the information * required for their analysis. It also replaces calls using "magic" field * names (primarily in IDDecoder) with proper interface methods. * * Measurements, such as the position, are within a global coordinate * system based at (0,0,0), unless otherwise noted. Indices, however, * may refer to a local or global system. For instance, ix would probably * translate to local coordinates in a readout plate, while iphi is most * likely a global phi index. * * Any method that does not apply to a given subclass of CalorimeterCell may * either throw an exception from an unimplemented method (preferred way) or * just return an invalid or dummy value. For some values, e.g. layer, an * invalid value like -1 would be fairly obvious. For others, like phi or * theta indices, an invalid value may be unclear so the method should probably * just throw an exception. * * The list of MCParticles from SimCalorimeterHit has not been included. * The MCParticle associations should be held externally * in a CalorimeterCell => MCParticle relation map based on data from * the input CalorimeterHits. (It is done this way in ATLAS, LHCb, et al.) * This approach eliminates an explicit dependency on the MCParticle interface, * and it would also make the relationship between CalorimeterCells and * MCParticles a lot more flexible. Additionally, the approach can be * applied generically so that a specialized hit interface using the * Monte Carlo is not required and any hit object could be associated * with a particle in the MC truth. * * @author Jeremy McCormick * */ public interface CalorimeterCell { /** * 64-bit identifier of this cell * * @see CalorimeterHit.getCellId() */ long cellId(); /** * Hash code uniquely identifying the CalorimeterCell object * * NOTE: Could be different from cellId() * * FIXME: Java provides this already automatically? * */ long hashcode(); /** * Raw energy in GeV * * @see CalorimeterHit.getRawEnergy() */ double energyRaw(); /** * Corrected energy in GeV * * @see CalorimeterHit.getCorrectedEnergy() * */ double energyCorrected(); /** * Shortcut for energy != 0 */ boolean isHit(); /** * Time in nanoseconds * * @see CalorimeterHit.getTime() * */ double time(); /** * Center position in mm * * @see CalorimeterHit.getPosition() * @see IDDecoder.getPosition() */ Hep3Vector position(); /** * x at cell center in mm * * @see IDDecoder.getX() * */ double x(); /** * y at cell center in mm * * @see IDDecoder.getY() * */ double y(); /** * z at cell center in mm * * @see IDDecoder.getZ() * */ double z(); /** * Is the given point within tolerance of the cell center? */ boolean isNear(Hep3Vector point, double tolerance); /** * Distance to center of cell from point */ double howNear(Hep3Vector point); /** * Is the given point inside this cell? */ boolean isInside(Hep3Vector point); /** * Theta at cell center in radians * * @see IDDecoder.getTheta() * */ double theta(); /** * Minimum theta extent at edge of cell in radians */ double thetaMin(); /** * Maximum theta extent at edge of cell in radians */ double thetaMax(); /** * Size of the cell in theta, i.e. thetaMax() - thetaMin(), in radians */ double thetaSize(); /** * Phi at cell center, in radians * * @see IDDecoder.getPhi() * */ double phi(); /** * Minimum phi measurement at one edge of the cell in radians */ double phiMin(); /** * Maximum phi measurement at one edge of the cell in radians */ double phiMax(); /** * Size of the cell in phi, i.e. phiMax - phiMin, in radians */ double phiSize(); /** * Radius to the cell midpoint in mm */ double rho(); /** * Minimum radius, i.e. inner radius, in mm */ double rhoMin(); /** * Maximum radius, i.e. outer radius, in mm */ double rhoMax(); /** * Size of the cell in rho, i.e. rhoMax - rhoMin, in mm * * NOTE: This method could also be called thickness() or width(). * */ double rhoSize(); /** * X index * * @see IDDecoder.getValue() * @see GridXYZ.getXBin() * */ int ix(); /** * Y index * * @see IDDecoder.getValue() * @see GridXYZ.getYBin() * */ int iy(); /** * Z index * * @see IDDecoder.getValue() * @see GridXYZ.getZBin() * */ int iz(); /** * Theta index */ int itheta(); /** * Phi index */ int iphi(); /** * System number uniquely identifying the Subdetector of this cell * * @see IDDecoder.getSystemID() * */ int system(); /** * Section of the calorimeter along the z axis * * NOTE: See Mokka's HCAL models for an example of calorimeter's with sections along z. * * NOTE: Only applies to calorimeter's that are subdivided in z, though other types * could "fake it" based on iz() or z(). * */ int section(); /** * Module number in the section * * NOTE: Usually there are as many modules as sides to the calorimeter's polyhedra envelope. * * NOTE: Only applies to realistic polyhedra calorimeters, though cylindrical types * could "fake it" based on iphi() or phi(). * */ int module(); /** * Stave number in the module * * NOTE: Mokka's HCAL is an example of a calorimeter with multiple staves per module. * */ int stave(); /** * Layer number * * @see IDDecoder.getLayer() * */ int layer(); /** * Row number in a plate of cells * * NOTE: This is primarily applicable to calorimeters with planar readout volumes, * such as those within trapezoidal staves. It could also apply to testbeams. */ int row(); /** * Column number in a plate of cells * * NOTE: This is primarily applicable to calorimeters with planar readout volumes, * such as those within trapezoidal staves. It could also apply to testbeams. * */ int column(); /** * Tower number * * NOTE: The tower number identifies a projective tower spanning calorimeter subsystems. * * FIXME: Possibly a deprecated/superceded concept? * */ int tower(); /** * Is the cell flagged as an absorber layer that has been made sensitive for debugging? * * NOTE: There are possibly other ways to know whether a cell is actually from an absorber, * but an interface method is the most straightforward way for user's to access this * information. * */ boolean isAbsorber(); /** * Is the cell in a barrel? * * @see IDDecoder.getBarrelEndcapFlag() * @see BarrelEndcapFlag.isBarrel() * */ boolean isBarrel(); /** * Is the cell in an endcap? * * @see IDDecoder.getBarrelEndcapFlag() * @see BarrelEndcapFlag.isEndcap() */ boolean isEndcap(); /** * Does the cell have a positive z measurement? * * NOTE: This function may use the encoded setting from the barrel field * or just examine the sign of CalorimeterCell.z(). * * @see IDDecoder.getBarrelEndcapFlag() * @see BarrelEndcapFlag.isEndcapNorth() * */ boolean isNorth(); /** * Does the cell have a negative z measurement? * * NOTE: This function may use the encoded setting from the barrel field * or just examine the sign of CalorimeterCell.z(). * * @see IDDecoder.getBarrelEndcapFlag() * @see BarrelEndcapFlag.isEndcapSouth() * */ boolean isSouth(); /** * Is the cell from an ECAL subdetector? * * @see Calorimeter.getCalorimeterType() * @see CalorimeterType * */ boolean isECAL(); /** * Is the cell from an HCAL subdetector? * * @see Calorimeter.getCalorimeterType() * @see CalorimeterType * */ boolean isHCAL(); /** * Is the cell from a MUON subdetector? * * @see Calorimeter.getCalorimeterType() * @see CalorimeterType * */ boolean isMUON(); /** * Is the cell from a FWD subdetector? (forward calorimeter) * * @see Calorimeter.getCalorimeterType() * @see CalorimeterType * */ boolean isFWD(); /** * Subdetector associated with this CalorimeterCell * * @see CalorimeterHit.getSubdetector() * @see IDDecoder.getSubdetector() * * FIXME: This breaks the usual OO heuristic that a contained object should not * reference its container. * * FIXME: Need to make sure that a Subdetector reference is not stored with each CalorimeterCell. * */ Subdetector subdetector(); /** * IDDecoder associated with this CalorimeterCell * * @see CalorimeterHit.getIDDecoder() * * FIXME: Need to make sure that an IDDecoder reference is not stored with each CalorimeterCell. * */ IDDecoder decoder(); /** * Neighbor indices * * @see Calorimeter.getNeighbors() * * FIXME: This should be spelled "neighbors". Oh, well! * * FIXME: Neighbor-finding should return a Neighborhood class rather * than double array. * * FIXME: It should be possible to specifiy the type of neighbors. * For instance, crosstalk is usually only applied to cardinal * neighbors, rather than the Moore Neighborhood (i.e. cardinal * and ordinal neighbors). * * FIXME: In my opinion, neighbor-finding should be completely externalized * to allow for greater flexibility and functionality, though * removal of neighbor-finding from IDDecoder would break a * lot of existing code. */ long[] neighbours(int deltaLayer, int deltaTheta, int deltaPhi); /** * Does this cell type support neighbor-finding? * * @see IDDecoder.supportsNeighbours() * * FIXME: This is a superfluous function, because the IDDecoder * interface has a neighbor-finding function. Shouldn't * it just throw an exception if not implemented? */ boolean supportsNeighbours(); /** * * Get the generic DetectorElement for this cell. * * NOTE: For the future! * * FIXME: Need a DetectorElement interface, first. * */ DetectorElement detectorElement(); }