#ifndef __JTRIGGER__JTIMESLICEROUTER__ #define __JTRIGGER__JTIMESLICEROUTER__ #include #include #include #include #include #include "km3net-dataformat/online/JDAQ.hh" #include "km3net-dataformat/online/JDAQModuleIdentifier.hh" #include "km3net-dataformat/online/JDAQSuperFrame.hh" #include "km3net-dataformat/online/JDAQTimeslice.hh" #include "JTools/JHashMap.hh" #include "JTools/JElement.hh" #include "JTools/JGrid.hh" #include "JTools/JGridCollection.hh" #include "JDetector/JTimeRange.hh" #include "JTrigger/JTriggerException.hh" #include "JLang/JPointer.hh" /** * \author mdejong */ namespace JTRIGGER {} namespace JPP { using namespace JTRIGGER; } namespace JTRIGGER { using JLANG::JPointer; using KM3NETDAQ::JDAQTimeslice; using KM3NETDAQ::JDAQModuleIdentifier; using KM3NETDAQ::JDAQFrameSubset; using JDETECTOR::JTimeRange; /** * Auxiliary base class for JTimesliceRouter. */ struct JTimesliceRouter_t { /** * Constructor. * * \param numberOfBins number of bins of the hit look-up table */ JTimesliceRouter_t(const int numberOfBins) : TMIN_NS(std::numeric_limits::min()), TMAX_NS(std::numeric_limits::max()), DAQHIT_MIN(0, TMIN_NS, 0), DAQHIT_MAX(0, TMAX_NS, 0), numberOfBins(numberOfBins) {} const JDAQHit::JTDC_t TMIN_NS; //!< minimal TDC value const JDAQHit::JTDC_t TMAX_NS; //!< maximal TDC value const JDAQHit DAQHIT_MIN; //!< begin hit marker const JDAQHit DAQHIT_MAX; //!< end hit marker protected: int numberOfBins; }; /** * Router for fast addressing of hits in KM3NETDAQ::JDAQTimeslice data structure * as a function of the optical module identifier and time. * * Note that the data in a frame from the same PMT are time ordered * but the data from different PMTs are not necessarily time orderd.\n * The fast routing is based on the assumption that the time difference * between consecutive hits in the same frame is limited.\n * The access speed is then determined by this time difference. * * The time slice router class comprises two internal look-up tables: * * - The first table consists of a one dimensional look-up table which is * is used to map the module identifier to the index of the corresponding * data frame in the time slice. * * - The second table consists of a two dimensional array. * In this, the first index of matches with the index of the corresponding data frame in the time slice. * Each first index is mapped to a one dimensional look-up table. * This one dimensional look-up table maps an uncalibrated time t1 * to a pair of indices (lpos,rpos), where: * -# lpos is the index of the first hit in the data frame with time >= t1; * -# rpos is the index of the last hit in the data frame with time < t1; */ struct JTimesliceRouter : public JTimesliceRouter_t, public JPointer { /** * Auxiliary structure for indexing hits in a data frame. */ struct pair_type { int lpos; int rpos; }; typedef JTOOLS::JElement2D element_type; typedef JTOOLS::JGridCollection grid_type; typedef JDAQTimeslice::const_iterator const_iterator; typedef JTOOLS::JHashMap router_type; /** * Constructor. * * \param numberOfBins number of bins of the hit look-up table */ JTimesliceRouter(const int numberOfBins) : JTimesliceRouter_t(numberOfBins) {} /** * Constructor. * * \param timeslice timeslice * \param numberOfBins number of bins of the hit look-up table */ JTimesliceRouter(const JDAQTimeslice& timeslice, const int numberOfBins) : JTimesliceRouter_t(numberOfBins) { configure(timeslice); } /** * Configure. * * Note that method reset should be called used after use. * * \param timeslice timeslice */ void configure(const JDAQTimeslice& timeslice) { using namespace std; using namespace JPP; using namespace KM3NETDAQ; typedef std::vector buffer_type; typedef std::vector frame_type; router.clear(); this->set(×lice); for (const_iterator i = this->get()->begin(); i != this->get()->end(); ++i) { if (router.has(i->getModuleID())) { THROW(JTriggerException, "Multiple data from module " << i->getModuleID()); } router.put(i->getModuleID(), distance(this->get()->begin(), i)); } // setup grid int number_of_elements = 2; for (const_iterator i = this->get()->begin(); i != this->get()->end(); ++i) { if (i->size() > number_of_elements) { number_of_elements = i->size(); } } if (numberOfBins > 1 && numberOfBins + 1 < number_of_elements) { number_of_elements = numberOfBins + 1; } double Tmin_ns = getTimeSinceRTS(this->get()->getFrameIndex()) - 0.05 * getFrameTime(); // [ns] double Tmax_ns = getTimeSinceRTS(this->get()->getFrameIndex()) + 1.05 * getFrameTime(); // [ns] if (Tmin_ns < TMIN_NS) { Tmin_ns = TMIN_NS; } if (Tmax_ns > TMAX_NS) { Tmax_ns = TMAX_NS; } const JGrid bounds(number_of_elements, Tmin_ns, Tmax_ns); // grid of abscissa values for lookup of hit indices based on time buffer_type limits(bounds.getSize() + 1); // abscissa values of grid with proper data type for (int i = 0; i != bounds.getSize(); ++i) { limits[i] = (JDAQHit::JTDC_t) bounds.getX(i); } limits[bounds.getSize()] = TMAX_NS; // this will make rpos refer to the next abscissa value in grid table.resize(this->get()->size()); // lookup table with same indexing as current time slice frame_type buffer; // copy of raw data with additional begin and end marker vector::iterator grid = table.begin(); for (const_iterator frame = this->get()->begin(); frame != this->get()->end(); ++frame, ++grid) { grid->configure(bounds); if (!frame->empty()) { buffer.resize(frame->size() + 2); // reserve space for begin and end marker copy(frame->begin(), frame->end(), buffer.begin() + 1); *buffer. begin() = DAQHIT_MIN; // begin marker *buffer.rbegin() = DAQHIT_MAX; // end markr { frame_type ::const_iterator hit = buffer.begin(); ++hit; // skip begin marker buffer_type::const_iterator t1 = limits.begin(); // corresponds to index in grid for (grid_type::iterator i = grid->begin(); i != grid->end(); ++i, ++t1) { while (hit->getT() < *t1) { ++hit; } i->getY().lpos = distance(buffer.cbegin(), hit) - 1; // correct distance for begin marker } } { frame_type ::const_reverse_iterator hit = buffer.rbegin(); ++hit; // skip end marker buffer_type::const_reverse_iterator t1 = limits.rbegin(); // corresponds to index in grid plus one for (grid_type::reverse_iterator i = grid->rbegin(); i != grid->rend(); ++i, ++t1) { while (hit->getT() >= *t1) { ++hit; } i->getY().rpos = distance(buffer.cbegin(), hit.base()) - 1; // correct distance for begin marker } } } } } /** * Get address of module. * * \param module module * \return address */ const int getAddress(const JDAQModuleIdentifier& module) const { return router.get(module.getModuleID()); } /** * Check presence of module. * * \param module module * \return true if module present; else false */ bool hasSuperFrame(const JDAQModuleIdentifier& module) const { return router.has(module.getModuleID()); } /** * Get super frame. * * \param module module * \return super frame */ const JDAQSuperFrame& getSuperFrame(const JDAQModuleIdentifier& module) const { return (*(this->get()))[this->getAddress(module)]; } /** * Get subset of frame given module identifier and range of hit times. * * Note that the hit times should have been corrected for the maximal and minimal * time offsets of the PMTs in the corresponding optical module. * * \param module module * \param timeRange time range [ns] * \return subset with begin and end iterators */ JDAQFrameSubset getFrameSubset(const JDAQModuleIdentifier& module, const JTimeRange& timeRange) const { const int address = this->getAddress(module); const grid_type& grid = table [address]; const JDAQSuperFrame& frame = (*(this->get()))[address]; int first = grid.getIndex(timeRange.getLowerLimit()); int second = grid.getIndex(timeRange.getUpperLimit()); if (first < 0) { first = 0; } if (second >= grid.getSize()) { second = grid.size() - 1; } return frame.subset(grid.getY(first).lpos, grid.getY(second).rpos); } private: router_type router; std::vector table; }; } #endif