#ifndef __JDETECTOR__JCLBDEFAULTSIMULATORINTERFACE__ #define __JDETECTOR__JCLBDEFAULTSIMULATORINTERFACE__ #include #include #include "TRandom3.h" #include "km3net-dataformat/online/JDAQ.hh" #include "km3net-dataformat/online/JDAQClock.hh" #include "km3net-dataformat/online/JDAQHit.hh" #include "km3net-dataformat/online/JDAQSuperFrame.hh" #include "km3net-dataformat/online/JDAQClock.hh" #include "JLang/JSinglePointer.hh" #include "JDAQ/JHighRateVeto.hh" #include "JDetector/JCLBSimulator.hh" #include "JDetector/JModuleIdentifier.hh" #include "JDetector/JPMTIdentifier.hh" /** * \author mdejong */ namespace JDETECTOR {} namespace JPP { using namespace JDETECTOR; } namespace JDETECTOR { using KM3NETDAQ::JDAQHit; using KM3NETDAQ::JDAQSuperFrame; /** * Default CLB simulation. * * This class provides for a default implementation of the JCLBSimulator interface * which is based on a simulation of the TDC and the state machine inside the CLB. * The actual number of hits may change due to the high-rate veto and UDP packet loss * (loss of hits) and the dynamic range of the time-over-threshold (gain of hits). * * The nested class JStateMachine constitutes a user interface for the simulation * of the state machine through method JStateMachine::maybeSwapped(). * With the default implementation, the overall time ordering if hits is maintained. * For a realistic simulation of the CLB, a pointer to a designated implementation * of this interface should be provided. * * The implementation of the virtual method JCLBDefaultSimulatorInterface::processData * provides for the settings of the status of the data frame.\n * In this, the high-rate veto is set when: * - virtual method JCLBDefaultSimulatorInterface::getHighRateVeto returns true for the given PMT; or * - number of hits from the PMT exceeds KM3NETDAQ::getMaximalNumberOfHits. */ class JCLBDefaultSimulatorInterface : public JCLBSimulator { public: typedef JDAQHit::JPMT_t JPMT_t; typedef JDAQHit::JTDC_t JTDC_t; typedef JDAQHit::JTOT_t JTOT_t; /** * Interface for TDC. */ class JTDC { public: /** * Virtual destructor. */ virtual ~JTDC() {} /** * Make DAQ hit. * * \param pmt PMT channel * \param t_ns time of hit [ns] * \param tot_ns time over threshold [ns] * \return DAQ hit */ virtual JDAQHit makeHit(const JPMT_t pmt, const double t_ns, const JTOT_t tot_ns) const { return JDAQHit(pmt, (JTDC_t) t_ns, tot_ns); } }; /** * Interface to mimic hit ordering effects due to state machine inside CLB. */ class JStateMachine { public: /** * Virtual destructor. */ virtual ~JStateMachine() {} /** * Test whether two consecutive hits may be swapped. * * \param first first DAQ hit * \param second second DAQ hit * \return true if first and second hit may be swapped; else false */ virtual bool maybeSwapped(const JDAQHit& first, const JDAQHit& second) const { return false; } }; /** * Constructor. * * This class owns the objects pointed to. * * \param TDC pointer to TDC simulator * \param state_machine pointer to state machine */ JCLBDefaultSimulatorInterface(JTDC* TDC, JStateMachine* state_machine) : JCLBSimulator(), TDC (TDC), state_machine(state_machine) {} /** * Get DAQ frame status of given module. * * \param id module identifier * \return DAQ frame status */ JDAQFrameStatus getDAQFrameStatus(const JModuleIdentifier& id) const { using namespace KM3NETDAQ; int daq = (DAQ_UDP_RECEIVED_PACKETS.write(getUDPNumberOfReceivedPackets(id)) | // DAQ_UDP_SEQUENCE_NUMBER .write(getUDPMaximalSequenceNumber (id))); // DAQ status int status = DAQ_WHITE_RABBIT.write(1); // TDC status int fifo = DAQ_UDP_TRAILER .write(hasUDPTrailer(id) ? 1 : 0); // FIFO status for (size_t pmt = 0; pmt != NUMBER_OF_PMTS; ++pmt) { JBit(pmt).set(status, getHighRateVeto(JPMTIdentifier(id,pmt)) ? 1 : 0) ; // high-rate veto } return JDAQFrameStatus(daq, status, fifo); } /** * Process data. * * \param id module identifier * \param input PMT data * \param output CLB data */ virtual void processData(const JModuleIdentifier& id, const JCLBInput& input, JDAQSuperFrame& output) const override { using namespace std; using namespace KM3NETDAQ; const double Tmin = 0.0; // Minimal TDC value [ns] const double Tmax = getFrameTime(); // Maximal TDC value [ns] output.setDAQFrameStatus(getDAQFrameStatus(id)); buffer.clear(); size_t ns = 0; // current number of hits in data frame for (size_t pmt = 0; pmt != input.size(); ++pmt) { const JPMTData& in = input[pmt]; // TDC for (JPMTData::const_iterator hit = in.begin(); hit != in.end(); ++hit) { if (hit->t_ns >= Tmin && hit->t_ns <= Tmax) { double t1 = hit->t_ns; double tot = hit->tot_ns; // generate multiple hits if time-over-threshold exceeds dynamic range while (tot > JDAQHit::getMaximalToT()) { buffer.push_back(TDC->makeHit((JPMT_t) pmt, t1, (JTOT_t) JDAQHit::getMaximalToT())); t1 += JDAQHit::getMaximalToT(); tot -= JDAQHit::getMaximalToT(); } if (tot > getMinimalToT()) { buffer.push_back(TDC->makeHit((JPMT_t) pmt, t1, (JTOT_t) (tot + 0.5))); } } } if (buffer.size() > ns + getMaximalNumberOfHits()) { output.setHighRateVeto(pmt, true); buffer.resize(ns + getMaximalNumberOfHits()); } inplace_merge(buffer.begin(), buffer.begin() + ns, buffer.end()); ns = buffer.size(); } // simulate UDP packet loss const int n1 = getUDPNumberOfReceivedPackets(id); const int n2 = getUDPMaximalSequenceNumber (id); if (n1 < n2 + 1) { JTDC_t t0 = (JTDC_t) Tmin; JTDC_t ts = (JTDC_t) ((Tmax - Tmin) / (n2 + 1)); for (int i = 0; i != n2 + 1; ++i, t0 += ts) { if (gRandom->Rndm() * (n2 + 1) >= (double) n1) { std::vector::iterator p = lower_bound(buffer.begin(), buffer.end(), t0, compare); std::vector::iterator q = lower_bound(buffer.begin(), buffer.end(), t0 + ts, compare); buffer.erase(p,q); } } } // process data through state machine if (buffer.size() > 1) { for (std::vector::iterator q = buffer.begin(), p = q++; q != buffer.end(); ++p, ++q) { if (state_machine->maybeSwapped(*p,*q)) { iter_swap(p,q); } } } // store data output.add(buffer.size(), buffer.data()); } /** * Get number of received UDP packets. * * \param id module identifier * \return 2 */ virtual int getUDPNumberOfReceivedPackets(const JModuleIdentifier& id) const { return 2; } /** * Get maximal sequence number of UDP packet. * * \param id module identifier * \return 1 */ virtual int getUDPMaximalSequenceNumber(const JModuleIdentifier& id) const { return 1; } /** * Get UDP trailer status. * * \param id module identifier * \return true */ virtual bool hasUDPTrailer(const JModuleIdentifier& id) const { return true; } /** * Get high-rate veto of given PMT. * * \param id PMT identifier * \return false */ virtual bool getHighRateVeto(const JPMTIdentifier& id) const { return false; } /** * Get minimal pulse length of time-over-threshold measurement. * * \return TDC value [ns] */ static double getMinimalToT() { return 0.5; } /** * Auxiliary data structure for sorting of hits. */ static const struct compare { /** * Compare hits by time. * * \param first first hit * \param second second hit * \return true if first earlier than second; else false */ bool operator()(const JDAQHit& first, const JDAQHit& second) const { return first.getT() < second.getT(); } /** * Compare hit and TDC value. * * \param hit hit * \param tdc TDC * \return true if hit earlier than given TDC value; else false */ bool operator()(const JDAQHit& hit, const JTDC_t tdc) const { return hit.getT() < tdc; } } compare; private: JLANG::JSinglePointer TDC; JLANG::JSinglePointer state_machine; mutable std::vector buffer; }; } #endif