コード例 #1
0
ファイル: DetectorDriver.cpp プロジェクト: akeeler/pixie_scan
void DetectorDriver::LoadProcessors(Messenger& m) {
    pugi::xml_document doc;
    pugi::xml_parse_result result = doc.load_file("Config.xml");
    if (!result) {
        stringstream ss;
        ss << "DetectorDriver: error parsing file Config.xml";
        ss << " : " << result.description();
        throw IOException(ss.str());
    }

    DetectorLibrary::get();

    pugi::xml_node driver = doc.child("Configuration").child("DetectorDriver");
    for (pugi::xml_node processor = driver.child("Processor"); processor;
        processor = processor.next_sibling("Processor")) {
        string name = processor.attribute("name").value();

        m.detail("Loading " + name);
        if (name == "BetaScintProcessor") {
            double gamma_beta_limit =
                processor.attribute("gamma_beta_limit").as_double(200.e-9);
            if (gamma_beta_limit == 200.e-9)
                m.warning("Using default gamme_beta_limit = 200e-9", 1);
            double energy_contraction =
                processor.attribute("energy_contraction").as_double(1.0);
            if (energy_contraction == 1)
                m.warning("Using default energy contraction = 1", 1);
            vecProcess.push_back(new BetaScintProcessor(gamma_beta_limit,
                                                        energy_contraction));
        } else if (name == "GeProcessor") {
            double gamma_threshold =
                processor.attribute("gamma_threshold").as_double(1.0);
            if (gamma_threshold == 1.0)
                m.warning("Using default gamma_threshold = 1.0", 1);
            double low_ratio =
                processor.attribute("low_ratio").as_double(1.0);
            if (low_ratio == 1.0)
                m.warning("Using default low_ratio = 1.0", 1);
            double high_ratio =
                processor.attribute("high_ratio").as_double(3.0);
            if (high_ratio == 3.0)
                m.warning("Using default high_ratio = 3.0", 1);
            double sub_event =
                processor.attribute("sub_event").as_double(100.e-9);
            if (sub_event == 100.e-9)
                m.warning("Using default sub_event = 100e-9", 1);
            double gamma_beta_limit =
                processor.attribute("gamma_beta_limit").as_double(200.e-9);
            if (gamma_beta_limit == 200.e-9)
                m.warning("Using default gamme_beta_limit = 200e-9", 1);
            double gamma_gamma_limit =
                processor.attribute("gamma_gamma_limit").as_double(200.e-9);
            if (gamma_gamma_limit == 200.e-9)
                m.warning("Using default gamma_gamma_limit = 200e-9", 1);
            double cycle_gate1_min =
                processor.attribute("cycle_gate1_min").as_double(0.0);
            if (cycle_gate1_min == 0.0)
                m.warning("Using default cycle_gate1_min = 0.0", 1);
            double cycle_gate1_max =
                processor.attribute("cycle_gate1_max").as_double(0.0);
            if (cycle_gate1_max == 0.0)
                m.warning("Using default cycle_gate1_max = 0.0", 1);
            double cycle_gate2_min =
                processor.attribute("cycle_gate2_min").as_double(0.0);
            if (cycle_gate2_min == 0.0)
                m.warning("Using default cycle_gate2_min = 0.0", 1);
            double cycle_gate2_max =
                processor.attribute("cycle_gate2_max").as_double(0.0);
            if (cycle_gate2_max == 0.0)
                m.warning("Using default cycle_gate2_max = 0.0", 1);
            vecProcess.push_back(new GeProcessor(gamma_threshold, low_ratio,
                high_ratio, sub_event, gamma_beta_limit, gamma_gamma_limit,
                cycle_gate1_min, cycle_gate1_max, cycle_gate2_min,
                cycle_gate2_max));
        } else if (name == "GeCalibProcessor") {
            double gamma_threshold =
                processor.attribute("gamma_threshold").as_double(1);
            double low_ratio =
                processor.attribute("low_ratio").as_double(1);
            double high_ratio =
                processor.attribute("high_ratio").as_double(3);
            vecProcess.push_back(new GeCalibProcessor(gamma_threshold,
                low_ratio, high_ratio));
        } else if (name == "Hen3Processor") {
            vecProcess.push_back(new Hen3Processor());
        } else if (name == "IonChamberProcessor") {
            vecProcess.push_back(new IonChamberProcessor());
        } else if (name == "LiquidScintProcessor") {
            vecProcess.push_back(new LiquidScintProcessor());
        } else if (name == "LogicProcessor") {
            vecProcess.push_back(new LogicProcessor());
        } else if (name == "NeutronScintProcessor") {
            vecProcess.push_back(new NeutronScintProcessor());
        } else if (name == "PositionProcessor") {
            vecProcess.push_back(new PositionProcessor());
        } else if (name == "PulserProcessor") {
            vecProcess.push_back(new PulserProcessor());
        } else if (name == "SsdProcessor") {
            vecProcess.push_back(new SsdProcessor());
        } else if (name == "VandleProcessor") {
            double res = processor.attribute("res").as_double(2.0);
            double offset = processor.attribute("offset").as_double(200.0);
            unsigned int numStarts = processor.attribute("NumStarts").as_int(2);
            vector<string> types =
                strings::tokenize(processor.attribute("types").as_string(),",");
            vecProcess.push_back(new VandleProcessor(types, res,
                offset, numStarts));
        } else if (name == "TeenyVandleProcessor") {
                vecProcess.push_back(new TeenyVandleProcessor());
        } else if (name == "DoubleBetaProcessor") {
            vecProcess.push_back(new DoubleBetaProcessor());
        } else if (name == "PspmtProcessor") {
                vecProcess.push_back(new PspmtProcessor());
        } else if (name == "TemplateProcessor") {
            vecProcess.push_back(new TemplateProcessor());
        } else if (name == "TemplateExpProcessor") {
            vecProcess.push_back(new TemplateExpProcessor());
	}
#ifdef useroot
        else if (name == "RootProcessor") {
            vecProcess.push_back(new RootProcessor("tree.root", "tree"));
        }
#endif
        else {
            stringstream ss;
            ss << "DetectorDriver: unknown processor type" << name;
            throw GeneralException(ss.str());
        }
        stringstream ss;
        for (pugi::xml_attribute_iterator ait = processor.attributes_begin();
            ait != processor.attributes_end(); ++ait) {
            ss.str("");
            ss << ait->name();
            if (ss.str().compare("name") != 0) {
                ss << " = " << ait->value();
                m.detail(ss.str(), 1);
            }
        }
    }

    for (pugi::xml_node analyzer = driver.child("Analyzer"); analyzer;
        analyzer = analyzer.next_sibling("Analyzer")) {
        string name = analyzer.attribute("name").value();
        m.detail("Loading " + name);

	if(name == "TraceFilterAnalyzer") {
	    vecAnalyzer.push_back(new TraceFilterAnalyzer());
	}/* else if (name == "DoubleTraceAnalyzer") {
            double gain_match = analyzer.attribute("gain_match").as_double(1.0);
            if (gain_match == 1.0)
                m.warning("Using gain_match = 1.0", 1);
            int fast_rise = analyzer.attribute("fast_rise").as_int(10);
            if (fast_rise == 10)
                m.warning("Using fast_rise = 10", 1);
            int fast_gap = analyzer.attribute("fast_gap").as_int(10);
            if (fast_gap == 10)
                m.warning("Using fast_gap = 10", 1);
            int fast_threshold =
                analyzer.attribute("fast_threshold").as_int(50);
            if (fast_threshold == 50)
                m.warning("Using fast_threshold = 50", 1);
            int energy_rise = analyzer.attribute("energy_rise").as_int(50);
            if (energy_rise == 50)
                m.warning("Using energy_rise = 50", 1);
            int energy_gap = analyzer.attribute("energy_gap").as_int(50);
            if (energy_gap == 50)
                m.warning("Using energy_gap = 50", 1);
            int slow_rise = analyzer.attribute("slow_rise").as_int(20);
            if (slow_rise == 20)
                m.warning("Using slow_rise = 20", 1);
            int slow_gap = analyzer.attribute("slow_gap").as_int(20);
            if (slow_gap == 20)
                m.warning("Using slow_gap = 20", 1);
            int slow_threshold =
                analyzer.attribute("slow_threshold").as_int(10);
            if (slow_threshold == 10)
                m.warning("Using slow_threshold = 10", 1);
            else if (name == "DoubleTraceAnalyzer")
                vecAnalyzer.push_back(new DoubleTraceAnalyzer(gain_match,
                    fast_rise, fast_gap, fast_threshold, energy_rise,
                    energy_gap, slow_rise, slow_gap, slow_threshold));
		    }*/ else if (name == "TauAnalyzer") {
            vecAnalyzer.push_back(new TauAnalyzer());
        } else if (name == "TraceExtractor") {
            string type = analyzer.attribute("type").as_string();
            string subtype = analyzer.attribute("subtype").as_string();
            string tag = analyzer.attribute("tag").as_string();
            vecAnalyzer.push_back(new TraceExtractor(type, subtype,tag));
        } else if (name == "WaveformAnalyzer") {
            vecAnalyzer.push_back(new WaveformAnalyzer());
        } else if (name == "FittingAnalyzer") {
            vecAnalyzer.push_back(new FittingAnalyzer());
        } else if (name == "CfdAnalyzer") {
            vecAnalyzer.push_back(new CfdAnalyzer());
        } else {
            stringstream ss;
            ss << "DetectorDriver: unknown analyzer type" << name;
            throw GeneralException(ss.str());
        }

        for (pugi::xml_attribute_iterator ait = analyzer.attributes_begin();
             ait != analyzer.attributes_end(); ++ait) {
            stringstream ss;
            ss << ait->name();
            if (ss.str().compare("name") != 0) {
                ss << " = " << ait->value();
                m.detail(ss.str(), 1);
            }
        }
    }
}
コード例 #2
0
ファイル: Globals.cpp プロジェクト: gottardo7/pixie_scan
void Globals::WarnOfUnknownParameter(Messenger &m,
                                     pugi::xml_node_iterator &it) {
    std::stringstream ss;
    ss << "Unknown parameter in Config.xml : " << it->path();
    m.warning(ss.str());
}
コード例 #3
0
ファイル: PixieStd.cpp プロジェクト: kmiernik/pixie_scan
/** \brief event by event analysis
 *
 * ScanList() operates on the time sorted list of all channels that triggered in
 * a given spill.  Starting from the begining of the list and continuing to the
 * end, an individual channel event time is compared with the previous channel
 * event time to determine if they occur within a time period defined by the
 * diff_t variable (time is in units of 10 ns).  Depending on the answer,
 * different actions are performed:
 *   - yes - the two channels are grouped together as belonging to the same event
 *   and the current channel is added to the list of channels for the rawevent
 *   - no - the previous rawevent is sent for processing and once finished, the
 *   rawevent is zeroed and the current channel placed inside it.
 * \param [in] eventList : The event list to scan
 * \param [in] rawev : the raw event to read */
void ScanList(vector<ChanEvent*> &eventList, RawEvent& rawev) {
    unsigned long chanTime, eventTime;

    DetectorLibrary* modChan = DetectorLibrary::get();
    DetectorDriver* driver = DetectorDriver::get();
    Messenger messenger;
    stringstream ss;
    /** Rejection regions */
    vector< pair<int, int> > rejectRegions = Globals::get()->rejectRegions();

    // local variable for the detectors used in a given event
    set<string> usedDetectors;

    vector<ChanEvent*>::iterator iEvent = eventList.begin();

    // local variables for the times of the current event, previous
    // event and time difference between the two
    double diffTime = 0;

    //set last_t to the time of the first event
    double lastTime = (*iEvent)->GetTime();
    double currTime = lastTime;
    unsigned int id = (*iEvent)->GetID();

    /* KM
     * Save time of the beginning of the file,
     * this is needed for the rejection regions */
    static double firstTime = lastTime;
    HistoStats(id, diffTime, lastTime, BUFFER_START);

    //loop over the list of channels that fired in this buffer
    for(; iEvent != eventList.end(); iEvent++) {
        id = (*iEvent)->GetID();
        if (id == pixie::U_DELIMITER) {
            ss << "pattern 0 ignore";
            messenger.warning(ss.str());
            ss.str("");
            continue;
        }
        if ((*modChan)[id].GetType() == "ignore") {
            continue;
        }

        // this is a channel we're interested in
        chanTime  = (*iEvent)->GetTrigTime();
        eventTime = (*iEvent)->GetEventTimeLo();

        /* retrieve the current event time and determine the time difference
        between the current and previous events.
        */
        currTime = (*iEvent)->GetTime();
        diffTime = currTime - lastTime;

        /* KM: rejection of bad regions
         * If time (in sec) is within the 'bad' region
         * just drop the rest of this for loop and go for another buffer
         *
         * Do checks only if hasReject flag is True.
         */
        if (Globals::get()->hasReject()) {
            double bufferTime = (currTime - firstTime) *
                                 Globals::get()->clockInSeconds();
            bool rejectBuffer = false;
            for (vector< pair<int, int> >::iterator region = rejectRegions.begin();
                 region != rejectRegions.end();
                 ++region ) {
                /** If event time is within a rejection region
                 * set rejectBuffer flag true and stop checking */
                if (bufferTime > region->first &&
                    bufferTime < region->second) {
                    rejectBuffer = true;
                    break;
                }
            }
            if (rejectBuffer)
                continue;
        }
        /* end KM */

        /* if the time difference between the current and previous event is
        larger than the event width, finalize the current event, otherwise
        treat this as part of the current event
        */
        if ( diffTime > Globals::get()->eventWidth() ) {
            if(rawev.Size() > 0) {
            /* detector driver accesses rawevent externally in order to
            have access to proper detector_summaries
            */
                driver->ProcessEvent(rawev);
            }

            //after processing zero the rawevent variable
            rawev.Zero(usedDetectors);
            usedDetectors.clear();

            // Now clear all places in correlator (if resetable type)
            for (map<string, Place*>::iterator it =
                    TreeCorrelator::get()->places_.begin();
                it != TreeCorrelator::get()->places_.end(); ++it)
                if ((*it).second->resetable())
                    (*it).second->reset();
            HistoStats(id, diffTime, currTime, EVENT_START);
        } else HistoStats(id, diffTime, currTime, EVENT_CONTINUE);

        unsigned long dtimebin = 2000 + eventTime - chanTime;
        if (dtimebin < 0 || dtimebin > (unsigned)(SE)) {
            ss << "strange dtime for id " << id << ":" << dtimebin;
            messenger.warning(ss.str());
            ss.str("");
        }
        driver->plot(D_TIME + id, dtimebin);
        usedDetectors.insert((*modChan)[id].GetType());
        rawev.AddChan(*iEvent);

        // update the time of the last event
        lastTime = currTime;
    } //end loop over event list

    //process the last event in the buffer
    if (rawev.Size() > 0) {
        string mode;
        HistoStats(id, diffTime, currTime, BUFFER_END);

        driver->ProcessEvent(rawev);
        rawev.Zero(usedDetectors);
    }
}
コード例 #4
0
ファイル: PixieStd.cpp プロジェクト: kmiernik/pixie_scan
/**
 * At various points in the processing of data in ScanList(), HistoStats() is
 * called to increment some low level pixie16 informational and diagnostic
 * spectra.  The list of spectra filled includes runtime in second and
 * milliseconds, the deadtime, time between events, and time width of an event.
 * \param [in] id : the id of the channel
 * \param [in] diff : The difference between current clock and last one
 * \param [in] clock : The current clock
 * \param [in] event : The type of event we are dealing with
 */
void HistoStats(unsigned int id, double diff, double clock, HistoPoints event) {
    static const int specNoBins = SE;

    static double start, stop;
    static int count;
    static double firstTime = 0.;
    static double bufStart;

    double runTimeSecs   = (clock - firstTime) *
                           Globals::get()->clockInSeconds();
    int    rowNumSecs    = int(runTimeSecs / specNoBins);
    double remainNumSecs = runTimeSecs - rowNumSecs * specNoBins;

    double runTimeMsecs   = runTimeSecs * 1000;
    int    rowNumMsecs    = int(runTimeMsecs / specNoBins);
    double remainNumMsecs = runTimeMsecs - rowNumMsecs * specNoBins;

    static double bufEnd = 0, bufLength = 0;
    // static double deadTime = 0 // not used
    DetectorDriver* driver = DetectorDriver::get();
    Messenger messenger;
    stringstream ss;

    if (firstTime > clock) {
        ss << "Backwards clock jump detected: prior start " << firstTime
           << ", now " << clock;
        messenger.warning(ss.str());
        ss.str("");
        // detect a backwards clock jump which occurs when some of the
        //   last buffers of a previous run sneak into the beginning of the
        //   next run, elapsed time of last buffers is usually small but
        //   just in case make some room for it
        double elapsed = stop - firstTime;
        // make an artificial 10 second gap by
        //   resetting the first time accordingly
        firstTime = clock - 10 / Globals::get()->clockInSeconds() - elapsed;
        ss << elapsed * Globals::get()->clockInSeconds()
           << " prior seconds elapsed "
           << ", resetting first time to " << firstTime;
        messenger.detail(ss.str());
        ss.str("");
    }

    switch (event) {
        case BUFFER_START:
            bufStart = clock;
            if(firstTime == 0.) {
                firstTime = clock;
            } else if (bufLength != 0.){
                //plot time between buffers as a function
                //of time - dead time spectrum
                // deadTime += (clock - bufEnd)*pixie::clockInSeconds;
                // plot(DD_DEAD_TIME_CUMUL,remainNumSecs,rownum,int(deadTime/runTimeSecs));
                driver->plot(dammIds::raw::DD_BUFFER_START_TIME, remainNumSecs,
                             rowNumSecs, (clock-bufEnd)/bufLength*1000.);
            }
            break;
        case BUFFER_END:
            driver->plot(D_BUFFER_END_TIME, (stop - bufStart) *
                                      Globals::get()->clockInSeconds() * 1000);
            bufEnd = clock;
            bufLength = clock - bufStart;
        case EVENT_START:
            driver->plot(D_EVENT_LENGTH, stop - start);
            driver->plot(D_EVENT_GAP, diff);
            driver->plot(D_EVENT_MULTIPLICITY, count);

            start = stop = clock; // reset the counters
            count = 1;
            break;
        case EVENT_CONTINUE:
            count++;
            if(diff > 0.) {
                driver->plot(D_SUBEVENT_GAP, diff + 100);
            }
            stop = clock;
            break;
        default:
            ss << "Unexpected type " << event << " given to HistoStats";
            messenger.warning(ss.str());
            ss.str("");
    }

    //fill these spectra on all events, id plots and runtime.
    // Exclude event type 0/1 since it will also appear as an
    // event type 11
    if ( event != BUFFER_START && event != BUFFER_END ){
        driver->plot(DD_RUNTIME_SEC, remainNumSecs, rowNumSecs);
        driver->plot(DD_RUNTIME_MSEC, remainNumMsecs, rowNumMsecs);
        //fill scalar spectrum (per second)
        driver->plot(D_HIT_SPECTRUM, id);
        driver->plot(D_SCALAR + id, runTimeSecs);
    }
}
コード例 #5
0
ファイル: PixieStd.cpp プロジェクト: kmiernik/pixie_scan
extern "C" void hissub_(unsigned short *ibuf[],unsigned short *nhw)
#endif
{
    static float hz = sysconf(_SC_CLK_TCK); // get the number of clock ticks per second
    static clock_t clockBegin; // initialization time
    static struct tms tmsBegin;

    vector<ChanEvent*> eventList; // vector to hold the events

    /* Pointer to singleton DetectorLibrary class */
    DetectorLibrary* modChan = DetectorLibrary::get();
    /* Pointer to singleton DetectorDriver class */
    DetectorDriver* driver = DetectorDriver::get();
    /* Screen messenger */
    Messenger messenger;
    stringstream ss;

    // local version of ibuf pointer
    word_t *lbuf;

    int retval = 0; // return value from various functions

    unsigned long bufLen;

    /*
      Various event counters
    */
    unsigned long numEvents = 0;
    static int counter = 0; // the number of times this function is called
    static int evCount;     // the number of times data is passed to ScanList
    static unsigned int lastVsn; // the last vsn read from the data
    time_t theTime = 0;

    /*
      Assign the local variable lbuf to the variable ibuf which is passed into
      the routine.  The difference between the new and old pixie16 readouts is
      the type of the variable and source of the variable ibuf.

      In the new readout ibuf is from a C++ function and is of type unsigned int*
      In the old readout ibuf is from a Fortran function and is of type
      unsigned short*

      This results in two different assignment statements depending on
      the readout.
    */
#ifdef newreadout
    lbuf=(word_t *)ibuf[0];
#else
    lbuf=(word_t *)ibuf; //old readout
#endif

    /* Initialize the scan program before the first event */
    if (counter==0) {
        /* Retrieve the current time for use later to determine the total
        * running time of the analysis.
        */
        messenger.start("Initializing scan");

        string revision = Globals::get()->revision();
        // Initialize function pointer to point to
        // correct version of ReadBuffData
        if (revision == "D" || revision == "F")
            ReadBuffData = ReadBuffDataDF;
        else if (revision == "A")
            ReadBuffData = ReadBuffDataA;

        clockBegin = times(&tmsBegin);

        ss << "First buffer at " << clockBegin << " sys time";
        messenger.detail(ss.str());
        ss.str("");

        /* After completion the descriptions of all channels are in the modChan
        * vector, the DetectorDriver and rawevent have been initialized with the
        * detectors that will be used in this analysis.
        */
        modChan->PrintUsedDetectors(rawev);
        driver->Init(rawev);

        /* Make a last check to see that everything is in order for the driver
        * before processing data. SanityCheck function throws exception if
        * something went wrong.
        */
        try {
            driver->SanityCheck();
        } catch (GeneralException &e) {
            messenger.fail();
            cout << "Exception caught while checking DetectorDriver"
                 << " sanity in PixieStd" << endl;
            cout << "\t" << e.what() << endl;
            exit(EXIT_FAILURE);
        } catch (GeneralWarning &w) {
            cout << "Warning caught during checking DetectorDriver"
                 << " at PixieStd" << endl;
            cout << "\t" << w.what() << endl;
        }

        lastVsn=-1; // set last vsn to -1 so we expect vsn 0 first

        ss << "Init at " << times(&tmsBegin) << " sys time.";
        messenger.detail(ss.str());
        messenger.done();
    }
    counter++;

    unsigned int nWords=0;  // buffer counter, reset only for new buffer

    // true if the buffer being analyzed is split across a spill from pixie
    bool multSpill;

    do {
        word_t vsn = pixie::U_DELIMITER;
        //true if spill had all vsn's
        bool fullSpill = false;
        //assume all buffers are not split between spills
        multSpill = false;

        /* while the current location in the buffer has not gone beyond the end
         * of the buffer (ignoring the last three delimiters,
         * continue reading */
        while (nWords < (nhw[0]/2 - 6)) {
            /*
            Retrieve the record length and the vsn number
            */
            word_t lenRec = lbuf[nWords];
            vsn = lbuf[nWords+1];

            /* If the record length is -1 (after end of spill), increment the
            location in the buffer by two and start over with the while loop
            */
            if (lenRec == pixie::U_DELIMITER) {
                nWords += 2;  // increment two whole words and try again
                continue;
            }
            // Buffer with vsn 1000 was inserted with
            // the time for superheavy exp't
            if (vsn == pixie::clockVsn) {
                memcpy(&theTime, &lbuf[nWords+2], sizeof(time_t));
                nWords += lenRec;
            }

            /* If the record length is 6, this is an empty channel.
             * Skip this vsn and continue with the next
            */
            //! Revision specific, so move to ReadBuffData
            if (lenRec == 6) {
                nWords += lenRec+1; // one additional word for delimiter
                lastVsn=vsn;
                continue;
            }
            /* If both the current vsn inspected is within an
             * acceptable range, begin reading the buffer.
             */
            if ( vsn < modChan->GetPhysicalModules()  ) {
                if ( lastVsn != pixie::U_DELIMITER) {
                // the modules should be read out cyclically
                    if ( ((lastVsn+1) % modChan->GetPhysicalModules() ) !=
                           vsn ) {
#ifdef VERBOSE
                            ss << " MISSING BUFFER " << vsn << "/"
                            << modChan->GetPhysicalModules()
                            << " -- lastVsn = " << lastVsn << "  "
                            << ", length = " << lenRec;
                            messenger.warning(ss.str());
                            ss.str("");
#endif
                            RemoveList(eventList);
                            fullSpill=true;
                    }
                }
                /* Read the buffer.  After read, the vector eventList will
                   contain pointers to all channels that fired in this buffer
                */
                retval= (*ReadBuffData)(&lbuf[nWords], &bufLen, eventList);
                /* If the return value is less than the error code,
                   reading the buffer failed for some reason.
                   Print error message and reset variables if necessary
                 */
                if ( retval <= readbuff::ERROR ) {
                    ss << " READOUT PROBLEM " << retval
                       << " in event " << counter;
                    messenger.warning(ss.str());
                    ss.str("");
                    if ( retval == readbuff::ERROR ) {
                        ss << "  Remove list " << lastVsn
                           << " " << vsn;
                        RemoveList(eventList);
                        messenger.warning(ss.str());
                        ss.str("");
                    }
                    return;
                } else if ( retval == 0 ) {
                    // empty buffers are regular in Rev. D data
                    // cout << " EMPTY BUFFER" << endl;
                    nWords += lenRec + 1;
                    lastVsn = vsn;
                    continue;
                } else if ( retval > 0 ) {
                    /* increment the total number of events observed */
                    numEvents += retval;
                }
                /* Update the variables that are keeping track of what has been
                   analyzed and increment the location in the current buffer
                */
                    lastVsn = vsn;
                    nWords += lenRec+1; // one extra word for delimiter
            } else {
                // bail out if we have lost our place,
                //   (bad vsn) and process events
                if (vsn != 9999 && vsn != pixie::clockVsn) {
#ifdef VERBOSE
                    ss << "UNEXPECTED VSN " << vsn;
                    messenger.warning(ss.str());
                    ss.str("");
#endif
                }
                break;
            }
        } // while still have words
        if (nWords > nhw[0] / 2 - 6) {
            ss << "This actually happens!";
            messenger.run_message(ss.str());
            ss.str("");
        }

        /* If the vsn is 9999 this is the end of a spill, signal this buffer
           for processing and determine if the buffer is split between spills.
        */
            if ( vsn == 9999 || vsn == pixie::clockVsn ) {
                fullSpill = true;
                nWords += 3;//skip it
                if (lbuf[nWords+1] != pixie::U_DELIMITER) {
                    ss << "this actually happens!";
                    messenger.warning(ss.str());
                    ss.str("");
                    multSpill = true;
                }
                lastVsn=pixie::U_DELIMITER;
            }

            /* if there are events to process, continue */
            if( numEvents > 0 ) {
                if (fullSpill) { 	  // if full spill process events
                    // sort the vector of pointers eventlist according to time
                    double lastTimestamp = (*(eventList.rbegin()))->GetTime();

                    sort(eventList.begin(),eventList.end(),CompareTime);
                    driver->CorrelateClock(lastTimestamp, theTime);

                    /* once the vector of pointers eventlist is sorted
                     * based on time, begin the event processing in ScanList()
                    */
                    ScanList(eventList, rawev);

                    /* once the eventlist has been scanned, remove it
                     * from memory and reset the number of events to zero
                     * and update the event counter
                    */

                    evCount++;
                    /*
                    every once in a while (when evcount is a multiple of 1000)
                    print the time elapsed doing the analysis
                    */
                    if(evCount % 1000 == 0 || evCount == 1) {
                        tms tmsNow;
                        clock_t clockNow = times(&tmsNow);

                        stringstream ss;
                        if (theTime != 0) {
                            string timestamp = string(ctime(&theTime));
                            timestamp.erase(timestamp.find_last_not_of(" \t\n\r") + 1);
                            ss << "Data read up to poll status time "
                            << timestamp;
                            messenger.run_message(ss.str());
                            ss.str("");
                        }
                        ss << "buffer = " << evCount << ", user time = "
                           << (tmsNow.tms_utime - tmsBegin.tms_utime) / hz
                           << ", system time = "
                           << (tmsNow.tms_stime - tmsBegin.tms_stime) / hz
                           << ", real time = "
                           << (clockNow - clockBegin) / hz
                           << ", ts = " << lastTimestamp;
                        messenger.run_message(ss.str());
                    }
                    RemoveList(eventList);
                    numEvents = 0;
                } // end fullSpill
                else {
                    stringstream ss;
                    ss << "Spill split between buffers";
                    messenger.run_message(ss.str());
                    //! this tosses out all events read into the vector so far
                    return;
                }
            }  // end numEvents > 0
            else if (retval != readbuff::STATS) {
                stringstream ss;
                ss << "bad buffer, numEvents = " << numEvents;
                messenger.warning(ss.str());
                return;
            }
    } while (multSpill); // end while loop over multiple spills
    return;
}