Back to home page

sPhenix code displayed by LXR

 
 

    


Warning, file /coresoftware/offline/packages/mbd/MbdEvent.cc was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 #include "MbdEvent.h"
0002 #include "MbdCalib.h"
0003 #include "MbdGeomV1.h"
0004 #include "MbdOut.h"
0005 #include "MbdRawContainer.h"
0006 #include "MbdRawHit.h"
0007 #include "MbdPmtContainer.h"
0008 #include "MbdPmtHit.h"
0009 
0010 #ifndef ONLINE
0011 #include <ffarawobjects/CaloPacket.h>
0012 #include <ffarawobjects/CaloPacketContainer.h>
0013 #include <ffarawobjects/Gl1Packet.h>
0014 #include <fun4all/Fun4AllReturnCodes.h>
0015 #include <phool/phool.h>
0016 #include <phool/recoConsts.h>
0017 #include <phool/getClass.h>
0018 #include <g4main/PHG4TruthInfoContainer.h>
0019 #include <g4main/PHG4VtxPoint.h>
0020 #endif
0021 
0022 #include <Event/Event.h>
0023 #include <Event/EventTypes.h>
0024 
0025 #include <TCanvas.h>
0026 #include <TDirectory.h>
0027 #include <TF1.h>
0028 #include <TGraphErrors.h>
0029 #include <TH1.h>
0030 #include <TH2.h>
0031 #include <TSystem.h>
0032 
0033 #include <algorithm>
0034 #include <array>
0035 #include <cmath>
0036 #include <iomanip>
0037 #include <iostream>
0038 
0039 MbdEvent::MbdEvent(const int cal_pass, const bool proc_charge) :
0040   _nsamples(MbdDefs::MAX_SAMPLES),
0041   _calpass(cal_pass),
0042   _always_process_charge(proc_charge)
0043 {
0044   // set default values
0045 
0046    // Set to maximum initially, reset when we get a packet
0047 
0048 #ifndef ONLINE
0049   recoConsts *rc = recoConsts::instance();
0050   if (rc->FlagExist("MBD_TEMPLATEFIT"))
0051   {
0052     do_templatefit = rc->get_IntFlag("MBD_TEMPLATEFIT");
0053   }
0054   else
0055   {
0056     do_templatefit = 1;
0057   }
0058 #else
0059   do_templatefit = 0;
0060   _is_online = 1;
0061 #endif
0062 
0063   for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++)
0064   {
0065     // std::cout << PHWHERE << "Creating _mbdsig " << ifeech << std::endl;
0066     _mbdsig.emplace_back(ifeech, _nsamples);
0067   }
0068 
0069   std::string name;
0070   std::string title;
0071   for (int iarm = 0; iarm < 2; iarm++)
0072   {
0073     //
0074     name = "hevt_bbct";
0075     name += std::to_string(iarm);
0076     title = "bbc times, arm ";
0077     title += std::to_string(iarm);
0078     hevt_bbct[iarm] = new TH1F(name.c_str(), title.c_str(), 2000, -25., 25.);
0079     hevt_bbct[iarm]->SetLineColor(4);
0080   }
0081 
0082   for (float &iboard : TRIG_SAMP)
0083   {
0084     iboard = -1;
0085   }
0086 
0087   // Debug stuff
0088   _debug = 0;
0089   if (_debug )
0090   {
0091     //ReadSyncFile();
0092   }
0093 
0094   Clear();
0095 }
0096 
0097 ///
0098 MbdEvent::~MbdEvent()
0099 {
0100   for (auto &iarm : hevt_bbct)
0101   {
0102     delete iarm;
0103   }
0104 
0105   delete h2_smax[0];
0106   delete h2_smax[1];
0107   delete ac;
0108   delete gausfit[0];
0109   delete gausfit[1];
0110   delete _mbdgeom;
0111   delete _mbdcal;
0112   delete _syncttree;
0113 }
0114 
0115 int MbdEvent::InitRun()
0116 {
0117   Clear();
0118 
0119 #ifndef ONLINE
0120   recoConsts *rc = recoConsts::instance();
0121   _runnum = rc->get_IntFlag("RUNNUMBER");
0122   if (_verbose)
0123   {
0124     std::cout << PHWHERE << "RUNNUMBER " << _runnum << std::endl;
0125   }
0126 #else
0127   _runnum = 0;  // for online, not used
0128 #endif
0129 
0130   if (_mbdgeom == nullptr)
0131   {
0132     _mbdgeom = new MbdGeomV1();
0133   }
0134 
0135   // Always reload calibrations on InitRun()
0136   
0137   
0138   delete _mbdcal;
0139   
0140   _mbdcal = new MbdCalib();
0141   if ( _simflag )
0142   {
0143     std::cout << PHWHERE << "SIMFLAG IS " << _simflag << std::endl;
0144   }
0145   if ( _calpass > 0 )
0146   {
0147     std::cout << PHWHERE << "CALPASS IS " << _calpass << std::endl;
0148     _mbdcal->Verbosity(1);
0149   }
0150 
0151   _mbdcal->SetRawDstFlag( _rawdstflag );
0152   _mbdcal->SetFitsOnly( _fitsonly );
0153   _mbdcal->Download_All();
0154 
0155   if ( _simflag == 0 )  // do following for real data
0156   {
0157     // load pass1 calibs from local file for calpass2+
0158     if ( _calpass>1 )
0159     {
0160       std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_sampmax.calib";
0161       std::cout << "Loading local sampmax, " << calfname << std::endl;
0162       _mbdcal->Download_SampMax( calfname );
0163 
0164       calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_ped.calib";
0165       std::cout << "Loading local ped, " << calfname << std::endl;
0166       _mbdcal->Download_Ped( calfname );
0167     }
0168 
0169     // check if sampmax and ped calibs exist
0170     int scheck = _mbdcal->get_sampmax(0);
0171 
0172     if ( (scheck<0 || _is_online) && _calpass!=1 )
0173     {
0174       _no_sampmax = 1000;    // num events for on the fly calculation
0175       _calib_done = 0;
0176       std::cout << PHWHERE << ",no sampmax calib, determining it on the fly using first " << _no_sampmax << " evts." << std::endl;
0177     }
0178   }
0179 
0180   // Init parameters of the signal processing
0181   for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++)
0182   {
0183     _mbdsig[ifeech].SetCalib(_mbdcal);
0184 
0185     // Do evt-by-evt pedestal using sample range below
0186     if ( _calpass==1 || _is_online || _no_sampmax>0 )
0187     {
0188       _mbdsig[ifeech].SetEventPed0Range(0,1);
0189     }
0190     else
0191     {
0192       const int presamp = 5;  // start from 5 samples before sampmax
0193       const int nsamps = -1;  // use all to sample 0
0194       _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech));
0195     }
0196 
0197     // Read in template if specified
0198     if ( do_templatefit && _mbdgeom->get_type(ifeech)==1 )
0199     {
0200       // std::cout << PHWHERE << "Reading template " << ifeech << std::endl;
0201       // std::cout << "SIZES0 " << _mbdcal->get_shape(ifeech).size() << std::endl;
0202       //  Should set template size automatically here
0203       _mbdsig[ifeech].SetTemplate(_mbdcal->get_shape(ifeech), _mbdcal->get_sherr(ifeech));
0204       _mbdsig[ifeech].SetMinMaxFitTime(_mbdcal->get_sampmax(ifeech) - 2 - 3, _mbdcal->get_sampmax(ifeech) - 2 + 3);
0205       //_mbdsig[ifeech].SetMinMaxFitTime( 0, 31 );
0206     }
0207   }
0208 
0209   if ( _calpass > 0 )
0210   {
0211     _caldir = "results/"; _caldir += _runnum; _caldir += "/";
0212     TString cmd = "mkdir -p " + _caldir;
0213     gSystem->Exec( cmd );
0214     std::cout << "OUTPUT CALDIR = " << _caldir << std::endl;
0215   }
0216 
0217   if ( _no_sampmax>0 || _is_online || _calpass == 1 )
0218   {
0219     TDirectory *orig_dir = gDirectory;
0220     if ( _calpass == 1 && h2_smax[0]==nullptr )
0221     {
0222       std::cout << "MBD Cal Pass 1" << std::endl;
0223 
0224       TString savefname = _caldir; savefname += "mbdcalpass1.root";
0225       std::cout << "Saving calpass 1 results to " << savefname << std::endl;
0226       _calpass1_tfile = std::make_unique<TFile>(savefname,"RECREATE");
0227     }
0228 
0229     std::string name;
0230 
0231     if ( h2_smax[0]==nullptr )
0232     {
0233       for (int ich=0; ich<MbdDefs::MBD_N_FEECH; ich++)
0234       {
0235         name = "h_smax"; name += std::to_string(ich);
0236         h_smax[ich] = new TH1F(name.c_str(),name.c_str(),_nsamples,-0.5,_nsamples-0.5);
0237         h_smax[ich]->SetXTitle("sample");
0238         h_smax[ich]->SetYTitle("ch");
0239       }
0240       h2_smax[0] = new TH2F("h2_tsmax","time smax vs ch", MbdDefs::MAX_SAMPLES, -0.5, MbdDefs::MAX_SAMPLES-0.5, 128, 0, 128);
0241       h2_smax[1] = new TH2F("h2_qsmax","chg smax vs ch", MbdDefs::MAX_SAMPLES, -0.5, MbdDefs::MAX_SAMPLES-0.5, 128, 0, 128);
0242       h2_wave[0] = new TH2F("h2_twave","time adc vs ch", MbdDefs::MAX_SAMPLES, -0.5, MbdDefs::MAX_SAMPLES-0.5, 128, 0, 128);
0243       h2_wave[1] = new TH2F("h2_qwave","chg adc vs ch", MbdDefs::MAX_SAMPLES, -0.5, MbdDefs::MAX_SAMPLES-0.5, 128, 0, 128);
0244 
0245       for (int itype=0; itype<2; itype++)
0246       {
0247         h2_smax[itype]->SetXTitle("sample");
0248         h2_smax[itype]->SetYTitle("ch");
0249 
0250         h2_wave[itype]->SetXTitle("sample");
0251         h2_wave[itype]->SetYTitle("ch");
0252       }
0253     }
0254     else
0255     {
0256       // Reset histograms
0257       //for (int ich=0; ich<MbdDefs::MBD_N_FEECH; ich++)
0258       for (auto *h : h_smax )
0259       {
0260         h->Reset();
0261       }
0262       h2_smax[0]->Reset();
0263       h2_smax[1]->Reset();
0264       h2_wave[0]->Reset();
0265       h2_wave[1]->Reset();
0266     }
0267 
0268     if ( _calpass==1 )
0269     {
0270       orig_dir->cd();
0271     }
0272   }
0273 
0274   if ( _calpass == 2 )
0275   {
0276     // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge
0277     std::cout << "MBD Cal Pass 2" << std::endl;
0278     _mbdcal->Reset_TTT0();
0279     _mbdcal->Reset_TQT0();
0280     _mbdcal->Reset_Gains();
0281 
0282     TDirectory *orig_dir = gDirectory;
0283 
0284     if ( h2_trange==nullptr )
0285     {
0286       TString savefname = _caldir; savefname += "mbdcalpass2.root";
0287       std::cout << "Saving calpass 2 results to " << savefname << std::endl;
0288       _calpass2_tfile = std::make_unique<TFile>(savefname,"RECREATE");
0289 
0290       h2_trange_raw = new TH2F("h2_trange_raw","tadc (raw) at trig samp vs ch",1600,0,16384,128,0,128);
0291       h2_trange = new TH2F("h2_trange","tadc at trig samp vs ch",1638,-100,16280,128,0,128);
0292     }
0293     else
0294     {
0295       h2_trange_raw->Reset();
0296       h2_trange->Reset();
0297     }
0298 
0299     orig_dir->cd();
0300   }
0301 
0302   // Create TCanvas for debugging if requested
0303   //_verbose = 5;
0304   if (_verbose)
0305   {
0306     std::cout << "Creating canvas" << std::endl;
0307     if (ac == nullptr)
0308     {
0309       ac = new TCanvas("ac", "ac", 550 * 1.5, 425 * 1.5);
0310       ac->Divide(2, 1);
0311     }
0312   }
0313 
0314   return 0;
0315 }
0316 
0317 int MbdEvent::End()
0318 {
0319   //std::cout << "MbdEvent::End()" << std::endl;
0320   if ( _calpass == 1 )
0321   {
0322     CalcSampMaxCalib();
0323 
0324     std::string fname = _caldir.Data(); fname += "mbd_sampmax.calib";
0325     _mbdcal->Write_SampMax( fname );
0326 
0327     fname = _caldir.Data(); fname += "mbd_sampmax-";
0328     fname += std::to_string(_runnum); fname += ".root";
0329 #ifndef ONLINE
0330     _mbdcal->Write_CDB_SampMax( fname );
0331 #endif
0332 
0333     TDirectory *orig_dir = gDirectory;
0334     _calpass1_tfile->cd();
0335 
0336     for (auto & sig : _mbdsig)
0337     {
0338       sig.WritePedHist();
0339     }
0340 
0341     CalcPedCalib();
0342 
0343     std::string pedfname = _caldir.Data(); pedfname += "mbd_ped.calib";
0344     _mbdcal->Write_Ped( pedfname );
0345 
0346     pedfname = _caldir.Data(); pedfname += "mbd_ped-";
0347     pedfname += std::to_string(_runnum); pedfname += ".root";
0348     //std::cout << "PEDFNAME " << pedfname << std::endl;
0349 #ifndef ONLINE
0350     _mbdcal->Write_CDB_Ped( pedfname );
0351 #endif
0352 
0353     _calpass1_tfile->Write();
0354 
0355     orig_dir->cd();
0356   }
0357   else if ( _calpass == 2 )
0358   {
0359     TDirectory *orig_dir = gDirectory;
0360     _calpass2_tfile->Write();
0361     orig_dir->cd();
0362   }
0363 
0364   return 1;
0365 }
0366 
0367 ///
0368 void MbdEvent::Clear()
0369 {
0370   // Reset BBC/MBD raw data
0371   std::fill_n(m_pmttt, 128, std::numeric_limits<Float_t>::quiet_NaN());
0372   std::fill_n(m_pmttq, 128, std::numeric_limits<Float_t>::quiet_NaN());
0373   std::fill_n(m_pmtq, 128, 0.);
0374   std::fill_n(m_ampl, 256, 0.);
0375   std::fill_n(m_ttdc, 128, std::numeric_limits<Float_t>::quiet_NaN());
0376   std::fill_n(m_qtdc, 128, std::numeric_limits<Float_t>::quiet_NaN());
0377 
0378   // Reset BBC/MBD Arm Data
0379   for (int iarm = 0; iarm < 2; iarm++)
0380   {
0381     m_bbcn[iarm] = 0;
0382     m_bbcq[iarm] = 0.;
0383     m_bbct[iarm] = std::numeric_limits<Float_t>::quiet_NaN();
0384     m_bbcte[iarm] = std::numeric_limits<Float_t>::quiet_NaN();
0385     m_bbctl[iarm] = std::numeric_limits<Float_t>::quiet_NaN();
0386     hevt_bbct[iarm]->Reset();
0387     hevt_bbct[iarm]->GetXaxis()->SetRangeUser(-25, 25);
0388   }
0389 
0390   // Reset end product to prepare next event
0391   m_bbcz = std::numeric_limits<Float_t>::quiet_NaN();
0392   m_bbczerr = std::numeric_limits<Float_t>::quiet_NaN();
0393   m_bbct0 = std::numeric_limits<Float_t>::quiet_NaN();
0394   m_bbct0err = std::numeric_limits<Float_t>::quiet_NaN();
0395 }
0396 
0397 
0398 bool MbdEvent::isbadtch(const int ipmtch)
0399 {
0400   return std::fabs(_mbdcal->get_tt0(ipmtch))>100.;
0401 }
0402 
0403 
0404 #ifndef ONLINE
0405 // Get raw data from event combined DSTs
0406 int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts, Gl1Packet *gl1raw)
0407 {
0408   //std::cout << "MbdEvent::SetRawData()" << std::endl;
0409   // First check if there is any event (ie, reading from PRDF)
0410   if (dstp[0] == nullptr && dstp[1] == nullptr)
0411   {
0412     return Fun4AllReturnCodes::DISCARDEVENT;
0413   }
0414 
0415   // Only use MBDNS triggered events for MBD calibrations
0416   if ( _calpass>0 && gl1raw != nullptr )
0417   {
0418     const uint64_t MBDTRIGS = 0x7c00;  // MBDNS trigger bits
0419     //uint64_t trigvec = gl1raw->getTriggerVector();  // raw trigger only (obsolete, was only available in run1)
0420     uint64_t strig = gl1raw->getScaledVector();  // scaled trigger only
0421     int evtseq = gl1raw->getEvtSequence();
0422     if ( Verbosity() )
0423     {
0424       static int counter = 0;
0425       if ( counter<100 )
0426       {
0427         std::cout << "evt " << evtseq << ", strig " << std::hex << strig << std::dec << std::endl;
0428         counter++;
0429       }
0430     }
0431     if ( (strig&MBDTRIGS) == 0 )
0432     {
0433       return Fun4AllReturnCodes::ABORTEVENT;
0434     }
0435   }
0436 
0437   // Get Packets
0438   for (int ipkt = 0; ipkt < 2; ipkt++)
0439   {
0440     int pktid = 1001 + ipkt;  // packet id
0441 
0442     if (Verbosity() > 0)
0443     {
0444       static int counter = 0;
0445       if (counter < 4)
0446       {
0447         std::cout << "Found packet " << pktid << "\t" << dstp[ipkt] << std::endl;
0448         counter++;
0449       }
0450     }
0451     if (dstp[ipkt])
0452     {
0453       _nsamples = dstp[ipkt]->iValue(0, "SAMPLES");
0454       {
0455         static bool printcount{true};
0456         if ( printcount && Verbosity() > 0)
0457         {
0458           std::cout << "NSAMPLES = " << _nsamples << std::endl;
0459       printcount = false;
0460         }
0461       }
0462 
0463       m_xmitclocks[ipkt] = static_cast<UShort_t>(dstp[ipkt]->iValue(0, "CLOCK"));
0464 
0465       m_femclocks[ipkt][0] = static_cast<UShort_t>(dstp[ipkt]->iValue(0, "FEMCLOCK"));
0466       m_femclocks[ipkt][1] = static_cast<UShort_t>(dstp[ipkt]->iValue(1, "FEMCLOCK"));
0467 
0468       for (int ich = 0; ich < NCHPERPKT; ich++)
0469       {
0470         int feech = (ipkt * NCHPERPKT) + ich;
0471         for (int isamp = 0; isamp < _nsamples; isamp++)
0472         {
0473           m_adc[feech][isamp] = dstp[ipkt]->iValue(isamp, ich);
0474           m_samp[feech][isamp] = isamp;
0475 
0476           /*
0477           if ( m_adc[feech][isamp] <= 100 )
0478           {
0479             //flag_err = 1;
0480             std::cout << "BAD " << m_evt << "\t" << feech << "\t" << m_samp[feech][isamp]
0481                 << "\t" << m_adc[feech][isamp] << std::endl;
0482           }
0483           */
0484         }
0485 
0486         _mbdsig[feech].SetNSamples( _nsamples );
0487         _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]);
0488 
0489         /*
0490         std::cout << "feech " << feech << std::endl;
0491         _mbdsig[feech].Print();
0492         */
0493       }
0494 
0495       //delete dstp[ipkt];
0496       //dstp[ipkt] = nullptr;
0497     }
0498     else
0499     {
0500       // flag_err = 1;
0501       std::cout << PHWHERE << " ERROR, evt " << m_evt << " Missing Packet " << pktid << std::endl;
0502       return Fun4AllReturnCodes::ABORTEVENT;
0503     }
0504   }
0505 
0506   // Fill MbdRawContainer
0507   int status = ProcessPackets(bbcraws);
0508 
0509   if ( _fitsonly )
0510   {
0511     return status;
0512   }
0513 
0514   // Fill MbdPmtContainer and MbdOut
0515   status = ProcessRawContainer(bbcraws,bbcpmts);
0516 
0517   return status;
0518 }
0519 #endif  // ONLINE
0520 
0521 int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts)
0522 {
0523   // First check if there is any event (ie, reading from PRDF)
0524   if (event == nullptr)
0525   {
0526 #ifndef ONLINE
0527     return Fun4AllReturnCodes::DISCARDEVENT;
0528 #else
0529     return 1;
0530 #endif
0531   }
0532 
0533   int evt_type = event->getEvtType();
0534   if (evt_type != DATAEVENT)
0535   {
0536     std::cout << PHWHERE << "MbdEvent: Event type is not DATAEVENT, skipping" << std::endl;
0537 #ifndef ONLINE
0538     return Fun4AllReturnCodes::DISCARDEVENT;
0539 #else
0540     return 1;
0541 #endif
0542   }
0543 
0544   m_evt = event->getEvtSequence();
0545 
0546   // Get the relevant packets from the Event object and transfer the
0547   // data to the subsystem-specific table.
0548 
0549   // int flag_err = 0;
0550   Packet *p[2]{nullptr};
0551   for (int ipkt = 0; ipkt < 2; ipkt++)
0552   {
0553     int pktid = 1001 + ipkt;  // packet id
0554     p[ipkt] = event->getPacket(pktid);
0555 
0556     if (Verbosity() > 0)
0557     {
0558       static int counter = 0;
0559       if (counter < 4)
0560       {
0561         std::cout << "Found packet " << pktid << "\t" << p[ipkt] << std::endl;
0562         counter++;
0563       }
0564     }
0565     if (p[ipkt])
0566     {
0567       _nsamples = p[ipkt]->iValue(0, "SAMPLES");
0568       {
0569         static int counter = 0;
0570         if ( counter<1 )
0571         {
0572           std::cout << "NSAMPLES = " << _nsamples << std::endl;
0573         }
0574         counter++;
0575       }
0576 
0577       m_xmitclocks[ipkt] = static_cast<UShort_t>(p[ipkt]->iValue(0, "CLOCK"));
0578 
0579       m_femclocks[ipkt][0] = static_cast<UShort_t>(p[ipkt]->iValue(0, "FEMCLOCK"));
0580       m_femclocks[ipkt][1] = static_cast<UShort_t>(p[ipkt]->iValue(1, "FEMCLOCK"));
0581 
0582       for (int ich = 0; ich < NCHPERPKT; ich++)
0583       {
0584         int feech = (ipkt * NCHPERPKT) + ich;
0585         // std::cout << "feech " << feech << std::endl;
0586         for (int isamp = 0; isamp < _nsamples; isamp++)
0587         {
0588           m_adc[feech][isamp] = p[ipkt]->iValue(isamp, ich);
0589           m_samp[feech][isamp] = isamp;
0590 
0591           /*
0592           if ( m_adc[feech][isamp] <= 100 )
0593           {
0594             //flag_err = 1;
0595             //std::cout << "BAD " << m_evt << "\t" << feech << "\t" << m_samp[feech][isamp]
0596             //    << "\t" << m_adc[feech][isamp] << std::endl;
0597           }
0598           */
0599         }
0600 
0601         _mbdsig[feech].SetNSamples( _nsamples );
0602         _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]);
0603         //_mbdsig[feech].Print();
0604       }
0605 
0606       delete p[ipkt];
0607       p[ipkt] = nullptr;
0608     }
0609     else
0610     {
0611       // flag_err = 1;
0612       std::cout << PHWHERE << " ERROR, evt " << m_evt << " Missing Packet " << pktid << std::endl;
0613 #ifndef ONLINE
0614       return Fun4AllReturnCodes::ABORTEVENT;
0615 #else
0616       return -1;
0617 #endif
0618     }
0619   }
0620 
0621   // Fill MbdRawContainer
0622   int status = ProcessPackets(bbcraws);
0623   if ( _fitsonly )
0624   {
0625     return status;
0626   }
0627 
0628   // Fill MbdPmtContainer and MbdOut
0629   status = ProcessRawContainer(bbcraws,bbcpmts);
0630 
0631   return status;
0632 }
0633 
0634 int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws)
0635 {
0636   //std::cout << "In ProcessPackets" << std::endl;
0637   // Do a quick sanity check that all fem counters agree
0638   if (m_xmitclocks[0] != m_xmitclocks[1])
0639   {
0640     std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree" << std::endl;
0641   }
0642   /*
0643   // format changed in run2024, need to update check
0644   for (auto &femclock : femclocks)
0645   {
0646     for (unsigned short iadc : femclock)
0647     {
0648       if (iadc != femclocks[0][0])
0649       {
0650         std::cout << __FILE__ << ":" << __LINE__ << " ERROR, femclocks don't agree" << std::endl;
0651       }
0652     }
0653   }
0654   */
0655 
0656   // Store the clock info. We use just the first one, and assume all are consistent.
0657   m_clk = m_xmitclocks[0];
0658   m_femclk = m_femclocks[0][0];
0659 
0660   Clear();
0661 
0662   // We get SAMPMAX on this pass
0663   if ( _calpass == 1 || _no_sampmax > 0 )
0664   {
0665     //std::cout << "fillsamp " << _no_sampmax << std::endl;
0666     FillSampMaxCalib();
0667     m_evt++;
0668     return -1001; // stop processing event (negative return values end event processing)
0669   }
0670 
0671   for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++)
0672   {
0673     int pmtch = _mbdgeom->get_pmt(ifeech);
0674     int type = _mbdgeom->get_type(ifeech);  // 0 = T-channel, 1 = Q-channel
0675 
0676     // time channel
0677     if (type == 0)
0678     {
0679       m_ttdc[pmtch] = _mbdsig[ifeech].MBDTDC(_mbdcal->get_sampmax(ifeech));
0680 
0681       if ( m_ttdc[pmtch] < 40. || std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) )
0682       {
0683         m_ttdc[pmtch] = std::numeric_limits<Float_t>::quiet_NaN();   // no hit
0684       }
0685     }
0686     else if ( type == 1 && (!std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) || _always_process_charge ) )
0687     {
0688       // we process charge channels which have good time hit
0689       // or have time channels marked as bad
0690       // or have always_process_charge set to 1 (useful for threshold studies)
0691 
0692       // Use dCFD method to seed time in charge channels (or as primary if not fitting template)
0693       // std::cout << "getspline " << ifeech << std::endl;
0694       _mbdsig[ifeech].GetSplineAmpl();
0695       Double_t threshold = 0.5;
0696       m_qtdc[pmtch] = _mbdsig[ifeech].dCFD(threshold);
0697       m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in adc units
0698       if (do_templatefit)
0699       {
0700         //std::cout << "fittemplate" << std::endl;
0701         _mbdsig[ifeech].FitTemplate( _mbdcal->get_sampmax(ifeech) );
0702 
0703         if ( _verbose )
0704         {
0705           std::cout << "tt " << ifeech << " " << pmtch << " " << m_pmttt[pmtch] << std::endl;
0706         }
0707         m_qtdc[pmtch] = _mbdsig[ifeech].GetTime();  // in units of sample number
0708         m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in units of adc
0709       }
0710 
0711       // calpass 2, uncal_mbd. template fit. make sure qgain = 1, tq_t0 = 0
0712  
0713       // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25
0714       if ( ((m_ampl[ifeech] < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. )
0715       {
0716         m_qtdc[pmtch] = std::numeric_limits<Float_t>::quiet_NaN();
0717       }
0718     }
0719 
0720   }
0721 
0722   // Copy to output
0723   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
0724   {
0725     int feech = _mbdgeom->get_feech(ipmt);
0726     bbcraws->get_pmt(ipmt)->set_pmt(ipmt, m_ampl[feech], m_ttdc[ipmt], m_qtdc[ipmt]);
0727   }
0728   bbcraws->set_npmt(MbdDefs::BBC_N_PMT);  // this would need to be changed if we zero-suppressed
0729   bbcraws->set_clocks(m_evt, m_clk, m_femclk);
0730 
0731   return m_evt;
0732 }
0733 
0734 int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbcpmts)
0735 {
0736   //std::cout << "In ProcessRawContainer" << std::endl;
0737   for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++)
0738   {
0739     int pmtch = _mbdgeom->get_pmt(ifeech);
0740     int type = _mbdgeom->get_type(ifeech);  // 0 = T-channel, 1 = Q-channel
0741 
0742     // time channel
0743     if (type == 0)
0744     {
0745       if ( std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) )
0746       {
0747         m_pmttt[pmtch] = std::numeric_limits<Float_t>::quiet_NaN();  // no hit
0748       }
0749       else
0750       {
0751         m_pmttt[pmtch] = _mbdcal->get_tcorr(ifeech,bbcraws->get_pmt(pmtch)->get_ttdc());
0752 
0753         // at calpass 2, we use tcorr (uncal_mbd pass). make sure tt_t0 = 0.
0754         m_pmttt[pmtch] -= _mbdcal->get_tt0(pmtch);
0755       }
0756 
0757     }
0758     else if ( type == 1 && (!std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) || _always_process_charge ) )
0759     {
0760       // we process charge channels which have good time hit
0761       // or have time channels marked as bad
0762       // or have always_process_charge set to 1 (useful for threshold studies)
0763 
0764       m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc();
0765 
0766       if ( !std::isnan(m_pmttq[pmtch]) )
0767       {
0768         m_pmttq[pmtch] -= (_mbdcal->get_sampmax(ifeech) - 2);
0769         m_pmttq[pmtch] *= 17.7623;  // convert from sample to ns (1 sample = 1/56.299 MHz)
0770         m_pmttq[pmtch] = m_pmttq[pmtch] - _mbdcal->get_tq0(pmtch);
0771 
0772         // if ( m_pmttq[pmtch]<-50. && ifeech==255 ) std::cout << "hit_times " << ifeech << "\t" << m_pmttq[pmtch] << std::endl;
0773         // if ( arm==1 ) std::cout << "hit_times " << ifeech << "\t" << setw(10) << m_pmttq[pmtch] << "\t" << board << "\t" << TRIG_SAMP[board] << std::endl;
0774 
0775         // if tt is bad, use tq
0776         if ( std::fabs(_mbdcal->get_tt0(pmtch))>100. )
0777         {
0778           m_pmttt[pmtch] = m_pmttq[pmtch];
0779         }
0780         else
0781         {
0782           // we have a good tt ch. correct for slew if there is a hit
0783           //if ( ifeech==0 ) std::cout << "applying scorr" << std::endl;
0784           if ( !std::isnan(m_pmttt[pmtch]) )
0785           {
0786             m_pmttt[pmtch] -= _mbdcal->get_scorr(ifeech-8,bbcraws->get_pmt(pmtch)->get_adc());
0787           }
0788         }
0789       }
0790 
0791       if ( _mbdcal->get_qgain(pmtch) > 0. )
0792       {
0793         m_pmtq[pmtch] = bbcraws->get_pmt(pmtch)->get_adc() / _mbdcal->get_qgain(pmtch);
0794       }
0795       else
0796       {
0797         m_pmtq[pmtch] = 0.;
0798       }
0799 
0800       if (m_pmtq[pmtch] < 0.25 && (_runnum < 40000) )
0801       {
0802         m_pmtq[pmtch] = 0.;
0803         m_pmttq[pmtch] = std::numeric_limits<Float_t>::quiet_NaN();
0804       }
0805 
0806       /*
0807       if ( m_evt<3 && ifeech==255 && bbcraws->get_pmt(pmtch)->get_adc() )
0808       {
0809         std::cout << "dcfdcalc " << m_evt << "\t" << ifeech << "\t" << m_pmttq[pmtch] << "\t" << bbcraws->get_pmt(pmtch)->get_adc() << std::endl;
0810       }
0811       */
0812     }
0813 
0814   }
0815 
0816   // bbcpmts->Reset();
0817   //std::cout << "q10 " << bbcpmts->get_tower_at_channel(10)->get_q() << std::endl;
0818 
0819   // Copy to output
0820   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
0821   {
0822     bbcpmts->get_pmt(ipmt)->set_pmt(ipmt, m_pmtq[ipmt], m_pmttt[ipmt], m_pmttq[ipmt]);
0823   }
0824   bbcpmts->set_npmt(MbdDefs::BBC_N_PMT);
0825 
0826   m_clk = bbcraws->get_clock();
0827   m_femclk = bbcraws->get_femclock();
0828 
0829   PostProcessChannels(bbcpmts);
0830 
0831   m_evt++;
0832 
0833   // Have uncalibrated charge and time at this pass
0834   if ( _calpass == 2 )
0835   {
0836     for (int ifeech = 0; ifeech<MbdDefs::MBD_N_FEECH; ifeech++)
0837     {
0838       // determine the trig_samp board by board
0839       int type = _mbdgeom->get_type(ifeech);  // 0 = T-channel, 1 = Q-channel
0840       int pmtch = _mbdgeom->get_pmt(ifeech);
0841 
0842       // fill the h2_trange histograms
0843       if ( type==0 )
0844       {
0845         int samp_max = _mbdcal->get_sampmax( ifeech );
0846 
0847         h2_trange_raw->Fill( m_adc[ifeech][samp_max], pmtch );
0848 
0849         /*
0850         if ( pmtch == 127 )
0851         {
0852           std::cout << "xxx " << samp_max << "\t" << m_adc[ifeech][samp_max] << std::endl;
0853         }
0854         */
0855 
0856         TGraphErrors *gsubpulse = _mbdsig[ifeech].GetGraph();
0857         Double_t *y = gsubpulse->GetY();
0858         h2_trange->Fill( y[samp_max], pmtch );  // fill ped-subtracted tdc
0859       }
0860     }
0861 
0862     //return -1002;
0863     return m_evt;
0864   }
0865 
0866   return m_evt;
0867 }
0868 
0869 /// Processing after all channels have been calibrated, to remove outliers, etc
0870 void MbdEvent::PostProcessChannels(MbdPmtContainer *bbcpmts)
0871 {
0872   int orig_verbose = _verbose;
0873   _verbose = 0;
0874 
0875   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
0876   {
0877     MbdPmtHit *bbcpmt = bbcpmts->get_pmt(ipmt);
0878 
0879     float tt = bbcpmt->get_tt();    // hit time of pmt from time channel
0880     float tq = bbcpmt->get_tq();    // hit time of pmt from charge channel
0881     float q  = bbcpmt->get_q();     // charge in pmt
0882 
0883     if ( _verbose>0 && std::isnan(tt) && q>0. )
0884     {
0885       std::cout << "bad tt, good q\t" << ipmt << "\t" << tt << "\t" << tq << "\t" << q << std::endl;
0886       int t_feech = _mbdgeom->get_feech(ipmt,0);
0887       int q_feech = _mbdgeom->get_feech(ipmt,1);
0888       ac->cd(1);
0889       _mbdsig[t_feech].DrawWaveform();
0890       ac->cd(2);
0891       _mbdsig[q_feech].DrawWaveform();
0892       std::string junk;
0893       std::cout << "? " << std::endl;
0894       std::cin >> junk;
0895     }
0896   }
0897 
0898   _verbose = orig_verbose;
0899 }
0900 
0901 ///
0902 int MbdEvent::Calculate(MbdPmtContainer *bbcpmts, MbdOut *bbcout, PHCompositeNode *topNode)
0903 {
0904   if ( _debug )
0905   {
0906     _verbose = 100;
0907     std::cout << topNode << std::endl;
0908 
0909 #ifndef ONLINE
0910     GetPrimaryVtx(topNode);
0911 #endif
0912 
0913     // use intt vertex
0914     //_refz = intz[_syncevt]/10.;
0915   }
0916   //_verbose = 100;
0917  
0918   if (_verbose >= 10)
0919   {
0920     std::cout << "In MbdEvent::Calculate() " << m_evt << std::endl;
0921   }
0922   Clear();
0923   if (bbcout != nullptr)
0924   {
0925     bbcout->Reset();
0926   }
0927 
0928   // Debug stuff
0929 /*
0930   if ( _debug && (bbevt[_syncevt] != (m_evt - 1)))
0931   {
0932     _verbose = 0;
0933     return 1;
0934   }
0935 */
0936 
0937   if (gausfit[0] == nullptr)
0938   {
0939     TString name;
0940     for (int iarm = 0; iarm < 2; iarm++)
0941     {
0942       name = "gausfit";
0943       name += iarm;
0944       gausfit[iarm] = new TF1(name, "gaus", 0, 20);
0945       gausfit[iarm]->FixParameter(2, _tres);  // set sigma to timing resolution
0946       gausfit[iarm]->SetLineColor(2);
0947     }
0948   }
0949 
0950   std::array<std::vector<float>,2> hit_times;  // times of the hits in each [arm]
0951 
0952   // calculate bbc global variables
0953   if (_verbose >= 10)
0954   {
0955     std::cout << "Hit PMT info " << std::endl;
0956   }
0957 
0958   for (int iarm=0; iarm<2; iarm++)
0959   {
0960     epmt[iarm] = -1;       // pmt of earliest time
0961     //lpmt[iarm] -1;   // pmt of latest time
0962     tepmt[iarm] = 1e9;    // earliest time
0963     tlpmt[iarm] = -1e9;  // latest time
0964   }
0965 
0966   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
0967   {
0968     MbdPmtHit *bbcpmt = bbcpmts->get_pmt(ipmt);
0969     int arm = _mbdgeom->get_arm( ipmt );
0970 
0971     float t_pmt = bbcpmt->get_time();  // hit time of pmt
0972     float q_pmt = bbcpmt->get_q();     // charge in pmt
0973 
0974     if (_verbose >= 2000 && !std::isnan(t_pmt) )
0975     {
0976       std::cout << ipmt << "\t" << t_pmt << "\t" << q_pmt << std::endl;
0977     }
0978 
0979     if (std::fabs(t_pmt) < 25. && q_pmt > 0.)
0980     {
0981       hit_times[arm].push_back(t_pmt);
0982       hevt_bbct[arm]->Fill(t_pmt);
0983 
0984       m_bbcn[arm]++;
0985       m_bbcq[arm] += q_pmt;
0986 
0987       if (_verbose >= 10)
0988       {
0989         std::cout << ipmt << "\t" << t_pmt << "\t" << q_pmt << std::endl;
0990 
0991         if (t_pmt < tepmt[arm])
0992         {
0993           epmt[arm] = ipmt;
0994           tepmt[arm] = t_pmt;
0995         }
0996         tlpmt[arm] = std::max<double>(t_pmt, tlpmt[arm]);
0997       }
0998     }
0999   }
1000 
1001   if (_verbose >= 10)
1002   {
1003     std::cout << "nhits " << m_bbcn[0] << "\t" << m_bbcn[1] << std::endl;
1004     // std::cout << "bbcte " << m_bbcte[0] << "\t" << m_bbcte[1] << std::endl;
1005   }
1006 
1007   for (int iarm = 0; iarm < 2; iarm++)
1008   {
1009     if (hit_times[iarm].empty())
1010     {
1011       // std::cout << "hit_times size == 0" << std::endl;
1012       continue;
1013     }
1014 
1015     // std::cout << "EARLIEST " << iarm << std::endl;
1016     // std::cout << "ERROR hit_times size == " << hit_times[iarm].size() << std::endl;
1017 
1018     std::sort(hit_times[iarm].begin(), hit_times[iarm].end());
1019     float earliest = hit_times[iarm].at(0);
1020     float latest = hit_times[iarm].back();
1021     // std::cout << "earliest" << iarm << "\t" << earliest << std::endl;
1022  
1023     // Cluster earliest hits
1024     double mean;
1025     double rms;
1026     double rmin;
1027     double rmax;
1028     ClusterEarliest( hit_times[iarm], mean, rms, rmin, rmax );
1029 
1030     gausfit[iarm]->SetParameter(0, 5);
1031     gausfit[iarm]->SetParameter(1, mean);
1032     gausfit[iarm]->SetParameter(2, rms);
1033     double binwid = hevt_bbct[iarm]->GetBinWidth(1);
1034     gausfit[iarm]->SetRange(rmin-binwid,rmax+binwid);
1035     // gausfit[iarm]->SetParameter(1, earliest);
1036     // gausfit[iarm]->SetRange(6, earliest + 5 * 0.05);
1037     /*
1038     gausfit[iarm]->SetParameter(1, hevt_bbct[iarm]->GetMean());
1039     gausfit[iarm]->SetParameter(2, hevt_bbct[iarm]->GetRMS());
1040     gausfit[iarm]->SetRange(hevt_bbct[iarm]->GetMean() - 5, hevt_bbct[iarm]->GetMean() + 5);
1041     */
1042 
1043     if ( hevt_bbct[iarm]->GetEntries()==0 )//chiu
1044     {
1045       std::cout << PHWHERE << " hevt_bbct EMPTY" << std::endl;
1046     }
1047 
1048     hevt_bbct[iarm]->Fit(gausfit[iarm], "BNQLR");
1049 
1050     // m_bbct[iarm] = m_bbct[iarm] / m_bbcn[iarm];
1051     //m_bbct[iarm] = gausfit[iarm]->GetParameter(1);  // gaus fit
1052     m_bbct[iarm] = mean;
1053 
1054     m_bbcte[iarm] = earliest;
1055     m_bbctl[iarm] = latest;
1056 
1057     /*
1058     if ( m_bbcn[iarm]==1 )
1059     {
1060       m_bbct[iarm] = earliest;
1061     }
1062     */
1063 
1064     //_bbcout->set_arm(iarm, m_bbcn[iarm], m_bbcq[iarm], m_bbct[iarm]);
1065 
1066   }
1067 
1068   // Get Zvertex, T0
1069   if (m_bbcn[0] > 0 && m_bbcn[1] > 0)
1070   {
1071     /*
1072     if ( m_bbcn[0]==1 || m_bbcn[1]==1 )
1073     {
1074       _verbose = 100;
1075     }
1076     */
1077 
1078     // Now calculate zvtx, t0 from best times
1079     if (_verbose >= 10)
1080     {
1081       std::cout << "Evt " << m_evt << "\tt0\t" << m_bbct[0] << "\t" << m_bbct[1] << std::endl;
1082       std::cout << "bbcn " << m_bbcn[0] << "\t" << m_bbcn[1] << std::endl;
1083       std::cout << "bbcq " << m_bbcq[0] << "\t" << m_bbcq[1] << std::endl;
1084     }
1085     m_bbcz = (m_bbct[0] - m_bbct[1]) * TMath::C() * 1e-7 / 2.0;   // in cm
1086     m_bbct0 = (m_bbct[0] + m_bbct[1]) / 2.0;                      // in ns
1087 
1088     // correct t0
1089     m_bbct0 -= _mbdcal->get_t0corr();
1090     //std::cout << "correcting m_bbct0 with " << _mbdcal->get_t0corr() << std::endl;
1091 
1092     // hard code these for now
1093     // need study to determine muliplicity dependence
1094     m_bbczerr = 1.0;    // cm
1095     m_bbct0err = 0.05;  // ns
1096 
1097     /*
1098     // Use earliest time
1099     //cout << "t0\t" << m_bbct[0] << "\t" << m_bbct[1] << std::endl;
1100     //cout << "te\t" << m_bbcte[0] << "\t" << m_bbcte[1] << std::endl;
1101     m_bbcz = (m_bbcte[0] - m_bbcte[1]) * TMath::C() * 1e-7 / 2.0; // in cm
1102     m_bbct0 = (m_bbcte[0] + m_bbcte[1]) / 2.0;
1103     */
1104 
1105     // if ( _verbose && mybbz[_syncevt]< -40. )
1106     if (_verbose>20)
1107     {
1108       std::cout << "bbcz " << m_bbcz << std::endl;
1109       std::string junk;
1110       std::cout << "? ";
1111       std::cin >> junk;
1112       _verbose = 0;
1113     }
1114   }
1115 
1116   // Fill rest of MbdOut
1117   if (bbcout != nullptr)
1118   {
1119     for (int iarm = 0; iarm < 2; iarm++)
1120     {
1121       bbcout->set_arm(iarm, get_bbcn(iarm), get_bbcq(iarm), get_bbct(iarm));
1122       bbcout->set_clocks(m_evt, m_clk, m_femclk);  // only for V2
1123       if (_verbose > 10)
1124       {
1125         std::cout << get_bbcn(iarm) << "\t" << get_bbcq(iarm) << "\t" << get_bbct(iarm) << std::endl;
1126       }
1127     }
1128 
1129     if (get_bbcn(0) > 0 && get_bbcn(1) > 0)
1130     {
1131       bbcout->set_t0(get_bbct0(), get_bbct0err());
1132       bbcout->set_zvtx(get_bbcz(), get_bbczerr());
1133       
1134 /*
1135       if ( _debug )
1136       {
1137         bbcout->set_t0(intz[_syncevt]/10.);
1138       }
1139 */
1140 
1141     }
1142   }
1143 
1144   // if ( _verbose && mybbz[_syncevt]< -40. )
1145   if ( _debug && fabs(m_bbcz - _refz)>5.0 )
1146   {
1147     PlotDebug();
1148 
1149     //_syncevt++;
1150     _verbose = 0;
1151   }
1152 
1153   return 1;
1154 }
1155 
1156 
1157 // get the values for the earliest cluster
1158 void MbdEvent::ClusterEarliest(std::vector<float>& times, double& mean, double& rms, double& rmin, double& rmax)
1159 {
1160   _verbose = 0;
1161 
1162   rmin = times[0];
1163   rmax = times[0];
1164 
1165   double npts = 0.;
1166   double sum = 0.;
1167   double sum2 = 0.;
1168   mean = times[0];
1169   for ( size_t it = 0; it<times.size(); it++ )
1170   {
1171     if ( _verbose )
1172     {
1173       std::cout << "C " << times[it] << std::endl;
1174     }
1175     double dt = fabs( times[it] - mean );
1176     if ( dt > 0.060*3.0 )
1177     {
1178       break;
1179     }
1180 
1181     sum += times[it];
1182     sum2 += (times[it]*times[it]);
1183 
1184     mean = sum/(it+1.0);
1185     npts += 1.0;
1186 
1187     rmax = times[it];
1188   }
1189 
1190   if ( npts>1.0 )
1191   {
1192     rms = std::max( sqrt( (sum2/npts) - (mean*mean) ), 0.05);
1193   }
1194   else
1195   {
1196     rms = 0.;
1197   }
1198 
1199   if ( _verbose )
1200   {
1201     std::cout << "CLUSTER " << mean << "\t" << rms << "\t" << npts << "\t" << rmin << "\t" << rmax << std::endl;
1202   }
1203 }
1204 
1205 void MbdEvent::PlotDebug()
1206 {
1207   for (int iarm=0; iarm<2; iarm++)
1208   {
1209     ac->cd(iarm + 1);
1210 
1211     hevt_bbct[iarm]->GetXaxis()->SetRangeUser(tepmt[iarm] - 3., tlpmt[iarm] + 3.);
1212     // hevt_bbct[iarm]->GetXaxis()->SetRangeUser(-20,20);
1213     hevt_bbct[iarm]->Draw();
1214     if ( m_bbcn[iarm]>1 )
1215     {
1216       gausfit[iarm]->Draw("same");
1217     }
1218     gPad->Modified();
1219     gPad->Update();
1220     if (iarm == 1)
1221     {
1222       double zearly = (tepmt[0] - tepmt[1]) * MbdDefs::C / 2.0;
1223       double znew = (m_bbct[0] - m_bbct[1]) * MbdDefs::C / 2.0;
1224 
1225       if (_debug)
1226       {
1227         double refzdiff = _refz - m_bbcz;
1228         double refzediff = _refz - zearly;
1229         if (fabs(znew - m_bbcz) > 0.1)
1230         {
1231           std::cout << "**ERR** " << znew << "\t" << m_bbcz << std::endl;
1232         }
1233         std::cout << m_evt << "\t" << m_bbct[0] << "\t" << m_bbct[1] << std::endl;
1234         std::cout << m_evt << " gmean " << gausfit[0]->GetParameter(1) << "\t" << gausfit[1]->GetParameter(1) << std::endl;
1235         std::cout << m_evt << " mean " << hevt_bbct[0]->GetMean(1) << "\t" << hevt_bbct[1]->GetMean(1) << std::endl;
1236         std::cout << m_evt << " gsigma " << gausfit[0]->GetParameter(2) << "\t" << gausfit[1]->GetParameter(2) << std::endl;
1237         std::cout << m_evt << " rms " << hevt_bbct[0]->GetRMS() << "\t" << hevt_bbct[1]->GetRMS() << std::endl;
1238         //std::cout << m_evt << " te ch " << epmt[0] << "\t" << epmt[1] << "\t" << tepmt[0] << "\t" << tepmt[1] << std::endl;
1239         std::cout << m_evt << " tetl " << m_bbcte[0] << "\t" << m_bbctl[0] << "\t" << m_bbcte[1] << "\t" << m_bbctl[1] << std::endl;
1240         std::cout << m_evt << " bz refz " << m_bbcz << "\t" << _refz << "\t" << refzdiff << "\t" << refzdiff * 2.0 / MbdDefs::C << std::endl;
1241         std::cout << m_evt << " bze " << zearly << "\t" << refzediff << std::endl;
1242       }
1243     }
1244   }
1245 
1246   std::string junk;
1247   std::cout << "? ";
1248   std::cin >> junk;
1249 }
1250 
1251 // Store data for sampmax calibration (to correct ADC sample offsets by channel)
1252 int MbdEvent::FillSampMaxCalib()
1253 {
1254   for (int ifeech = 0; ifeech<MbdDefs::MBD_N_FEECH; ifeech++)
1255   {
1256     // determine the trig_samp board by board
1257     int type = _mbdgeom->get_type(ifeech);  // 0 = T-channel, 1 = Q-channel
1258     int pmtch = _mbdgeom->get_pmt(ifeech);
1259                                                                                   
1260     //_mbdsig[ifeech].SetXY(m_samp[ifeech], m_adc[ifeech]);
1261 
1262     for (int isamp=0; isamp<_nsamples; isamp++)
1263     {
1264       // sanity check
1265       if ( m_samp[ifeech][isamp] != isamp )
1266       {
1267         std::cerr << PHWHERE << ", ch" << ifeech << ", msamp != isamp, " << m_samp[ifeech][isamp] << " " << isamp << std::endl;
1268       }
1269       h2_wave[type]->Fill( isamp , pmtch, m_adc[ifeech][isamp] );
1270     }
1271 
1272     double maxsamp;
1273     double maxadc;
1274     _mbdsig[ifeech].LocMax( maxsamp, maxadc );
1275 
1276     if ( maxadc > 20 )
1277     {
1278       h_smax[ifeech]->Fill( maxsamp );
1279       h2_smax[type]->Fill( maxsamp, pmtch );
1280       //std::cout << "fillint h2_smax " << pmtch << "\t" << maxsamp << std::endl;
1281       //_mbdsig[ifeech].Print();
1282     }
1283 
1284   }
1285 
1286   // _no_sampmax keeps track of how many events to use for on-the-fly calibration
1287   _no_sampmax--;
1288 
1289   if ( _no_sampmax==0 && _calpass != 1 )
1290   {
1291     CalcSampMaxCalib();
1292     _calib_done = 1;
1293     std::cout << PHWHERE << " on the fly sampmax calib done" << std::endl;
1294 
1295     for (int ifeech=0; ifeech<MbdDefs::MBD_N_FEECH; ifeech++)
1296     {
1297       _mbdsig[ifeech].SetEventPed0Range(-9999,-9999);
1298 
1299       const int presamp = 5;  // start from 5 samples before sampmax
1300       const int nsamps = -1;  // use all to sample 0
1301       _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech));
1302     }
1303   }
1304 
1305   return 1;
1306 }
1307 
1308 int MbdEvent::CalcSampMaxCalib()
1309 {
1310   TDirectory *orig_dir = gDirectory;
1311   if ( _calpass==1 )
1312   {
1313     _calpass1_tfile->cd();
1314   }
1315 
1316   // sampmax for each board, for time and ch channels
1317   int feech = 0;
1318   for (int iboard=0; iboard<16; iboard++)
1319   {
1320     int min_ybin = (iboard*8) + 1;
1321     int max_ybin = (iboard*8) + 8;
1322 
1323     // sampmax for time channels
1324     TString name = "t_sampmax_bd"; name += iboard;
1325     TH1 *h_projx = h2_smax[0]->ProjectionX(name,min_ybin,max_ybin);
1326     int maxbin = h_projx->GetMaximumBin();
1327     int samp_max = h_projx->GetBinCenter( maxbin );
1328     for (int ich=0; ich<8; ich++)
1329     {
1330       _mbdcal->set_sampmax( feech, samp_max );
1331       feech++;
1332     }
1333     delete h_projx;
1334 
1335     // sampmax for charge channels
1336     name = "t_sampmax_bd"; name += iboard;
1337     h_projx = h2_smax[1]->ProjectionX(name,min_ybin,max_ybin);
1338     maxbin = h_projx->GetMaximumBin();
1339     samp_max = h_projx->GetBinCenter( maxbin );
1340     for (int ich=0; ich<8; ich++)
1341     {
1342       _mbdcal->set_sampmax( feech, samp_max );
1343       //std::cout << "sampmax " << feech << "\t" << samp_max << std::endl;
1344       feech++;
1345     }
1346     delete h_projx;
1347   }
1348 
1349   if ( _calpass==1 )
1350   {
1351     orig_dir->cd();
1352   }
1353 
1354   _no_sampmax = 0;  // now we have samp max
1355 
1356   return 1;
1357 }
1358 
1359 int MbdEvent::CalcPedCalib()
1360 {
1361   TDirectory *orig_dir = gDirectory;
1362   if ( _calpass==1 )
1363   {
1364     _calpass1_tfile->cd();
1365   }
1366 
1367   // ped for each feech
1368   TF1 *pedgaus = new TF1("pedgaus","gaus",0.,2999.);
1369   for (int ifeech=0; ifeech<MbdDefs::MBD_N_FEECH; ifeech++)
1370   {
1371     TH1 *hped0 = _mbdsig[ifeech].GetPedHist();
1372     float mean = hped0->GetBinCenter( hped0->GetMaximumBin() );
1373     float ampl = hped0->GetBinContent( hped0->GetMaximumBin() );
1374     float sigma = 4.0;
1375 
1376     pedgaus->SetParameters(ampl,mean,sigma);
1377     pedgaus->SetRange(mean-(4*sigma), mean+(4*sigma));
1378     if ( hped0->GetEntries()==0 ) //chiu
1379     {
1380       std::cout << "HPED0 EMPTY" << std::endl;
1381     }
1382     hped0->Fit(pedgaus,"RNQ");
1383 
1384     mean = pedgaus->GetParameter(1);
1385     float meanerr = pedgaus->GetParError(1);
1386     sigma = pedgaus->GetParameter(2);
1387     float sigmaerr = pedgaus->GetParError(2);
1388 
1389     _mbdcal->set_ped( ifeech, mean, meanerr, sigma, sigmaerr );
1390   }
1391   delete pedgaus;
1392 
1393   if ( _calpass==1 )
1394   {
1395     orig_dir->cd();
1396   }
1397 
1398   return 1;
1399 }
1400 
1401 int MbdEvent::Read_Charge_Calib(const std::string &gainfname)
1402 {
1403   std::ifstream gainfile(gainfname);
1404 
1405   std::cout << "Reading gains from " << gainfname << std::endl;
1406   int ch;
1407   float integ;
1408   float integerr;
1409   float peak;
1410   float peakerr;
1411   float width;
1412   float widtherr;
1413   float chi2ndf;
1414   while (gainfile >> ch >> integ >> peak >> width >> integerr >> peakerr >> widtherr >> chi2ndf)
1415   {
1416     gaincorr[ch] = 1.0 / peak;
1417 
1418     // std::cout << ch << "\t" << peak << std::endl;
1419   }
1420 
1421   gainfile.close();
1422 
1423   return 1;
1424 }
1425 
1426 // Read in tq t0 offset calibrations
1427 int MbdEvent::Read_TQ_T0_Offsets(const std::string &t0cal_fname)
1428 {
1429   std::ifstream tcalibfile(t0cal_fname);
1430 
1431   std::cout << "Reading tq_t0 offset calibrations from " << t0cal_fname << std::endl;
1432 
1433   int pmtnum;
1434   float meanerr;
1435   float sigma;
1436   float sigmaerr;
1437   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
1438   {
1439     tcalibfile >> pmtnum >> tq_t0_offsets[ipmt] >> meanerr >> sigma >> sigmaerr;
1440     if (pmtnum != ipmt)
1441     {
1442       std::cout << "ERROR, pmtnum != ipmt, " << pmtnum << "\t" << ipmt << std::endl;
1443     }
1444   }
1445 
1446   tcalibfile.close();
1447 
1448   return 1;
1449 }
1450 
1451 // Read in tq clk offset calibrations
1452 int MbdEvent::Read_TQ_CLK_Offsets(const std::string &t0cal_fname)
1453 {
1454   std::ifstream tcalibfile(t0cal_fname);
1455 
1456   std::cout << "Reading tq_clk offset calibrations from " << t0cal_fname << std::endl;
1457 
1458   int pmtnum;
1459   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
1460   {
1461     tcalibfile >> pmtnum >> tq_clk_offsets[ipmt];
1462     if (pmtnum != ipmt)
1463     {
1464       std::cout << "ERROR, pmtnum != ipmt, " << pmtnum << "\t" << ipmt << std::endl;
1465     }
1466   }
1467 
1468   tcalibfile.close();
1469 
1470   return 1;
1471 }
1472 
1473 // Read in tt clk offset calibrations
1474 int MbdEvent::Read_TT_CLK_Offsets(const std::string &t0cal_fname)
1475 {
1476   std::ifstream tcalibfile(t0cal_fname);
1477 
1478   std::cout << "Reading tq_clk offset calibrations from " << t0cal_fname << std::endl;
1479 
1480   int pmtnum;
1481   for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++)
1482   {
1483     tcalibfile >> pmtnum >> tt_clk_offsets[ipmt];
1484     if (pmtnum != ipmt)
1485     {
1486       std::cout << "ERROR, pmtnum != ipmt, " << pmtnum << "\t" << ipmt << std::endl;
1487     }
1488   }
1489 
1490   tcalibfile.close();
1491 
1492   return 1;
1493 }
1494 
1495 void MbdEvent::ReadSyncFile(const char *fname)
1496 {
1497   Int_t f_evt{0};
1498   UShort_t f_femclk{0};
1499   Float_t f_bz{0.};
1500   Long64_t bco_full{0};
1501   Double_t ES_zvtx{0.};
1502   Double_t mbd_bz{0.};
1503 
1504   _synctfile = std::make_unique<TFile>(fname, "READ");
1505   _syncttree = (TTree *) _synctfile->Get("t2");
1506   _syncttree->SetBranchAddress("evt", &f_evt);
1507   _syncttree->SetBranchAddress("femclk", &f_femclk);
1508   _syncttree->SetBranchAddress("bz", &f_bz);
1509   _syncttree->SetBranchAddress("bco_full", &bco_full);
1510   _syncttree->SetBranchAddress("ES_zvtx", &ES_zvtx);
1511   _syncttree->SetBranchAddress("mbd_bz", &mbd_bz);
1512 
1513   Stat_t nentries = _syncttree->GetEntries();
1514   for (int ientry = 0; ientry < nentries; ientry++)
1515   {
1516     _syncttree->GetEntry(ientry);
1517 
1518     bbevt.push_back(f_evt);
1519     bbclk.push_back(f_femclk);
1520     mybbz.push_back(f_bz);
1521     bco.push_back(bco_full);
1522     intz.push_back(ES_zvtx);
1523     bbz.push_back(mbd_bz);
1524   }
1525 
1526   std::cout << "Read in " << bbevt.size() << " INTT sync events" << std::endl;
1527 }
1528 
1529 
1530 #ifndef ONLINE
1531 PHG4VtxPoint *MbdEvent::GetPrimaryVtx(PHCompositeNode *topNode)
1532 {
1533   // Get True Vertex from TruthInfoContainer
1534   _truth_container = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
1535   if(_truth_container == nullptr)
1536   {
1537     static int ctr = 0;
1538     if ( ctr<4 )
1539     {
1540       std::cout << PHWHERE << " PHG4TruthInfoContainer node not found on node tree" << std::endl;
1541       ctr++;
1542     }
1543     _vtxp = nullptr;
1544     return nullptr;
1545   }
1546 
1547   _vtxp = _truth_container->GetPrimaryVtx( _truth_container->GetPrimaryVertexIndex() );
1548   _refz = _vtxp->get_z();
1549 
1550   return _vtxp;
1551 
1552 }
1553 #endif