Esempio n. 1
0
bool PspmtProcessor::PreProcess(RawEvent &event) {
    if (!EventProcessor::PreProcess(event))
        return false;

    static const vector<ChanEvent *> &pspmtEvents = sumMap["pspmt"]->GetList();

    data_.Clear();

    double q1 = 0, q2 = 0, q3 = 0, q4 = 0, qd = 0;
    double qdc1 = 0, qdc2 = 0, qdc3 = 0, qdc4 = 0, qdcd = 0;
    double tre1 = 0, tre2 = 0, tre3 = 0, tre4 = 0, tred = 0;

    double qright = 0, qleft = 0, qtop = 0, qbottom = 0, qsum = 0;
    double xright = 0, xleft = 0, ytop = 0, ybottom = 0;

    double qtre_r = 0, qtre_l = 0, qtre_t = 0, qtre_b = 0, qtre_s = 0;
    double xtre_r = 0, xtre_l = 0, ytre_t = 0, ytre_b = 0;

    double qqdc_r = 0, qqdc_l = 0, qqdc_t = 0, qqdc_b = 0, qqdc_s = 0;
    //double xqdc_r=0,xqdc_l=0,yqdc_t=0,yqdc_b=0;

    double pxright = 0, pxleft = 0, pytop = 0, pybottom = 0;
    double pxtre_r = 0, pxtre_l = 0, pytre_t = 0, pytre_b = 0;

    // tentatively local params //
    double threshold = 260;
    double slope = 0.0606;
    double intercept = 10.13;
    //////////////////////////////
    static int traceNum;

    double f = 0.1;

    for (vector<ChanEvent *>::const_iterator it = pspmtEvents.begin();
         it != pspmtEvents.end(); it++) {

        ChanEvent *chan = *it;
        string subtype = chan->GetChanID().GetSubtype();
        int ch = chan->GetChanID().GetLocation();
        double calEnergy = chan->GetCalibratedEnergy();
        //double pspmtTime  = chan->GetTime();
        Trace trace = chan->GetTrace();

        double trace_energy;
        //double trace_time;
        //double baseline;
        double qdc;
        //int    num        = trace.GetValue("numPulses");

        if (!trace.GetFilteredEnergies().empty()) {
            traceNum++;
            //trace_time      = trace.GetValue("filterTime");
            trace_energy = trace.GetFilteredEnergies().front();
            //baseline         = trace.GetValue("baseline");
            qdc = trace.GetQdc();

            if (ch == 0) {
                qdc1 = qdc;
                tre1 = trace_energy;
                histo.Plot(D_QDC_TRACE1, qdc1);
                histo.Plot(D_ENERGY_TRACE1, tre1);
            } else if (ch == 1) {
                qdc2 = qdc;
                tre2 = trace_energy;
                histo.Plot(D_QDC_TRACE2, qdc2);
                histo.Plot(D_ENERGY_TRACE2, tre2);
            } else if (ch == 2) {
                qdc3 = qdc;
                tre3 = trace_energy;
                histo.Plot(D_QDC_TRACE3, qdc3);
                histo.Plot(D_ENERGY_TRACE3, tre3);
            } else if (ch == 3) {
                qdc4 = qdc;
                tre4 = trace_energy;
                histo.Plot(D_QDC_TRACE4, qdc4);
                histo.Plot(D_ENERGY_TRACE4, tre4);
            } else if (ch == 4) {
                qdcd = qdc;
                tred = trace_energy;
                histo.Plot(D_QDC_TRACED, qdcd);
                histo.Plot(D_ENERGY_TRACED, tred);
            }
        }

        if (ch == 0) {
            q1 = calEnergy;
            histo.Plot(D_RAW1, q1);
        } else if (ch == 1) {
            q2 = calEnergy;
            histo.Plot(D_RAW2, q2);
        } else if (ch == 2) {
            q3 = calEnergy;
            histo.Plot(D_RAW3, q3);
        } else if (ch == 3) {
            q4 = calEnergy;
            histo.Plot(D_RAW4, q4);
        } else if (ch == 4) {
            qd = calEnergy;
            histo.Plot(D_RAWD, qd);
        }

        if (q1 > 0 && q2 > 0 && q3 > 0 && q4 > 0) {
            qtop = (q1 + q2) / 2;
            qleft = (q2 + q3) / 2;
            qbottom = (q3 + q4) / 2;
            qright = (q4 + q1) / 2;

            qsum = (q1 + q2 + q3 + q4) / 2;
            xright = (qright / qsum) * 512 + 100;
            xleft = (qleft / qsum) * 512 + 100;
            ytop = (qtop / qsum) * 512 + 100;
            ybottom = (qbottom / qsum) * 512 + 100;
            histo.Plot(D_SUM, qsum);
        }

        if (tre1 > 0 && tre2 > 0 && tre3 > 0 && tre4 > 0) {
            qtre_t = (tre1 + tre2) / 2;
            qtre_l = (tre2 + tre3) / 2;
            qtre_b = (tre3 + tre4) / 2;
            qtre_r = (tre4 + tre1) / 2;
            qtre_s = (tre1 + tre2 + tre3 + tre4) / 2;

            xtre_r = (qtre_r / qtre_s) * 512 + 100;
            xtre_l = (qtre_l / qtre_s) * 512 + 100;
            ytre_t = (qtre_t / qtre_s) * 512 + 100;
            ytre_b = (qtre_b / qtre_s) * 512 + 100;

            pxtre_r = trunc(slope * xtre_l - intercept);
            pxtre_l = trunc(slope * xtre_r - intercept);
            pytre_t = trunc(slope * ytre_t - intercept);
            pytre_b = trunc(slope * ytre_b - intercept);

            histo.Plot(D_ENERGY_TRACESUM, qtre_s);

            if (tre1 > threshold && tre2 > threshold && tre3 > threshold &&
                tre4 > threshold) {
                histo.Plot(DD_POS1_RAW_TRACE, xtre_r, ytre_t);
                histo.Plot(DD_POS2_RAW_TRACE, xtre_l, ytre_b);
                histo.Plot(DD_POS1_TRACE, pxtre_r, pytre_t);
                histo.Plot(DD_POS2_TRACE, pxtre_l, pytre_b);
            }
        }

        if (qdc1 > 0 && qdc2 > 0 && qdc3 > 0 && qdc4 > 0) {
            qqdc_t = (qdc1 + qdc2) / 2;
            qqdc_l = (qdc2 + qdc3) / 2;
            qqdc_b = (qdc3 + qdc4) / 2;
            qqdc_r = (qdc4 + qdc1) / 2;
            qqdc_s = (qqdc_t + qqdc_l + qqdc_b + qqdc_r) / 2;

//            xqdc_r=(qqdc_r/qqdc_s)*512+100;
//            xqdc_l=(qqdc_l/qqdc_s)*512+100;
//            yqdc_t=(qqdc_t/qqdc_s)*512+100;
//            yqdc_b=(qqdc_b/qqdc_s)*512+100;

            histo.Plot(D_ENERGY_TRACESUM, qqdc_s);
        }

        if (q1 > threshold && q2 > threshold && q3 > threshold &&
            q4 > threshold) {
            pxleft = trunc(slope * xleft - intercept);
            pxright = trunc(slope * xright - intercept);
            pytop = trunc(slope * ytop - intercept);
            pybottom = trunc(slope * ybottom - intercept);

            histo.Plot(DD_POS1_RAW, xright, ytop);
            histo.Plot(DD_POS2_RAW, xleft, ybottom);
            histo.Plot(DD_POS1, pxright, pytop);
            histo.Plot(DD_POS2, pxleft, pybottom);

            if (xright > 341 && xright < 356 && ytop > 200 && ytop < 211) {
                histo.Plot(D_TEMP0, f * q1);
                histo.Plot(D_TEMP1, f * q2);
                histo.Plot(D_TEMP2, f * q3);
                histo.Plot(D_TEMP3, f * q4);
                histo.Plot(D_TEMP4, f * qd);
            }

            for (vector<unsigned int>::iterator ittr = trace.begin();
                 ittr != trace.end(); ittr++)
                histo.Plot(DD_SINGLE_TRACE, ittr - trace.begin(), traceNum, *ittr);
        }
    } // end of channel event

    EndProcess();
    return (true);
}
Esempio n. 2
0
bool ImplantSsdProcessor::Process(RawEvent &event)
{
    using namespace dammIds::implantSsd;

    if (!EventProcessor::Process(event)) {
        EndProcess();
	return false;
    }

    static bool firstTime = true;
    static LogicProcessor *logProc = NULL;

    static Correlator &corr = event.GetCorrelator();
    static const DetectorSummary *tacSummary  = event.GetSummary("generic:tac", true);
    static DetectorSummary *impSummary  = event.GetSummary("ssd:sum", true);
    static const DetectorSummary *mcpSummary  = event.GetSummary("logic:mcp", true);
    static const DetectorSummary *vetoSummary = event.GetSummary("ssd:veto", true);
    static const DetectorSummary *boxSummary  = event.GetSummary("ssd:box", true);
    DetectorDriver* driver = DetectorDriver::get();

    if (impSummary->GetMult() == 0) {
      EndProcess();
      return false;
    }
    if (firstTime) {
      vector<EventProcessor *> vecProc = driver->GetProcessors("logic");
      for (vector< EventProcessor * >::iterator it = vecProc.begin(); it != vecProc.end(); it++) {
	if ( (*it)->GetName() == "triggerlogic" || (*it)->GetName() == "logic" ) {
	  logProc = reinterpret_cast < LogicProcessor * >(*it);
  	  cout << "Implant SSD processor grabbed logic processor" << endl;
        }
      }
      firstTime=false;
    }

    EventInfo info;
    ChanEvent *ch  = impSummary->GetMaxEvent(true);
    info.hasVeto = ( vetoSummary && vetoSummary->GetMult() > 0 );

    int location = ch->GetChanID().GetLocation();
    if (ch->IsSaturated()) {
	info.energy = 16000; // arbitrary large number
    } else {
	info.energy  = ch->GetCalEnergy();
    }
    if (ch->GetTrace().HasValue("position")) {
	info.position = ch->GetTrace().GetValue("position");
    } // else it defaults to nan

    info.time    = ch->GetTime();
    info.beamOn  = true;

    // recect noise events
    if (info.energy < 10 || ch->GetTrace().HasValue("badqdc")) {
	EndProcess();
	return true;
    }

    if (logProc) {
	info.clockCount = logProc->StartCount(2);
	if (logProc->LogicStatus(3) || logProc->LogicStatus(4) || logProc->LogicStatus(5)) {
	    info.beamOn = true;
	    info.offTime = 0;
	} else {
	    info.beamOn = false;
	    if (!logProc->LogicStatus(3))
		info.offTime = logProc->TimeOff(3, info.time);
	    else if (!logProc->LogicStatus(4))
		info.offTime = logProc->TimeOff(4, info.time) + 300e-6;
	    else if (!logProc->LogicStatus(5))
		info.offTime = logProc->TimeOff(5, info.time) + 600e-6;
	}
	for (int i=0; i < dammIds::logic::MAX_LOGIC; i++) {
	    info.logicBits[i] = (logProc->LogicStatus(i) ? '1' : '0');
	}
    }
    double digitalTof = NAN;
    if (mcpSummary) {
	info.mcpMult = mcpSummary->GetMult();
	vector<ChanEvent*> mcpEvents = mcpSummary->GetList();

	double dtMin = DBL_MAX;

	for (vector<ChanEvent*>::iterator it = mcpEvents.begin();
	     it != mcpEvents.end(); it++) {
	    double dt = info.time - (*it)->GetTime();

	    plot(D_TDIFF_FOIL_IMPLANT, 500 + dt);
	    if (mcpEvents.size() == 1) {
		digitalTof = -10.*dt;
		plot(D_TDIFF_FOIL_IMPLANT_MULT1, 500 + dt);
	    }
	    dtMin = min(dtMin, dt);
	}
	if (dtMin != DBL_MAX)
	    info.foilTime= dtMin;
    } else {
	info.mcpMult  = 0;
	info.foilTime = NAN;
    }
    if (impSummary) {
	info.impMult = impSummary->GetMult();
    } else {
	info.impMult = 0;
    }
    if (boxSummary) {
	info.boxMult = boxSummary->GetMult();

	if (info.boxMult > 0) {
	    const ChanEvent *boxCh = boxSummary->GetMaxEvent();

	    info.energyBox = boxCh->GetCalEnergy(); //raw?
	    info.boxMax = boxCh->GetChanID().GetLocation();
	} else {
	    info.energyBox = 0;
	    info.boxMax = -1;
	}
    } else {
	info.boxMult = 0;
    }
    info.tof = NAN;
    if (tacSummary) {
	const vector<ChanEvent*> events = tacSummary->GetList();
	for (vector<ChanEvent*>::const_iterator it = events.begin(); it != events.end(); it++) {
	    int loc = (*it)->GetChanID().GetLocation();
	    if (loc == 2) {
		info.tof = (*it)->GetCalEnergy();
		info.hasTof = true;
		break;
	    }
	}
    } else {
	info.hasTof = true;
    }

    Trace &trace = ch->GetTrace();
    if (trace.HasValue("filterEnergy2")) {
	info.pileUp = true;
    }

    SetType(info);
    Correlate(corr, info, location);

    // TOF spectra update
    if (tacSummary) {
	const vector<ChanEvent*> events = tacSummary->GetList();
	for (vector<ChanEvent*>::const_iterator it = events.begin();
	     it != events.end(); it++) {
	    double tof  = (*it)->GetCalEnergy();
	    int ntof = (*it)->GetChanID().GetLocation();

	    plot(DD_ALL_ENERGY__TOFX + ntof - 1, info.energy, tof);
	    if (!isnan(digitalTof) && digitalTof > 1500. && digitalTof < 2000)
		plot(DD_ALL_ENERGY__TOFX_GATED + ntof - 1, info.energy, tof);
	    if (info.type == EventInfo::IMPLANT_EVENT) {
		plot(DD_IMPLANT_ENERGY__TOFX + ntof - 1, info.energy, tof);
	    } else if (info.type == EventInfo::PROTON_EVENT) {
		plot(DD_VETO_ENERGY__TOFX + ntof - 1, info.energy, tof);
	    }
	}
	// TAC channel 0 is missing, so use it for the digital tof
	if (!isnan(digitalTof)) {
	    plot(DD_ALL_ENERGY__TOFX, info.energy, digitalTof);
	    if (info.type == EventInfo::IMPLANT_EVENT) {
		plot(DD_IMPLANT_ENERGY__TOFX, info.energy, digitalTof);
	    } else if (info.type == EventInfo::PROTON_EVENT) {
		plot(DD_VETO_ENERGY__TOFX, info.energy, digitalTof);
	    }
	}
    }

    if (info.type == EventInfo::PROTON_EVENT) {
        const ChanEvent *chVeto = vetoSummary->GetMaxEvent();

        unsigned int posVeto = chVeto->GetChanID().GetLocation();
        double vetoEnergy = chVeto->GetCalEnergy();

        plot(DD_LOC_VETO__LOC_SSD, posVeto, location);
        plot(DD_TOTENERGY__ENERGY, vetoEnergy + info.energy, info.energy);
    }

    if (info.pileUp) {
        double trigTime = info.time;

        info.energy = driver->cali.GetCalEnergy(ch->GetChanID(),
                                              trace.GetValue("filterEnergy2"));
        info.time = trigTime + trace.GetValue("filterTime2") - trace.GetValue("filterTime");

        SetType(info);
        Correlate(corr, info, location);

        int numPulses = trace.GetValue("numPulses");

        if ( numPulses > 2 ) {
            corr.Flag(location, 1);
            cout << "Flagging triple event" << endl;
            for (int i=3; i <= numPulses; i++) {
            stringstream str;
            str << "filterEnergy" << i;
            info.energy = driver->cali.GetCalEnergy(ch->GetChanID(),
                                              trace.GetValue(str.str()));
            str.str(""); // clear it
            str << "filterTime" << i;
            info.time   = trigTime + trace.GetValue(str.str()) - trace.GetValue("filterTime");

            SetType(info);
            Correlate(corr, info, location);
            }
        }
        // corr.Flag(location, 1);
#ifdef VERBOSE
        cout << "Flagging for pileup" << endl;

        cout << "fast trace " << fastTracesWritten << " in strip " << location
            << " : " << trace.GetValue("filterEnergy") << " " << trace.GetValue("filterTime")
            << " , " << trace.GetValue("filterEnergy2") << " " << trace.GetValue("filterTime2") << endl;
        cout << "  mcp mult " << info.mcpMult << endl;
#endif // VERBOSE

        if (fastTracesWritten < numTraces) {
            trace.Plot(D_FAST_DECAY_TRACE + fastTracesWritten);
            fastTracesWritten++;
        }
    }

    if (info.energy > 10000 && !ch->IsSaturated() && !isnan(info.position) ) {
	corr.Flag(location, info.position);
    }

    if (info.energy > 8000 && !trace.empty()) {
#ifdef VERBOSE
	cout << "high energy decay of " << info.energy
	     << "(raw energy " << ch->GetEnergy() << ") with beam "
	     << (info.beamOn ? "present" : "absent") << endl;

	cout << "Flagging for high energy " << info.energy << " with trace" << endl;
#endif //VERBOSE
	// corr.Flag(location, 1);

	if (highTracesWritten < numTraces) {
	    trace.Plot(D_HIGH_ENERGY_TRACE + highTracesWritten);
	    highTracesWritten++;
	}
    }

    EndProcess(); // update the processing time
    return true;
}
/**
 *  Process the QDC data involved in top/bottom side for a strip 
 *  Note QDC lengths are HARD-CODED at the moment for the plots and to determine the position
 */
bool PositionProcessor::Process(RawEvent &event) {
    if (!EventProcessor::Process(event))
        return false;

    static const vector<ChanEvent*> &sumEvents = 
	event.GetSummary("ssd:sum", true)->GetList();
    static const vector<ChanEvent*> &digisumEvents =
	event.GetSummary("ssd:digisum", true)->GetList();
    static const vector<ChanEvent*> &topEvents =
	event.GetSummary("ssd:top", true)->GetList();
    static const vector<ChanEvent*> &bottomEvents =
	event.GetSummary("ssd:bottom", true)->GetList();

    vector<ChanEvent *> allEvents;
    // just add in the digisum events for now
    allEvents.insert(allEvents.begin(), digisumEvents.begin(), digisumEvents.end());
    allEvents.insert(allEvents.begin(), sumEvents.begin(), sumEvents.end());

    for (vector<ChanEvent*>::const_iterator it = allEvents.begin();
	     it != allEvents.end(); ++it) {
         ChanEvent *sumchan   = *it;

        int location = sumchan->GetChanID().GetLocation();

        // Don't waste our time with noise events
        if ( (*it)->GetEnergy() < 10. || (*it)->GetEnergy() > 16374 ) {
            using namespace dammIds::position;

            plot(D_INFO_LOCX + location, INFO_NOISE);
            plot(D_INFO_LOCX + LOC_SUM , INFO_NOISE);
            continue;
        }

        const ChanEvent *top    = FindMatchingEdge(sumchan, topEvents.begin(), topEvents.end());
        const ChanEvent *bottom = FindMatchingEdge(sumchan, bottomEvents.begin(), bottomEvents.end());


        if (top == NULL || bottom == NULL) {
            using namespace dammIds::position;

            if (top == NULL) {
                // [6] -> Missing top
                plot(D_INFO_LOCX + location, INFO_MISSING_TOP);
                plot(D_INFO_LOCX + LOC_SUM, INFO_MISSING_TOP);
            }

            if (bottom == NULL) {
                // [5] -> Missing bottom
                plot(D_INFO_LOCX + location, INFO_MISSING_BOTTOM);
                plot(D_INFO_LOCX + LOC_SUM, INFO_MISSING_BOTTOM);
            }
            continue;
        }

        /* Make sure we get the same match going backwards to insure there is only one in the vector */
        if ( FindMatchingEdge(sumchan, topEvents.rbegin(), topEvents.rend()) != top) {
            using namespace dammIds::position;
            // [4] -> Multiple top
            plot(D_INFO_LOCX + location, INFO_MULTIPLE_TOP);
            plot(D_INFO_LOCX + LOC_SUM, INFO_MULTIPLE_TOP);
            continue;
        }
        if ( FindMatchingEdge(sumchan, bottomEvents.rbegin(), bottomEvents.rend()) != bottom) {
            using namespace dammIds::position;
            // [3] -> Multiple bottom
            plot(D_INFO_LOCX + location, INFO_MULTIPLE_BOTTOM);
            plot(D_INFO_LOCX + LOC_SUM, INFO_MULTIPLE_BOTTOM);
            continue;
        }

        using namespace dammIds::position;
        
        float topQdc[numQdcs];
        float bottomQdc[numQdcs];
        float topQdcTot = 0;
        float bottomQdcTot = 0;
        float position = NAN;
        
        topQdc[0] = top->GetQdcValue(0);
        bottomQdc[0] = bottom->GetQdcValue(0);
        if (bottomQdc[0] == U_DELIMITER || topQdc[0] == U_DELIMITER) {
            // This happens naturally for traces which have double triggers
            //   Onboard DSP does not write QDCs in this case
#ifdef VERBOSE
            cout << "SSD strip edges are missing QDC information for location " << location << endl;
#endif
            if (topQdc[0] == U_DELIMITER) {
                // [2] -> Missing top QDC
                plot(D_INFO_LOCX + location, INFO_MISSING_TOP_QDC);
                plot(D_INFO_LOCX + LOC_SUM, INFO_MISSING_TOP_QDC);
                // Recreate qdc from trace
                if ( !top->GetTrace().empty() ) {
                    topQdc[0] = accumulate(top->GetTrace().begin(), top->GetTrace().begin() + qdcLen[0], 0);
                } else {
                    topQdc[0] = 0;
                }
            }
            if (bottomQdc[0] == U_DELIMITER) {
                // [1] -> Missing bottom QDC
                plot(D_INFO_LOCX + location, INFO_MISSING_BOTTOM_QDC);
                plot(D_INFO_LOCX + LOC_SUM, INFO_MISSING_BOTTOM_QDC);
                // Recreate qdc from trace
                if ( !bottom->GetTrace().empty() ) {
                    bottomQdc[0] = accumulate(bottom->GetTrace().begin(), bottom->GetTrace().begin() + qdcLen[0], 0);
                } else {
                    bottomQdc[0] = 0;
                }
            }
            if ( topQdc[0] == 0 || bottomQdc[0] == 0 ) {
                continue;
            }
        }
        // [0] -> good stuff
        plot(D_INFO_LOCX + location, INFO_OKAY);
        plot(D_INFO_LOCX + LOC_SUM, INFO_OKAY);


        for (int i = 1; i < numQdcs; ++i) {		
            if (top->GetQdcValue(i) == U_DELIMITER) {
                // Recreate qdc from trace
                topQdc[i] = accumulate(top->GetTrace().begin() + qdcPos[i-1],
                top->GetTrace().begin() + qdcPos[i], 0);
            } else {
                topQdc[i] = top->GetQdcValue(i);
            }

            topQdc[i] -= topQdc[0] * qdcLen[i] / qdcLen[0];
            topQdcTot += topQdc[i];
            topQdc[i] /= qdcLen[i];		
            
            if (bottom->GetQdcValue(i) == U_DELIMITER) {
                // Recreate qdc from trace
                bottomQdc[i] = accumulate(bottom->GetTrace().begin() + qdcPos[i-1],
                                          bottom->GetTrace().begin() + qdcPos[i], 0);
            } else {
                bottomQdc[i] = bottom->GetQdcValue(i);
            }

            bottomQdc[i] -= bottomQdc[0] * qdcLen[i] / qdcLen[0];
            bottomQdcTot += bottomQdc[i];
            bottomQdc[i] /= qdcLen[i];
            
            plot(DD_QDCN__QDCN_LOCX + QDC_JUMP * i + location, topQdc[i] + 10, bottomQdc[i] + 10);
            plot(DD_QDCN__QDCN_LOCX + QDC_JUMP * i + LOC_SUM, topQdc[i], bottomQdc[i]);
            
            float frac = topQdc[i] / (topQdc[i] + bottomQdc[i]) * 1000.; // per mil
            
            plot(D_QDCNORMN_LOCX + QDC_JUMP * i + location, frac);
            plot(D_QDCNORMN_LOCX + QDC_JUMP * i + LOC_SUM, frac);
            if (i == whichQdc) {
                position = posScale * (frac - minNormQdc[location]) / 
                    (maxNormQdc[location] - minNormQdc[location]);		
                sumchan->GetTrace().InsertValue("position", position);
                plot(DD_POSITION__ENERGY_LOCX + location, position, sumchan->GetCalEnergy());
                plot(DD_POSITION__ENERGY_LOCX + LOC_SUM, position, sumchan->GetCalEnergy());
            }
            if (i == 6 && !sumchan->IsSaturated()) {
                // compare the long qdc to the energy
                int qdcSum = topQdc[i] + bottomQdc[i];
                
                // MAGIC NUMBERS HERE, move to qdc.txt
                if (qdcSum < 1000 && sumchan->GetCalEnergy() > 15000) {
                    sumchan->GetTrace().InsertValue("badqdc", 1);
                } else if ( !isnan(position) ) {
                    plot(DD_POSITION, location, position);
                }
            }
        } // end loop over qdcs
        // KM QDC - QDC correlations
        double ratio[4] = {0};
        for (int i = 1; i < 5; ++i) {
                ratio[i - 1] = topQdc[i] / (bottomQdc[i] + topQdc[i]) * 1000.0;
        }

        plot(DD_QDCR2__QDCR1_LOCX + location, ratio[1], ratio[0]);
        plot(DD_QDCR2__QDCR3_LOCX + location, ratio[1], ratio[2]);
        plot(DD_QDCR2__QDCR4_LOCX + location, ratio[1], ratio[3]);

        plot(DD_QDC1R__POS_LOCX + location, ratio[0], position * 10.0 + 200.0);
        plot(DD_QDC2R__POS_LOCX + location, ratio[1], position * 10.0 + 200.0);
        plot(DD_QDC3R__POS_LOCX + location, ratio[2], position * 10.0 + 200.0);
        plot(DD_QDC4R__POS_LOCX + location, ratio[3], position * 10.0 + 200.0);

        topQdcTot    /= totLen;
        bottomQdcTot /= totLen;
        
        plot(DD_QDCTOT__QDCTOT_LOCX + location, topQdcTot, bottomQdcTot);
        plot(DD_QDCTOT__QDCTOT_LOCX + LOC_SUM, topQdcTot, bottomQdcTot);
    } // end iteration over sum events

   // test

    EndProcess();

    return true;
}