#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace RAT { inline bool Cmp_TPulse_TimeAscending(const TriggerPulse *a, const TriggerPulse *b) { double atime = a->GetStartTime(); double btime = b->GetStartTime(); return atime < btime; } TriggerProc::TriggerProc() : Processor("Trigger"), fBits(NULL), fN100(NULL), fN20(NULL), fEHI(NULL), fELO(NULL), fMasterTrigger(NULL), fCAEN(NULL),fTUBii(NULL) { } void TriggerProc::BeginOfRun(DS::Run&) { fFECD.BeginOfRun(); DBLinkPtr fLdaq = DB::Get()->GetLink("DAQ"); DBLinkPtr fRLdaq = DB::Get()->GetLink("DAQ_RUN_LEVEL"); // fEventTime->SetStart(); //sets start time of MC in JDay,secs,nsecs fTrigSteppingTimeDB = fLdaq->GetD("trig_step_time"); fFullTrigWord = fLdaq->GetI("fulltriggerword"); //width of trigger pulses fN100PulseWidthDB = fLdaq->GetD("n100_width"); fN20PulseWidthDB = fLdaq->GetD("n20_width"); fESUMPulseWidthDB = fLdaq->GetD("esum_width"); float RawTrigWidth = fLdaq->GetD("rawtrigwidth"); //Risetime of NHIT trigger pulses fN100RisetimeDB = fLdaq->GetD("n100_rise"); fN20RisetimeDB = fLdaq->GetD("n20_rise"); //Get ESUM information fLowGainFact = fLdaq->GetD("lowgain_factor"); fmVperPE = fLdaq->GetD("esum_mvperpe"); fADCperPE = fLdaq->GetD("esum_adcperpe"); //delay of trigger signals to FEC fTriggerFECDelay = fLdaq->GetD("triggerfecdelay"); fGTDelay = fLdaq->GetD("gtriggerdelay"); fGate = fLdaq->GetD("triggergate"); //Baseline, dropout, and noise fDropoutDB = fLdaq->GetD("nhit_dropout"); fBaselineDriftDB = fLdaq->GetD("baseline_drift"); fNhitNoiseDB = fLdaq->GetD("nhit_noise"); fESumNoise = fLdaq->GetD("esum_noise"); float PulseGTDefault = fLdaq->GetD("pulse_gt_default"); //trigger thresholds float N100LoThresholdDB = fRLdaq->GetD("n100_lo_thresh"); float N100MedThresholdDB = fRLdaq->GetD("n100_med_thresh"); float N100HiThresholdDB = fRLdaq->GetD("n100_hi_thresh"); float N20ThresholdDB = fRLdaq->GetD("n20_thresh"); float N20LBThresholdDB = fRLdaq->GetD("n20_lb_thresh"); float ESHiThresholdDB = fRLdaq->GetD("eshi_thresh"); float ESLoThresholdDB = fRLdaq->GetD("eslo_thresh"); // Retriggers int retrigN100 = fRLdaq->GetI("n100_retrig"); int retrigN20 = fRLdaq->GetI("n20_retrig"); int retrigEHi = fRLdaq->GetI("eshi_retrig"); int retrigELo = fRLdaq->GetI("eslo_retrig"); // Uncomment these once OWL trigs are implemented: /* int retrigOwlN = fRLdaq->GetI("owln_retrig"); int retrigOwlEHi = fRLdaq->GetI("owlehi_retrig"); int retrigOwlELo = fRLdaq->GetI("owlelo_retrig");*/ //External trigger values ExtAsyTimeDB = fLdaq->GetD("extasync_time"); //External Async trigger //Digital trigger values int PrescaleDB = fRLdaq->GetI("prescale"); float PrescaleWidthDB = fLdaq->GetD("prescale_width"); float PrescaleDelayDB = fLdaq->GetD("prescale_delay"); fLatchDelayDB = fLdaq->GetD("trig_latch"); double PulseGTDB = fRLdaq->GetD("pulse_gt"); double PulseGTMinDB = fLdaq->GetD("pulse_gtmin"); float PulseGTWidth = fLdaq->GetD("pulsegtwidth"); unsigned int TriggerMaskDB = fRLdaq->GetI("trigger_mask"); fTriggerEnableDB = fRLdaq->GetI("trigger_enable"); fTrigLockoutDB = fLdaq->GetD("lockout"); // Perfect trigger efficiency simulation fDoPerfectTrigger = fLdaq->GetI("perfect_trigger"); if(fDoPerfectTrigger){ warn << "TriggerProc: WARNING, simulating perfect trigger efficiency. Overriding other DAQ params." << newline; } // Which Trigs are enabled? fBits = new BitManip(); fIsN100L = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::N100Low); fIsN100M = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::N100Med); fIsN100H = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::N100High); fIsN20 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::N20); fIsN20LB = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::N20LB); fIsEL = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::ESLow); fIsEH = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::ESHigh); fIsON = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::OWLN); fIsOEL = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::OWLESLow); fIsOEH = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::OWLESHigh); fIsPGT = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::PulseGT); fIsPre = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::Prescale); fIsPed = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::Pedestal); fIsPong = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::Pong); fIsSync = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::Sync); fIsEXTASY = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXTASY); fIsExt2 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT2); fIsExt3 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT3); fIsExt4 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT4); fIsExt5 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT5); fIsExt6 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT6); fIsExt7 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT7); fIsExt8 = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::EXT8PulseAsy); fIsSRaw = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::SPRaw); fIsNCD = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::NCD); fIsSGT = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::SoftGT); fIsMiss = fBits->TestBit(fTriggerEnableDB, DU::TrigBits::MissTrig); fIsN100t = fIsN100L || fIsN100M || fIsN100H; fIsN20t = fIsN20 || fIsN20LB; fIsAnalogue = fIsN100t || fIsN20t || fIsEL || fIsEH || fIsON || fIsOEL || fIsOEH; fChannelMask = fRLdaq->GetI("channelMask"); //Set up MTC/A objects fN100 = new MTCA(3); fN100->SetThreshold(N100LoThresholdDB,0); fN100->SetThreshold(N100MedThresholdDB,1); fN100->SetThreshold(N100HiThresholdDB,2); // Only set retriggers if the trigs are enabled if(fIsN100t)fN100->SetNRetrig(retrigN100); fN100->SetRawTrigWidth(RawTrigWidth); fN20 = new MTCA(2); fN20->SetThreshold(N20ThresholdDB,0); fN20->SetThreshold(N20LBThresholdDB,1); if(fIsN20t)fN20->SetNRetrig(retrigN20); fN20->SetRawTrigWidth(RawTrigWidth); fEHI = new MTCA(1); fEHI->SetThreshold(ESHiThresholdDB,0); if(fIsEH)fEHI->SetNRetrig(retrigEHi); fEHI->SetRawTrigWidth(RawTrigWidth); fELO = new MTCA(1); fELO->SetThreshold(ESLoThresholdDB,0); if(fIsEL)fELO->SetNRetrig(retrigELo); fELO->SetRawTrigWidth(RawTrigWidth); // Initialise event count such that first eventID is 0 fEvCount = 0; //Create and initialize MTC/D object fMasterTrigger = new MTCD(); fMasterTrigger->SetGTCount(fEvCount); fMasterTrigger->SetTriggerMask(TriggerMaskDB); fMasterTrigger->SetPrescale(PrescaleDB); fMasterTrigger->SetPrescaleDelay(PrescaleDelayDB); fMasterTrigger->SetPrescaleWidth(PrescaleWidthDB); fMasterTrigger->SetPulseGTDefault(PulseGTDefault); fMasterTrigger->SetPulseGT(PulseGTDB); fMasterTrigger->SetPulseGTMin(PulseGTMinDB); fMasterTrigger->SetPulseGTWidth(PulseGTWidth); fMasterTrigger->SetPulseGTFreq(); fMasterTrigger->SetLatchDelay(fLatchDelayDB); fMasterTrigger->SetExtAsyTime(ExtAsyTimeDB); // Enable digital triggers if(fIsPGT)fMasterTrigger->EnablePGT(); if(fIsPre)fMasterTrigger->EnablePrescale(); //Create arrays of amplitudes for NHIT triggers int numChans = 9728; float amplitudeJitterDB = fLdaq->GetD("trig_jitter"); for (int ipmt=0; ipmt < numChans; ipmt++) { if(fDoPerfectTrigger){ fN100Amplitude.push_back(1.0); fN20Amplitude.push_back(1.0); } else{ fN100Amplitude.push_back(1.0 + amplitudeJitterDB * CLHEP::RandGauss::shoot()); fN20Amplitude.push_back(1.0 + amplitudeJitterDB * CLHEP::RandGauss::shoot()); } } // Create and initialise CAEN object fDigTrigSum = fLdaq->GetI("digTrigSum"); fGTCaenDelay = fLdaq->GetD("gtCaenDelay"); fCAEN = new CAEN(); fCAEN->BeginOfRun(); fCAEN->SetClock(); //Create TUBii Object fTUBii = new TUBII(); detail << newline << newline; detail << "TriggerProc::BeginOfRun: DAQ constants loaded" << newline << newline; detail << "Triggers Masked In Enabled:" << newline; detail << " N100LO " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N100Low) ? " Yes" : " No") << " "<< (fIsN100L ? " Yes " : " No") << newline; detail << " N100MED " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N100Med) ? " Yes" : " No") << " "<< (fIsN100M ? " Yes " : " No")<< newline; detail << " N100HI " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N100High) ? " Yes" : " No") << " "<< (fIsN100H ? " Yes " : " No")<< newline; detail << " N20 " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N20) ? " Yes" : " No") << " "<< (fIsN20 ? " Yes " : " No")<< newline; detail << " N20LB " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N20LB) ? " Yes" : " No") << " "<< (fIsN20LB ? " Yes " : " No")<< newline; detail << " ESUMLO " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::ESLow) ? " Yes" : " No") << " "<< (fIsEL ? " Yes " : " No")<< newline; detail << " ESUMHI " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::N100Low) ? " Yes" : " No") << " "<< (fIsEH ? " Yes " : " No")<< newline; detail << " OWLN " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::OWLN) ? " Yes" : " No") << " "<< (fIsON ? " Yes " : " No")<< newline; detail << " OWLELO " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::OWLESLow) ? " Yes" : " No") << " "<< (fIsOEL ? " Yes " : " No")<< newline; detail << " OWLEHI " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::OWLESHigh) ? " Yes" : " No") << " "<< (fIsOEH ? " Yes " : " No")<< newline; detail << " PULGT" << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::PulseGT) ? " Yes" : " No") << " "<< (fIsPGT ? " Yes " : " No")<< newline; detail << " Prescale " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::Prescale) ? " Yes" : " No") << " "<< (fIsPre ? " Yes " : " No")<< newline; detail << " Pedestal " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::Pedestal) ? " Yes" : " No") << " "<< (fIsPed ? " Yes " : " No")<< newline; detail << " PONG " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::Pong) ? " Yes" : " No") << " "<< (fIsPong ? " Yes " : " No")<< newline; detail << " SYNC " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::Sync) ? " Yes" : " No") << " "<< (fIsSync ? " Yes " : " No")<< newline; detail << " EXT_ASYNC " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::EXTASY) ? " Yes" : " No") << " "<< (fIsEXTASY ? " Yes " : " No")<< newline; //Currently not logging external trigger bits other than EXTASY detail << " SoftGT " << (fBits->TestBit(TriggerMaskDB,DU::TrigBits::SoftGT) ? " Yes" : " No") << " "<< (fIsSGT ? " Yes " : " No")<< newline; detail << newline; detail << "Analog Trigger Thresholds:" << newline; detail << dformat ("N100LO:.......... %5.1f Hits\n",N100LoThresholdDB); detail << dformat ("N100MED:......... %5.1f Hits\n",N100MedThresholdDB); detail << dformat ("N100HI:.......... %5.1f Hits\n",N100HiThresholdDB); detail << dformat ("N20:............. %5.1f Hits\n",N20ThresholdDB); detail << dformat ("N20LB:........... %5.1f Hits\n",N20LBThresholdDB); detail << dformat ("ESUMLO:.......... %5.1f mV\n",ESLoThresholdDB); detail << dformat ("ESUMHI:.......... %5.1f mV\n",ESHiThresholdDB); detail << newline << newline; detail << "Digital Trigger Settings:" << newline; detail << dformat ("Prescale:.......... %6i \n",PrescaleDB); detail << dformat ("Pulse GT:.......... %6.1f Hz\n",PulseGTDB); detail << newline << newline; } TriggerProc::~TriggerProc() { delete fBits; delete fMasterTrigger; delete fN100; delete fN20; delete fEHI; delete fELO; delete fCAEN; delete fTUBii; } TriggerProc::Result TriggerProc::DSEvent(DS::Run& run, DS::Entry& ds) { // -- First check that the MC branch does exist. In case of real data it won't exist // Of course, I have no idea why people would run this processor on real data, but // better safe than sorry if (!run.GetMCFlag()) { warn << "TriggerProc::DSEvent : There is no MC branch for this Run. Most likely this is real data. Aborting..." << newline; warn << "TriggerProc::DSEvent : Check the options in your macro, and your input file." << newline; return Processor::ABORT; } DS::MC& mc = ds.GetMC(); DS::MCHits& mcHits = mc.GetUnbuiltMCHits(); const DU::ChanHWStatus& channelHardwareStatus = DU::Utility::Get()->GetChanHWStatus(); fDigTrigSums = run.GetDigitiserTrigSums(); // Counter for detector events (per MC event) int nev = 0; double mctime = mc.GetMCTime(); fMasterTrigger->SetMCEventTime(mctime); fCAEN->SetMCEventTime(mctime); // We need to build up arrays of TriggerPulse objects, sort them, and // then sum them to decide if we have a trigger. TriggerSum perfectSum; //perfect trigger sum for sorting and reference TriggerSum *n100Sum = new TriggerSum(); //nhit 100 trigger sum TriggerSum *n20Sum = new TriggerSum(); //nhit 20 trigger sum TriggerSum *ehiSum = new TriggerSum(); //EsumHi trigger sum TriggerSum *eloSum= new TriggerSum(); //EsumLo trigger sum if(!fDoPerfectTrigger){ float dropout = CLHEP::RandPoisson::shoot(fDropoutDB); float baseline = fBaselineDriftDB*CLHEP::RandGauss::shoot(); float n100Baseline = baseline+dropout; n100Sum->SetBaseline(n100Baseline); n100Sum->SetNoiseAmplitude(fNhitNoiseDB); float n20Dropout = CLHEP::RandPoisson::shoot(dropout);//fake correlation float n20baseline = baseline*CLHEP::RandGauss::shoot(); //fake correlation float n20Baseline = n20baseline+n20Dropout; n20Sum->SetBaseline(n20Baseline); n20Sum->SetNoiseAmplitude(fNhitNoiseDB); ehiSum->SetNoiseAmplitude(fESumNoise); eloSum->SetNoiseAmplitude(fESumNoise); } else{ n100Sum->SetBaseline(0.0); n100Sum->SetNoiseAmplitude(0.0); n20Sum->SetBaseline(0.0); n20Sum->SetNoiseAmplitude(0.0); ehiSum->SetNoiseAmplitude(0.0); eloSum->SetNoiseAmplitude(0.0); } // No baseline drift or dropout on the ESUM ehiSum->SetBaseline(0.0); eloSum->SetBaseline(0.0); for (size_t imchit=0; imchit < mcHits.GetAllCount(); imchit++) { DS::MCHit& mchit = mcHits.GetAllPMT(imchit); int crate = mchit.GetCrate(); int card = mchit.GetCard(); // Ignore NECK/OWL/FECD Hits // FIXME if OWL triggers are implemented if((crate == 3 || crate == 13 || crate == 17 || crate == 18) && card == 15) continue; //Now create a `perfect' trigger pulse for each //hit. We'll time-sort these, and then we can copy the //sorted times into the real trigger types. // Would just be better if we had a way of time-sorting // the MCSamples themselves. GenericTrigPulse *perfectPulse = new GenericTrigPulse();//perfect trigger perfectPulse->SetStartTime(mchit.GetTime()+fTriggerFECDelay); perfectPulse->SetPulseHeight(1.0); perfectPulse->SetPMTID(mchit.GetID()); perfectPulse->SetCharge(mchit.GetQHS()); //will have to eventually //include multiple photons //properly here perfectSum.fPulse.push_back(perfectPulse); } //end loop over hits associated with this event. if (!perfectSum.fPulse.empty()){//Check to ensure there >0 trigger pulses //Create sorted times std::sort(perfectSum.fPulse.begin(),perfectSum.fPulse.end(), Cmp_TPulse_TimeAscending); //And now we create all the real analog trigger waveforms, by copying the //times from the (now time-sorted) `perfect' trigger sum for (unsigned int i = 0; iGetStartTime(); int ipmt = perfectSum.fPulse[i]->GetPMTID(); //fN100 if(fIsN100t){ NHITTrigPulse *n100pulse = new NHITTrigPulse(); n100pulse->SetStartTime(sorttime); n100pulse->SetPulseWidth(fN100PulseWidthDB); if(!fDoPerfectTrigger){ n100pulse->SetPulseRisetime(fN100RisetimeDB); } else{ n100pulse->SetPulseRisetime(0.0); } // GDOG: Check if we want to use DQXX info to determine tube status // If not, continue as you were // If so, check whether the tube has its trig bit set---if not, // give it a zero amplitude bool deadN100 = false; if( channelHardwareStatus.IsEnabled() ) deadN100 = !(channelHardwareStatus.IsNHit100Enabled( ipmt )); if (!deadN100){ n100pulse->SetPulseHeight(fN100Amplitude.at(ipmt)); } else{ n100pulse->SetPulseHeight(0.0); } n100Sum->fPulse.push_back(n100pulse); } //fN20 if(fIsN20t){ NHITTrigPulse *n20pulse = new NHITTrigPulse(); n20pulse->SetStartTime(sorttime); n20pulse->SetPulseWidth(fN20PulseWidthDB); if(!fDoPerfectTrigger){ n20pulse->SetPulseRisetime(fN20RisetimeDB); } else{ n20pulse->SetPulseRisetime(0.0); } //Check if we want to turn off chans whose fN20 trigger signal is dead bool deadN20 = false; if( channelHardwareStatus.IsEnabled() ) deadN20 = !(channelHardwareStatus.IsNHit20Enabled( ipmt )); if (!deadN20){ n20pulse->SetPulseHeight(fN20Amplitude.at(ipmt)); } else{ n20pulse->SetPulseHeight(0.0); } n20Sum->fPulse.push_back(n20pulse); } //Now ESUMs const float charge = (float) perfectSum.fPulse[i]->GetCharge(); //ESUM HI if(fIsEH){ EsumTrigPulse *ehipulse = new EsumTrigPulse(); ehipulse->SetStartTime(sorttime); ehipulse->SetPulseWidth(fESUMPulseWidthDB); ehipulse->SetmVperPE(fmVperPE); ehipulse->SetADCperPE(fADCperPE); //Check if we want to turn off chans whose EsumHi trigger is not inc in sum bool deadEHi = false; if( channelHardwareStatus.IsEnabled() ) deadEHi = !(channelHardwareStatus.IsEsumHighEnabled( ipmt )); if (!deadEHi){ ehipulse->SetPulseHeight(charge); } else{ ehipulse->SetPulseHeight(0.0); } ehiSum->fPulse.push_back(ehipulse); } //ESUM LO if(fIsEL){ EsumTrigPulse *elopulse = new EsumTrigPulse(); elopulse->SetStartTime(sorttime); elopulse->SetPulseWidth(fESUMPulseWidthDB); elopulse->SetmVperPE(fmVperPE); elopulse->SetADCperPE(fADCperPE); //Check if we want to turn off chans whose EsumLo trigger is not inc in sum bool deadELo = false; if( channelHardwareStatus.IsEnabled() ) deadELo = !(channelHardwareStatus.IsEsumLowEnabled( ipmt )); if (!deadELo){ elopulse->SetPulseHeight(charge/fLowGainFact); } else{ elopulse->SetPulseHeight(0.0); } eloSum->fPulse.push_back(elopulse); } } //Now we begin the trigger loop, looking for all threshold crossings and //creating a trigger each time. We step through times, evaluating each sum //at the given time increment. //keep track of last hit included in an event //double LastTime = perfectSum.fPulse[0]->GetStartTime(); //Get start time, one stepping time before first pulse double T = perfectSum.fPulse[0]->GetStartTime()-fTrigSteppingTimeDB; if ((T>ExtAsyTimeDB) && fIsEXTASY) {T=ExtAsyTimeDB;} int lastPulseIndex = perfectSum.fPulse.size()-1; unsigned int n100Raw=0; unsigned int n20Raw=0; unsigned int ehiRaw=0; unsigned int eloRaw=0; unsigned int extAsyRaw=0; bool noAsyncYet = true; UInt_t analogRawTriggers=0; UInt_t extRawTriggers=0; Int_t GTID; UInt_t TriggerWord; bool GlobalTrigger = false; bool inLockout = false; fN100->SetGTPrime(0); fN20->SetGTPrime(0); fEHI->SetGTPrime(0); fELO->SetGTPrime(0); bool RetrigsRemain = false; bool EndTrigSum = false; float lodelay = fTriggerFECDelay+fGTDelay + fTrigLockoutDB - fGate; double gTrigTime=0.0; UInt_t holdTrigWord = 0; bool SeenMissedTrig = false; // Can stop looking for a missed trig once we find one (per EV) bool lookGT = false; while (TGetStartTime() +fN100PulseWidthDB || RetrigsRemain){ // If we're outside the extent of trigSum, send signal if(!(TGetStartTime() +fN100PulseWidthDB))EndTrigSum = true; // if we're simulating missedTrig (therefore stepping through all T steps) // look for when to send GT' signal, and reset trig word if(lookGT && T >= (gTrigTime + lodelay)){ // Send GT' to MTCA+s fN100->SetGTPrime(1); fN20->SetGTPrime(1); fEHI->SetGTPrime(1); fELO->SetGTPrime(1); // Reset temp trig word store, since we only want to allow trigs from now onwards holdTrigWord = 0; lookGT = false; } if(EndTrigSum){ fN100->SendEndTrigSum(); fN20->SendEndTrigSum(); fEHI->SendEndTrigSum(); fELO->SendEndTrigSum(); } //Check External Async trigger if ((T>=ExtAsyTimeDB) && fIsEXTASY && noAsyncYet){ extAsyRaw = 1; T = ExtAsyTimeDB; noAsyncYet = 0; } // First step that falls outside LO, // send LO* signal to MTCAs to set-up potential retriggers if(inLockout && (T-gTrigTime)>=fTrigLockoutDB){ fN100->SendLockoutStar(); fN20->SendLockoutStar(); fEHI->SendLockoutStar(); fELO->SendLockoutStar(); } // Check for a t/h crossing if(fIsN100t)n100Raw = fN100->Discriminate(T,n100Sum); if(fIsN20t)n20Raw = fN20->Discriminate(T,n20Sum); if(fIsEH)ehiRaw = fEHI->Discriminate(T,ehiSum); if(fIsEL)eloRaw = fELO->Discriminate(T,eloSum); // If we're in lockout, store the trigger word if(inLockout)holdTrigWord|=((eloRaw<=fTrigLockoutDB){ inLockout=0; analogRawTriggers = holdTrigWord; } // Check for missed Trigs if(fIsMiss && (!SeenMissedTrig || fFullTrigWord) && inLockout){ extRawTriggers=0; extRawTriggers |= (extAsyRaw << DU::TrigBits::EXTASY); bool missedTrig = fMasterTrigger->CheckMissedTrigger(holdTrigWord,extRawTriggers,T); if(missedTrig){ // Set bit in TrigWord from prev event DS::EV& thisev = ds.GetEV(nev-1); DS::MCEV& thismcev = ds.GetMCEV(nev-1); // If there were any missed triggers, update the mcev trigger word // with the full trigger word. This trigger word would not include // missed triggers, but it does include triggers that were not latched // to the standard trigger word thismcev.SetFullTrigType(holdTrigWord); unsigned int trigWord = thisev.GetTrigType(); trigWord = fBits->SetBit(trigWord, DU::TrigBits::MissTrig); thisev.SetTrigType(trigWord); SeenMissedTrig = true; } } if(!inLockout){ analogRawTriggers|=((eloRaw<CheckGlobalTrigger(analogRawTriggers,extRawTriggers,T); if (GlobalTrigger){ //Fill trigger words if (fBits->TestBit(extRawTriggers, DU::TrigBits::EXTASY)){ extAsyRaw = 0; } DS::EV ev; DS::MCEV mcev; ++nev; fMasterTrigger->IncrementGTCount(); bool isSYNC = fMasterTrigger->GetSYNC(); bool isSYNC24 = fMasterTrigger->GetSYNC24(); fMasterTrigger->SetTrigErrBits(); GTID = fMasterTrigger->GetGTCount(); TriggerWord = fMasterTrigger->GetTriggerWord(); ev.SetGTID(GTID); mcev.SetGTID(GTID); ev.SetTrigType(TriggerWord); ev.SetTrigError(fMasterTrigger->GetTrigErrBits()); mcev.SetFullTrigType(TriggerWord); gTrigTime=fMasterTrigger->GetGlobalTriggerTime(); EventTime gUTTrigTime; gUTTrigTime.SetUniversalTime( mc.GetUniversalTime() ); gUTTrigTime.IncrementUT(gTrigTime); // Digitise Trig Sums (if required) if(fDigTrigSum==1){ // time at which GT reaches CAEN RELATIVE to when trig sums reach CAEN // i.e. add delay for GT and subtract delay for trig sums fCAEN->SetTrigTime(gTrigTime + fGTCaenDelay); fCAEN->SetIO(isSYNC, isSYNC24); // Init Event fCAEN->TriggerEvent(); // Write header info DS::Digitiser digitiser; digitiser.SetEventID(fCAEN->GetEventID()); digitiser.SetTrigTime(fCAEN->GetTriggerTime()); digitiser.SetNWords(fCAEN->GetWordCount()); digitiser.SetBoardID(fCAEN->GetBoardID()); digitiser.SetBit24(fCAEN->GetBit24()); digitiser.SetDataFormat(fCAEN->GetFormat()); digitiser.SetIOPins(fCAEN->GetIOPins()); // Digitise required trig Sums for(size_t i=0;i0 && (fChannelMask & (1 << i))){ // Only allow to digitise NH100, NH20, ESHi, ESLo for now int type = fDigTrigSums[i] / 10; unsigned gain = fDigTrigSums[i] % 10; //Check that the trig type isn't weird if(gain >2 || type >4) { warn<<"TriggerProc::Result:Unexpected trigger sum type: " <ScaleTrigSum(n100Sum,gainMap[gain]); TUBiiTransformedSum = fTUBii->PerformAnalogTransform(MTCAScaledSum,0); fCAEN->Digitise(TUBiiTransformedSum,i); } if(type == 2) { MTCAScaledSum = fN20->ScaleTrigSum(n20Sum,gainMap[gain]); TUBiiTransformedSum = fTUBii->PerformAnalogTransform(MTCAScaledSum,1); fCAEN->Digitise(TUBiiTransformedSum,i); } if(type == 3) { MTCAScaledSum = fEHI->ScaleTrigSum(ehiSum,gainMap[gain]); TUBiiTransformedSum = fTUBii->PerformAnalogTransform(MTCAScaledSum,2); fCAEN->Digitise(TUBiiTransformedSum,i); } if(type == 4) { MTCAScaledSum = fELO->ScaleTrigSum(eloSum,gainMap[gain]); TUBiiTransformedSum = fTUBii->PerformAnalogTransform(MTCAScaledSum,3); fCAEN->Digitise(TUBiiTransformedSum,i); } // Record in event if (type == 1 || type == 2 || type == 3 || type == 4) { digitiser.SetWaveform(fDigTrigSums[i], fCAEN->GetChannelInfo(i)); } //Try not to leak memory if(MTCAScaledSum) { delete MTCAScaledSum; } if(TUBiiTransformedSum) { delete TUBiiTransformedSum; } } } ev.SetDigitiser( digitiser ); } if (fBits->TestBit(extRawTriggers, DU::TrigBits::EXTASY)){ //special handling for EXTASY ev.SetClockCount50(fMasterTrigger->GetClockCount50(gUTTrigTime)); } else{ ev.SetClockCount50(fMasterTrigger->GetClockCount50()+1); } ev.SetClockCount10(fMasterTrigger->GetClockCount10(gUTTrigTime)); EventTime clock10 = fMasterTrigger->GetClockTime10(); // Set EV time to next 10MHz clock tick ev.SetUniversalTime( clock10.GetUniversalTime() ); // Set GT time in MC time frame (ns since event began) mcev.SetGTTime(gTrigTime); ev.SetTrigError(fMasterTrigger->GetTrigErrBits()); analogRawTriggers = 0; GlobalTrigger=0; if ((T>=ExtAsyTimeDB) && fIsEXTASY) { //Turn off Ext Async if we've had a trigger and now //we're past Ext Async time noAsyncYet=0; } // We're in lockout inLockout=1; // Normal operation if(!fIsMiss){ // Jump to GT + suitable delays fN100->SetGTPrime(1); fN20->SetGTPrime(1); fEHI->SetGTPrime(1); fELO->SetGTPrime(1); // If we're past extent of TrigSum, only retrig left // so jump by LO // otherwise, jump to GT' if(EndTrigSum){T = gTrigTime + fTrigLockoutDB;} else{T = gTrigTime + lodelay;} } // Deal with missed trigger operation if(fIsMiss){ // Jump to raw trig time + strobe delay T = fMasterTrigger->GetRawTriggerTime() + fLatchDelayDB; lookGT = true; } RetrigsRemain = fN100->DoRetrigsRemain() || fN20->DoRetrigsRemain() || fEHI->DoRetrigsRemain() || fELO->DoRetrigsRemain(); // Reset temp Trig word store holdTrigWord = 0; SeenMissedTrig = false; fEvCount++; // Send rawTrig to fecd fFECD.SetRawTrigTime(fMasterTrigger->GetRawTriggerTime()); fFECD.SendRawTrig(mc); ds.AddEV( ev ); ds.AddMCEV(mcev); } else{ if (perfectSum.GetHeight(T)==0 && !EndTrigSum && !fIsMiss){ T = perfectSum.GetNextTime(T); } else{ T+=fTrigSteppingTimeDB; } } } // end of loop for outside lockout else{T+=fTrigSteppingTimeDB;} } // end of time loop } // end of trigsum!=0 fMasterTrigger->ResetPrescaleBit(); fMasterTrigger->SetPrescaleTime(-10.0); delete n100Sum; delete n20Sum; delete ehiSum; delete eloSum; return OK; } } // namespace RAT