#ifndef _mdet_PMT_h #define _mdet_PMT_h #include #include #include // // Boost's iterators used here require a complete type ('cause they use boost::is_pod) // With GCC 4.3.3 there wasn't any compiling problem, but with 4.4.3 there was. #include // #include // just forward it, to declare friendship. // #include namespace mdet { class Module; class Pixel; /** * \class PMT PMT.h "mdet/PMT.h" * \brief Multiple-pixel photo-multiplier tube. * * This class representes the multi-pixel photo-multiplier tubes used * whithin each module. It groups its pixels and manages the relationships * between them as being part of the PMT (for example, the cross-talk * matrix). * * The PMT is allowed to be only square; in the real case the PMTs are * likely to be 64x64 sized. The generalization to rectangular PMT (that's * NxM sizes) is straightforward since the square dependant logic is * buried in to the functions that calculate the size of the PMT, in fact * in only of them; but would need another parameter to specify how to distribute * the pixels among rows and column (for example, column width). * * The pixels id's are asumed to be consecutive, row-by-row * starting from the upper-left corner and ending on the lower-right (fact that's * actually checked on construction). With this the neighboring relations are * constructed; for example (if existing) the right side neighbor is + 1 id. * The neighbor relationship is based on first-neighbor scope and allowed in the * diagonal direction: there are 8 neighbors. * * \author Rodolfo Federico Gamarra * \date 08 Mar 2009 * \ingroup mdet */ class PMT : public MDetectorComponent::Type { private: /** * \brief Type for the set of associated mdet::Pixel. */ typedef MComponentGroup::Type PixelGroup; /** * \brief Non-const private alias. */ typedef PixelGroup::Iterator PixelIterator; public: /** * \brief Assumed value for central pixel self-talk. * * The general usage for cross-talk matrices * is express the to-neighbors talk as the number of pusles * in there when in the central pixel one hundred pulse * detections were made. */ static const double kCentralPixelSelfTalk; /** * \brief Number of neighbors for a pixel inside (ie * in the middle) the PMT's cathode. * * The assumed layout for the neighbors is as follows: * * 1 2 3 * 4 X 5 * 6 7 8 * * where X is the pixel whose neighbors are represented. * The numbers are the position within the linearized * representation of the cross-talk matrix of pixel X. */ static const unsigned int kNumNeighborsInside = 8; /** * \brief Number of neighbors for a pixel on the side of * the PMT's cathode. * * The assumed layout for the neighbors is as follows: * * - Left side central pixel: * 0 1 * X 2 * 4 3 * * - Right side central pixel: * 1 0 * 2 X * 3 4 * * - Top side central pixel; * 0 X 4 * 1 2 3 * * - Bottom side central pixel: * 1 2 3 * 0 X 4 * * @sa kNumNeighborsCorner */ static const unsigned int kNumNeighborsSide = 5; /** * \brief Number of neighbors for a pixel on the corner * of the PMT's cathode. * The assumed layout for the neighbors' coefficientes is as follows: * * - Upper-left side pixel: * X 0 * 2 1 * * - Upper-right side pixel: * 0 X * 1 2 * * - Lower-left side pixel: * 2 1 * X 0 * * - Lower-right side pixel: * 1 2 * 0 X * * This supposed arrangement allows (if desired) to configure * a single cross-talk matrix for several pixels disregarding * the actual position of a single pixel (ie in which side a * given pixel is on). For instance, the cross-talk coefficient * for the pixel diagonally next to the X one is always the #1. */ static const unsigned int kNumNeighborsCorner = 3; /** * \brief Convenience typedef for const iterator over * the contained mdet::Pixel instances. */ typedef PixelGroup::ConstIterator PixelConstIterator; /** * \brief Typedef for mdet::Pixel neighbor container. * * This declaration is for use in mdet::Pixel, is not * useful for client code. It could be made private and * friendship given to mdet::Pixel. */ typedef std::vector NeighborsContainer; /** * \brief Typedef for mdet::Pixel crosstalk container. * * \sa NeighborsContainer */ typedef std::vector CrossTalkContainer; /** * \brief Convenience typedef for iteration over * neighbors. * * This typedef should be the same than PixelConstIterator * but anothe type is needed cause of the different * implementations for iteration in each case. Another * possibility would have been to provide a conversion * from one of the backing iterator over the other * or try to use the same kind of iterator in each case. * Seems better to have different types. * * \sa NeighborsBegin * \sa NeighborsEnd */ typedef boost::indirect_iterator NeighborConstIterator; static const char* const kComponentName; static const char* const kComponentId; /** * \brief Begin iterator over the contained pixels. */ PixelConstIterator PixelsBegin() const { return fPixels.Begin(); } /** * \brief End iterator over the contained pixels. */ PixelConstIterator PixelsEnd() const { return fPixels.End(); } /** * \brief Begin iterator over neighbors of the given pixel. */ NeighborConstIterator NeighborsBegin(const Pixel& p) const; /** * \brief End iterator over neighbors of the given pixel. */ NeighborConstIterator NeighborsEnd(const Pixel& p) const; /** * \brief Computes a destination pixel according to crosstalk effect. * * Randomizes according crosstalk configuration and then chooses a neighbor * or source pixel itself. This method gives sense to the bare crosstalk * coeficients, and is the best choice to be used by the clients of this class, * tough the access to the raw coefficients is granted. * * \sa GetCrossTalkProportion * \sa GetCrossTalk */ const Pixel& ComputePulseDestination(const Pixel& src) const; /** * \brief Tells whether \p dst is one of the neighbors of \p src. * * Tells if both Pixel are neighbors within the PMT. * It's a simmetrical, non-reflexive relationship. */ bool IsNeighbor(const Pixel& src, const Pixel& dst) const; /** * \brief The module to which this PMT belongs. */ const Module& GetModule() const; private: /** * \brief Perform update in this component and forward to * subcomponents. */ void Update(bool invalidateData, bool invalidateComponents); /** * \brief Returns the cross-talk coefficient for \p dst seen * as a neighbor of \p src. * * Returns the cross-talk coefficient for cross-talk started from Pixel * \p src towards Pixel \p dst, that's * the (mean) number of pulses went to \p dst when the number arrived * to \p src equals one hundred. Note that is not a percentage. * Note that the cross-talk matrix is defined for every pair of pixels * within the PMT (may be zero in some cases). * * Note that, in the most general case, the cross-talk may depend * in components that are external to the PMT, like the (numerical aperture * of the) optical fibers that take the light to each of the PMT's pixels. * Despite that, it seems proper to define this cross-talk matrix at the * PMT level. If, further on, it seems that that components of the cross-talk * (that is, the ones depending on components that are external to the PMT) are * better placed somewhere else, this GetCrosstalk may be kept here to mean * the coeffients depending exclusively on the PMT (having the proper changes * in the configuration). * * \sa kCentralPixelSelfTalk * \sa GetCrossTalkProportion */ double GetCrossTalk(const Pixel& src, const Pixel& dst) const; /** * \brief The cross-talk proportion coefficient for \p dst seen as a neighbor * of \ src. * * This coefficient is a number between (inclusively) 0 and 1, indicating the * proportion of pulses that belonging initially to pixel * \p src end in pixel \p dst, which may (likely) be equal to \p src. * * \sa GetCrossTalk */ double GetCrossTalkProportion(const Pixel& src, const Pixel& dst) const; /** * \brief Helper method to manage the conversion factor for cross-talk. * * This conversion factor allows to compute a percentual cross-talk values. */ double GetCrossTalkNormalizationFactor(const mdet::Pixel& pix) const; /** * \brief Constructs the tube. * * \param pId The identifier to be used. * \param parentMap The identifiers of the parent within the hierarchy. * \param parent The parent mdet::Module. * * A reference to the parent is kept in this class and part * of the construction is delegated to the first super-class. * * This method is kept private creation of these objects is not * meant to be performed by client code. See the related friendship * declaration. * * \sa mdet::MDectectorComponent::Type */ PMT(int pId, const det::VManager::IndexMap& parentMap, const Module& parent); /** * \brief Initilization and validations related to pixels. */ void InitPixels(); /** * \brief Destructor (!). */ ~PMT() { } /** * \brief Accesses the group of pixels. */ const PixelGroup& GetPixels() const { return fPixels; } /** * \brief Neighbor finding helper function. */ template NeighborsContainer::const_iterator IsNeighbor(const Pixel& src, const Pixel& dst, const Predicate& p) const; /** * \brief Retrieves the number of rows. */ PixelGroup::SizeType GetRows() const; /** * \brief Retrieves the number of columns. */ PixelGroup::SizeType GetCols() const; /** * \brief Friendship to allow construction. Also allows * access to fPixels (through GetPixels) in function * GetPixelFor (handles component linkage). */ friend class Module; /** * \brief Frienship to allow destruction. * * This comes from the fact that the PMT is * kept (in mdet::Module) within one of these. */ friend class utl::ShadowPtr; PixelGroup fPixels; const Module& fModule; /** * \brief Minimum id among PMT's ids. */ int fFirstIdPMT; }; } #endif // _mdet_PMT_h