diff --git a/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.cpp b/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.cpp new file mode 100644 index 000000000..5f7f4c6ee --- /dev/null +++ b/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.cpp @@ -0,0 +1,2409 @@ +#include "ANNIEEventTreeMaker.h" + +ANNIEEventTreeMaker::ANNIEEventTreeMaker() : Tool() {} + +bool ANNIEEventTreeMaker::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("ANNIEEventTreeMakerVerbosity", ANNIEEventTreeMakerVerbosity); + m_variables.Get("isData", isData); + m_variables.Get("HasGenie", hasGenie); + + fillAllTriggers = true; + m_variables.Get("fillAllTriggers", fillAllTriggers); + fill_singleTrigger = true; + m_variables.Get("fill_singleTrigger", fill_singleTrigger); + fill_singleTriggerWord = 14; + m_variables.Get("fill_singleTriggerWord", fill_singleTriggerWord); + fill_TriggerWord = {14, 47}; + + m_variables.Get("fillCleanEventsOnly", fillCleanEventsOnly); + m_variables.Get("fillLAPPDEventsOnly", fillLAPPDEventsOnly); + + m_variables.Get("TankHitInfo_fill", TankHitInfo_fill); + m_variables.Get("TankCluster_fill", TankCluster_fill); + m_variables.Get("cluster_TankHitInfo_fill", cluster_TankHitInfo_fill); + m_variables.Get("MRDHitInfo_fill", MRDHitInfo_fill); + m_variables.Get("RWMBRF_fill", RWMBRF_fill); + + m_variables.Get("MCTruth_fill", MCTruth_fill); + m_variables.Get("MRDReco_fill", MRDReco_fill); + m_variables.Get("TankReco_fill", TankReco_fill); + m_variables.Get("RecoDebug_fill", RecoDebug_fill); + m_variables.Get("muonTruthRecoDiff_fill", muonTruthRecoDiff_fill); + m_variables.Get("LAPPDData_fill", LAPPDData_fill); + m_variables.Get("SiPMPulseInfo_fill", SiPMPulseInfo_fill); + m_variables.Get("LAPPDReco_fill", LAPPDReco_fill); + m_variables.Get("LAPPD_PPS_fill", LAPPD_PPS_fill); + + std::string output_filename = "ANNIEEventTree.root"; + m_variables.Get("OutputFile", output_filename); + fOutput_tfile = new TFile(output_filename.c_str(), "recreate"); + fANNIETree = new TTree("Event", "ANNIE Phase II Event Tree"); + + m_data->CStore.Get("AuxChannelNumToTypeMap", AuxChannelNumToTypeMap); + m_data->CStore.Get("ChannelNumToTankPMTSPEChargeMap", ChannelKeyToSPEMap); + m_data->CStore.Get("pmt_tubeid_to_channelkey_data", pmtid_to_channelkey); + m_data->CStore.Get("channelkey_to_pmtid", channelkey_to_pmtid); + m_data->CStore.Get("channelkey_to_mrdpmtid", channelkey_to_mrdpmtid); + m_data->CStore.Get("mrdpmtid_to_channelkey_data", mrdpmtid_to_channelkey_data); + m_data->CStore.Get("channelkey_to_faccpmtid", channelkey_to_faccpmtid); + + auto get_geometry = m_data->Stores.at("ANNIEEvent")->Header->Get("AnnieGeometry", geom); + if (!get_geometry) + { + Log("ANNIEEventTreeMaker Tool: Error retrieving Geometry from ANNIEEvent!", v_error, ANNIEEventTreeMakerVerbosity); + return false; + } + + // general information in an event + fANNIETree->Branch("runNumber", &fRunNumber, "runNumber/I"); + fANNIETree->Branch("subrunNumber", &fSubrunNumber, "subrunNumber/I"); + fANNIETree->Branch("partFileNumber", &fPartFileNumber, "partFileNumber/I"); + fANNIETree->Branch("runType", &fRunType, "runType/I"); + fANNIETree->Branch("eventNumber", &fEventNumber, "eventNumber/I"); // + fANNIETree->Branch("PrimaryTriggerWord", &fPrimaryTriggerWord, "PrimaryTriggerWord/I"); + fANNIETree->Branch("GroupedTriggerTime", &fGroupedTriggerTime); + fANNIETree->Branch("GroupedTriggerWord", &fGroupedTriggerWord); + fANNIETree->Branch("trigword", &fTriggerword, "trigword/I"); // keep for trigger 5 or 14 + + // flags from event selector + fANNIETree->Branch("Extended", &fExtended, "Extended/I"); + fANNIETree->Branch("HasTank", &fHasTank, "HasTank/I"); + fANNIETree->Branch("HasMRD", &fHasMRD, "HasMRD/I"); + fANNIETree->Branch("HasLAPPD", &fHasLAPPD, "HasLAPPD/I"); + fANNIETree->Branch("TankMRDCoinc", &fTankMRDCoinc, "TankMRDCoinc/I"); + fANNIETree->Branch("NoVeto", &fNoVeto, "NoVeto/I"); + + // event information of data + fANNIETree->Branch("eventTimeTank", &fEventTimeTank, "eventTimeTank/l"); + fANNIETree->Branch("eventTimeMRD", &fEventTimeMRD, "eventTimeMRD/l"); + + // beam information + if (BeamInfo_fill) + { + fANNIETree->Branch("beam_pot_875", &fPot, "beam_pot_875/D"); + fANNIETree->Branch("beam_ok", &fBeamok, "beam_ok/I"); + fANNIETree->Branch("beam_E_TOR860", &beam_E_TOR860, "beam_E_TOR860/D"); + fANNIETree->Branch("beam_E_TOR875", &beam_E_TOR875, "beam_E_TOR875/D"); + fANNIETree->Branch("beam_THCURR", &beam_THCURR, "beam_THCURR/D"); + fANNIETree->Branch("beam_BTJT2", &beam_BTJT2, "beam_BTJT2/D"); + fANNIETree->Branch("beam_HP875", &beam_HP875, "beam_HP875/D"); + fANNIETree->Branch("beam_VP875", &beam_VP875, "beam_VP875/D"); + fANNIETree->Branch("beam_HPTG1", &beam_HPTG1, "beam_HPTG1/D"); + fANNIETree->Branch("beam_VPTG1", &beam_VPTG1, "beam_VPTG1/D"); + fANNIETree->Branch("beam_HPTG2", &beam_HPTG2, "beam_HPTG2/D"); + fANNIETree->Branch("beam_VPTG2", &beam_VPTG2, "beam_VPTG2/D"); + fANNIETree->Branch("beam_BTH2T2", &beam_BTH2T2, "beam_BTH2T2/D"); + fANNIETree->Branch("BeamInfoTime", &fBeamInfoTime, "BeamInfoTime/l"); + fANNIETree->Branch("BeamInfoTimeToTriggerDiff", &fBeamInfoTimeToTriggerDiff, "BeamInfoTimeToTriggerDiff/L"); + } + + if (RWMBRF_fill) + { + fANNIETree->Branch("RWMRisingStart", &fRWMRisingStart, "fRWMRisingStart/D"); + fANNIETree->Branch("RWMRisingEnd", &fRWMRisingEnd, "fRWMRisingEnd/D"); + fANNIETree->Branch("RWMHalfRising", &fRWMHalfRising, "fRWMHalfRising/D"); + fANNIETree->Branch("RWMFHWM", &fRWMFHWM, "fRWMFHWM/D"); + fANNIETree->Branch("RWMFirstPeak", &fRWMFirstPeak, "fRWMFirstPeak/D"); + + fANNIETree->Branch("BRFFirstPeak", &fBRFFirstPeak, "fBRFFirstPeak/D"); + fANNIETree->Branch("BRFAveragePeak", &fBRFAveragePeak, "fBRFAveragePeak/D"); + fANNIETree->Branch("BRFFirstPeakFit", &fBRFFirstPeakFit, "fBRFFirstPeakFit/D"); + } + + //********************************************************// + + // Tank cluster information + + fANNIETree->Branch("numberOfClusters", &fNumberOfClusters, "fNumberOfClusters/I"); + fANNIETree->Branch("clusterTime", &fClusterTimeV); + fANNIETree->Branch("clusterCharge", &fClusterChargeV); + fANNIETree->Branch("clusterPE", &fClusterPEV); + fANNIETree->Branch("clusterMaxPE", &fClusterMaxPEV); + fANNIETree->Branch("clusterChargePointX", &fClusterChargePointXV); + fANNIETree->Branch("clusterChargePointY", &fClusterChargePointYV); + fANNIETree->Branch("clusterChargePointZ", &fClusterChargePointZV); + fANNIETree->Branch("clusterChargeBalance", &fClusterChargeBalanceV); + fANNIETree->Branch("clusterHits", &fClusterHits); + fANNIETree->Branch("Cluster_HitX", &fCluster_HitX); + fANNIETree->Branch("Cluster_HitY", &fCluster_HitY); + fANNIETree->Branch("Cluster_HitZ", &fCluster_HitZ); + fANNIETree->Branch("Cluster_HitT", &fCluster_HitT); + fANNIETree->Branch("Cluster_HitQ", &fCluster_HitQ); + fANNIETree->Branch("Cluster_HitPE", &fCluster_HitPE); + fANNIETree->Branch("Cluster_HitType", &fCluster_HitType); + fANNIETree->Branch("Cluster_HitDetID", &fCluster_HitDetID); + fANNIETree->Branch("Cluster_HitChankey", &fCluster_HitChankey); + fANNIETree->Branch("Cluster_HitChankeyMC", &fCluster_HitChankeyMC); + + // MRD cluster information + fANNIETree->Branch("eventTimeMRD", &fEventTimeMRD_Tree); + fANNIETree->Branch("MRDClusterNumber", &fMRDClusterNumber); + fANNIETree->Branch("MRDClusterTime", &fMRDClusterTime); + fANNIETree->Branch("MRDClusterTimeSigma", &fMRDClusterTimeSigma); + fANNIETree->Branch("MRDClusterHitNumber", &fMRDClusterHitNumber); + + if (TankHitInfo_fill) + { + // Tank Hit information + fANNIETree->Branch("nhits", &fNHits, "nhits/I"); + fANNIETree->Branch("filter", &fIsFiltered); + fANNIETree->Branch("hitX", &fHitX); + fANNIETree->Branch("hitY", &fHitY); + fANNIETree->Branch("hitZ", &fHitZ); + fANNIETree->Branch("hitT", &fHitT); + fANNIETree->Branch("hitQ", &fHitQ); + fANNIETree->Branch("hitPE", &fHitPE); + fANNIETree->Branch("hitType", &fHitType); + fANNIETree->Branch("hitDetID", &fHitDetID); + fANNIETree->Branch("hitChankey", &fHitChankey); + fANNIETree->Branch("hitChankeyMC", &fHitChankeyMC); + } + + if (SiPMPulseInfo_fill) + { + fANNIETree->Branch("SiPMhitQ", &fSiPMHitQ); + fANNIETree->Branch("SiPMhitT", &fSiPMHitT); + fANNIETree->Branch("SiPMhitAmplitude", &fSiPMHitAmplitude); + fANNIETree->Branch("SiPMNum", &fSiPMNum); + fANNIETree->Branch("SiPM1NPulses", &fSiPM1NPulses, "SiPM1NPulses/I"); + fANNIETree->Branch("SiPM2NPulses", &fSiPM2NPulses, "SiPM2NPulses/I"); + } + + if (LAPPDData_fill) + { + fANNIETree->Branch("LAPPD_ID", &fLAPPD_ID); + fANNIETree->Branch("fLAPPD_Count", &fLAPPD_Count); + fANNIETree->Branch("LAPPD_Beamgate_ns", &fLAPPD_Beamgate_ns); + fANNIETree->Branch("LAPPD_Timestamp_ns", &fLAPPD_Timestamp_ns); + fANNIETree->Branch("LAPPD_Beamgate_Raw", &fLAPPD_Beamgate_Raw); + fANNIETree->Branch("LAPPD_Timestamp_Raw", &fLAPPD_Timestamp_Raw); + fANNIETree->Branch("LAPPD_Offset", &fLAPPD_Offset); + fANNIETree->Branch("LAPPD_TSCorrection", &fLAPPD_TSCorrection); + fANNIETree->Branch("LAPPD_BGCorrection", &fLAPPD_BGCorrection); + fANNIETree->Branch("LAPPD_OSInMinusPS", &fLAPPD_OSInMinusPS); + if (LAPPD_PPS_fill) + { + fANNIETree->Branch("LAPPD_BGPPSBefore", &fLAPPD_BGPPSBefore); + fANNIETree->Branch("LAPPD_BGPPSAfter", &fLAPPD_BGPPSAfter); + fANNIETree->Branch("LAPPD_BGPPSDiff", &fLAPPD_BGPPSDiff); + fANNIETree->Branch("LAPPD_BGPPSMissing", &fLAPPD_BGPPSMissing); + fANNIETree->Branch("LAPPD_TSPPSBefore", &fLAPPD_TSPPSBefore); + fANNIETree->Branch("LAPPD_TSPPSAfter", &fLAPPD_TSPPSAfter); + fANNIETree->Branch("LAPPD_TSPPSDiff", &fLAPPD_TSPPSDiff); + fANNIETree->Branch("LAPPD_TSPPSMissing", &fLAPPD_TSPPSMissing); + } + fANNIETree->Branch("LAPPD_BG_switchBit0", &fLAPPD_BG_switchBit0); + fANNIETree->Branch("LAPPD_BG_switchBit1", &fLAPPD_BG_switchBit1); + } + + // LAPPD reconstruction information + if (LAPPDReco_fill) + { + // fANNIETree->Branch("LAPPDPulseTimeStampUL", &fLAPPDPulseTimeStampUL, "LAPPDPulseTimeStampUL/l"); + // fANNIETree->Branch("LAPPDPulseBeamgateUL", &fLAPPDPulseBeamgateUL, "LAPPDPulseBeamgateUL/l"); + // actually we don't need these two for pulse and hit, because it is impossible to have multiple events from one LAPPD in one ANNIEEvent due to the dead time and the trigger scheme + // LAPPD ID is enough to find the corresponding unix timestamp + // but leave them there in case + + fANNIETree->Branch("LAPPD_PulseIDs", &fLAPPD_IDs); + fANNIETree->Branch("LAPPD_ChannelID", &fChannelID); + fANNIETree->Branch("LAPPD_PeakTime", &fPulsePeakTime); + fANNIETree->Branch("LAPPD_PulseHalfHeightTime", &fPulseHalfHeightTime); + fANNIETree->Branch("LAPPD_PeakAmp", &fPulsePeakAmp); + fANNIETree->Branch("LAPPD_Charge", &fPulseCharge); + fANNIETree->Branch("LAPPD_PulseStart", &fPulseStart); + fANNIETree->Branch("LAPPD_PulseEnd", &fPulseEnd); + fANNIETree->Branch("LAPPD_PulseWidth", &fPulseWidth); + fANNIETree->Branch("LAPPD_PulseSide", &fPulseSide); + fANNIETree->Branch("LAPPD_PulseStripNum", &fPulseStripNum); + + // fANNIETree->Branch("LAPPDHitTimeStampUL", &fLAPPDHitTimeStampUL, "LAPPDHitTimeStampUL/l"); + // fANNIETree->Branch("LAPPDHitBeamgateUL", &fLAPPDHitBeamgateUL, "LAPPDHitBeamgateUL/l"); + + fANNIETree->Branch("LAPPDID_Hit", &fLAPPDHit_IDs); + fANNIETree->Branch("LAPPDHitChannel", &fLAPPDHitChannel); + fANNIETree->Branch("LAPPDHitStrip", &fLAPPDHitStrip); + fANNIETree->Branch("LAPPDHitTime", &fLAPPDHitTime); + fANNIETree->Branch("LAPPDHitAmp", &fLAPPDHitAmp); + fANNIETree->Branch("LAPPDHitParallelPos", &fLAPPDHitParallelPos); + fANNIETree->Branch("LAPPDHitTransversePos", &fLAPPDHitTransversePos); + fANNIETree->Branch("LAPPDHitP1StartTime", &fLAPPDHitP1StartTime); + fANNIETree->Branch("LAPPDHitP2StartTime", &fLAPPDHitP2StartTime); + fANNIETree->Branch("LAPPDHitP1EndTime", &fLAPPDHitP1EndTime); + fANNIETree->Branch("LAPPDHitP2EndTime", &fLAPPDHitP2EndTime); + + fANNIETree->Branch("LAPPDHitP1PeakTime", &fLAPPDHitP1PeakTime); + fANNIETree->Branch("LAPPDHitP2PeakTime", &fLAPPDHitP2PeakTime); + fANNIETree->Branch("LAPPDHitP1PeakAmp", &fLAPPDHitP1PeakAmp); + fANNIETree->Branch("LAPPDHitP2PeakAmp", &fLAPPDHitP2PeakAmp); + fANNIETree->Branch("LAPPDHitP1HalfHeightTime", &fLAPPDHitP1HalfHeightTime); + fANNIETree->Branch("LAPPDHitP2HalfHeightTime", &fLAPPDHitP2HalfHeightTime); + fANNIETree->Branch("LAPPDHitP1HalfEndTime", &fLAPPDHitP1HalfEndTime); + fANNIETree->Branch("LAPPDHitP2HalfEndTime", &fLAPPDHitP2HalfEndTime); + fANNIETree->Branch("LAPPDHitP1Charge", &fLAPPDHitP1Charge); + fANNIETree->Branch("LAPPDHitP2Charge", &fLAPPDHitP2Charge); + + /* + fANNIETree->Branch("LAPPDWaveformChankey", &LAPPDWaveformChankey, "LAPPDWaveformChankey/I"); + fANNIETree->Branch("WaveformMax", &waveformMaxValue, "WaveformMax/D"); + fANNIETree->Branch("WaveformRMS", &waveformRMSValue, "WaveformRMS/D"); + fANNIETree->Branch("WaveformMaxTimeBin", &waveformMaxTimeBinValue, "WaveformMaxTimeBin/I"); + fANNIETree->Branch("waveformMaxFoundNear", &waveformMaxFoundNear, "waveformMaxFoundNear/O"); // O is boolean + fANNIETree->Branch("WaveformMaxNearing", &waveformMaxNearingValue, "WaveformMaxNearing/D"); + */ + } + + if (MRDHitInfo_fill) + { + fANNIETree->Branch("MRDHitClusterIndex", &fMRDHitClusterIndex); + fANNIETree->Branch("MRDhitT", &fMRDHitT); + fANNIETree->Branch("MRDHitCharge", &fMRDHitCharge); + fANNIETree->Branch("MRDHitDigitPMT", &fMRDHitDigitPMT); + + fANNIETree->Branch("MRDhitDetID", &fMRDHitDetID); + fANNIETree->Branch("MRDhitChankey", &fMRDHitChankey); + fANNIETree->Branch("MRDhitChankeyMC", &fMRDHitChankeyMC); + fANNIETree->Branch("FMVhitT", &fFMVHitT); + fANNIETree->Branch("FMVhitDetID", &fFMVHitDetID); + fANNIETree->Branch("FMVhitChankey", &fFMVHitChankey); + fANNIETree->Branch("FMVhitChankeyMC", &fFMVHitChankeyMC); + fANNIETree->Branch("vetoHit", &fVetoHit, "vetoHit/I"); + } + + if (MRDReco_fill) + { + fANNIETree->Branch("MRDClusterIndex", &fMRDClusterIndex); + fANNIETree->Branch("NumClusterTracks", &fNumClusterTracks); + fANNIETree->Branch("MRDTrackAngle", &fMRDTrackAngle); + fANNIETree->Branch("MRDTrackAngleError", &fMRDTrackAngleError); + fANNIETree->Branch("MRDPenetrationDepth", &fMRDPenetrationDepth); + fANNIETree->Branch("MRDTrackLength", &fMRDTrackLength); + fANNIETree->Branch("MRDEntryPointRadius", &fMRDEntryPointRadius); + fANNIETree->Branch("MRDEnergyLoss", &fMRDEnergyLoss); + fANNIETree->Branch("MRDEnergyLossError", &fMRDEnergyLossError); + fANNIETree->Branch("MRDTrackStartX", &fMRDTrackStartX); + fANNIETree->Branch("MRDTrackStartY", &fMRDTrackStartY); + fANNIETree->Branch("MRDTrackStartZ", &fMRDTrackStartZ); + fANNIETree->Branch("MRDTrackStopX", &fMRDTrackStopX); + fANNIETree->Branch("MRDTrackStopY", &fMRDTrackStopY); + fANNIETree->Branch("MRDTrackStopZ", &fMRDTrackStopZ); + fANNIETree->Branch("MRDSide", &fMRDSide); + fANNIETree->Branch("MRDStop", &fMRDStop); + fANNIETree->Branch("MRDThrough", &fMRDThrough); + } + + fANNIETree->Branch("eventStatusApplied", &fEventStatusApplied, "eventStatusApplied/I"); + fANNIETree->Branch("eventStatusFlagged", &fEventStatusFlagged, "eventStatusFlagged/I"); + + // MC truth information for muons + // Output to tree when MCTruth_fill = 1 in config + if (MCTruth_fill) + { + fTrueNeutCapVtxX = new std::vector; + fTrueNeutCapVtxY = new std::vector; + fTrueNeutCapVtxZ = new std::vector; + fTrueNeutCapNucleus = new std::vector; + fTrueNeutCapTime = new std::vector; + fTrueNeutCapGammas = new std::vector; + fTrueNeutCapE = new std::vector; + fTrueNeutCapGammaE = new std::vector; + fTruePrimaryPdgs = new std::vector; + fANNIETree->Branch("triggerNumber", &fiMCTriggerNum, "triggerNumber/I"); + fANNIETree->Branch("mcEntryNumber", &fMCEventNum, "mcEntryNumber/I"); + fANNIETree->Branch("trueVtxX", &fTrueVtxX, "trueVtxX/D"); + fANNIETree->Branch("trueVtxY", &fTrueVtxY, "trueVtxY/D"); + fANNIETree->Branch("trueVtxZ", &fTrueVtxZ, "trueVtxZ/D"); + fANNIETree->Branch("trueVtxTime", &fTrueVtxTime, "trueVtxTime/D"); + fANNIETree->Branch("trueDirX", &fTrueDirX, "trueDirX/D"); + fANNIETree->Branch("trueDirY", &fTrueDirY, "trueDirY/D"); + fANNIETree->Branch("trueDirZ", &fTrueDirZ, "trueDirZ/D"); + fANNIETree->Branch("trueAngle", &fTrueAngle, "trueAngle/D"); + fANNIETree->Branch("truePhi", &fTruePhi, "truePhi/D"); + fANNIETree->Branch("trueMuonEnergy", &fTrueMuonEnergy, "trueMuonEnergy/D"); + fANNIETree->Branch("truePrimaryPdg", &fTruePrimaryPdg, "truePrimaryPdg/I"); + fANNIETree->Branch("trueTrackLengthInWater", &fTrueTrackLengthInWater, "trueTrackLengthInWater/D"); + fANNIETree->Branch("trueTrackLengthInMRD", &fTrueTrackLengthInMRD, "trueTrackLengthInMRD/D"); + fANNIETree->Branch("trueMultiRing", &fTrueMultiRing, "trueMultiRing/I"); + fANNIETree->Branch("Pi0Count", &fPi0Count, "Pi0Count/I"); + fANNIETree->Branch("PiPlusCount", &fPiPlusCount, "PiPlusCount/I"); + fANNIETree->Branch("PiMinusCount", &fPiMinusCount, "PiMinusCount/I"); + fANNIETree->Branch("K0Count", &fK0Count, "K0Count/I"); + fANNIETree->Branch("KPlusCount", &fKPlusCount, "KPlusCount/I"); + fANNIETree->Branch("KMinusCount", &fKMinusCount, "KMinusCount/I"); + fANNIETree->Branch("truePrimaryPdgs", &fTruePrimaryPdgs); + fANNIETree->Branch("trueNeutCapVtxX", &fTrueNeutCapVtxX); + fANNIETree->Branch("trueNeutCapVtxY", &fTrueNeutCapVtxY); + fANNIETree->Branch("trueNeutCapVtxZ", &fTrueNeutCapVtxZ); + fANNIETree->Branch("trueNeutCapNucleus", &fTrueNeutCapNucleus); + fANNIETree->Branch("trueNeutCapTime", &fTrueNeutCapTime); + fANNIETree->Branch("trueNeutCapGammas", &fTrueNeutCapGammas); + fANNIETree->Branch("trueNeutCapE", &fTrueNeutCapE); + fANNIETree->Branch("trueNeutCapGammaE", &fTrueNeutCapGammaE); + fANNIETree->Branch("trueNeutrinoEnergy", &fTrueNeutrinoEnergy, "trueNeutrinoEnergy/D"); + fANNIETree->Branch("trueNeutrinoMomentum_X", &fTrueNeutrinoMomentum_X, "trueNeutrinoMomentum_X/D"); + fANNIETree->Branch("trueNeutrinoMomentum_Y", &fTrueNeutrinoMomentum_Y, "trueNeutrinoMomentum_Y/D"); + fANNIETree->Branch("trueNeutrinoMomentum_Z", &fTrueNeutrinoMomentum_Z, "trueNeutrinoMomentum_Z/D"); + fANNIETree->Branch("trueNuIntxVtx_X", &fTrueNuIntxVtx_X, "trueNuIntxVtx_X/D"); + fANNIETree->Branch("trueNuIntxVtx_Y", &fTrueNuIntxVtx_Y, "trueNuIntxVtx_Y/D"); + fANNIETree->Branch("trueNuIntxVtx_Z", &fTrueNuIntxVtx_Z, "trueNuIntxVtx_Z/D"); + fANNIETree->Branch("trueNuIntxVtx_T", &fTrueNuIntxVtx_T, "trueNuIntxVtx_T/D"); + fANNIETree->Branch("trueFSLVtx_X", &fTrueFSLVtx_X, "trueFSLVtx_X/D"); + fANNIETree->Branch("trueFSLVtx_Y", &fTrueFSLVtx_Y, "trueFSLVtx_Y/D"); + fANNIETree->Branch("trueFSLVtx_Z", &fTrueFSLVtx_Z, "trueFSLVtx_Z/D"); + fANNIETree->Branch("trueFSLMomentum_X", &fTrueFSLMomentum_X, "trueFSLMomentum_X/D"); + fANNIETree->Branch("trueFSLMomentum_Y", &fTrueFSLMomentum_Y, "trueFSLMomentum_Y/D"); + fANNIETree->Branch("trueFSLMomentum_Z", &fTrueFSLMomentum_Z, "trueFSLMomentum_Z/D"); + fANNIETree->Branch("trueFSLTime", &fTrueFSLTime, "trueFSLTime/D"); + fANNIETree->Branch("trueFSLMass", &fTrueFSLMass, "trueFSLMass/D"); + fANNIETree->Branch("trueFSLPdg", &fTrueFSLPdg, "trueFSLPdg/I"); + fANNIETree->Branch("trueFSLEnergy", &fTrueFSLEnergy, "trueFSLEnergy/D"); + fANNIETree->Branch("trueQ2", &fTrueQ2, "trueQ2/D"); + fANNIETree->Branch("trueCC", &fTrueCC, "trueCC/I"); + fANNIETree->Branch("trueNC", &fTrueNC, "trueNC/I"); + fANNIETree->Branch("trueQEL", &fTrueQEL, "trueQEL/I"); + fANNIETree->Branch("trueRES", &fTrueRES, "trueRES/I"); + fANNIETree->Branch("trueDIS", &fTrueDIS, "trueDIS/I"); + fANNIETree->Branch("trueCOH", &fTrueCOH, "trueCOH/I"); + fANNIETree->Branch("trueMEC", &fTrueMEC, "trueMEC/I"); + fANNIETree->Branch("trueNeutrons", &fTrueNeutrons, "trueNeutrons/I"); + fANNIETree->Branch("trueProtons", &fTrueProtons, "trueProtons/I"); + fANNIETree->Branch("truePi0", &fTruePi0, "truePi0/I"); + fANNIETree->Branch("truePiPlus", &fTruePiPlus, "truePiPlus/I"); + fANNIETree->Branch("truePiPlusCher", &fTruePiPlusCher, "truePiPlusCher/I"); + fANNIETree->Branch("truePiMinus", &fTruePiMinus, "truePiMinus/I"); + fANNIETree->Branch("truePiMinusCher", &fTruePiMinusCher, "truePiMinusCher/I"); + fANNIETree->Branch("trueKPlus", &fTrueKPlus, "trueKPlus/I"); + fANNIETree->Branch("trueKPlusCher", &fTrueKPlusCher, "trueKPlusCher/I"); + fANNIETree->Branch("trueKMinus", &fTrueKMinus, "trueKMinus/I"); + fANNIETree->Branch("trueKMinusCher", &fTrueKMinusCher, "trueKMinusCher/I"); + } + + // Reconstructed variables after full Muon Reco Analysis + if (TankReco_fill) + { + fANNIETree->Branch("recoVtxX", &fRecoVtxX, "recoVtxX/D"); + fANNIETree->Branch("recoVtxY", &fRecoVtxY, "recoVtxY/D"); + fANNIETree->Branch("recoVtxZ", &fRecoVtxZ, "recoVtxZ/D"); + fANNIETree->Branch("recoVtxTime", &fRecoVtxTime, "recoVtxTime/D"); + fANNIETree->Branch("recoDirX", &fRecoDirX, "recoDirX/D"); + fANNIETree->Branch("recoDirY", &fRecoDirY, "recoDirY/D"); + fANNIETree->Branch("recoDirZ", &fRecoDirZ, "recoDirZ/D"); + fANNIETree->Branch("recoAngle", &fRecoAngle, "recoAngle/D"); + fANNIETree->Branch("recoPhi", &fRecoPhi, "recoPhi/D"); + fANNIETree->Branch("recoVtxFOM", &fRecoVtxFOM, "recoVtxFOM/D"); + fANNIETree->Branch("recoStatus", &fRecoStatus, "recoStatus/I"); + } + + // Reconstructed variables from each step in Muon Reco Analysis + // Currently output when RecoDebug_fill = 1 in config + if (RecoDebug_fill) + { + fANNIETree->Branch("seedVtxX", &fSeedVtxX); + fANNIETree->Branch("seedVtxY", &fSeedVtxY); + fANNIETree->Branch("seedVtxZ", &fSeedVtxZ); + fANNIETree->Branch("seedVtxFOM", &fSeedVtxFOM); + fANNIETree->Branch("seedVtxTime", &fSeedVtxTime, "seedVtxTime/D"); + + fANNIETree->Branch("pointPosX", &fPointPosX, "pointPosX/D"); + fANNIETree->Branch("pointPosY", &fPointPosY, "pointPosY/D"); + fANNIETree->Branch("pointPosZ", &fPointPosZ, "pointPosZ/D"); + fANNIETree->Branch("pointPosTime", &fPointPosTime, "pointPosTime/D"); + fANNIETree->Branch("pointPosFOM", &fPointPosFOM, "pointPosFOM/D"); + fANNIETree->Branch("pointPosStatus", &fPointPosStatus, "pointPosStatus/I"); + + fANNIETree->Branch("pointDirX", &fPointDirX, "pointDirX/D"); + fANNIETree->Branch("pointDirY", &fPointDirY, "pointDirY/D"); + fANNIETree->Branch("pointDirZ", &fPointDirZ, "pointDirZ/D"); + fANNIETree->Branch("pointDirTime", &fPointDirTime, "pointDirTime/D"); + fANNIETree->Branch("pointDirStatus", &fPointDirStatus, "pointDirStatus/I"); + fANNIETree->Branch("pointDirFOM", &fPointDirFOM, "pointDirFOM/D"); + + fANNIETree->Branch("pointVtxPosX", &fPointVtxPosX, "pointVtxPosX/D"); + fANNIETree->Branch("pointVtxPosY", &fPointVtxPosY, "pointVtxPosY/D"); + fANNIETree->Branch("pointVtxPosZ", &fPointVtxPosZ, "pointVtxPosZ/D"); + fANNIETree->Branch("pointVtxTime", &fPointVtxTime, "pointVtxTime/D"); + fANNIETree->Branch("pointVtxDirX", &fPointVtxDirX, "pointVtxDirX/D"); + fANNIETree->Branch("pointVtxDirY", &fPointVtxDirY, "pointVtxDirY/D"); + fANNIETree->Branch("pointVtxDirZ", &fPointVtxDirZ, "pointVtxDirZ/D"); + fANNIETree->Branch("pointVtxFOM", &fPointVtxFOM, "pointVtxFOM/D"); + fANNIETree->Branch("pointVtxStatus", &fPointVtxStatus, "pointVtxStatus/I"); + } + + // Difference in MC Truth and Muon Reconstruction Analysis + // Output to tree when muonTruthRecoDiff_fill = 1 in config + if (muonTruthRecoDiff_fill) + { + fANNIETree->Branch("deltaVtxX", &fDeltaVtxX, "deltaVtxX/D"); + fANNIETree->Branch("deltaVtxY", &fDeltaVtxY, "deltaVtxY/D"); + fANNIETree->Branch("deltaVtxZ", &fDeltaVtxZ, "deltaVtxZ/D"); + fANNIETree->Branch("deltaVtxR", &fDeltaVtxR, "deltaVtxR/D"); + fANNIETree->Branch("deltaVtxT", &fDeltaVtxT, "deltaVtxT/D"); + fANNIETree->Branch("deltaParallel", &fDeltaParallel, "deltaParallel/D"); + fANNIETree->Branch("deltaPerpendicular", &fDeltaPerpendicular, "deltaPerpendicular/D"); + fANNIETree->Branch("deltaAzimuth", &fDeltaAzimuth, "deltaAzimuth/D"); + fANNIETree->Branch("deltaZenith", &fDeltaZenith, "deltaZenith/D"); + fANNIETree->Branch("deltaAngle", &fDeltaAngle, "deltaAngle/D"); + } + + return true; +} + +bool ANNIEEventTreeMaker::Execute() +{ + //****************************** Reset Variables *************************************// + ResetVariables(); + + //****************************** fillCleanEventsOnly *************************************// + // If only clean events are built, return true for dirty events + auto get_flagsapp = m_data->Stores.at("RecoEvent")->Get("EventFlagApplied", fEventStatusApplied); + auto get_flags = m_data->Stores.at("RecoEvent")->Get("EventFlagged", fEventStatusFlagged); + + if (fillCleanEventsOnly) + { + // auto get_cutstatus = m_data->Stores.at("RecoEvent")->Get("EventCutStatus",fEventCutStatus); + if (!get_flagsapp || !get_flags) + { + Log("PhaseITreeMaker tool: No Event status applied or flagged bitmask!!", v_error, ANNIEEventTreeMakerVerbosity); + return false; + } + // check if event passes the cut + if ((fEventStatusFlagged) != 0) + { + // if (!fEventCutStatus){ + Log("ANNIEEventTreeMaker Tool: Event was flagged with one of the active cuts.", v_debug, ANNIEEventTreeMakerVerbosity); + return true; + } + } + // done + + //****************************** Fill Event Info *************************************// + bool keepLoading = LoadEventInfo(); + if (!keepLoading) + return false; + LoadBeamInfo(); + // done + + //****************************** Fill RWM BRF Info *************************************// + if (RWMBRF_fill) + { + LoadRWMBRFInfo(); + } + + //****************************** Fill Hit Info *************************************// + if (TankHitInfo_fill) + { + // this will fill all hits in this event + LoadAllTankHits(); + } + if (SiPMPulseInfo_fill) + { + LoadSiPMHits(); + } + // done + //****************************** Fill Cluster Info *************************************// + if (TankCluster_fill) + { + LoadClusterInfo(); + } + + //****************************** Fill LAPPD Info *************************************// + if (LAPPDData_fill) + { + LoadLAPPDInfo(); + } + + //****************************** Fill MRD Info *************************************// + if (MRDHitInfo_fill) + { + LoadMRDCluster(); + } + + //****************************** Fill Reco Info *************************************// + bool got_reco = false; + if (TankReco_fill) + { + got_reco = FillTankRecoInfo(); + } + + if (RecoDebug_fill) + FillRecoDebugInfo(); + + //****************************** Fill MCTruth Info *************************************// + bool gotmctruth = false; + if (MCTruth_fill) + { + gotmctruth = FillMCTruthInfo(); // todo + } + if (muonTruthRecoDiff_fill) + this->FillTruthRecoDiffInfo(gotmctruth, got_reco); + + //****************************** Fill Reco Summary *************************************// + if (got_reco && gotmctruth && (ANNIEEventTreeMakerVerbosity > 4)) + { + RecoSummary(); + } + + //****************************** Fill Tree *************************************// + fANNIETree->Fill(); + + processedEvents++; + return true; +} + +bool ANNIEEventTreeMaker::Finalise() +{ + Log("ANNIEEventTreeMaker Tool: Got " + std::to_string(processedEvents) + " events", 0, ANNIEEventTreeMakerVerbosity); + fOutput_tfile->cd(); + fANNIETree->Write(); + fOutput_tfile->Close(); + Log("ANNIEEventTreeMaker Tool: Tree written to file", 0, ANNIEEventTreeMakerVerbosity); + + return true; +} + +void ANNIEEventTreeMaker::ResetVariables() +{ + // Reset all variables + + // Event Info + fRunNumber = 0; + fSubrunNumber = 0; + fPartFileNumber = 0; + fEventNumber = 0; + fPrimaryTriggerWord = 0; + fPrimaryTriggerTime = 0; + fTriggerword = 0; + fExtended = 0; + fTankMRDCoinc = 0; + fNoVeto = 0; + fHasTank = 0; + fHasMRD = 0; + fHasLAPPD = 0; + fGroupedTriggerTime.clear(); + fGroupedTriggerWord.clear(); + fDataStreams.clear(); + fEventTimeTank = 0; + fEventTimeMRD = 0; + + // beam info + fPot = -9999; + fBeamok = 0; + beam_E_TOR860 = -9999; + beam_E_TOR875 = -9999; + beam_THCURR = -9999; + beam_BTJT2 = -9999; + beam_HP875 = -9999; + beam_VP875 = -9999; + beam_HPTG1 = -9999; + beam_VPTG1 = -9999; + beam_HPTG2 = -9999; + beam_VPTG2 = -9999; + beam_BTH2T2 = -9999; + fBeamInfoTime = 0; + fBeamInfoTimeToTriggerDiff = -9999; + + // RWM BRF info + fRWMRisingStart = -9999; + fRWMRisingEnd = -9999; + fRWMHalfRising = -9999; + fRWMFHWM = -9999; + fRWMFirstPeak = -9999; + fBRFFirstPeak = -9999; + fBRFAveragePeak = -9999; + fBRFFirstPeakFit = -9999; + + // TankHitInfo + fNHits = 0; + fIsFiltered.clear(); + fHitX.clear(); + fHitY.clear(); + fHitZ.clear(); + fHitT.clear(); + fHitQ.clear(); + fHitPE.clear(); + fHitType.clear(); + fHitDetID.clear(); + fHitChankey.clear(); + fHitChankeyMC.clear(); + + // SiPMPulse Info + fSiPM1NPulses = 0; + fSiPM2NPulses = 0; + fSiPMHitQ.clear(); + fSiPMHitT.clear(); + fSiPMHitAmplitude.clear(); + fSiPMNum.clear(); + + // LAPPDData_fill + fLAPPD_Count = 0; + fLAPPD_ID.clear(); + fLAPPD_Beamgate_ns.clear(); + fLAPPD_Timestamp_ns.clear(); + fLAPPD_Beamgate_Raw.clear(); + fLAPPD_Timestamp_Raw.clear(); + fLAPPD_Offset.clear(); + fLAPPD_TSCorrection.clear(); + fLAPPD_BGCorrection.clear(); + fLAPPD_OSInMinusPS.clear(); + fLAPPD_BG_switchBit0.clear(); + fLAPPD_BG_switchBit1.clear(); + // LAPPD_PPS_fill + fLAPPD_BGPPSBefore.clear(); + fLAPPD_BGPPSAfter.clear(); + fLAPPD_BGPPSDiff.clear(); + fLAPPD_BGPPSMissing.clear(); + fLAPPD_TSPPSBefore.clear(); + fLAPPD_TSPPSAfter.clear(); + fLAPPD_TSPPSDiff.clear(); + fLAPPD_TSPPSMissing.clear(); + + // LAPPD Reco Fill + fLAPPDPulseTimeStampUL.clear(); + fLAPPDPulseBeamgateUL.clear(); + fLAPPD_IDs.clear(); + fChannelID.clear(); + fPulsePeakTime.clear(); + fPulseHalfHeightTime.clear(); + fPulseCharge.clear(); + fPulsePeakAmp.clear(); + fPulseStart.clear(); + fPulseEnd.clear(); + fPulseWidth.clear(); + fPulseSide.clear(); + fPulseStripNum.clear(); + fChannelBaseline.clear(); + + fLAPPDHitTimeStampUL.clear(); + fLAPPDHitBeamgateUL.clear(); + fLAPPDHit_IDs.clear(); + fLAPPDHitChannel.clear(); + fLAPPDHitStrip.clear(); + fLAPPDHitTime.clear(); + fLAPPDHitAmp.clear(); + fLAPPDHitParallelPos.clear(); + fLAPPDHitTransversePos.clear(); + fLAPPDHitP1StartTime.clear(); + fLAPPDHitP2StartTime.clear(); + fLAPPDHitP1EndTime.clear(); + fLAPPDHitP2EndTime.clear(); + fLAPPDHitP1PeakTime.clear(); + fLAPPDHitP2PeakTime.clear(); + fLAPPDHitP1PeakAmp.clear(); + fLAPPDHitP2PeakAmp.clear(); + fLAPPDHitP1HalfHeightTime.clear(); + fLAPPDHitP2HalfHeightTime.clear(); + fLAPPDHitP1HalfEndTime.clear(); + fLAPPDHitP2HalfEndTime.clear(); + fLAPPDHitP1Charge.clear(); + fLAPPDHitP2Charge.clear(); + + LAPPDWaveformChankey.clear(); + waveformMaxValue.clear(); + waveformRMSValue.clear(); + waveformMaxFoundNear.clear(); + waveformMaxNearingValue.clear(); + waveformMaxTimeBinValue.clear(); + + // tank cluster information + fNumberOfClusters = 0; + + fClusterHits.clear(); + fClusterChargeV.clear(); + fClusterTimeV.clear(); + fClusterPEV.clear(); + + fCluster_HitX.clear(); + fCluster_HitY.clear(); + fCluster_HitZ.clear(); + fCluster_HitT.clear(); + fCluster_HitQ.clear(); + fCluster_HitPE.clear(); + fCluster_HitType.clear(); + fCluster_HitDetID.clear(); + fCluster_HitChankey.clear(); + fCluster_HitChankeyMC.clear(); + + fClusterMaxPEV.clear(); + fClusterChargePointXV.clear(); + fClusterChargePointYV.clear(); + fClusterChargePointZV.clear(); + fClusterChargeBalanceV.clear(); + + // MRD cluster information + fEventTimeMRD_Tree = 0; + fMRDClusterNumber = 0; + fMRDClusterHitNumber.clear(); + fMRDClusterTime.clear(); + fMRDClusterTimeSigma.clear(); + + fVetoHit = 0; + fMRDHitClusterIndex.clear(); + fMRDHitT.clear(); + fMRDHitCharge.clear(); + fMRDHitDigitPMT.clear(); + fMRDHitDetID.clear(); + fMRDHitChankey.clear(); + fMRDHitChankeyMC.clear(); + fFMVHitT.clear(); + fFMVHitDetID.clear(); + fFMVHitChankey.clear(); + fFMVHitChankeyMC.clear(); + + fNumMRDClusterTracks = 0; + fMRDTrackAngle.clear(); + fMRDTrackAngleError.clear(); + fMRDPenetrationDepth.clear(); + fMRDTrackLength.clear(); + fMRDEntryPointRadius.clear(); + fMRDEnergyLoss.clear(); + fMRDEnergyLossError.clear(); + fMRDTrackStartX.clear(); + fMRDTrackStartY.clear(); + fMRDTrackStartZ.clear(); + fMRDTrackStopX.clear(); + fMRDTrackStopY.clear(); + fMRDTrackStopZ.clear(); + fMRDSide.clear(); + fMRDStop.clear(); + fMRDThrough.clear(); + fMRDClusterIndex.clear(); + fNumClusterTracks.clear(); + + // fillCleanEventsOnly + fEventStatusApplied = 0; + fEventStatusFlagged = 0; + + // MCTruth_fill + if (MCTruth_fill) + { + fMCEventNum = 0; + fMCTriggerNum = 0; + fiMCTriggerNum = -9999; + + fTrueVtxX = -9999; + fTrueVtxY = -9999; + fTrueVtxZ = -9999; + fTrueVtxTime = -9999; + fTrueDirX = -9999; + fTrueDirY = -9999; + fTrueDirZ = -9999; + fTrueAngle = -9999; + fTruePhi = -9999; + fTrueMuonEnergy = -9999; + fTruePrimaryPdg = -9999; + fTrueTrackLengthInWater = -9999; + fTrueTrackLengthInMRD = -9999; + fTruePrimaryPdgs->clear(); + fTrueNeutCapVtxX->clear(); + fTrueNeutCapVtxY->clear(); + fTrueNeutCapVtxZ->clear(); + fTrueNeutCapNucleus->clear(); + fTrueNeutCapTime->clear(); + fTrueNeutCapGammas->clear(); + fTrueNeutCapE->clear(); + fTrueNeutCapGammaE->clear(); + fTrueMultiRing = -9999; + } + + // Genie information for event + fTrueNeutrinoEnergy = -9999; + fTrueNeutrinoMomentum_X = -9999; + fTrueNeutrinoMomentum_Y = -9999; + fTrueNeutrinoMomentum_Z = -9999; + fTrueNuIntxVtx_X = -9999; + fTrueNuIntxVtx_Y = -9999; + fTrueNuIntxVtx_Z = -9999; + fTrueNuIntxVtx_T = -9999; + fTrueFSLVtx_X = -9999; + fTrueFSLVtx_Y = -9999; + fTrueFSLVtx_Z = -9999; + fTrueFSLMomentum_X = -9999; + fTrueFSLMomentum_Y = -9999; + fTrueFSLMomentum_Z = -9999; + fTrueFSLTime = -9999; + fTrueFSLMass = -9999; + fTrueFSLPdg = -9999; + fTrueFSLEnergy = -9999; + fTrueQ2 = -9999; + fTrueCC = -9999; + fTrueNC = -9999; + fTrueQEL = -9999; + fTrueRES = -9999; + fTrueDIS = -9999; + fTrueCOH = -9999; + fTrueMEC = -9999; + fTrueNeutrons = -9999; + fTrueProtons = -9999; + fTruePi0 = -9999; + fTruePiPlus = -9999; + fTruePiPlusCher = -9999; + fTruePiMinus = -9999; + fTruePiMinusCher = -9999; + fTrueKPlus = -9999; + fTrueKPlusCher = -9999; + fTrueKMinus = -9999; + fTrueKMinusCher = -9999; + + // TankReco_fill + fRecoVtxX = -9999; + fRecoVtxY = -9999; + fRecoVtxZ = -9999; + fRecoVtxTime = -9999; + fRecoVtxFOM = -9999; + fRecoDirX = -9999; + fRecoDirY = -9999; + fRecoDirZ = -9999; + fRecoAngle = -9999; + fRecoPhi = -9999; + fRecoStatus = -9999; + + // RecoDebug_fill + fSeedVtxX.clear(); + fSeedVtxY.clear(); + fSeedVtxZ.clear(); + fSeedVtxFOM.clear(); + fSeedVtxTime = -9999; + + // Reco vertex + // Point Position Vertex + fPointVtxPosX = -9999; + fPointVtxPosY = -9999; + fPointVtxPosZ = -9999; + fPointVtxTime = -9999; + fPointPosFOM = -9999; + fPointPosStatus = -9999; + fPointVtxDirX = -9999; + fPointVtxDirY = -9999; + fPointVtxDirZ = -9999; + fPointDirTime = -9999; + fPointDirFOM = -9999; + fPointDirStatus = -9999; + + // Point Vertex Finder + fPointVtxPosX = -9999; + fPointVtxPosY = -9999; + fPointVtxPosZ = -9999; + fPointVtxTime = -9999; + fPointVtxDirX = -9999; + fPointVtxDirY = -9999; + fPointVtxDirZ = -9999; + fPointVtxFOM = -9999; + fPointVtxStatus = -9999; + + // Difference between MC and Truth + fDeltaVtxX = -9999; + fDeltaVtxY = -9999; + fDeltaVtxZ = -9999; + fDeltaVtxR = -9999; + fDeltaVtxT = -9999; + fDeltaParallel = -9999; + fDeltaPerpendicular = -9999; + fDeltaAzimuth = -9999; + fDeltaZenith = -9999; + fDeltaAngle = -9999; + + // Pion and kaon counts for event + fPi0Count = 0; + fPiPlusCount = 0; + fPiMinusCount = 0; + fK0Count = 0; + fKPlusCount = 0; + fKMinusCount = 0; + + // Event Info + fDataStreams.clear(); + GroupedTrigger.clear(); + + // LAPPDData_fill + LAPPDDataMap.clear(); + LAPPDBeamgate_ns.clear(); + LAPPDTimeStamps_ns.clear(); + LAPPDTimeStampsRaw.clear(); + LAPPDBeamgatesRaw.clear(); + LAPPDOffsets.clear(); + LAPPDTSCorrection.clear(); + LAPPDBGCorrection.clear(); + LAPPDOSInMinusPS.clear(); + SwitchBitBG.clear(); + // LAPPD_PPS_fill + LAPPDBG_PPSBefore.clear(); + LAPPDBG_PPSAfter.clear(); + LAPPDBG_PPSDiff.clear(); + LAPPDBG_PPSMissing.clear(); + LAPPDTS_PPSBefore.clear(); + LAPPDTS_PPSAfter.clear(); + LAPPDTS_PPSDiff.clear(); + LAPPDTS_PPSMissing.clear(); + + // LAPPD Reco Fill + lappdPulses.clear(); + lappdHits.clear(); + + waveformMax.clear(); + waveformRMS.clear(); + waveformMaxLast.clear(); + waveformMaxNearing.clear(); + waveformMaxTimeBin.clear(); +} + +bool ANNIEEventTreeMaker::LoadEventInfo() +{ + Log("ANNIEEventTreeMaker Tool: LoadEventInfo", v_warning, ANNIEEventTreeMakerVerbosity); + m_data->Stores["ANNIEEvent"]->Get("RunNumber", fRunNumber); + m_data->Stores["ANNIEEvent"]->Get("SubRunNumber", fSubrunNumber); + m_data->Stores["ANNIEEvent"]->Get("PartNumber", fPartFileNumber); + bool gotEventNumber = m_data->Stores["ANNIEEvent"]->Get("EventNumber", fEventNumber); + if (!gotEventNumber) + { + uint32_t enm = 9998; + m_data->CStore.Get("EventNumberTree", enm); + cout << "ANNIEEventTreeMaker Tool: Not get the event number from ANNIEEvent, get from CStore: " << enm << endl; + fEventNumber = static_cast(enm); + } + + m_data->Stores["ANNIEEvent"]->Get("PrimaryTriggerWord", fPrimaryTriggerWord); + if (fPrimaryTriggerWord == 14) + trigword = 5; + else + trigword = fPrimaryTriggerWord; + m_data->Stores["ANNIEEvent"]->Get("PrimaryTriggerTime", fPrimaryTriggerTime); + m_data->Stores["ANNIEEvent"]->Get("GroupedTrigger", GroupedTrigger); + m_data->Stores["ANNIEEvent"]->Get("TriggerWord", fTriggerword); + m_data->Stores["ANNIEEvent"]->Get("TriggerExtended", fExtended); + m_data->Stores["ANNIEEvent"]->Get("DataStreams", fDataStreams); + + bool pmtmrdcoinc, noveto; + m_data->Stores["RecoEvent"]->Get("PMTMRDCoinc", pmtmrdcoinc); + m_data->Stores["RecoEvent"]->Get("NoVeto", noveto); + if (pmtmrdcoinc) + fTankMRDCoinc = 1; + else + fTankMRDCoinc = 0; + + if (noveto) + fNoVeto = 1; + else + fNoVeto = 0; + + if (fDataStreams["Tank"] == 1) + fHasTank = 1; + else + fHasTank = 0; + + if (fDataStreams["MRD"] == 1) + fHasMRD = 1; + else + fHasMRD = 0; + + if (fDataStreams["LAPPD"] == 1) + fHasLAPPD = 1; + else + fHasLAPPD = 0; + + for (std::map::iterator it = GroupedTrigger.begin(); it != GroupedTrigger.end(); ++it) + { + uint64_t key = it->first; + uint32_t value = it->second; + + fGroupedTriggerTime.push_back(key); + fGroupedTriggerWord.push_back(value); + } + + bool gotETT = m_data->Stores["ANNIEEvent"]->Get("EventTimeTank", fEventTimeTank); + if (!gotETT) + fEventTimeTank = 0; + + TimeClass tm; + bool gotETMRD = m_data->Stores["ANNIEEvent"]->Get("EventTimeMRD", tm); + fEventTimeMRD = (ULong64_t)tm.GetNs(); + + if (!gotETMRD) + fEventTimeMRD = 0; + + if (fillAllTriggers) + return true; + else if (fill_singleTrigger) + { + if (fPrimaryTriggerWord == fill_singleTriggerWord) + return true; + else + return false; + } + else if (fill_TriggerWord.size() > 0) + { + for (auto trig : fill_TriggerWord) + { + if (fPrimaryTriggerWord == trig) + return true; + } + return false; + } + else + return true; +} + +void ANNIEEventTreeMaker::LoadBeamInfo() +{ + Log("ANNIEEventTreeMaker Tool: LoadBeamInfo", v_debug, ANNIEEventTreeMakerVerbosity); + + m_data->Stores["ANNIEEvent"]->Get("beam_E_TOR860", beam_E_TOR860); + m_data->Stores["ANNIEEvent"]->Get("beam_E_TOR875", beam_E_TOR875); + m_data->Stores["ANNIEEvent"]->Get("beam_THCURR", beam_THCURR); + m_data->Stores["ANNIEEvent"]->Get("beam_BTJT2", beam_BTJT2); + m_data->Stores["ANNIEEvent"]->Get("beam_HP875", beam_HP875); + m_data->Stores["ANNIEEvent"]->Get("beam_VP875", beam_VP875); + m_data->Stores["ANNIEEvent"]->Get("beam_HPTG1", beam_HPTG1); + m_data->Stores["ANNIEEvent"]->Get("beam_VPTG1", beam_VPTG1); + m_data->Stores["ANNIEEvent"]->Get("beam_HPTG2", beam_HPTG2); + m_data->Stores["ANNIEEvent"]->Get("beam_VPTG2", beam_VPTG2); + m_data->Stores["ANNIEEvent"]->Get("beam_BTH2T2", beam_BTH2T2); + + m_data->Stores["ANNIEEvent"]->Get("beam_E_TOR875", fPot); + m_data->Stores["ANNIEEvent"]->Get("beam_good", fBeamok); + + m_data->Stores["ANNIEEvent"]->Get("BeamInfoTime", fBeamInfoTime); + m_data->Stores["ANNIEEvent"]->Get("BeamInfoTimeToTriggerDiff", fBeamInfoTimeToTriggerDiff); +} + +void ANNIEEventTreeMaker::LoadRWMBRFInfo() +{ + Log("ANNIEEventTreeMaker Tool: LoadRWMBRFInfo", v_debug, ANNIEEventTreeMakerVerbosity); + m_data->Stores["ANNIEEvent"]->Get("RWMRisingStart", fRWMRisingStart); + m_data->Stores["ANNIEEvent"]->Get("RWMRisingEnd", fRWMRisingEnd); + m_data->Stores["ANNIEEvent"]->Get("RWMHalfRising", fRWMHalfRising); + m_data->Stores["ANNIEEvent"]->Get("RWMFHWM", fRWMFHWM); + m_data->Stores["ANNIEEvent"]->Get("RWMFirstPeak", fRWMFirstPeak); + + m_data->Stores["ANNIEEvent"]->Get("BRFFirstPeak", fBRFFirstPeak); + m_data->Stores["ANNIEEvent"]->Get("BRFAveragePeak", fBRFAveragePeak); + m_data->Stores["ANNIEEvent"]->Get("BRFFirstPeakFit", fBRFFirstPeakFit); +} + +void ANNIEEventTreeMaker::LoadAllTankHits() +{ + Log("ANNIEEventTreeMaker Tool: LoadAllTankHits", v_debug, ANNIEEventTreeMakerVerbosity); + std::map> *Hits = nullptr; + std::map> *MCHits = nullptr; + bool got_hits = false; + if (isData) + got_hits = m_data->Stores["ANNIEEvent"]->Get("Hits", Hits); + else + got_hits = m_data->Stores["ANNIEEvent"]->Get("MCHits", MCHits); + if (!got_hits) + { + std::cout << "No Hits store in ANNIEEvent. Continuing to build tree " << std::endl; + return; + } + + Position detector_center = geom->GetTankCentre(); + double tank_center_x = detector_center.X(); + double tank_center_y = detector_center.Y(); + double tank_center_z = detector_center.Z(); + fNHits = 0; + + std::map>::iterator it_tank_data; + std::map>::iterator it_tank_mc; + if (isData) + it_tank_data = (*Hits).begin(); + else + it_tank_mc = (*MCHits).begin(); + bool loop_tank = true; + int hits_size = (isData) ? Hits->size() : MCHits->size(); + if (hits_size == 0) + loop_tank = false; + + while (loop_tank) + { + // start to fill tank info to vectors + unsigned long channel_key; + if (isData) + channel_key = it_tank_data->first; + else + channel_key = it_tank_mc->first; + Detector *this_detector = geom->ChannelToDetector(channel_key); + Position det_position = this_detector->GetDetectorPosition(); + unsigned long detkey = this_detector->GetDetectorID(); + unsigned long channel_key_data = channel_key; + if (!isData) + { + int wcsimid = channelkey_to_pmtid.at(channel_key); + channel_key_data = pmtid_to_channelkey[wcsimid]; + } + std::map::iterator it = ChannelKeyToSPEMap.find(channel_key); + std::map::iterator it_mc = ChannelKeyToSPEMap.find(channel_key_data); + bool SPE_available = true; + if (isData) + SPE_available = (it != ChannelKeyToSPEMap.end()); + else + SPE_available = (it_mc != ChannelKeyToSPEMap.end()); + if (SPE_available) + { // Charge to SPE conversion is available + if (isData) + { + std::vector ThisPMTHits = it_tank_data->second; + fNHits += ThisPMTHits.size(); + for (Hit &ahit : ThisPMTHits) + { + double hit_charge = ahit.GetCharge(); + double hit_PE = hit_charge / ChannelKeyToSPEMap.at(channel_key); + fHitX.push_back((det_position.X() - tank_center_x)); + fHitY.push_back((det_position.Y() - tank_center_y)); + fHitZ.push_back((det_position.Z() - tank_center_z)); + fHitT.push_back(ahit.GetTime()); + fHitQ.push_back(hit_charge); + fHitPE.push_back(hit_PE); + fHitDetID.push_back(detkey); + fHitChankey.push_back(channel_key); + fHitChankeyMC.push_back(channel_key); + fHitType.push_back(RecoDigit::PMT8inch); // 0 For PMTs + } + } + else + { + std::vector ThisPMTHits = it_tank_mc->second; + fNHits += ThisPMTHits.size(); + for (MCHit &ahit : ThisPMTHits) + { + double hit_PE = ahit.GetCharge(); + double hit_charge = hit_PE * ChannelKeyToSPEMap.at(channel_key_data); + fHitX.push_back((det_position.X() - tank_center_x)); + fHitY.push_back((det_position.Y() - tank_center_y)); + fHitZ.push_back((det_position.Z() - tank_center_z)); + fHitT.push_back(ahit.GetTime()); + fHitQ.push_back(hit_charge); + fHitPE.push_back(hit_PE); + fHitDetID.push_back(detkey); + fHitChankey.push_back(channel_key_data); + fHitChankeyMC.push_back(channel_key); + fHitType.push_back(RecoDigit::PMT8inch); // 0 For PMTs + } + } + } + + if (isData) + { + it_tank_data++; + if (it_tank_data == (*Hits).end()) + loop_tank = false; + } + else + { + it_tank_mc++; + if (it_tank_mc == (*MCHits).end()) + loop_tank = false; + } + } + return; +} + +void ANNIEEventTreeMaker::LoadSiPMHits() +{ + Log("ANNIEEventTreeMaker Tool: LoadSiPMHits", v_debug, ANNIEEventTreeMakerVerbosity); + std::map>> aux_pulse_map; + m_data->Stores.at("ANNIEEvent")->Get("RecoADCAuxHits", aux_pulse_map); + fSiPM1NPulses = 0; + fSiPM2NPulses = 0; + for (const auto &temp_pair : aux_pulse_map) + { + const auto &channel_key = temp_pair.first; + // For now, only calibrate the SiPM waveforms + int sipm_number = -1; + if (AuxChannelNumToTypeMap->at(channel_key) == "SiPM1") + { + sipm_number = 1; + } + else if (AuxChannelNumToTypeMap->at(channel_key) == "SiPM2") + { + sipm_number = 2; + } + else + continue; + + std::vector> sipm_minibuffers = temp_pair.second; + size_t num_minibuffers = sipm_minibuffers.size(); // Should be size 1 in FrankDAQ mode + for (size_t mb = 0; mb < num_minibuffers; ++mb) + { + std::vector thisbuffer_pulses = sipm_minibuffers.at(mb); + if (sipm_number == 1) + fSiPM1NPulses += thisbuffer_pulses.size(); + if (sipm_number == 2) + fSiPM2NPulses += thisbuffer_pulses.size(); + for (size_t i = 0; i < thisbuffer_pulses.size(); i++) + { + ADCPulse apulse = thisbuffer_pulses.at(i); + fSiPMHitAmplitude.push_back(apulse.amplitude()); + fSiPMHitT.push_back(apulse.peak_time()); + fSiPMHitQ.push_back(apulse.charge()); + fSiPMNum.push_back(sipm_number); + } + } + } +} + +void ANNIEEventTreeMaker::LoadLAPPDInfo() +{ + m_data->Stores["ANNIEEvent"]->Get("LAPPDDataMap", LAPPDDataMap); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + m_data->Stores["ANNIEEvent"]->Get("LAPPDOffsets", LAPPDOffsets); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTSCorrection", LAPPDTSCorrection); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBGCorrection", LAPPDBGCorrection); + m_data->Stores["ANNIEEvent"]->Get("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); + m_data->Stores["ANNIEEvent"]->Get("SwitchBitBG", SwitchBitBG); + + if (LAPPDDataMap.size() != 0) + { + FillLAPPDInfo(); + // print the content of fDataStreams, and the size of data map + // cout<<"Found LAPPDData, LAPPDDataMap Size: "<::iterator it = LAPPDDataMap.begin(); it != LAPPDDataMap.end(); ++it) + { + uint64_t key = it->first; + PsecData psecData = it->second; + fLAPPD_ID.push_back(psecData.LAPPD_ID); + fLAPPD_Beamgate_ns.push_back(LAPPDBeamgate_ns[key]); + fLAPPD_Timestamp_ns.push_back(LAPPDTimeStamps_ns[key]); + fLAPPD_Beamgate_Raw.push_back(LAPPDBeamgatesRaw[key]); + fLAPPD_Timestamp_Raw.push_back(LAPPDTimeStampsRaw[key]); + fLAPPD_Offset.push_back(LAPPDOffsets[key]); + fLAPPD_TSCorrection.push_back(LAPPDTSCorrection[key]); + fLAPPD_BGCorrection.push_back(LAPPDBGCorrection[key]); + fLAPPD_OSInMinusPS.push_back(LAPPDOSInMinusPS[key]); + fLAPPD_BGPPSBefore.push_back(LAPPDBG_PPSBefore[key]); + fLAPPD_BGPPSAfter.push_back(LAPPDBG_PPSAfter[key]); + fLAPPD_BGPPSDiff.push_back(LAPPDBG_PPSDiff[key]); + fLAPPD_BGPPSMissing.push_back(LAPPDBG_PPSMissing[key]); + fLAPPD_TSPPSBefore.push_back(LAPPDTS_PPSBefore[key]); + fLAPPD_TSPPSAfter.push_back(LAPPDTS_PPSAfter[key]); + fLAPPD_TSPPSDiff.push_back(LAPPDTS_PPSDiff[key]); + fLAPPD_TSPPSMissing.push_back(LAPPDTS_PPSMissing[key]); + // check if SwitchBitBG has the key + if (SwitchBitBG.find(psecData.LAPPD_ID) != SwitchBitBG.end()) + { + if (SwitchBitBG[psecData.LAPPD_ID].size() != 2) + { + cout << "ANNIEEventTreeMaker: SwitchBitBG size is not 2, LAPPD_ID: " << psecData.LAPPD_ID << ", size: " << SwitchBitBG[psecData.LAPPD_ID].size() << endl; + continue; + } + fLAPPD_BG_switchBit0.push_back(SwitchBitBG[psecData.LAPPD_ID][0]); + fLAPPD_BG_switchBit1.push_back(SwitchBitBG[psecData.LAPPD_ID][1]); + continue; + } + } +} + +void ANNIEEventTreeMaker::FillLAPPDPulse() +{ + bool gotPulse = m_data->Stores["ANNIEEvent"]->Get("LAPPDPulses", lappdPulses); + if (gotPulse) + { + + std::map>>::iterator it; + for (it = lappdPulses.begin(); it != lappdPulses.end(); it++) + { + int stripno = it->first; + vector> stripPulses = it->second; + + vector pulse0 = stripPulses.at(0); + vector pulse1 = stripPulses.at(1); + for (int i = 0; i < pulse0.size(); i++) + { + fPulseSide.push_back(0); + LAPPDPulse thisPulse = pulse0.at(i); + fLAPPD_IDs.push_back(thisPulse.GetTubeId()); + fChannelID.push_back(thisPulse.GetChannelID()); + fPulseStripNum.push_back(stripno); + fPulsePeakTime.push_back(thisPulse.GetTime()); + fPulseHalfHeightTime.push_back(thisPulse.GetHalfHeightTime()); + fPulseCharge.push_back(thisPulse.GetCharge()); + fPulsePeakAmp.push_back(thisPulse.GetPeak()); + fPulseStart.push_back(thisPulse.GetLowRange()); + fPulseEnd.push_back(thisPulse.GetHiRange()); + fPulseWidth.push_back(thisPulse.GetHiRange() - thisPulse.GetLowRange()); + } + for (int i = 0; i < pulse1.size(); i++) + { + fPulseSide.push_back(1); + LAPPDPulse thisPulse = pulse1.at(i); + fLAPPD_IDs.push_back(thisPulse.GetTubeId()); + fChannelID.push_back(thisPulse.GetChannelID()); + fPulseStripNum.push_back(stripno); + fPulsePeakTime.push_back(thisPulse.GetTime()); + fPulseHalfHeightTime.push_back(thisPulse.GetHalfHeightTime()); + fPulseCharge.push_back(thisPulse.GetCharge()); + fPulsePeakAmp.push_back(thisPulse.GetPeak()); + fPulseStart.push_back(thisPulse.GetLowRange()); + fPulseEnd.push_back(thisPulse.GetHiRange()); + fPulseWidth.push_back(thisPulse.GetHiRange() - thisPulse.GetLowRange()); + } + } + } +} + +void ANNIEEventTreeMaker::FillLAPPDHit() +{ + bool gotHit = m_data->Stores["ANNIEEvent"]->Get("LAPPDHits", lappdHits); + + if (gotHit) + { + std::map>::iterator it; + for (it = lappdHits.begin(); it != lappdHits.end(); it++) + { + int stripno = it->first; + vector stripHits = it->second; + for (int i = 0; i < stripHits.size(); i++) + { + LAPPDHit thisHit = stripHits.at(i); + LAPPDPulse p1 = thisHit.GetPulse1(); + LAPPDPulse p2 = thisHit.GetPulse2(); + fLAPPDHit_IDs.push_back(thisHit.GetTubeId()); + fLAPPDHitStrip.push_back(stripno); + fLAPPDHitTime.push_back(thisHit.GetTime()); + fLAPPDHitAmp.push_back(thisHit.GetCharge()); + vector position = thisHit.GetPosition(); + /* + XPosTank = position.at(0); + YPosTank = position.at(1); + ZPosTank = position.at(2);*/ + vector localPosition = thisHit.GetLocalPosition(); + fLAPPDHitParallelPos.push_back(localPosition.at(0)); + fLAPPDHitTransversePos.push_back(localPosition.at(1)); + // fLAPPDHitP1StartTime.push_back(thisHit.GetPulse1StartTime()); + // fLAPPDHitP2StartTime.push_back(thisHit.GetPulse2StartTime()); + // fLAPPDHitP1EndTime.push_back(thisHit.GetPulse1LastTime()); + // fLAPPDHitP2EndTime.push_back(thisHit.GetPulse2LastTime()); + // cout<<"Pulse 1 start time: "<> *m_all_clusters = nullptr; + std::map> *m_all_clusters_MC = nullptr; + std::map> *m_all_clusters_detkeys = nullptr; + + bool get_clusters = false; + if (isData) + { + get_clusters = m_data->CStore.Get("ClusterMap", m_all_clusters); + if (!get_clusters) + { + std::cout << "ANNIEEventTreeMaker tool: No clusters found!" << std::endl; + return false; + } + } + else + { + get_clusters = m_data->CStore.Get("ClusterMapMC", m_all_clusters_MC); + if (!get_clusters) + { + std::cout << "ANNIEEventTreeMaker tool: No clusters found (MC)!" << std::endl; + return false; + } + } + get_clusters = m_data->CStore.Get("ClusterMapDetkey", m_all_clusters_detkeys); + if (!get_clusters) + { + std::cout << "ANNIEEventTreeMaker tool: No cluster detkeys found!" << std::endl; + return false; + } + Log("ANNIEEventTreeMaker Tool: Accessing pairs in all_clusters map", v_debug, ANNIEEventTreeMakerVerbosity); + + int cluster_num = 0; + int cluster_size = 0; + if (isData) + cluster_size = (int)m_all_clusters->size(); + else + cluster_size = (int)m_all_clusters_MC->size(); + + std::map>::iterator it_cluster_pair; + std::map>::iterator it_cluster_pair_mc; + bool loop_map = true; + if (isData) + it_cluster_pair = (*m_all_clusters).begin(); + else + it_cluster_pair_mc = (*m_all_clusters_MC).begin(); + if (cluster_size == 0) + loop_map = false; + + fNumberOfClusters = cluster_size; + while (loop_map) + { + if (isData) + { + std::vector cluster_hits = it_cluster_pair->second; + double thisClusterTime = it_cluster_pair->first; + if (cluster_TankHitInfo_fill) + { + Log("ANNIEEventTreeMaker Tool: Loading tank cluster hits into cluster tree", v_debug, ANNIEEventTreeMakerVerbosity); + fClusterTimeV.push_back(thisClusterTime); + this->LoadTankClusterHits(cluster_hits); + } + + bool good_class = this->LoadTankClusterClassifiers(it_cluster_pair->first); + if (!good_class) + { + if (ANNIEEventTreeMakerVerbosity > 3) + Log("ANNIEEventTreeMaker Tool: No cluster classifiers. Continuing tree", v_debug, ANNIEEventTreeMakerVerbosity); + } + } + else + { + std::vector cluster_hits = it_cluster_pair_mc->second; + double thisClusterTime = it_cluster_pair_mc->first; + std::vector cluster_detkeys = m_all_clusters_detkeys->at(it_cluster_pair_mc->first); + if (cluster_TankHitInfo_fill) + { + Log("ANNIEEventTreeMaker Tool: Loading tank cluster hits into cluster tree", v_debug, ANNIEEventTreeMakerVerbosity); + fClusterTimeV.push_back(thisClusterTime); + this->LoadTankClusterHitsMC(cluster_hits, cluster_detkeys); + } + bool good_class = this->LoadTankClusterClassifiers(it_cluster_pair_mc->first); + if (!good_class) + { + if (ANNIEEventTreeMakerVerbosity > 3) + Log("ANNIEEventTreeMaker Tool: No cluster classifiers. Continuing tree", v_debug, ANNIEEventTreeMakerVerbosity); + } + } + + if (isData) + { + it_cluster_pair++; + if (it_cluster_pair == (*m_all_clusters).end()) + loop_map = false; + } + else + { + it_cluster_pair_mc++; + if (it_cluster_pair_mc == (*m_all_clusters_MC).end()) + loop_map = false; + } + } + + return true; +} + +void ANNIEEventTreeMaker::LoadTankClusterHits(std::vector cluster_hits) +{ + Position detector_center = geom->GetTankCentre(); + double tank_center_x = detector_center.X(); + double tank_center_y = detector_center.Y(); + double tank_center_z = detector_center.Z(); + + double ClusterCharge = 0; + double ClusterPE = 0; + int ClusterHitNum = 0; + vector HitXV; + vector HitYV; + vector HitZV; + vector HitTV; + vector HitQV; + vector HitPEV; + vector HitTypeV; + vector HitDetIDV; + vector HitChankeyV; + vector HitCKMC; + + for (int i = 0; i < (int)cluster_hits.size(); i++) + { + int channel_key = cluster_hits.at(i).GetTubeId(); + std::map::iterator it = ChannelKeyToSPEMap.find(channel_key); + if (it != ChannelKeyToSPEMap.end()) + { // Charge to SPE conversion is available + Detector *this_detector = geom->ChannelToDetector(channel_key); + unsigned long detkey = this_detector->GetDetectorID(); + Position det_position = this_detector->GetDetectorPosition(); + double hit_charge = cluster_hits.at(i).GetCharge(); + double hit_PE = hit_charge / ChannelKeyToSPEMap.at(channel_key); + HitXV.push_back((det_position.X() - tank_center_x)); + HitYV.push_back((det_position.Y() - tank_center_y)); + HitZV.push_back((det_position.Z() - tank_center_z)); + HitQV.push_back(hit_charge); + HitPEV.push_back(hit_PE); + HitTV.push_back(cluster_hits.at(i).GetTime()); + HitDetIDV.push_back(detkey); + + HitChankeyV.push_back(channel_key); + HitCKMC.push_back(channel_key); + HitTypeV.push_back(RecoDigit::PMT8inch); + ClusterCharge += hit_charge; + ClusterPE += hit_PE; + ClusterHitNum += 1; + } + else + { + if (ANNIEEventTreeMakerVerbosity > 4) + { + std::cout << "FOUND A HIT FOR CHANNELKEY " << channel_key << "BUT NO CONVERSION " << "TO PE AVAILABLE. SKIPPING PE." << std::endl; + } + } + } + fClusterHits.push_back(ClusterHitNum); + fClusterChargeV.push_back(ClusterCharge); + fClusterPEV.push_back(ClusterPE); + + fCluster_HitX.push_back(HitXV); + fCluster_HitY.push_back(HitYV); + fCluster_HitZ.push_back(HitZV); + fCluster_HitT.push_back(HitTV); + fCluster_HitQ.push_back(HitQV); + fCluster_HitPE.push_back(HitPEV); + fCluster_HitType.push_back(HitTypeV); + fCluster_HitDetID.push_back(HitDetIDV); + fCluster_HitChankey.push_back(HitChankeyV); + fCluster_HitChankeyMC.push_back(HitCKMC); + + return; +} + +void ANNIEEventTreeMaker::LoadTankClusterHitsMC(std::vector cluster_hits, std::vector cluster_detkeys) +{ + Position detector_center = geom->GetTankCentre(); + double tank_center_x = detector_center.X(); + double tank_center_y = detector_center.Y(); + double tank_center_z = detector_center.Z(); + + double ClusterCharge = 0; + double ClusterPE = 0; + int ClusterHitNum = 0; + vector HitXV; + vector HitYV; + vector HitZV; + vector HitTV; + vector HitQV; + vector HitPEV; + vector HitTypeV; + vector HitDetIDV; + vector HitChankeyV; + vector HitCKMC; + + for (int i = 0; i < (int)cluster_hits.size(); i++) + { + unsigned long detkey = cluster_detkeys.at(i); + int channel_key = (int)detkey; + int tubeid = cluster_hits.at(i).GetTubeId(); + unsigned long utubeid = (unsigned long)tubeid; + int wcsimid = channelkey_to_pmtid.at(utubeid); + unsigned long detkey_data = pmtid_to_channelkey[wcsimid]; + int channel_key_data = (int)detkey_data; + std::map::iterator it = ChannelKeyToSPEMap.find(channel_key_data); + if (it != ChannelKeyToSPEMap.end()) + { // Charge to SPE conversion is available + Detector *this_detector = geom->ChannelToDetector(tubeid); + Position det_position = this_detector->GetDetectorPosition(); + unsigned long detkey = this_detector->GetDetectorID(); + double hit_PE = cluster_hits.at(i).GetCharge(); + double hit_charge = hit_PE * ChannelKeyToSPEMap.at(channel_key_data); + HitXV.push_back((det_position.X() - tank_center_x)); + HitYV.push_back((det_position.Y() - tank_center_y)); + HitZV.push_back((det_position.Z() - tank_center_z)); + HitQV.push_back(hit_charge); + HitPEV.push_back(hit_PE); + HitTV.push_back(cluster_hits.at(i).GetTime()); + HitDetIDV.push_back(detkey); + HitChankeyV.push_back(channel_key_data); + HitCKMC.push_back(channel_key); + HitTypeV.push_back(RecoDigit::PMT8inch); + ClusterCharge += hit_charge; + ClusterPE += hit_PE; + ClusterHitNum += 1; + } + else + { + if (ANNIEEventTreeMakerVerbosity > 4) + { + std::cout << "FOUND A HIT FOR CHANNELKEY " << channel_key_data << "(MC detkey: " << channel_key << ", chankey = " << utubeid << ", wcsimid = " << wcsimid << ") BUT NO CONVERSION " << "TO PE AVAILABLE. SKIPPING PE." << std::endl; + } + } + } + fClusterHits.push_back(ClusterHitNum); + fClusterChargeV.push_back(ClusterCharge); + fClusterPEV.push_back(ClusterPE); + + fCluster_HitX.push_back(HitXV); + fCluster_HitY.push_back(HitYV); + fCluster_HitZ.push_back(HitZV); + fCluster_HitT.push_back(HitTV); + fCluster_HitQ.push_back(HitQV); + fCluster_HitPE.push_back(HitPEV); + fCluster_HitType.push_back(HitTypeV); + fCluster_HitDetID.push_back(HitDetIDV); + fCluster_HitChankey.push_back(HitChankeyV); + fCluster_HitChankeyMC.push_back(HitCKMC); + + return; +} + +bool ANNIEEventTreeMaker::LoadTankClusterClassifiers(double cluster_time) +{ + // Save classifiers to ANNIEEvent + Log("PhaseITreeMaker tool: Getting cluster classifiers", v_debug, ANNIEEventTreeMakerVerbosity); + std::map ClusterMaxPEs; + std::map ClusterChargePoints; + std::map ClusterChargeBalances; + + bool got_ccp = m_data->Stores.at("ANNIEEvent")->Get("ClusterChargePoints", ClusterChargePoints); + bool got_ccb = m_data->Stores.at("ANNIEEvent")->Get("ClusterChargeBalances", ClusterChargeBalances); + bool got_cmpe = m_data->Stores.at("ANNIEEvent")->Get("ClusterMaxPEs", ClusterMaxPEs); + bool good_classifiers = got_ccp && got_ccb && got_cmpe; + if (!good_classifiers) + { + Log("PhaseITreeMaker tool: One of the charge cluster classifiers is not available", v_debug, ANNIEEventTreeMakerVerbosity); + } + else + { + Log("PhaseITreeMaker tool: Setting fCluster variables to classifier parameters", v_debug, ANNIEEventTreeMakerVerbosity); + fClusterMaxPEV.push_back(ClusterMaxPEs.at(cluster_time)); + Position ClusterChargePoint = ClusterChargePoints.at(cluster_time); + fClusterChargePointXV.push_back(ClusterChargePoint.X()); + fClusterChargePointYV.push_back(ClusterChargePoint.Y()); + fClusterChargePointZV.push_back(ClusterChargePoint.Z()); + fClusterChargeBalanceV.push_back(ClusterChargeBalances.at(cluster_time)); + } + return good_classifiers; +} + +void ANNIEEventTreeMaker::LoadMRDCluster() +{ + std::vector mrddigittimesthisevent; + std::vector mrddigitchargesthisevent; + ; + std::vector mrddigitpmtsthisevent; + std::vector mrddigitchankeysthisevent; + std::vector> MrdTimeClusters; + + bool get_clusters = m_data->CStore.Get("MrdTimeClusters", MrdTimeClusters); + if (!get_clusters) + { + std::cout << "ANNIEEventTreeMaker tool: No MRD clusters found! Did you run the TimeClustering tool?" << std::endl; + return; + } + + int num_mrd_clusters; + m_data->CStore.Get("NumMrdTimeClusters", num_mrd_clusters); + + if (num_mrd_clusters > 0) + { + m_data->CStore.Get("MrdDigitTimes", mrddigittimesthisevent); + m_data->CStore.Get("MrdDigitPmts", mrddigitpmtsthisevent); + m_data->CStore.Get("MrdDigitChankeys", mrddigitchankeysthisevent); + m_data->CStore.Get("MrdDigitCharges", mrddigitchargesthisevent); + m_data->CStore.Get("MrdDigitPmts", mrddigitpmtsthisevent); + } + + std::map> *TDCData = nullptr; + std::map> *TDCData_MC = nullptr; + + int TrigHasVetoHit = 0; + bool has_tdc = false; + if (isData) + has_tdc = m_data->Stores["ANNIEEvent"]->Get("TDCData", TDCData); // a std::map> + else + has_tdc = m_data->Stores["ANNIEEvent"]->Get("TDCData", TDCData_MC); + if (!has_tdc) + { + std::cout << "No TDCData store in ANNIEEvent." << std::endl; + } + + int cluster_num = 0; + for (int i = 0; i < (int)MrdTimeClusters.size(); i++) + { + int tdcdata_size = (isData) ? TDCData->size() : TDCData_MC->size(); + int fMRDClusterHits = 0; + if (has_tdc && tdcdata_size > 0) + { + Log("ANNIEEventTreeMaker tool: Looping over FACC/MRD hits... looking for Veto activity", v_debug, ANNIEEventTreeMakerVerbosity); + if (isData) + { + for (auto &&anmrdpmt : (*TDCData)) + { + unsigned long chankey = anmrdpmt.first; + std::vector mrdhits = anmrdpmt.second; + Detector *thedetector = geom->ChannelToDetector(chankey); + unsigned long detkey = thedetector->GetDetectorID(); + if (thedetector->GetDetectorElement() == "Veto") + { + TrigHasVetoHit = 1; // this is a veto hit, not an MRD hit. + for (int j = 0; j < (int)mrdhits.size(); j++) + { + fFMVHitT.push_back(mrdhits.at(j).GetTime()); + fFMVHitDetID.push_back(detkey); + fFMVHitChankey.push_back(chankey); + fFMVHitChankeyMC.push_back(chankey); + } + } + } + } + else + { + for (auto &&anmrdpmt : (*TDCData_MC)) + { + unsigned long chankey = anmrdpmt.first; + Detector *thedetector = geom->ChannelToDetector(chankey); + unsigned long detkey = thedetector->GetDetectorID(); + if (thedetector->GetDetectorElement() == "Veto") + { + TrigHasVetoHit = 1; // this is a veto hit, not an MRD hit. + int wcsimid = channelkey_to_faccpmtid.at(chankey) - 1; + unsigned long chankey_data = wcsimid; + std::vector mrdhits = anmrdpmt.second; + for (int j = 0; j < (int)mrdhits.size(); j++) + { + fFMVHitT.push_back(mrdhits.at(j).GetTime()); + fFMVHitDetID.push_back(detkey); + fFMVHitChankey.push_back(chankey_data); + fFMVHitChankeyMC.push_back(chankey); + } + } + } + } + } + + fVetoHit = TrigHasVetoHit; + std::vector ThisClusterIndices = MrdTimeClusters.at(i); + for (int j = 0; j < (int)ThisClusterIndices.size(); j++) + { + Detector *thedetector = geom->ChannelToDetector(mrddigitchankeysthisevent.at(ThisClusterIndices.at(j))); + unsigned long detkey = thedetector->GetDetectorID(); + + fMRDHitT.push_back(mrddigittimesthisevent.at(ThisClusterIndices.at(j))); + fMRDHitClusterIndex.push_back(i); + fMRDHitCharge.push_back(mrddigitchargesthisevent.at(ThisClusterIndices.at(j))); + fMRDHitDigitPMT.push_back(mrddigitpmtsthisevent.at(ThisClusterIndices.at(j))); + fMRDHitDetID.push_back(detkey); + if (isData) + fMRDHitChankey.push_back(mrddigitchankeysthisevent.at(ThisClusterIndices.at(j))); + else + { + int wcsimid = channelkey_to_mrdpmtid.at(mrddigitchankeysthisevent.at(ThisClusterIndices.at(j))) - 1; + unsigned long chankey_data = mrdpmtid_to_channelkey_data[wcsimid]; + fMRDHitChankey.push_back(chankey_data); + } + fMRDHitChankeyMC.push_back(mrddigitchankeysthisevent.at(ThisClusterIndices.at(j))); + fMRDClusterHits += 1; + } + + double MRDThisClusterTime = 0; + double MRDThisClusterTimeSigma = 0; + ComputeMeanAndVariance(fMRDHitT, MRDThisClusterTime, MRDThisClusterTimeSigma); + // FIXME: calculate fMRDClusterTime + + // Standard run level information + Log("ANNIEEventTreeMaker Tool: MRD cluster, Getting run level information from ANNIEEvent", v_debug, ANNIEEventTreeMakerVerbosity); + + if (MRDReco_fill) + { + int ThisMRDClusterTrackNum = this->LoadMRDTrackReco(i); + fNumClusterTracks.push_back(ThisMRDClusterTrackNum); + // Get the track info + } + cluster_num++; + + fMRDClusterHitNumber.push_back(fMRDClusterHits); + fMRDClusterTime.push_back(MRDThisClusterTime); + fMRDClusterTimeSigma.push_back(MRDThisClusterTimeSigma); + } + fMRDClusterNumber = cluster_num; + Log("ANNIEEventTreeMaker Tool: MRD cluster, Finished loading MRD cluster info", v_debug, ANNIEEventTreeMakerVerbosity); +} + +int ANNIEEventTreeMaker::LoadMRDTrackReco(int SubEventID) +{ + std::vector *theMrdTracks; // the reconstructed tracks + int numtracksinev; + + // Check for valid track criteria + m_data->Stores["MRDTracks"]->Get("MRDTracks", theMrdTracks); + m_data->Stores["MRDTracks"]->Get("NumMrdTracks", numtracksinev); + // Loop over reconstructed tracks + + Position StartVertex; + Position StopVertex; + double TrackLength = -9999; + double TrackAngle = -9999; + double TrackAngleError = -9999; + double PenetrationDepth = -9999; + Position MrdEntryPoint; + double EnergyLoss = -9999; // in MeV + double EnergyLossError = -9999; + double EntryPointRadius = -9999; + bool IsMrdPenetrating; + bool IsMrdStopped; + bool IsMrdSideExit; + + int NumClusterTracks = 0; + for (int tracki = 0; tracki < numtracksinev; tracki++) + { + BoostStore *thisTrackAsBoostStore = &(theMrdTracks->at(tracki)); + int TrackEventID = -1; + // get track properties that are needed for the through-going muon selection + thisTrackAsBoostStore->Get("MrdSubEventID", TrackEventID); + if (TrackEventID != SubEventID) + continue; + + // If we're here, this track is associated with this cluster + thisTrackAsBoostStore->Get("StartVertex", StartVertex); + thisTrackAsBoostStore->Get("StopVertex", StopVertex); + thisTrackAsBoostStore->Get("TrackAngle", TrackAngle); + thisTrackAsBoostStore->Get("TrackAngleError", TrackAngleError); + thisTrackAsBoostStore->Get("PenetrationDepth", PenetrationDepth); + thisTrackAsBoostStore->Get("MrdEntryPoint", MrdEntryPoint); + thisTrackAsBoostStore->Get("EnergyLoss", EnergyLoss); + thisTrackAsBoostStore->Get("EnergyLossError", EnergyLossError); + thisTrackAsBoostStore->Get("IsMrdPenetrating", IsMrdPenetrating); // bool + thisTrackAsBoostStore->Get("IsMrdStopped", IsMrdStopped); // bool + thisTrackAsBoostStore->Get("IsMrdSideExit", IsMrdSideExit); + TrackLength = sqrt(pow((StopVertex.X() - StartVertex.X()), 2) + pow(StopVertex.Y() - StartVertex.Y(), 2) + pow(StopVertex.Z() - StartVertex.Z(), 2)) * 100.0; + EntryPointRadius = sqrt(pow(MrdEntryPoint.X(), 2) + pow(MrdEntryPoint.Y(), 2)) * 100.0; // convert to cm + PenetrationDepth = PenetrationDepth * 100.0; + + // Push back some properties + fMRDTrackAngle.push_back(TrackAngle); + fMRDTrackAngleError.push_back(TrackAngleError); + fMRDTrackLength.push_back(TrackLength); + fMRDPenetrationDepth.push_back(PenetrationDepth); + fMRDEntryPointRadius.push_back(EntryPointRadius); + fMRDEnergyLoss.push_back(EnergyLoss); + fMRDEnergyLossError.push_back(EnergyLossError); + fMRDTrackStartX.push_back(StartVertex.X()); + fMRDTrackStartY.push_back(StartVertex.Y()); + fMRDTrackStartZ.push_back(StartVertex.Z()); + fMRDTrackStopX.push_back(StopVertex.X()); + fMRDTrackStopY.push_back(StopVertex.Y()); + fMRDTrackStopZ.push_back(StopVertex.Z()); + fMRDStop.push_back(IsMrdStopped); + fMRDSide.push_back(IsMrdSideExit); + fMRDThrough.push_back(IsMrdPenetrating); + NumClusterTracks += 1; + fMRDClusterIndex.push_back(SubEventID); + } + return NumClusterTracks; +} + +// MC and tank reco information below + +bool ANNIEEventTreeMaker::FillTankRecoInfo() +{ + bool got_reco_info = true; + auto *reco_event = m_data->Stores["RecoEvent"]; + if (!reco_event) + { + Log("Error: The PhaseITreeMaker tool could not find the RecoEvent Store", v_error, ANNIEEventTreeMakerVerbosity); + got_reco_info = false; + } + // Read reconstructed Vertex + RecoVertex *recovtx = 0; + auto get_extendedvtx = m_data->Stores.at("RecoEvent")->Get("ExtendedVertex", recovtx); + if (!get_extendedvtx) + { + Log("Warning: The PhaseITreeMaker tool could not find ExtendedVertex. Continuing to build tree", v_message, ANNIEEventTreeMakerVerbosity); + got_reco_info = false; + } + else + { + fRecoVtxX = recovtx->GetPosition().X(); + fRecoVtxY = recovtx->GetPosition().Y(); + fRecoVtxZ = recovtx->GetPosition().Z(); + fRecoVtxTime = recovtx->GetTime(); + fRecoVtxFOM = recovtx->GetFOM(); + fRecoDirX = recovtx->GetDirection().X(); + fRecoDirY = recovtx->GetDirection().Y(); + fRecoDirZ = recovtx->GetDirection().Z(); + fRecoAngle = TMath::ACos(fRecoDirZ); + if (fRecoDirX > 0.0) + { + fRecoPhi = atan(fRecoDirY / fRecoDirX); + } + if (fRecoDirX < 0.0) + { + fRecoPhi = atan(fRecoDirY / fRecoDirX); + if (fRecoDirY > 0.0) + fRecoPhi += TMath::Pi(); + if (fRecoDirY <= 0.0) + fRecoPhi -= TMath::Pi(); + } + if (fRecoDirX == 0.0) + { + if (fRecoDirY > 0.0) + fRecoPhi = 0.5 * TMath::Pi(); + else if (fRecoDirY < 0.0) + fRecoPhi = -0.5 * TMath::Pi(); + else + fRecoPhi = 0; + } + fRecoStatus = recovtx->GetStatus(); + } + return got_reco_info; +} + +void ANNIEEventTreeMaker::FillRecoDebugInfo() +{ + // Read Seed candidates + std::vector *seedvtxlist = 0; + auto get_seedvtxlist = m_data->Stores.at("RecoEvent")->Get("vSeedVtxList", seedvtxlist); ///> Get List of seeds from "RecoEvent" + if (get_seedvtxlist) + { + for (auto &seed : *seedvtxlist) + { + fSeedVtxX.push_back(seed.GetPosition().X()); + fSeedVtxY.push_back(seed.GetPosition().Y()); + fSeedVtxZ.push_back(seed.GetPosition().Z()); + fSeedVtxTime = seed.GetTime(); + } + } + else + { + Log("ANNIEEventTreeMaker Tool: No Seed List found. Continuing to build tree ", v_message, ANNIEEventTreeMakerVerbosity); + } + std::vector *seedfomlist = 0; + auto get_seedfomlist = m_data->Stores.at("RecoEvent")->Get("vSeedFOMList", seedfomlist); ///> Get List of seed FOMs from "RecoEvent" + if (get_seedfomlist) + { + for (auto &seedFOM : *seedfomlist) + { + fSeedVtxFOM.push_back(seedFOM); + } + } + else + { + Log("ANNIEEventTreeMaker Tool: No Seed FOM List found. Continuing to build tree ", v_message, ANNIEEventTreeMakerVerbosity); + } + + // Read PointPosition-fitted Vertex + RecoVertex *pointposvtx = 0; + auto get_pointposdata = m_data->Stores.at("RecoEvent")->Get("PointPosition", pointposvtx); + if (get_pointposdata) + { + fPointPosX = pointposvtx->GetPosition().X(); + fPointPosY = pointposvtx->GetPosition().Y(); + fPointPosZ = pointposvtx->GetPosition().Z(); + fPointPosTime = pointposvtx->GetTime(); + fPointPosFOM = pointposvtx->GetFOM(); + fPointPosStatus = pointposvtx->GetStatus(); + } + else + { + Log("ANNIEEventTreeMaker Tool: No PointPosition Tool data found. Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + } + + // Read PointDirection-fitted Vertex + RecoVertex *pointdirvtx = 0; + auto get_pointdirdata = m_data->Stores.at("RecoEvent")->Get("PointDirection", pointdirvtx); + if (get_pointdirdata) + { + fPointDirX = pointdirvtx->GetDirection().X(); + fPointDirY = pointdirvtx->GetDirection().Y(); + fPointDirZ = pointdirvtx->GetDirection().Z(); + fPointDirTime = pointdirvtx->GetTime(); + fPointDirFOM = pointdirvtx->GetFOM(); + fPointDirStatus = pointdirvtx->GetStatus(); + } + else + { + Log("ANNIEEventTreeMaker Tool: No PointDirection Tool data found. Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + } + + // Read PointVertex Tool's fitted Vertex + RecoVertex *pointvtx = 0; + auto get_pointvtxdata = m_data->Stores.at("RecoEvent")->Get("PointVertex", pointvtx); + if (get_pointvtxdata) + { + fPointVtxPosX = pointvtx->GetPosition().X(); + fPointVtxPosY = pointvtx->GetPosition().Y(); + fPointVtxPosZ = pointvtx->GetPosition().Z(); + fPointVtxDirX = pointvtx->GetDirection().X(); + fPointVtxDirY = pointvtx->GetDirection().Y(); + fPointVtxDirZ = pointvtx->GetDirection().Z(); + fPointVtxTime = pointvtx->GetTime(); + fPointVtxFOM = pointvtx->GetFOM(); + fPointVtxStatus = pointvtx->GetStatus(); + } + else + { + Log("ANNIEEventTreeMaker Tool: No PointVertex Tool data found. Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + } +} + +bool ANNIEEventTreeMaker::FillMCTruthInfo() +{ + bool successful_load = true; + // MC entry number + m_data->Stores.at("ANNIEEvent")->Get("MCEventNum", fMCEventNum); + // MC trigger number + m_data->Stores.at("ANNIEEvent")->Get("MCTriggernum", fMCTriggerNum); + std::string logmessage = " Retriving information for MCEntry " + to_string(fMCEventNum) + + ", MCTrigger " + to_string(fMCTriggerNum) + ", EventNumber " + to_string(fEventNumber); + Log(logmessage, v_message, ANNIEEventTreeMakerVerbosity); + + fiMCTriggerNum = (int)fMCTriggerNum; + + std::map> MCNeutCap; + bool get_neutcap = m_data->Stores.at("ANNIEEvent")->Get("MCNeutCap", MCNeutCap); + if (!get_neutcap) + { + Log("ANNIEEventTreeMaker: Did not find MCNeutCap in ANNIEEvent Store!", v_warning, ANNIEEventTreeMakerVerbosity); + } + std::map>> MCNeutCapGammas; + bool get_neutcap_gammas = m_data->Stores.at("ANNIEEvent")->Get("MCNeutCapGammas", MCNeutCapGammas); + if (!get_neutcap_gammas) + { + Log("ANNIEEventTreeMaker: Did not find MCNeutCapGammas in ANNIEEvent Store!", v_warning, ANNIEEventTreeMakerVerbosity); + } + + for (std::map>>::iterator it = MCNeutCapGammas.begin(); it != MCNeutCapGammas.end(); it++) + { + std::vector> mcneutgammas = it->second; + for (int i_cap = 0; i_cap < (int)mcneutgammas.size(); i_cap++) + { + std::vector capgammas = mcneutgammas.at(i_cap); + for (int i_gamma = 0; i_gamma < (int)capgammas.size(); i_gamma++) + { + std::cout << "gamma # " << i_gamma << ", energy: " << capgammas.at(i_gamma) << std::endl; + } + } + } + + RecoVertex *truevtx = 0; + auto get_muonMC = m_data->Stores.at("RecoEvent")->Get("TrueVertex", truevtx); + auto get_muonMCEnergy = m_data->Stores.at("RecoEvent")->Get("TrueMuonEnergy", fTrueMuonEnergy); + auto get_pdg = m_data->Stores.at("RecoEvent")->Get("PdgPrimary", fTruePrimaryPdg); + if (get_muonMC && get_muonMCEnergy) + { + fTrueVtxX = truevtx->GetPosition().X(); + fTrueVtxY = truevtx->GetPosition().Y(); + fTrueVtxZ = truevtx->GetPosition().Z(); + fTrueVtxTime = truevtx->GetTime(); + fTrueDirX = truevtx->GetDirection().X(); + fTrueDirY = truevtx->GetDirection().Y(); + fTrueDirZ = truevtx->GetDirection().Z(); + double TrueAngRad = TMath::ACos(fTrueDirZ); + fTrueAngle = TrueAngRad / (TMath::Pi() / 180.0); // radians->degrees + if (fTrueDirX > 0.0) + { + fTruePhi = atan(fTrueDirY / fTrueDirX); + } + if (fTrueDirX < 0.0) + { + fTruePhi = atan(fTrueDirY / fTrueDirX); + if (fTrueDirY > 0.0) + fTruePhi += TMath::Pi(); + if (fTrueDirY <= 0.0) + fTruePhi -= TMath::Pi(); + } + if (fTrueDirX == 0.0) + { + if (fTrueDirY > 0.0) + fTruePhi = 0.5 * TMath::Pi(); + else if (fTrueDirY < 0.0) + fTruePhi = -0.5 * TMath::Pi(); + else + fTruePhi = 0; + } + } + else + { + Log("ANNIEEventTreeMaker Tool: Missing MC Energy/Vertex info; is this MC? Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + double waterT, MRDT; + auto get_tankTrackLength = m_data->Stores.at("RecoEvent")->Get("TrueTrackLengthInWater", waterT); + auto get_MRDTrackLength = m_data->Stores.at("RecoEvent")->Get("TrueTrackLengthInMRD", MRDT); + if (get_tankTrackLength && get_MRDTrackLength) + { + fTrueTrackLengthInWater = waterT; + fTrueTrackLengthInMRD = MRDT; + } + else + { + Log("ANNIEEventTreeMaker Tool: True track lengths missing. Continuing to build tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + + bool IsMultiRing = false; + bool get_multi = m_data->Stores.at("RecoEvent")->Get("MCMultiRingEvent", IsMultiRing); + if (get_multi) + { + fTrueMultiRing = (IsMultiRing) ? 1 : 0; + } + else + { + Log("ANNIEEventTreeMaker Tool: True Multi Ring information missing. Continuing to build tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + + std::vector primary_pdgs; + bool has_primaries = m_data->Stores.at("RecoEvent")->Get("PrimaryPdgs", primary_pdgs); + if (has_primaries) + { + for (int i_part = 0; i_part < (int)primary_pdgs.size(); i_part++) + { + fTruePrimaryPdgs->push_back(primary_pdgs.at(i_part)); + } + } + else + { + Log("ANNIEEventTreeMaker Tool: Primary Pdgs information missing. Continuing to build tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + + int pi0count, pipcount, pimcount, K0count, Kpcount, Kmcount; + auto get_pi0 = m_data->Stores.at("RecoEvent")->Get("MCPi0Count", pi0count); + auto get_pim = m_data->Stores.at("RecoEvent")->Get("MCPiMinusCount", pimcount); + auto get_pip = m_data->Stores.at("RecoEvent")->Get("MCPiPlusCount", pipcount); + auto get_k0 = m_data->Stores.at("RecoEvent")->Get("MCK0Count", K0count); + auto get_km = m_data->Stores.at("RecoEvent")->Get("MCKMinusCount", Kmcount); + auto get_kp = m_data->Stores.at("RecoEvent")->Get("MCKPlusCount", Kpcount); + if (get_pi0 && get_pim && get_pip && get_k0 && get_km && get_kp) + { + // set values in tree to thouse grabbed from the RecoEvent Store + fPi0Count = pi0count; + fPiPlusCount = pipcount; + fPiMinusCount = pimcount; + fK0Count = K0count; + fKPlusCount = Kpcount; + fKMinusCount = Kmcount; + } + else + { + Log("ANNIEEventTreeMaker Tool: Missing MC Pion/Kaon count information. Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + + if (MCNeutCap.count("CaptVtxX") > 0) + { + std::vector n_vtxx = MCNeutCap["CaptVtxX"]; + std::vector n_vtxy = MCNeutCap["CaptVtxY"]; + std::vector n_vtxz = MCNeutCap["CaptVtxZ"]; + std::vector n_parent = MCNeutCap["CaptParent"]; + std::vector n_ngamma = MCNeutCap["CaptNGamma"]; + std::vector n_totale = MCNeutCap["CaptTotalE"]; + std::vector n_time = MCNeutCap["CaptTime"]; + std::vector n_nuc = MCNeutCap["CaptNucleus"]; + + for (int i_cap = 0; i_cap < (int)n_vtxx.size(); i_cap++) + { + fTrueNeutCapVtxX->push_back(n_vtxx.at(i_cap)); + fTrueNeutCapVtxY->push_back(n_vtxy.at(i_cap)); + fTrueNeutCapVtxZ->push_back(n_vtxz.at(i_cap)); + fTrueNeutCapNucleus->push_back(n_nuc.at(i_cap)); + fTrueNeutCapTime->push_back(n_time.at(i_cap)); + fTrueNeutCapGammas->push_back(n_ngamma.at(i_cap)); + fTrueNeutCapE->push_back(n_totale.at(i_cap)); + } + } + + std::cout << "MCNeutCapGammas count CaptGammas: " << MCNeutCapGammas.count("CaptGammas") << std::endl; + if (MCNeutCapGammas.count("CaptGammas") > 0) + { + std::vector> cap_energies = MCNeutCapGammas["CaptGammas"]; + std::cout << "cap_energies size: " << cap_energies.size() << std::endl; + for (int i_cap = 0; i_cap < (int)cap_energies.size(); i_cap++) + { + for (int i_gamma = 0; i_gamma < cap_energies.at(i_cap).size(); i_gamma++) + { + std::cout << "gamma energy: " << cap_energies.at(i_cap).at(i_gamma) << std::endl; + fTrueNeutCapGammaE->push_back(cap_energies.at(i_cap).at(i_gamma)); + } + } + } + + // Load genie information + if (hasGenie) + { + double TrueNeutrinoEnergy, TrueQ2, TrueNuIntxVtx_X, TrueNuIntxVtx_Y, TrueNuIntxVtx_Z, TrueNuIntxVtx_T; + double TrueFSLeptonMass, TrueFSLeptonEnergy, TrueFSLeptonTime; + bool TrueCC, TrueNC, TrueQEL, TrueDIS, TrueCOH, TrueMEC, TrueRES; + int fsNeutrons, fsProtons, fsPi0, fsPiPlus, fsPiPlusCher, fsPiMinus, fsPiMinusCher; + int fsKPlus, fsKPlusCher, fsKMinus, fsKMinusCher, TrueNuPDG, TrueFSLeptonPdg; + Position TrueFSLeptonVtx; + Direction TrueFSLeptonMomentum; + Direction TrueNeutrinoMomentum; + bool get_neutrino_energy = m_data->Stores["GenieInfo"]->Get("NeutrinoEnergy", TrueNeutrinoEnergy); + bool get_neutrino_mom = m_data->Stores["GenieInfo"]->Get("NeutrinoMomentum", TrueNeutrinoMomentum); + bool get_neutrino_vtxx = m_data->Stores["GenieInfo"]->Get("NuIntxVtx_X", TrueNuIntxVtx_X); + bool get_neutrino_vtxy = m_data->Stores["GenieInfo"]->Get("NuIntxVtx_Y", TrueNuIntxVtx_Y); + bool get_neutrino_vtxz = m_data->Stores["GenieInfo"]->Get("NuIntxVtx_Z", TrueNuIntxVtx_Z); + bool get_neutrino_vtxt = m_data->Stores["GenieInfo"]->Get("NuIntxVtx_T", TrueNuIntxVtx_T); + bool get_q2 = m_data->Stores["GenieInfo"]->Get("EventQ2", TrueQ2); + bool get_cc = m_data->Stores["GenieInfo"]->Get("IsWeakCC", TrueCC); + bool get_nc = m_data->Stores["GenieInfo"]->Get("IsWeakNC", TrueNC); + bool get_qel = m_data->Stores["GenieInfo"]->Get("IsQuasiElastic", TrueQEL); + bool get_res = m_data->Stores["GenieInfo"]->Get("IsResonant", TrueRES); + bool get_dis = m_data->Stores["GenieInfo"]->Get("IsDeepInelastic", TrueDIS); + bool get_coh = m_data->Stores["GenieInfo"]->Get("IsCoherent", TrueCOH); + bool get_mec = m_data->Stores["GenieInfo"]->Get("IsMEC", TrueMEC); + bool get_n = m_data->Stores["GenieInfo"]->Get("NumFSNeutrons", fsNeutrons); + bool get_p = m_data->Stores["GenieInfo"]->Get("NumFSProtons", fsProtons); + bool get_pi0 = m_data->Stores["GenieInfo"]->Get("NumFSPi0", fsPi0); + bool get_piplus = m_data->Stores["GenieInfo"]->Get("NumFSPiPlus", fsPiPlus); + bool get_pipluscher = m_data->Stores["GenieInfo"]->Get("NumFSPiPlusCher", fsPiPlusCher); + bool get_piminus = m_data->Stores["GenieInfo"]->Get("NumFSPiMinus", fsPiMinus); + bool get_piminuscher = m_data->Stores["GenieInfo"]->Get("NumFSPiMinusCher", fsPiMinusCher); + bool get_kplus = m_data->Stores["GenieInfo"]->Get("NumFSKPlus", fsKPlus); + bool get_kpluscher = m_data->Stores["GenieInfo"]->Get("NumFSKPlusCher", fsKPlusCher); + bool get_kminus = m_data->Stores["GenieInfo"]->Get("NumFSKMinus", fsKMinus); + bool get_kminuscher = m_data->Stores["GenieInfo"]->Get("NumFSKMinusCher", fsKMinusCher); + bool get_fsl_vtx = m_data->Stores["GenieInfo"]->Get("FSLeptonVertex", TrueFSLeptonVtx); + bool get_fsl_momentum = m_data->Stores["GenieInfo"]->Get("FSLeptonMomentum", TrueFSLeptonMomentum); + bool get_fsl_time = m_data->Stores["GenieInfo"]->Get("FSLeptonTime", TrueFSLeptonTime); + bool get_fsl_mass = m_data->Stores["GenieInfo"]->Get("FSLeptonMass", TrueFSLeptonMass); + bool get_fsl_pdg = m_data->Stores["GenieInfo"]->Get("FSLeptonPdg", TrueFSLeptonPdg); + bool get_fsl_energy = m_data->Stores["GenieInfo"]->Get("FSLeptonEnergy", TrueFSLeptonEnergy); + std::cout << "get_neutrino_energy: " << get_neutrino_energy << "get_neutrino_vtxx: " << get_neutrino_vtxx << "get_neutrino_vtxy: " << get_neutrino_vtxy << "get_neutrino_vtxz: " << get_neutrino_vtxz << "get_neutrino_time: " << get_neutrino_vtxt << std::endl; + std::cout << "get_q2: " << get_q2 << ", get_cc: " << get_cc << ", get_qel: " << get_qel << ", get_res: " << get_res << ", get_dis: " << get_dis << ", get_coh: " << get_coh << ", get_mec: " << get_mec << std::endl; + std::cout << "get_n: " << get_n << ", get_p: " << get_p << ", get_pi0: " << get_pi0 << ", get_piplus: " << get_piplus << ", get_pipluscher: " << get_pipluscher << ", get_piminus: " << get_piminus << ", get_piminuscher: " << get_piminuscher << ", get_kplus: " << get_kplus << ", get_kpluscher: " << get_kpluscher << ", get_kminus: " << get_kminus << ", get_kminuscher: " << get_kminuscher << std::endl; + std::cout << "get_fsl_vtx: " << get_fsl_vtx << ", get_fsl_momentum: " << get_fsl_momentum << ", get_fsl_time: " << get_fsl_time << ", get_fsl_mass: " << get_fsl_mass << ", get_fsl_pdg: " << get_fsl_pdg << ", get_fsl_energy: " << get_fsl_energy << std::endl; + if (get_neutrino_energy && get_neutrino_mom && get_neutrino_vtxx && get_neutrino_vtxy && get_neutrino_vtxz && get_neutrino_vtxt && get_q2 && get_cc && get_nc && get_qel && get_res && get_dis && get_coh && get_mec && get_n && get_p && get_pi0 && get_piplus && get_pipluscher && get_piminus && get_piminuscher && get_kplus && get_kpluscher && get_kminus && get_kminuscher && get_fsl_vtx && get_fsl_momentum && get_fsl_time && get_fsl_mass && get_fsl_pdg && get_fsl_energy) + { + fTrueNeutrinoEnergy = TrueNeutrinoEnergy; + fTrueNeutrinoMomentum_X = TrueNeutrinoMomentum.X(); + fTrueNeutrinoMomentum_Y = TrueNeutrinoMomentum.Y(); + fTrueNeutrinoMomentum_Z = TrueNeutrinoMomentum.Z(); + fTrueNuIntxVtx_X = TrueNuIntxVtx_X; + fTrueNuIntxVtx_Y = TrueNuIntxVtx_Y; + fTrueNuIntxVtx_Z = TrueNuIntxVtx_Z; + fTrueNuIntxVtx_T = TrueNuIntxVtx_T; + fTrueFSLVtx_X = TrueFSLeptonVtx.X(); + fTrueFSLVtx_Y = TrueFSLeptonVtx.Y(); + fTrueFSLVtx_Z = TrueFSLeptonVtx.Z(); + fTrueFSLMomentum_X = TrueFSLeptonMomentum.X(); + fTrueFSLMomentum_Y = TrueFSLeptonMomentum.Y(); + fTrueFSLMomentum_Z = TrueFSLeptonMomentum.Z(); + fTrueFSLTime = TrueFSLeptonTime; + fTrueFSLMass = TrueFSLeptonMass; + fTrueFSLPdg = TrueFSLeptonPdg; + fTrueFSLEnergy = TrueFSLeptonEnergy; + fTrueQ2 = TrueQ2; + fTrueCC = (TrueCC) ? 1 : 0; + fTrueNC = (TrueNC) ? 1 : 0; + fTrueQEL = (TrueQEL) ? 1 : 0; + fTrueRES = (TrueRES) ? 1 : 0; + fTrueDIS = (TrueDIS) ? 1 : 0; + fTrueCOH = (TrueCOH) ? 1 : 0; + fTrueMEC = (TrueMEC) ? 1 : 0; + fTrueNeutrons = fsNeutrons; + fTrueProtons = fsProtons; + fTruePi0 = fsPi0; + fTruePiPlus = fsPiPlus; + fTruePiPlusCher = fsPiPlusCher; + fTruePiMinus = fsPiMinus; + fTruePiMinusCher = fsPiMinusCher; + fTrueKPlus = fsKPlus; + fTrueKPlusCher = fsKPlusCher; + fTrueKMinus = fsKMinus; + fTrueKMinusCher = fsKMinusCher; + } + else + { + Log("ANNIEEventTreeMaker tool: Did not find GENIE information. Continuing building remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + successful_load = false; + } + } // end if hasGenie + + return successful_load; +} + +void ANNIEEventTreeMaker::FillTruthRecoDiffInfo(bool successful_mcload, bool successful_recoload) +{ + if (!successful_mcload || !successful_recoload) + { + Log("ANNIEEventTreeMaker Tool: Error loading True Muon Vertex or Extended Vertex information. Continuing to build remaining tree", v_message, ANNIEEventTreeMakerVerbosity); + } + else + { + // Make sure MCTruth Information is loaded from store + // Let's fill in stuff from the RecoSummary + fDeltaVtxX = fRecoVtxX - fTrueVtxX; + fDeltaVtxY = fRecoVtxY - fTrueVtxY; + fDeltaVtxZ = fRecoVtxZ - fTrueVtxZ; + fDeltaVtxT = fRecoVtxTime - fTrueVtxTime; + fDeltaVtxR = sqrt(pow(fDeltaVtxX, 2) + pow(fDeltaVtxY, 2) + pow(fDeltaVtxZ, 2)); + fDeltaParallel = fDeltaVtxX * fRecoDirX + fDeltaVtxY * fRecoDirY + fDeltaVtxZ * fRecoDirZ; + fDeltaPerpendicular = sqrt(pow(fDeltaVtxR, 2) - pow(fDeltaParallel, 2)); + fDeltaAzimuth = (fRecoAngle - fTrueAngle) / (TMath::Pi() / 180.0); + fDeltaZenith = (fRecoPhi - fTruePhi) / (TMath::Pi() / 180.0); + double cosphi = fTrueDirX * fRecoDirX + fTrueDirY * fRecoDirY + fTrueDirZ * fRecoDirZ; + double phi = TMath::ACos(cosphi); // radians + double TheAngle = phi / (TMath::Pi() / 180.0); // radians->degrees + fDeltaAngle = TheAngle; + } +} + +void ANNIEEventTreeMaker::RecoSummary() +{ + + // get reconstruction output + double dx = fRecoVtxX - fTrueVtxX; + double dy = fRecoVtxY - fTrueVtxY; + double dz = fRecoVtxZ - fTrueVtxZ; + double dt = fRecoVtxTime - fTrueVtxTime; + double deltaR = sqrt(dx * dx + dy * dy + dz * dz); + double cosphi = 0., phi = 0., DeltaAngle = 0.; + cosphi = fTrueDirX * fRecoDirX + fTrueDirY * fRecoDirY + fTrueDirZ * fRecoDirZ; + phi = TMath::ACos(cosphi); // radians + DeltaAngle = phi / (TMath::Pi() / 180.0); // radians->degrees + std::cout << "============================================================================" << std::endl; + std::cout << " Event number " << fEventNumber << std::endl; + std::cout << " trueVtx=(" << fTrueVtxX << ", " << fTrueVtxY << ", " << fTrueVtxZ << ", " << fTrueVtxTime << std::endl + << " TrueMuonEnergy= " << fTrueMuonEnergy << " Primary Pdg = " << fTruePrimaryPdg << std::endl + << " " << fTrueDirX << ", " << fTrueDirY << ", " << fTrueDirZ << ") " << std::endl; + std::cout << " recoVtx=(" << fRecoVtxX << ", " << fRecoVtxY << ", " << fRecoVtxZ << ", " << fRecoVtxTime << std::endl + << " " << fRecoDirX << ", " << fRecoDirY << ", " << fRecoDirZ << ") " << std::endl; + std::cout << " DeltaR = " << deltaR << "[cm]" << "\t" << " DeltaAngle = " << DeltaAngle << " [degree]" << std::endl; + std::cout << " FOM = " << fRecoVtxFOM << std::endl; + std::cout << " RecoStatus = " << fRecoStatus << std::endl; + std::cout << std::endl; +} diff --git a/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.h b/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.h new file mode 100644 index 000000000..ea83a8151 --- /dev/null +++ b/UserTools/ANNIEEventTreeMaker/ANNIEEventTreeMaker.h @@ -0,0 +1,552 @@ +#ifndef ANNIEEventTreeMaker_H +#define ANNIEEventTreeMaker_H + +#include +#include + +#include "Tool.h" +// ROOT includes +#include "TApplication.h" +#include +#include +#include "TFile.h" +#include "TTree.h" +#include "TH1D.h" +#include "TMath.h" +#include "ADCPulse.h" +#include "Waveform.h" +#include "CalibratedADCWaveform.h" +#include "Hit.h" +#include "RecoDigit.h" +#include "ANNIEalgorithms.h" +#include "TimeClass.h" +#include "BeamStatus.h" +#include "PsecData.h" +#include "LAPPDPulse.h" +#include "LAPPDHit.h" + +/** + * \class ANNIEEventTreeMaker + * + * This tool is the end tool of BeamClusterAnalysis, it takes the processed data as input, and dump the data into a root file. + * This tool only work with the processed data generated by EventBuilderV2 tool chain. + * + * $Author: Yue Feng $ + * $Date: 2024/08 $ + * Contact: yuef@iaistate.edu + */ +class ANNIEEventTreeMaker : public Tool +{ + +public: + ANNIEEventTreeMaker(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + + bool LoadEventInfo(); + void LoadBeamInfo(); + + void LoadRWMBRFInfo(); + + void LoadAllTankHits(); + void LoadSiPMHits(); + + void LoadLAPPDInfo(); + void FillLAPPDInfo(); + void FillLAPPDHit(); + void FillLAPPDPulse(); + + bool LoadClusterInfo(); + + void LoadMRDCluster(); + + void LoadMRDInfo(); + void LoadLAPPDRecoInfo(); + void FillLAPPDRecoInfo(); + + bool FillMCTruthInfo(); + bool FillTankRecoInfo(); + int LoadMRDTrackReco(int SubEventNumber); + void LoadAllMRDHits(bool isData); + void FillRecoDebugInfo(); + void FillTruthRecoDiffInfo(bool got_mc, bool got_reco); + + void RecoSummary(); + void LoadTankClusterHits(std::vector cluster_hits); + void LoadTankClusterHitsMC(std::vector cluster_hits, std::vector cluster_detkeys); + bool LoadTankClusterClassifiers(double cluster_time); + + void ResetVariables(); + +private: + // General variables + bool isData = 1; + bool hasGenie; + + int ANNIEEventTreeMakerVerbosity = 0; + int v_error = 0; + int v_warning = 1; + int v_message = 2; + int v_debug = 3; + + int EventNumberIndex = 0; + + // What events will be filled - Triggers + bool fillAllTriggers; // if true, fill all events with any major trigger + // if fillAllTriggers = false: + bool fill_singleTrigger; // if true, only fill events with selected trigger, for example 14 + int fill_singleTriggerWord; + // if fillAllTriggers = false and fill_singleTrigger = false: + vector fill_TriggerWord; // fill events with any of these triggers in this vector + + // What events will be filled - status + bool fillCleanEventsOnly = 0; // Only output events not flagged by EventSelector tool + bool fillLAPPDEventsOnly = 0; // Only fill events with LAPPD data + + // What information will be filled + bool TankHitInfo_fill = 1; + bool TankCluster_fill = 1; + bool cluster_TankHitInfo_fill = 1; + bool MRDHitInfo_fill = 1; + bool LAPPDData_fill = 1; + bool RWMBRF_fill = 1; + bool LAPPD_PPS_fill = 1; + + // What reco information will be filled + bool MCTruth_fill = 0; // Output the MC truth information + bool TankReco_fill = 0; + bool MRDReco_fill = 1; + bool RecoDebug_fill = 0; // Outputs results of Reconstruction at each step (best fits, FOMs, etc.) + bool muonTruthRecoDiff_fill = 0; // Output difference in tmuonruth and reconstructed values + bool SiPMPulseInfo_fill = 0; + bool LAPPDReco_fill = 1; + bool BeamInfo_fill = 1; + + TFile *fOutput_tfile = nullptr; + TTree *fANNIETree = nullptr; + Geometry *geom = nullptr; + + int processedEvents = 0; + + // Variables for filling the tree + + // EventInfo + int fRunNumber; + int fSubrunNumber; + int fPartFileNumber; + int fRunType = 0; + int fEventNumber; + int fPrimaryTriggerWord; + int trigword; + uint64_t fPrimaryTriggerTime; + vector fGroupedTriggerTime; + vector fGroupedTriggerWord; + int fTriggerword; + int fExtended; + int fTankMRDCoinc; + int fNoVeto; + int fHasTank; + int fHasMRD; + int fHasLAPPD; + + ULong64_t fEventTimeTank; + ULong64_t fEventTimeMRD; + + // beam information + double fPot; + int fBeamok; + double beam_E_TOR860; + double beam_E_TOR875; + double beam_THCURR; + double beam_BTJT2; + double beam_HP875; + double beam_VP875; + double beam_HPTG1; + double beam_VPTG1; + double beam_HPTG2; + double beam_VPTG2; + double beam_BTH2T2; + uint64_t fBeamInfoTime; + int64_t fBeamInfoTimeToTriggerDiff; + + // RWM and BRF information + double fRWMRisingStart; // start of the rising of the waveform + double fRWMRisingEnd; // maximum of the rising of the waveform + double fRWMHalfRising; // half of the rising of the waveform, from start to maximum + double fRWMFHWM; // full width at half maximum of the waveform + double fRWMFirstPeak; // first peak of the waveform + + double fBRFFirstPeak; // first peak of the waveform + double fBRFAveragePeak; // average peak of the waveform + double fBRFFirstPeakFit; // first peak of the waveform, Gaussian fit + + // TankHitInfo_fill + int fNHits = 0; + std::vector fIsFiltered; + std::vector fHitX; + std::vector fHitY; + std::vector fHitZ; + std::vector fHitT; + std::vector fHitQ; + std::vector fHitPE; + std::vector fHitType; + std::vector fHitDetID; + std::vector fHitChankey; + std::vector fHitChankeyMC; + + // SiPMPulseInfo_fill + int fSiPM1NPulses; + int fSiPM2NPulses; + std::vector fSiPMHitQ; + std::vector fSiPMHitT; + std::vector fSiPMHitAmplitude; + std::vector fSiPMNum; + + // LAPPDData_fill + int fLAPPD_Count; + vector fLAPPD_ID; + vector fLAPPD_Beamgate_ns; + vector fLAPPD_Timestamp_ns; + vector fLAPPD_Beamgate_Raw; + vector fLAPPD_Timestamp_Raw; + vector fLAPPD_Offset; + vector fLAPPD_TSCorrection; + vector fLAPPD_BGCorrection; + vector fLAPPD_OSInMinusPS; + vector fLAPPD_BGPPSBefore; + vector fLAPPD_BGPPSAfter; + vector fLAPPD_BGPPSDiff; + vector fLAPPD_BGPPSMissing; + vector fLAPPD_TSPPSBefore; + vector fLAPPD_TSPPSAfter; + vector fLAPPD_TSPPSDiff; + vector fLAPPD_TSPPSMissing; + vector fLAPPD_BG_switchBit0; + vector fLAPPD_BG_switchBit1; + + // LAPPD Reco Fill + vector fLAPPDPulseTimeStampUL; + vector fLAPPDPulseBeamgateUL; + vector fLAPPD_IDs; + vector fChannelID; + vector fPulsePeakTime; + vector fPulseHalfHeightTime; + vector fPulseCharge; + vector fPulsePeakAmp; + vector fPulseStart; + vector fPulseEnd; + vector fPulseWidth; + vector fPulseSide; + vector fPulseStripNum; + std::map fChannelBaseline; + + vector fLAPPDHitTimeStampUL; + vector fLAPPDHitBeamgateUL; + vector fLAPPDHit_IDs; + vector fLAPPDHitChannel; + vector fLAPPDHitStrip; + vector fLAPPDHitTime; + vector fLAPPDHitAmp; + vector fLAPPDHitParallelPos; + vector fLAPPDHitTransversePos; + vector fLAPPDHitP1StartTime; + vector fLAPPDHitP2StartTime; + vector fLAPPDHitP1EndTime; + vector fLAPPDHitP2EndTime; + vector fLAPPDHitP1PeakTime; + vector fLAPPDHitP2PeakTime; + vector fLAPPDHitP1PeakAmp; + vector fLAPPDHitP2PeakAmp; + vector fLAPPDHitP1HalfHeightTime; + vector fLAPPDHitP2HalfHeightTime; + vector fLAPPDHitP1HalfEndTime; + vector fLAPPDHitP2HalfEndTime; + vector fLAPPDHitP1Charge; + vector fLAPPDHitP2Charge; + + // waveform + vector LAPPDWaveformChankey; + vector waveformMaxValue; + vector waveformRMSValue; + vector waveformMaxFoundNear; + vector waveformMaxNearingValue; + vector waveformMaxTimeBinValue; + + // finished **************************************************** + + // tank cluster information + + int fNumberOfClusters; // how many clusters in this event + // vector fClusterIndex; // index of which cluster this data belongs to + vector fClusterHits; // how many hits in this cluster + vector fClusterChargeV; + vector fClusterTimeV; + vector fClusterPEV; + + vector> fCluster_HitX; // each vector is a cluster, each element is a hit in that cluster + vector> fCluster_HitY; + vector> fCluster_HitZ; + vector> fCluster_HitT; + vector> fCluster_HitQ; + vector> fCluster_HitPE; + vector> fCluster_HitType; + vector> fCluster_HitDetID; + vector> fCluster_HitChankey; + vector> fCluster_HitChankeyMC; + + vector fClusterMaxPEV; + vector fClusterChargePointXV; + vector fClusterChargePointYV; + vector fClusterChargePointZV; + vector fClusterChargeBalanceV; + + // MRD cluster information + ULong64_t fEventTimeMRD_Tree; + int fMRDClusterNumber; + std::vector fMRDClusterHitNumber; + std::vector fMRDClusterTime; + std::vector fMRDClusterTimeSigma; + + // MRDHitInfo_fill + int fVetoHit; + std::vector fMRDHitClusterIndex; + std::vector fMRDHitT; + std::vector fMRDHitCharge; + std::vector fMRDHitDigitPMT; + std::vector fMRDHitDetID; + std::vector fMRDHitChankey; + std::vector fMRDHitChankeyMC; + + std::vector fFMVHitT; + std::vector fFMVHitDetID; + std::vector fFMVHitChankey; + std::vector fFMVHitChankeyMC; + + // MRDReco_fill + int fNumMRDClusterTracks; + std::vector fMRDTrackAngle; + std::vector fMRDTrackAngleError; + std::vector fMRDPenetrationDepth; + std::vector fMRDTrackLength; + std::vector fMRDEntryPointRadius; + std::vector fMRDEnergyLoss; + std::vector fMRDEnergyLossError; + std::vector fMRDTrackStartX; + std::vector fMRDTrackStartY; + std::vector fMRDTrackStartZ; + std::vector fMRDTrackStopX; + std::vector fMRDTrackStopY; + std::vector fMRDTrackStopZ; + std::vector fMRDSide; + std::vector fMRDStop; + std::vector fMRDThrough; + std::vector fMRDClusterIndex; + + std::vector fNumClusterTracks; + + // fillCleanEventsOnly + int fEventStatusApplied; + int fEventStatusFlagged; + + // MCTruth_fill + // ************ MC Truth Information **************** // + uint64_t fMCEventNum; + uint16_t fMCTriggerNum; + int fiMCTriggerNum; + // True muon + double fTrueVtxX; + double fTrueVtxY; + double fTrueVtxZ; + double fTrueVtxTime; + double fTrueDirX; + double fTrueDirY; + double fTrueDirZ; + double fTrueAngle; + double fTruePhi; + double fTrueMuonEnergy; + int fTruePrimaryPdg; + double fTrueTrackLengthInWater; + double fTrueTrackLengthInMRD; + std::vector *fTruePrimaryPdgs = nullptr; + std::vector *fTrueNeutCapVtxX = nullptr; + std::vector *fTrueNeutCapVtxY = nullptr; + std::vector *fTrueNeutCapVtxZ = nullptr; + std::vector *fTrueNeutCapNucleus = nullptr; + std::vector *fTrueNeutCapTime = nullptr; + std::vector *fTrueNeutCapGammas = nullptr; + std::vector *fTrueNeutCapE = nullptr; + std::vector *fTrueNeutCapGammaE = nullptr; + int fTrueMultiRing; + + // Genie information for event + double fTrueNeutrinoEnergy; + double fTrueNeutrinoMomentum_X; + double fTrueNeutrinoMomentum_Y; + double fTrueNeutrinoMomentum_Z; + double fTrueNuIntxVtx_X; + double fTrueNuIntxVtx_Y; + double fTrueNuIntxVtx_Z; + double fTrueNuIntxVtx_T; + double fTrueFSLVtx_X; + double fTrueFSLVtx_Y; + double fTrueFSLVtx_Z; + double fTrueFSLMomentum_X; + double fTrueFSLMomentum_Y; + double fTrueFSLMomentum_Z; + double fTrueFSLTime; + double fTrueFSLMass; + int fTrueFSLPdg; + double fTrueFSLEnergy; + double fTrueQ2; + int fTrueCC; + int fTrueNC; + int fTrueQEL; + int fTrueRES; + int fTrueDIS; + int fTrueCOH; + int fTrueMEC; + int fTrueNeutrons; + int fTrueProtons; + int fTruePi0; + int fTruePiPlus; + int fTruePiPlusCher; + int fTruePiMinus; + int fTruePiMinusCher; + int fTrueKPlus; + int fTrueKPlusCher; + int fTrueKMinus; + int fTrueKMinusCher; + + // TankReco_fill + double fRecoVtxX; + double fRecoVtxY; + double fRecoVtxZ; + double fRecoVtxTime; + double fRecoVtxFOM; + double fRecoDirX; + double fRecoDirY; + double fRecoDirZ; + double fRecoAngle; + double fRecoPhi; + int fRecoStatus; + + // RecoDebug_fill + // **************** Full reco chain information ************* // + // seed vertices + std::vector fSeedVtxX; + std::vector fSeedVtxY; + std::vector fSeedVtxZ; + std::vector fSeedVtxFOM; + double fSeedVtxTime; + + // Reco vertex + // Point Position Vertex + double fPointPosX; + double fPointPosY; + double fPointPosZ; + double fPointPosTime; + double fPointPosFOM; + int fPointPosStatus; + double fPointDirX; + double fPointDirY; + double fPointDirZ; + double fPointDirTime; + double fPointDirFOM; + int fPointDirStatus; + + // Point Vertex Finder + double fPointVtxPosX; + double fPointVtxPosY; + double fPointVtxPosZ; + double fPointVtxTime; + double fPointVtxDirX; + double fPointVtxDirY; + double fPointVtxDirZ; + double fPointVtxFOM; + int fPointVtxStatus; + + // muonTruthRecoDiff_fill + // ************* Difference between MC and Truth *********** // + double fDeltaVtxX; + double fDeltaVtxY; + double fDeltaVtxZ; + double fDeltaVtxR; + double fDeltaVtxT; + double fDeltaParallel; + double fDeltaPerpendicular; + double fDeltaAzimuth; + double fDeltaZenith; + double fDeltaAngle; + + // Pion and kaon counts for event + int fPi0Count; + int fPiPlusCount; + int fPiMinusCount; + int fK0Count; + int fKPlusCount; + int fKMinusCount; + + //******************************************************************************************************************** + + // data variables for filling the tree + // Event Info + std::map fDataStreams; + std::map GroupedTrigger; + + // LAPPDData_fill + std::map LAPPDDataMap; + std::map LAPPDBeamgate_ns; + std::map LAPPDTimeStamps_ns; // data and key are the same + std::map LAPPDTimeStampsRaw; + std::map LAPPDBeamgatesRaw; + std::map LAPPDOffsets; + std::map LAPPDTSCorrection; + std::map LAPPDBGCorrection; + std::map LAPPDOSInMinusPS; + std::map LAPPDBG_PPSBefore; + std::map LAPPDBG_PPSAfter; + std::map LAPPDBG_PPSDiff; + std::map LAPPDBG_PPSMissing; + std::map LAPPDTS_PPSBefore; + std::map LAPPDTS_PPSAfter; + std::map LAPPDTS_PPSDiff; + std::map LAPPDTS_PPSMissing; + std::map> SwitchBitBG; + + std::map>> lappdPulses; + std::map> lappdHits; + + //******************************************************************************************************************** + + // detector maps, don't clear + std::map *AuxChannelNumToTypeMap; + std::map ChannelKeyToSPEMap; + + std::map pmtid_to_channelkey; + std::map channelkey_to_pmtid; + std::map channelkey_to_mrdpmtid; + std::map mrdpmtid_to_channelkey_data; + std::map channelkey_to_faccpmtid; + std::map faccpmtid_to_channelkey_data; + + //******************************************************************************************************************** + // some left not used objects + + // left for raw data + std::vector fADCWaveformChankeys; + std::vector fADCWaveformSamples; + + // ************ Muon reconstruction level information ******** // + std::string MRDTriggertype; + + // ************* LAPPD RecoInfo *********** // + // left for LAPPD waveforms if needed + std::map> waveformMax; // strip number+30*side, value + std::map> waveformRMS; + std::map> waveformMaxLast; + std::map> waveformMaxNearing; + std::map> waveformMaxTimeBin; +}; + +#endif diff --git a/UserTools/ANNIEEventTreeMaker/README.md b/UserTools/ANNIEEventTreeMaker/README.md new file mode 100644 index 000000000..af113b8d2 --- /dev/null +++ b/UserTools/ANNIEEventTreeMaker/README.md @@ -0,0 +1,18 @@ +# ANNIEEventTreeMaker + +ANNIEEventTreeMaker +This tool is the end tool of BeamClusterAnalysis, it takes the processed data as input, and dump the data into a root file. + + +## Data + +This tool only work with the processed data generated by EventBuilderV2 tool chain. +The required data for different fill option is in it's fill function, please check code for details. + + +## Configuration + +output_filename: the name of output root file + +There are many fill options that will allow you fill different options. Please check code for details. Most of them are the same fill option like those in the PhaseIITreeMaker. +LAPPDReco_fill: this fill only works if the LAPPD reco tools are in the tool chain, it use the outputs from LAPPDThresReco tool. diff --git a/UserTools/EBLAPPD/EBLAPPD.cpp b/UserTools/EBLAPPD/EBLAPPD.cpp new file mode 100644 index 000000000..97c657453 --- /dev/null +++ b/UserTools/EBLAPPD/EBLAPPD.cpp @@ -0,0 +1,381 @@ +#include "EBLAPPD.h" + +EBLAPPD::EBLAPPD() : Tool() {} + +bool EBLAPPD::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("verbosityEBLAPPD", verbosityEBLAPPD); + matchTargetTrigger = 14; + m_variables.Get("matchTargetTrigger", matchTargetTrigger); + matchTolerance_ns = 400000; // default 400us + m_variables.Get("matchTolerance_ns", matchTolerance_ns); + matchToAllTriggers = false; + m_variables.Get("matchToAllTriggers", matchToAllTriggers); + exePerMatch = 500; + m_variables.Get("exePerMatch", exePerMatch); + + return true; +} + +bool EBLAPPD::Execute() +{ + m_data->CStore.Get("PairedLAPPDTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Get("PairedLAPPDTimeStamps", PairedLAPPDTimeStamps); + m_data->CStore.Get("PairedLAPPD_TriggerIndex", PairedLAPPD_TriggerIndex); + m_data->CStore.Get("Buffer_LAPPDData", Buffer_LAPPDData); + m_data->CStore.Get("Buffer_LAPPDTimestamp_ns", Buffer_LAPPDTimestamp_ns); + m_data->CStore.Get("Buffer_LAPPDBeamgate_ns", Buffer_LAPPDBeamgate_ns); + m_data->CStore.Get("Buffer_LAPPDOffset", Buffer_LAPPDOffset); + m_data->CStore.Get("Buffer_LAPPDBeamgate_Raw", Buffer_LAPPDBeamgate_Raw); + m_data->CStore.Get("Buffer_LAPPDTimestamp_Raw", Buffer_LAPPDTimestamp_Raw); + m_data->CStore.Get("Buffer_LAPPDBGCorrection", Buffer_LAPPDBGCorrection); + m_data->CStore.Get("Buffer_LAPPDTSCorrection", Buffer_LAPPDTSCorrection); + m_data->CStore.Get("Buffer_LAPPDOffset_minus_ps", Buffer_LAPPDOffset_minus_ps); + m_data->CStore.Get("Buffer_LAPPDRunCode", Buffer_RunCode); + + m_data->CStore.Get("Buffer_LAPPDBG_PPSBefore", Buffer_LAPPDBG_PPSBefore); + m_data->CStore.Get("Buffer_LAPPDBG_PPSAfter", Buffer_LAPPDBG_PPSAfter); + m_data->CStore.Get("Buffer_LAPPDBG_PPSDiff", Buffer_LAPPDBG_PPSDiff); + m_data->CStore.Get("Buffer_LAPPDBG_PPSMissing", Buffer_LAPPDBG_PPSMissing); + m_data->CStore.Get("Buffer_LAPPDTS_PPSBefore", Buffer_LAPPDTS_PPSBefore); + m_data->CStore.Get("Buffer_LAPPDTS_PPSAfter", Buffer_LAPPDTS_PPSAfter); + m_data->CStore.Get("Buffer_LAPPDTS_PPSDiff", Buffer_LAPPDTS_PPSDiff); + m_data->CStore.Get("Buffer_LAPPDTS_PPSMissing", Buffer_LAPPDTS_PPSMissing); + + Log("EBLAPPD: Got pairing information from CStore, PairedLAPPDTimeStamps[14] size = " + std::to_string(PairedLAPPDTimeStamps[14].size()), v_message, verbosityEBLAPPD); + + CleanData(); + m_data->CStore.Get("RunCode", currentRunCode); + + bool IsNewLAPPDData = false; + m_data->CStore.Get("NewLAPPDDataAvailable", IsNewLAPPDData); + Log("EBLAPPD: NewLAPPDDataAvailable = " + std::to_string(IsNewLAPPDData), v_message, verbosityEBLAPPD); + bool LoadingPPS = false; + m_data->CStore.Get("LoadingPPS", LoadingPPS); + + if (IsNewLAPPDData && !LoadingPPS) + LoadLAPPDData(); + + Log("EBLAPPD: Finished Loading LAPPD data to buffer, Buffer_LAPPDData size is now " + std::to_string(Buffer_LAPPDData.size()), v_message, verbosityEBLAPPD); + + string storeFileName; + m_data->CStore.Get("SaveToFileName", storeFileName); + + bool stopLoop = false; + m_data->vars.Get("StopLoop", stopLoop); + int runNum = thisRunNum; + m_data->vars.Get("RunNumber", thisRunNum); + bool ForceLAPPDMatching = false; + m_data->CStore.Get("ForceLAPPDMatching", ForceLAPPDMatching); + + if (stopLoop || runNum != thisRunNum || exeNum % exePerMatch == 0 || ForceLAPPDMatching) + { + Log("EBLAPPD: exeNum = " + std::to_string(exeNum) + ". Doing matching", v_message, verbosityEBLAPPD); + if (matchToAllTriggers) + { + Matching(0, 0); + } + else + { + bool BeamTriggerGroupped = false; + m_data->CStore.Get("BeamTriggerGroupped", BeamTriggerGroupped); + if (BeamTriggerGroupped) + Matching(14, 14); + else + Log("EBLAPPD: BeamTriggerGroupped is false, no beam trigger groupped in the grouper, stop matching", v_message, verbosityEBLAPPD); + + bool LaserTriggerGroupped = false; + m_data->CStore.Get("LaserTriggerGroupped", LaserTriggerGroupped); + if (LaserTriggerGroupped) + Matching(47, 47); + else + Log("EBLAPPD: LaserTriggerGroupped is false, no laser trigger groupped in the grouper, stop matching", v_message, verbosityEBLAPPD); + + bool CosmicTriggerGroupped = false; + m_data->CStore.Get("CosmicTriggerGroupped", CosmicTriggerGroupped); + if (CosmicTriggerGroupped) + Matching(45, 46); + else + Log("EBLAPPD: CosmicTriggerGroupped is false, no cosmic trigger groupped in the grouper, stop matching", v_message, verbosityEBLAPPD); + + bool LEDTriggerGroupped = false; + m_data->CStore.Get("LEDTriggerGroupped", LEDTriggerGroupped); + if (LEDTriggerGroupped) + Matching(31, 46); + else + Log("EBLAPPD: LEDTriggerGroupped is false, no LED trigger groupped in the grouper, stop matching", v_message, verbosityEBLAPPD); + + bool NuMITriggerGroupped = false; + m_data->CStore.Get("NuMITriggerGroupped", NuMITriggerGroupped); + if (NuMITriggerGroupped) + Matching(42, 46); + else + Log("EBLAPPD: NuMITriggerGroupped is false, no NuMI trigger groupped in the grouper, stop matching", v_message, verbosityEBLAPPD); + } + } + + // Set all matching info to CStore + m_data->CStore.Set("PairedLAPPDTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Set("PairedLAPPDTimeStamps", PairedLAPPDTimeStamps); + m_data->CStore.Set("PairedLAPPD_TriggerIndex", PairedLAPPD_TriggerIndex); + Log("EBLAPPD: Set pairing information to CStore, PairedLAPPDTimeStamps[14] size = " + std::to_string(PairedLAPPDTimeStamps[14].size()), v_message, verbosityEBLAPPD); + Log("EBLAPPD: Set pairing information to CStore, PairedLAPPDTimeStamps[47] size = " + std::to_string(PairedLAPPDTimeStamps[47].size()), v_message, verbosityEBLAPPD); + + // Set the indexing of buffer + m_data->CStore.Set("Buffer_LAPPDTimestamp_ns", Buffer_LAPPDTimestamp_ns); + + // Also set all buffers to CStore + m_data->CStore.Set("Buffer_LAPPDData", Buffer_LAPPDData); + m_data->CStore.Set("Buffer_LAPPDBeamgate_ns", Buffer_LAPPDBeamgate_ns); + m_data->CStore.Set("Buffer_LAPPDOffset", Buffer_LAPPDOffset); + m_data->CStore.Set("Buffer_LAPPDBeamgate_Raw", Buffer_LAPPDBeamgate_Raw); + m_data->CStore.Set("Buffer_LAPPDTimestamp_Raw", Buffer_LAPPDTimestamp_Raw); + m_data->CStore.Set("Buffer_LAPPDBGCorrection", Buffer_LAPPDBGCorrection); + m_data->CStore.Set("Buffer_LAPPDTSCorrection", Buffer_LAPPDTSCorrection); + m_data->CStore.Set("Buffer_LAPPDOffset_minus_ps", Buffer_LAPPDOffset_minus_ps); + m_data->CStore.Set("Buffer_LAPPDRunCode", Buffer_RunCode); + + m_data->CStore.Set("Buffer_LAPPDBG_PPSBefore", Buffer_LAPPDBG_PPSBefore); + m_data->CStore.Set("Buffer_LAPPDBG_PPSAfter", Buffer_LAPPDBG_PPSAfter); + m_data->CStore.Set("Buffer_LAPPDBG_PPSDiff", Buffer_LAPPDBG_PPSDiff); + m_data->CStore.Set("Buffer_LAPPDBG_PPSMissing", Buffer_LAPPDBG_PPSMissing); + m_data->CStore.Set("Buffer_LAPPDTS_PPSBefore", Buffer_LAPPDTS_PPSBefore); + m_data->CStore.Set("Buffer_LAPPDTS_PPSAfter", Buffer_LAPPDTS_PPSAfter); + m_data->CStore.Set("Buffer_LAPPDTS_PPSDiff", Buffer_LAPPDTS_PPSDiff); + m_data->CStore.Set("Buffer_LAPPDTS_PPSMissing", Buffer_LAPPDTS_PPSMissing); + + exeNum++; + + return true; +} + +bool EBLAPPD::Finalise() +{ + Log("\033[1;34mEBLAPPD: Finalising\033[0m", v_message, verbosityEBLAPPD); + Log("EBLAPPD: Matched LAPPD number = " + std::to_string(matchedLAPPDNumber), v_message, verbosityEBLAPPD); + Log("EBLAPPD: Unmatched LAPPD number = " + std::to_string(MatchBuffer_LAPPDTimestamp_ns.size()), v_message, verbosityEBLAPPD); + return true; +} + +bool EBLAPPD::CleanData() +{ + LAPPDBeamgate_ns = 0; + LAPPDTimestamp_ns = 0; + LAPPDOffset = 0; + LAPPDBeamgate_Raw = 0; + LAPPDTimestamp_Raw = 0; + LAPPDBGCorrection = 0; + LAPPDTSCorrection = 0; + LAPPDOffset_minus_ps = 0; + + LAPPDBG_PPSBefore = 0; + LAPPDBG_PPSAfter = 0; + LAPPDBG_PPSDiff = 0; + LAPPDBG_PPSMissing = 0; + LAPPDTS_PPSBefore = 0; + LAPPDTS_PPSAfter = 0; + LAPPDTS_PPSDiff = 0; + LAPPDTS_PPSMissing = 0; + + return true; +} + +bool EBLAPPD::LoadLAPPDData() +{ + // get the LAPPD beamgate + LAPPDBeamgate_Raw = 0; + LAPPDTimestamp_Raw = 0; + m_data->CStore.Get("LAPPDBeamgate_Raw", LAPPDBeamgate_Raw); + m_data->CStore.Get("LAPPDTimestamp_Raw", LAPPDTimestamp_Raw); + + LAPPDBeamgate_ns = LAPPDBeamgate_Raw * 3.125; + LAPPDTimestamp_ns = LAPPDTimestamp_Raw * 3.125; + + LAPPDBGCorrection = 0; + LAPPDTSCorrection = 0; + LAPPDOffset_minus_ps = 0; + m_data->CStore.Get("LAPPDBGCorrection", LAPPDBGCorrection); + m_data->CStore.Get("LAPPDTSCorrection", LAPPDTSCorrection); + m_data->CStore.Get("LAPPDOffset_minus_ps", LAPPDOffset_minus_ps); + LAPPDOffset = 0; + m_data->CStore.Get("LAPPDOffset", LAPPDOffset); + + LAPPDBeamgate_ns = LAPPDBeamgate_ns + LAPPDBGCorrection + LAPPDOffset; + LAPPDTimestamp_ns = LAPPDTimestamp_ns + LAPPDTSCorrection + LAPPDOffset; + + LAPPDBG_PPSBefore = 0; + LAPPDBG_PPSAfter = 0; + LAPPDBG_PPSDiff = 0; + LAPPDBG_PPSMissing = 0; + LAPPDTS_PPSBefore = 0; + LAPPDTS_PPSAfter = 0; + LAPPDTS_PPSDiff = 0; + LAPPDTS_PPSMissing = 0; + m_data->CStore.Get("BG_PPSBefore", LAPPDBG_PPSBefore); + m_data->CStore.Get("BG_PPSAfter", LAPPDBG_PPSAfter); + m_data->CStore.Get("BG_PPSDiff", LAPPDBG_PPSDiff); + m_data->CStore.Get("BG_PPSMissing", LAPPDBG_PPSMissing); + m_data->CStore.Get("TS_PPSBefore", LAPPDTS_PPSBefore); + m_data->CStore.Get("TS_PPSAfter", LAPPDTS_PPSAfter); + m_data->CStore.Get("TS_PPSDiff", LAPPDTS_PPSDiff); + m_data->CStore.Get("TS_PPSMissing", LAPPDTS_PPSMissing); + + if (verbosityEBLAPPD > 1) + { + cout << "Processing new LAPPD data from store" << endl; + cout << "Got info: LAPPDBeamgate_Raw: " << LAPPDBeamgate_Raw << ", LAPPDTimestamp_Raw: " << LAPPDTimestamp_Raw << ", LAPPDBGCorrection: " << LAPPDBGCorrection << ", LAPPDTSCorrection: " << LAPPDTSCorrection << ", LAPPDOffset: " << LAPPDOffset << ", LAPPDOffset_minus_ps: " << LAPPDOffset_minus_ps << ", LAPPDBG_PPSBefore: " << LAPPDBG_PPSBefore << ", LAPPDBG_PPSAfter: " << LAPPDBG_PPSAfter << ", LAPPDBG_PPSDiff: " << LAPPDBG_PPSDiff << ", LAPPDBG_PPSMissing: " << LAPPDBG_PPSMissing << ", LAPPDTS_PPSBefore: " << LAPPDTS_PPSBefore << ", LAPPDTS_PPSAfter: " << LAPPDTS_PPSAfter << ", LAPPDTS_PPSDiff: " << LAPPDTS_PPSDiff << ", LAPPDTS_PPSMissing: " << LAPPDTS_PPSMissing << endl; + cout << "LAPPDBeamgate_ns: " << LAPPDBeamgate_ns << endl; + cout << "LAPPDTimestamp_ns: " << LAPPDTimestamp_ns << endl; + } + + bool gotdata = m_data->CStore.Get("StoreLoadedLAPPDData", dat); + + if (gotdata) + { + Buffer_LAPPDTimestamp_ns.push_back(LAPPDTimestamp_ns); + + Buffer_LAPPDData.push_back(dat); + Buffer_LAPPDBeamgate_ns.push_back(LAPPDBeamgate_ns); + Buffer_LAPPDOffset.push_back(LAPPDOffset); + Buffer_LAPPDBeamgate_Raw.push_back(LAPPDBeamgate_Raw); + Buffer_LAPPDTimestamp_Raw.push_back(LAPPDTimestamp_Raw); + Buffer_LAPPDBGCorrection.push_back(LAPPDBGCorrection); + Buffer_LAPPDTSCorrection.push_back(LAPPDTSCorrection); + Buffer_LAPPDOffset_minus_ps.push_back(LAPPDOffset_minus_ps); + Buffer_RunCode.push_back(currentRunCode); + + Buffer_LAPPDBG_PPSBefore.push_back(LAPPDBG_PPSBefore); + Buffer_LAPPDBG_PPSAfter.push_back(LAPPDBG_PPSAfter); + Buffer_LAPPDBG_PPSDiff.push_back(LAPPDBG_PPSDiff); + Buffer_LAPPDBG_PPSMissing.push_back(LAPPDBG_PPSMissing); + Buffer_LAPPDTS_PPSBefore.push_back(LAPPDTS_PPSBefore); + Buffer_LAPPDTS_PPSAfter.push_back(LAPPDTS_PPSAfter); + Buffer_LAPPDTS_PPSDiff.push_back(LAPPDTS_PPSDiff); + Buffer_LAPPDTS_PPSMissing.push_back(LAPPDTS_PPSMissing); + + MatchBuffer_LAPPDTimestamp_ns.push_back(LAPPDTimestamp_ns); + + if (LAPPDTS_PPSMissing != LAPPDBG_PPSMissing) + Log("EBLAPPD: PPS missing in BG and TS are different, BG: " + std::to_string(LAPPDBG_PPSMissing) + ", TS: " + std::to_string(LAPPDTS_PPSMissing), v_warning, verbosityEBLAPPD); + + Log("EBLAPPD: Loaded LAPPD data to buffer, Buffer_LAPPDData size after this load is now " + std::to_string(Buffer_LAPPDData.size()), v_message, verbosityEBLAPPD); + } + + return true; +} + +bool EBLAPPD::Matching(int targetTrigger, int matchToTrack) +{ + cout << "\033[1;34m******* EBLAPPD : Matching *******\033[0m" << endl; + Log("EBLAPPD: Matching LAPPD data with target trigger " + std::to_string(targetTrigger) + " in track " + std::to_string(matchToTrack), v_message, verbosityEBLAPPD); + + std::map>> GroupedTriggersInTotal; // each map is a group of triggers, with the key is the target trigger word + m_data->CStore.Get("GroupedTriggersInTotal", GroupedTriggersInTotal); + // print how many trigger groups in each track + + vector matchedLAPPDTimes; + vector indexToRemove; + std::map matchedNumberInTrack; + + // loop the LAPPDDataBuffer keys, and loop all the grouped triggers + // in each group of trigger, find the target trigger word and it's time + // fine the minimum time difference, if smaller than matchTolerance_ns, then save the time to PairedCTCTimeStamps and PairedLAPPDTimeStamps + for (int i = 0; i < MatchBuffer_LAPPDTimestamp_ns.size(); i++) + { + uint64_t LAPPDtime = MatchBuffer_LAPPDTimestamp_ns.at(i); + // if found LAPPDtime at PairedLAPPDTimeStamps, skip //shouldn't happen + if (std::find(PairedLAPPDTimeStamps[matchToTrack].begin(), PairedLAPPDTimeStamps[matchToTrack].end(), LAPPDtime) != PairedLAPPDTimeStamps[matchToTrack].end()) + { + Log("EBLAPPD: Buffer " + std::to_string(i) + " with time " + std::to_string(Buffer_LAPPDTimestamp_ns.at(i)) + ": Found a match already", v_message, verbosityEBLAPPD); + continue; + } + + // set minDT to 5 min + uint64_t minDT = 5 * 60 * 1e9; + uint64_t minDTTrigger = 0; + uint64_t dt = 0; + uint32_t matchedTrigWord = 0; + int matchedTrack = 0; + int matchedIndex = 0; + + for (std::pair>> pair : GroupedTriggersInTotal) + { + int TrackTriggerWord = pair.first; + if (matchedNumberInTrack.find(TrackTriggerWord) == matchedNumberInTrack.end()) + matchedNumberInTrack.emplace(TrackTriggerWord, 0); + if (TrackTriggerWord != matchToTrack && !matchToAllTriggers) + { + // Log("EBLAPPD: Skipping TrackTriggerWord " + std::to_string(TrackTriggerWord), v_debug, verbosityEBLAPPD); + continue; + } + vector> GroupedTriggers = pair.second; + + for (int j = 0; j < GroupedTriggers.size(); j++) + { + map groupedTrigger = GroupedTriggers.at(j); + // itearte over all the grouped triggers, if the value is target trigger, then calculate the time difference + for (std::pair p : groupedTrigger) + { + if (matchToAllTriggers || p.second == targetTrigger) + { + + if (LAPPDtime > p.first) + { + dt = LAPPDtime - p.first; + } + else + { + dt = p.first - LAPPDtime; + } + if (dt < minDT) + { + minDT = dt; + minDTTrigger = p.first; + matchedTrigWord = p.second; + matchedTrack = TrackTriggerWord; + matchedIndex = j; + } + } + } + } + } + + Log("EBLAPPD: at buffer " + std::to_string(i) + " with time " + std::to_string(Buffer_LAPPDTimestamp_ns.at(i)) + ", minDT: " + std::to_string(minDT), v_debug, verbosityEBLAPPD); + if (minDT < matchTolerance_ns) + { + PairedCTCTimeStamps[matchedTrack].push_back(minDTTrigger); + PairedLAPPDTimeStamps[matchedTrack].push_back(LAPPDtime); + PairedLAPPD_TriggerIndex[matchedTrack].push_back(matchedIndex); + + matchedLAPPDTimes.push_back(LAPPDtime); + indexToRemove.push_back(i); + matchedLAPPDNumber++; + matchedNumberInTrack[matchedTrack]++; + Log("EBLAPPD: Buffer " + std::to_string(i) + " with time " + std::to_string(Buffer_LAPPDTimestamp_ns.at(i)) + ": Found a match for LAPPD data at " + std::to_string(LAPPDtime) + " with target trigger at " + std::to_string(minDTTrigger) + " with minDT " + std::to_string(minDT), v_message, verbosityEBLAPPD); + } + } + Log("EBLAPPD: Finished matching LAPPD data with target triggers, " + std::to_string(matchedLAPPDTimes.size()) + " new matched found, total matchedLAPPDNumber = " + std::to_string(matchedLAPPDNumber) + " in buffer size = " + std::to_string(MatchBuffer_LAPPDTimestamp_ns.size()), v_message, verbosityEBLAPPD); + + for (int i = indexToRemove.size() - 1; i >= 0; i--) + { + MatchBuffer_LAPPDTimestamp_ns.erase(MatchBuffer_LAPPDTimestamp_ns.begin() + indexToRemove.at(i)); + } + + Log("EBLAPPD: Finished removing paired LAPPD data from match buffer, MatchBuffer_LAPPDTimestamp_ns size is now " + std::to_string(MatchBuffer_LAPPDTimestamp_ns.size()), v_message, verbosityEBLAPPD); + // print all elements in matchedNumberInTrack with key and value + for (std::pair pair : matchedNumberInTrack) + { + Log("EBLAPPD: Match finished, matched number in Track " + std::to_string(pair.first) + " is = " + std::to_string(pair.second), v_message, verbosityEBLAPPD); + } + + return true; +} \ No newline at end of file diff --git a/UserTools/EBLAPPD/EBLAPPD.h b/UserTools/EBLAPPD/EBLAPPD.h new file mode 100644 index 000000000..a1dd6cfa3 --- /dev/null +++ b/UserTools/EBLAPPD/EBLAPPD.h @@ -0,0 +1,95 @@ +#ifndef EBLAPPD_H +#define EBLAPPD_H + +#include +#include + +#include "Tool.h" +#include "PsecData.h" +#include "BoostStore.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBLAPPD : public Tool +{ + +public: + EBLAPPD(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + bool LoadLAPPDData(); + bool CleanData(); + bool Matching(int targetTrigger, int matchToTrack); + +private: + int thisRunNum; + bool matchToAllTriggers; + int exePerMatch; + + PsecData dat; + uint64_t LAPPDBeamgate_ns; + uint64_t LAPPDTimestamp_ns; + uint64_t LAPPDOffset; + unsigned long LAPPDBeamgate_Raw; + unsigned long LAPPDTimestamp_Raw; + int LAPPDBGCorrection; + int LAPPDTSCorrection; + int LAPPDOffset_minus_ps; + uint64_t LAPPDBG_PPSBefore; + uint64_t LAPPDBG_PPSAfter; + uint64_t LAPPDBG_PPSDiff; + int LAPPDBG_PPSMissing; + uint64_t LAPPDTS_PPSBefore; + uint64_t LAPPDTS_PPSAfter; + uint64_t LAPPDTS_PPSDiff; + int LAPPDTS_PPSMissing; + + vector MatchBuffer_LAPPDTimestamp_ns; // used to indexing data for unmatched + + // TODO, maybe make a new "LAPPDBuildData" class? + vector Buffer_LAPPDTimestamp_ns; // used to indexing the data + vector Buffer_LAPPDData; + vector Buffer_LAPPDBeamgate_ns; + vector Buffer_LAPPDOffset; + vector Buffer_LAPPDBeamgate_Raw; + vector Buffer_LAPPDTimestamp_Raw; + vector Buffer_LAPPDBGCorrection; + vector Buffer_LAPPDTSCorrection; + vector Buffer_LAPPDOffset_minus_ps; + vector Buffer_RunCode; + vector Buffer_LAPPDBG_PPSBefore; + vector Buffer_LAPPDBG_PPSAfter; + vector Buffer_LAPPDBG_PPSDiff; + vector Buffer_LAPPDBG_PPSMissing; + vector Buffer_LAPPDTS_PPSBefore; + vector Buffer_LAPPDTS_PPSAfter; + vector Buffer_LAPPDTS_PPSDiff; + vector Buffer_LAPPDTS_PPSMissing; + + std::map> PairedCTCTimeStamps; + std::map> PairedLAPPD_TriggerIndex; + std::map> PairedLAPPDTimeStamps; + + int matchTargetTrigger; + uint64_t matchTolerance_ns; + int verbosityEBLAPPD; + + int matchedLAPPDNumber = 0; + int exeNum = 0; + int currentRunCode; + + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; +}; + +#endif diff --git a/UserTools/EBLAPPD/README.md b/UserTools/EBLAPPD/README.md new file mode 100644 index 000000000..c8b4796ae --- /dev/null +++ b/UserTools/EBLAPPD/README.md @@ -0,0 +1,35 @@ +# EBLAPPD + +EBLAPPD tool is a part of Event Building version 2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 + +EBLAPPD match the LAPPD beamgate + LAPPD offset to grouped trigger, and save the matching results to CStore for EBSaver. + +## Data + +**PairedCTCTimeStamps** +After matching, the matched trigger timestamp will be saved here. The key is the main trigger word for each run type. +Saved as PairedLAPPDTriggerTimestamp in CStore. + +**PairedLAPPDTimeStamps** +After matching, the matched LAPPD beamgate + offset will be saved here. The key is the main trigger word for each run type. +This and PairedCTCTimeStamps have the same index. A little bit dangerous, but overall works well. +Saved as PairedLAPPDTimeStamps in CStore + + +## Configuration + +**matchTargetTrigger** +This gives which trigger word that the LAPPD beamgate + offset should be matched to. + +**matchTolerance_ns** +This gives the maximum allowed time tolerance between the LAPPD beamgate + offset and the target trigger timestamp. + +**exePerMatch** +This gives how many loops need to be past for one matching between MLAPPD beamgate + offset and target trigger timestamps. +500 is generally fine with beam runs. + +**matchToAllTriggers** +1 or 0. 1 means match to all possible triggers, 0 means only match to the target trigger. + diff --git a/UserTools/EBLoadRaw/EBLoadRaw.cpp b/UserTools/EBLoadRaw/EBLoadRaw.cpp new file mode 100644 index 000000000..17685138d --- /dev/null +++ b/UserTools/EBLoadRaw/EBLoadRaw.cpp @@ -0,0 +1,685 @@ +#include "EBLoadRaw.h" + +EBLoadRaw::EBLoadRaw() : Tool() {} + +bool EBLoadRaw::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + m_variables.Get("verbosityEBLoadRaw", verbosityEBLoadRaw); + + ReadTriggerOverlap = false; + m_variables.Get("ReadTriggerOverlap", ReadTriggerOverlap); + m_variables.Get("InputFile", InputFile); + OrganizedFileList = OrganizeRunParts(InputFile); + + LoadCTC = false; + m_variables.Get("LoadCTC", LoadCTC); + LoadPMT = false; + m_variables.Get("LoadPMT", LoadPMT); + LoadMRD = false; + m_variables.Get("LoadMRD", LoadMRD); + LoadLAPPD = false; + m_variables.Get("LoadLAPPD", LoadLAPPD); + + FileCompleted = false; + JumpBecauseLAPPD = false; + ProcessingComplete = false; + PMTPaused = false; + MRDPaused = false; + LAPPDPaused = false; + CTCPaused = false; + usingTriggerOverlap = false; + LoadingFileNumber = 0; + + RunNumber = 0; + SubRunNumber = 0; + PartFileNumber = 0; + + CTCEntryNum = 0; + PMTEntryNum = 0; + MRDEntryNum = 0; + LAPPDEntryNum = 0; + + PMTTotalEntries = 0; + MRDTotalEntries = 0; + LAPPDTotalEntries = 0; + CTCTotalEntries = 0; + PMTEntriesCompleted = false; + MRDEntriesCompleted = false; + LAPPDEntriesCompleted = false; + CTCEntriesCompleted = false; + LoadedPMTTotalEntries = 0; + LoadedMRDTotalEntries = 0; + LoadedLAPPDTotalEntries = 0; + LoadedCTCTotalEntries = 0; + + RawData = new BoostStore(false, 0); + PMTData = new BoostStore(false, 2); + MRDData = new BoostStore(false, 2); + LAPPDData = new BoostStore(false, 2); + CTCData = new BoostStore(false, 2); + CData = new std::vector; + TData = new TriggerData; + MData = new MRDOut; + LData = new PsecData; + + m_data->CStore.Set("FileProcessingComplete", false); + RunCodeToSave = 0; + + return true; +} + +bool EBLoadRaw::Execute() +{ + m_data->CStore.Set("NewRawDataEntryAccessed", false); + m_data->CStore.Set("NewRawDataFileAccessed", false); + m_data->CStore.Set("SaveProcessedFile", false); + + ProcessingComplete = false; + if (FileCompleted) + { + if (CurrentFile != "NONE") + { + RunCodeToSave = RunCode(CurrentFile); + m_data->CStore.Set("RunCodeToSave", RunCodeToSave); + m_data->CStore.Set("SaveProcessedFile", true); + Log("EBLoadRaw: File completed, saving file " + CurrentFile + " with RunCode: " + std::to_string(RunCodeToSave), v_message, verbosityEBLoadRaw); + } + ProcessingComplete = LoadNewFile(); + } + + if (ProcessingComplete) + { + RunCodeToSave = RunCode(CurrentFile); + m_data->CStore.Set("RunCodeToSave", RunCodeToSave); + m_data->CStore.Set("SaveProcessedFile", true); + m_data->CStore.Set("SaveEverything", true); + Log("EBLoadRaw: File completed, saving file " + CurrentFile + " with RunCode: " + std::to_string(RunCodeToSave), v_message, verbosityEBLoadRaw); + + m_data->CStore.Set("FileProcessingComplete", true); + m_data->vars.Set("StopLoop", 1); + Log("EBLoadRaw: All files have been processed, set pause flags, PMT: " + std::to_string(PMTPaused) + ", MRD: " + std::to_string(MRDPaused) + ", CTC: " + std::to_string(CTCPaused) + ", LAPPD: " + std::to_string(LAPPDPaused), v_message, verbosityEBLoadRaw); + return true; + } + + m_data->CStore.Get("PauseTankDecoding", PMTPaused); + m_data->CStore.Get("PauseMRDDecoding", MRDPaused); + m_data->CStore.Get("PauseCTCDecoding", CTCPaused); + m_data->CStore.Get("PauseLAPPDDecoding", LAPPDPaused); + + if (OrganizedFileList.size() == 0) + { + Log("EBLoadRaw: No files to process.", v_warning, verbosityEBLoadRaw); + m_data->vars.Set("StopLoop", 1); + return true; + } + if (FileCompleted || CurrentFile == "NONE") + { + Log("EBLoadRaw: Loading new file. " + OrganizedFileList.at(LoadingFileNumber), v_message, verbosityEBLoadRaw); + CurrentFile = OrganizedFileList.at(LoadingFileNumber); + RawData->Initialise(CurrentFile.c_str()); + Log("EBLoadRaw: File loaded.", v_message, verbosityEBLoadRaw); + m_data->CStore.Set("NewRawDataFileAccessed", true); + if (verbosityEBLoadRaw > 4) + RawData->Print(false); + LoadRunInfo(); + LoadPMTData(); + LoadMRDData(); + LoadCTCData(); + LoadLAPPDData(); + } + else + { + Log("EBLoadRaw: Loading next entry of current file " + CurrentFile, v_message, verbosityEBLoadRaw); + } + + FileCompleted = false; + if (JumpBecauseLAPPD) + { + FileCompleted = true; + JumpBecauseLAPPD = false; + Log("EBLoadRaw: Jumping to next file due to LAPPD data.", v_message, verbosityEBLoadRaw); + return true; + } + + // if more MRD events than VME PMT events, jump to next file + // this is an old option, why? + if (MRDTotalEntries > PMTTotalEntries) + { + // FileCompleted = true; + Log("EBLoadRaw: Jumping to next file due to MRD entry is more than PMT entry.", v_message, verbosityEBLoadRaw); + // return true; + } + + if (LoadPMT && PMTEntryNum == PMTTotalEntries) + { + Log("EBLoadRaw: ALL PMT entries Loaded.", v_message, verbosityEBLoadRaw); + PMTEntriesCompleted = true; + PMTPaused = true; + } + if (LoadMRD && MRDEntryNum == MRDTotalEntries) + { + Log("EBLoadRaw: ALL MRD entries Loaded.", v_message, verbosityEBLoadRaw); + MRDEntriesCompleted = true; + MRDPaused = true; + } + if (LoadCTC && CTCEntryNum == CTCTotalEntries) + { + Log("EBLoadRaw: ALL CTC entries Loaded.", v_message, verbosityEBLoadRaw); + CTCEntriesCompleted = true; + CTCPaused = true; + } + if (LoadLAPPD && LAPPDEntryNum == LAPPDTotalEntries) + { + Log("EBLoadRaw: ALL LAPPD entries Loaded.", v_message, verbosityEBLoadRaw); + LAPPDEntriesCompleted = true; + LAPPDPaused = true; + } + + if (LoadLAPPD && LAPPDTotalEntries < 0) + LAPPDEntriesCompleted = true; + + m_data->CStore.Set("PauseTankDecoding", PMTPaused); + m_data->CStore.Set("PauseMRDDecoding", MRDPaused); + m_data->CStore.Set("PauseCTCDecoding", CTCPaused); + m_data->CStore.Set("PauseLAPPDDecoding", LAPPDPaused); + + Log("EBLoadRaw: Set pause flags, PMT: " + std::to_string(PMTPaused) + ", MRD: " + std::to_string(MRDPaused) + ", CTC: " + std::to_string(CTCPaused) + ", LAPPD: " + std::to_string(LAPPDPaused), v_message, verbosityEBLoadRaw); + + if (LoadPMT && !PMTPaused && !PMTEntriesCompleted) + LoadNextPMTData(); + if (LoadMRD && !MRDPaused && !MRDEntriesCompleted) + LoadNextMRDData(); + if (LoadCTC && !CTCPaused && !CTCEntriesCompleted) + LoadNextCTCData(); + if (LoadLAPPD && !LAPPDPaused && !LAPPDEntriesCompleted) + LoadNextLAPPDData(); + + // if all required data is loaded, set filecompleted flag to true + if ((!LoadPMT || PMTEntriesCompleted) && (!LoadMRD || MRDEntriesCompleted) && (!LoadCTC || CTCEntriesCompleted) && (!LoadLAPPD || LAPPDEntriesCompleted)) + { + FileCompleted = true; + Log("EBLoadRaw: All data loaded.", v_message, verbosityEBLoadRaw); + } + + if (verbosityEBLoadRaw > v_message) + { + std::cout << "**************************************************EBLoadRaw: Current progress after execute: " << std::endl; + std::cout << "EBLoadRaw: Current file: " << CurrentFile << std::endl; + if (LoadPMT) + std::cout << "EBLoadRaw: PMT entries: " << PMTEntryNum << " / " << PMTTotalEntries << " = " << static_cast(PMTEntryNum) / static_cast(PMTTotalEntries) * 100 << "%" << std::endl; + if (LoadMRD) + std::cout << "EBLoadRaw: MRD entries: " << MRDEntryNum << " / " << MRDTotalEntries << " = " << static_cast(MRDEntryNum) / static_cast(MRDTotalEntries) * 100 << "%" << std::endl; + if (LoadCTC) + std::cout << "EBLoadRaw: CTC entries: " << CTCEntryNum << " / " << CTCTotalEntries << " = " << static_cast(CTCEntryNum) / static_cast(CTCTotalEntries) * 100 << "%" << std::endl; + if (LoadLAPPD) + std::cout << "EBLoadRaw: LAPPD entries: " << LAPPDEntryNum << " / " << LAPPDTotalEntries << " = " << static_cast(LAPPDEntryNum) / static_cast(LAPPDTotalEntries) * 100 << "%" << std::endl; + std::cout << "**********************************************************************************************" << std::endl; + } + + m_data->CStore.Set("MRDEntriesCompleted", MRDEntriesCompleted); + m_data->CStore.Set("PMTEntriesCompleted", PMTEntriesCompleted); + m_data->CStore.Set("CTCEntriesCompleted", CTCEntriesCompleted); + m_data->CStore.Set("LAPPDEntriesCompleted", LAPPDEntriesCompleted); + Log("EBLoadRaw: Set entries completed flags, PMT: " + std::to_string(PMTEntriesCompleted) + ", MRD: " + std::to_string(MRDEntriesCompleted) + ", CTC: " + std::to_string(CTCEntriesCompleted) + ", LAPPD: " + std::to_string(LAPPDEntriesCompleted), v_message, verbosityEBLoadRaw); + + m_data->CStore.Set("NewRawDataEntryAccessed", true); + m_data->CStore.Set("FileCompleted", FileCompleted); + + Log("EBLoadRaw: Finished execution loop.", v_message, verbosityEBLoadRaw); + return true; +} + +bool EBLoadRaw::Finalise() +{ + RawData->Close(); + RawData->Delete(); + delete RawData; + if (LoadPMT) + { + PMTData->Close(); + PMTData->Delete(); + delete PMTData; + } + if (LoadMRD) + { + MRDData->Close(); + MRDData->Delete(); + delete MRDData; + } + if (LoadLAPPD) + { + LAPPDData->Close(); + LAPPDData->Delete(); + delete LAPPDData; + } + if (LoadCTC) + { + CTCData->Close(); + CTCData->Delete(); + delete CTCData; + } + + std::cout << "\033[1;34mEBLoadRaw: Finalising EBLoadRaw\033[0m" << std::endl; + std::cout << "EBLoadRaw: Loaded " << OrganizedFileList.size() << " files " + << " from " << OrganizedFileList.at(0) << " to " << OrganizedFileList.at(OrganizedFileList.size() - 1) << std::endl; + std::cout << "EBLoadRaw: Loaded " << LoadedPMTTotalEntries << " PMT entries. " << std::endl; + std::cout << "EBLoadRaw: Loaded " << LoadedMRDTotalEntries << " MRD entries. " << std::endl; + std::cout << "EBLoadRaw: Loaded " << LoadedCTCTotalEntries << " CTC entries. " << std::endl; + std::cout << "EBLoadRaw: Loaded " << LoadedLAPPDTotalEntries << " LAPPD entries. " << std::endl; + + return true; +} + +std::vector EBLoadRaw::OrganizeRunParts(std::string FileList) +{ + std::vector OrganizedFiles; + std::vector UnorganizedFileList; + std::vector RunCodes; + int ThisRunCode; + // First, parse the lines and get all files. + std::string line; + ifstream myfile(FileList.c_str()); + if (myfile.is_open()) + { + std::cout << "Lines in FileList being printed" << std::endl; // has our stuff; + while (getline(myfile, line)) + { + if (line.find("#") != std::string::npos) + continue; + std::string filename = line; + int RunCodeNumber = RunCode(filename); + + if (RunCodeNumber != -9999) + { + UnorganizedFileList.push_back(filename); + RunCodes.push_back(RunCodeNumber); + } + + } // End parsing each line in file + + // Now, organize files based on the part number array + std::vector> SortingVector; + for (int i = 0; i < (int)UnorganizedFileList.size(); i++) + { + SortingVector.push_back(std::make_pair(RunCodes.at(i), UnorganizedFileList.at(i))); + } + std::sort(SortingVector.begin(), SortingVector.end()); + for (int j = 0; j < (int)SortingVector.size(); j++) + { + OrganizedFiles.push_back(SortingVector.at(j).second); + } + } + // print the OrganizedFiles + for (int i = 0; i < (int)OrganizedFiles.size(); i++) + { + std::cout << OrganizedFiles.at(i) << std::endl; + } + + return OrganizedFiles; +} + +int EBLoadRaw::RunCode(string fileName) +{ + // extract run number and file number from filename + std::regex runNumber_regex("RAWDataR(\\d{4})"); + std::regex subrunNumber_regex("S(\\d{1,4})p"); + std::regex rawFileNumber_regex("p(\\d{1,4})$"); + std::smatch match; + int runNumber = -9999; + int subrunNumber = -9999; + int rawFileNumber = -9999; + bool allmatched = false; + if (std::regex_search(fileName, match, runNumber_regex) && match.size() > 1) + { + runNumber = std::stoi(match.str(1)); + if (verbosityEBLoadRaw > 0) + std::cout << "runNumber: " << runNumber << std::endl; + m_data->CStore.Set("runNumber", runNumber); + allmatched = true; + } + else + { + std::cout << "runNumber not found" << std::endl; + m_data->CStore.Set("rawFileNumber", -9999); + } + + if (std::regex_search(fileName, match, subrunNumber_regex) && match.size() > 1) + { + subrunNumber = std::stoi(match.str(1)); + if (verbosityEBLoadRaw > 0) + std::cout << "subrunNumber: " << subrunNumber << std::endl; + m_data->CStore.Set("subrunNumber", subrunNumber); + allmatched = true; + } + else + { + std::cout << "subrunNumber not found" << std::endl; + m_data->CStore.Set("subrunNumber", -9999); + } + + if (std::regex_search(fileName, match, rawFileNumber_regex) && match.size() > 1) + { + rawFileNumber = std::stoi(match.str(1)); + if (verbosityEBLoadRaw > 0) + std::cout << "rawFileNumber: " << rawFileNumber << std::endl; + m_data->CStore.Set("rawFileNumber", rawFileNumber); + allmatched = true; + } + else + { + std::cout << "rawFileNumber not found" << std::endl; + m_data->CStore.Set("runNumber", -9999); + } + + if (allmatched == true) + { + int runcode = runNumber * 100000 + ((subrunNumber + 1) * 10000) + rawFileNumber; + cout << "EBLoadRaw: RunCode: " << runcode << endl; + return runcode; + } + else + { + return -9999; + } +} + +bool EBLoadRaw::LoadRunInfo() +{ + int runCode = RunCode(CurrentFile); + Log("EBLoadRaw: Loading run information, RunCode: " + std::to_string(runCode), v_message, verbosityEBLoadRaw); + + RunNumber = runCode / 100000; + SubRunNumber = (runCode % 100000) / 10000 - 1; + PartFileNumber = runCode % 10000; + + Store Postgress; + + std::cout << "EBLoadRaw: loading run information, RunNumber: " << RunNumber << ", SubRunNumber: " << SubRunNumber << ", PartFileNumber: " << PartFileNumber << std::endl; + + Postgress.Set("RunNumber", RunNumber); + Postgress.Set("SubRunNumber", SubRunNumber); + Postgress.Set("PartFileNumber", PartFileNumber); + Postgress.Set("RunType", -1); + Postgress.Set("StartTime", -1); + + m_data->CStore.Set("RunInfoPostgress", Postgress); + + m_data->CStore.Set("RunNumber", RunNumber); + m_data->CStore.Set("SubRunNumber", SubRunNumber); + m_data->CStore.Set("PartFileNumber", PartFileNumber); + m_data->CStore.Set("RunCode", runCode); + + return true; +} + +// load new file and it's related boost store +bool EBLoadRaw::LoadNewFile() +{ + bool EndOfProcessing = false; + LoadingFileNumber++; + + RawData->Close(); + RawData->Delete(); + delete RawData; + RawData = new BoostStore(false, 0); + PMTData->Close(); + PMTData->Delete(); + delete PMTData; + PMTData = new BoostStore(false, 2); + MRDData->Close(); + MRDData->Delete(); + delete MRDData; + MRDData = new BoostStore(false, 2); + LAPPDData->Close(); + LAPPDData->Delete(); + delete LAPPDData; + LAPPDData = new BoostStore(false, 2); + CTCData->Close(); + CTCData->Delete(); + delete CTCData; + CTCData = new BoostStore(false, 2); + + PMTEntryNum = 0; + MRDEntryNum = 0; + LAPPDEntryNum = 0; + CTCEntryNum = 0; + + PMTEntriesCompleted = false; + MRDEntriesCompleted = false; + LAPPDEntriesCompleted = false; + CTCEntriesCompleted = false; + + m_data->CStore.Set("PauseTankDecoding", false); + m_data->CStore.Set("PauseMRDDecoding", false); + m_data->CStore.Set("PauseCTCDecoding", false); + m_data->CStore.Set("PauseLAPPDDecoding", false); + + if (LoadingFileNumber == OrganizedFileList.size()) + { + EndOfProcessing = true; + m_data->CStore.Set("PauseTankDecoding", true); + m_data->CStore.Set("PauseMRDDecoding", true); + m_data->CStore.Set("PauseCTCDecoding", true); + m_data->CStore.Set("PauseLAPPDDecoding", true); + } + + return EndOfProcessing; +} + +bool EBLoadRaw::LoadPMTData() +{ + Log("EBLoadRaw: Loading PMTData.", v_message, verbosityEBLoadRaw); + RawData->Get("PMTData", *PMTData); + PMTData->Header->Get("TotalEntries", PMTTotalEntries); + LoadedPMTTotalEntries += PMTTotalEntries; + Log("EBLoadRaw: PMTData loaded, TotalEntries: " + std::to_string(PMTTotalEntries), v_message, verbosityEBLoadRaw); + + if (verbosityEBLoadRaw > 3) + PMTData->Print(false); + if (verbosityEBLoadRaw > 3) + PMTData->Header->Print(false); + return true; +} + +bool EBLoadRaw::LoadMRDData() +{ + Log("EBLoadRaw: Loading MRDData.", v_message, verbosityEBLoadRaw); + RawData->Get("CCData", *MRDData); + MRDData->Header->Get("TotalEntries", MRDTotalEntries); + LoadedMRDTotalEntries += MRDTotalEntries; + Log("EBLoadRaw: MRDData loaded, TotalEntries: " + std::to_string(MRDTotalEntries), v_message, verbosityEBLoadRaw); + if (verbosityEBLoadRaw > 3) + MRDData->Print(false); + return true; +} + +bool EBLoadRaw::LoadCTCData() +{ + Log("EBLoadRaw: Loading CTCData.", v_message, verbosityEBLoadRaw); + RawData->Get("TrigData", *CTCData); + if (verbosityEBLoadRaw > 3) + CTCData->Print(false); + CTCData->Header->Get("TotalEntries", CTCTotalEntries); + LoadedCTCTotalEntries += CTCTotalEntries; + if (verbosityEBLoadRaw > 3) + CTCData->Header->Print(false); + if (ReadTriggerOverlap) + { + std::stringstream ss_trigoverlap; + ss_trigoverlap << "TrigOverlap_R" << RunNumber << "S" << SubRunNumber << "p" << PartFileNumber; + std::cout << "EBLoadRaw: Loading Trigger Overlap data: " << ss_trigoverlap.str() << std::endl; + BoostStore TrigOverlapStore; + bool store_exist = TrigOverlapStore.Initialise(ss_trigoverlap.str().c_str()); + std::cout << "EBLoadRaw: Trigger Overlap store exist: " << store_exist << std::endl; + if (store_exist) + { + CTCTotalEntries++; + std::cout << "EBLoadRaw: total trigger entry with overlap is: " << CTCTotalEntries << std::endl; + } + } + return true; +} + +bool EBLoadRaw::LoadLAPPDData() +{ + Log("EBLoadRaw: Loading LAPPDData.", v_message, verbosityEBLoadRaw); + try + { + RawData->Get("LAPPDData", *LAPPDData); + LAPPDData->Header->Get("TotalEntries", LAPPDTotalEntries); + Log("EBLoadRaw: LAPPDData loaded, TotalEntries: " + std::to_string(LAPPDTotalEntries), v_message, verbosityEBLoadRaw); + if (verbosityEBLoadRaw > 3) + { + LAPPDData->Print(false); + LAPPDData->Header->Print(false); + } + if (LAPPDTotalEntries < 0) + { + + cout << "EBLoadRaw: LAPPDData entry < 0, found " << LAPPDTotalEntries << ", set to 0" << endl; + LAPPDTotalEntries = 0; + LAPPDEntriesCompleted = true; + } + else if (LAPPDTotalEntries > 100000) + { + cout << "EBLoadRaw: LAPPDData entry very large, found " << LAPPDTotalEntries << ", return and set jump because LAPPD = true" << endl; + JumpBecauseLAPPD = true; + return true; + } + LoadedLAPPDTotalEntries += LAPPDTotalEntries; + } + catch (std::exception &e) + { + std::cout << "EBLoadRaw: LAPPDData not found in file." << std::endl; + LAPPDTotalEntries = 0; + LAPPDEntriesCompleted = true; + } + Log("EBLoadRaw: LAPPDData has " + std::to_string(LAPPDTotalEntries) + " entries.", v_message, verbosityEBLoadRaw); + return true; +} + +// load next entry of the current file +bool EBLoadRaw::LoadNextPMTData() +{ + Log("EBLoadRaw: Loading next PMTData entry " + std::to_string(PMTEntryNum) + " of " + std::to_string(PMTTotalEntries), v_warning, verbosityEBLoadRaw); + PMTData->GetEntry(PMTEntryNum); + Log("EBLoadRaw: Getting the PMT card data entry", v_warning, verbosityEBLoadRaw); + PMTData->Get("CardData", *CData); + Log("EBLoadRaw: Setting into CStore", v_warning, verbosityEBLoadRaw); + m_data->CStore.Set("CardData", CData); + Log("EBLoadRaw: Setting PMT entry num to CStore", v_warning, verbosityEBLoadRaw); + m_data->CStore.Set("TankEntryNum", PMTEntryNum); + PMTEntryNum++; + + if (PMTEntryNum == PMTTotalEntries) + { + // force the PMT matching when all PMT entries are completed or PMTEntryNum is greater than PMTTotalEntries + Log("EBLoadRaw: PMTEntriesCompleted, force PMT matching", v_message, verbosityEBLoadRaw); + bool ForcePMTMatching = true; + m_data->CStore.Set("ForcePMTMatching", ForcePMTMatching); + } + else + { + bool ForcePMTMatching = false; + m_data->CStore.Set("ForcePMTMatching", ForcePMTMatching); + } + + return true; +} + +bool EBLoadRaw::LoadNextMRDData() +{ + Log("EBLoadRaw: Loading next MRDData entry " + std::to_string(MRDEntryNum) + " of " + std::to_string(MRDTotalEntries), v_warning, verbosityEBLoadRaw); + MRDData->GetEntry(MRDEntryNum); + MRDData->Get("Data", *MData); + m_data->CStore.Set("MRDData", MData, true); + m_data->CStore.Set("MRDEntryNum", MRDEntryNum); + MRDEntryNum++; + + if (MRDEntryNum == MRDTotalEntries) + { + Log("EBLoadRaw: MRDEntriesCompleted, force MRD matching", v_message, verbosityEBLoadRaw); + bool ForceMRDMatching = true; + m_data->CStore.Set("ForceMRDMatching", ForceMRDMatching); + } + else + { + bool ForceMRDMatching = false; + m_data->CStore.Set("ForceMRDMatching", ForceMRDMatching); + } + + return true; +} + +bool EBLoadRaw::LoadNextLAPPDData() +{ + Log("EBLoadRaw: Loading next LAPPDData entry " + std::to_string(LAPPDEntryNum) + " of " + std::to_string(LAPPDTotalEntries), v_warning, verbosityEBLoadRaw); + LAPPDData->GetEntry(LAPPDEntryNum); + LAPPDData->Get("LAPPDData", *LData); + m_data->CStore.Set("LAPPDData", LData); + m_data->CStore.Set("LAPPDEntryNum", LAPPDEntryNum); + m_data->CStore.Set("LAPPDanaData", true); + LAPPDEntryNum++; + + if (LAPPDEntryNum == LAPPDTotalEntries) + { + Log("EBLoadRaw: LAPPDEntriesCompleted, force LAPPD matching", v_message, verbosityEBLoadRaw); + bool ForceLAPPDMatching = true; + m_data->CStore.Set("ForceLAPPDMatching", ForceLAPPDMatching); + } + else + { + bool ForceLAPPDMatching = false; + m_data->CStore.Set("ForceLAPPDMatching", ForceLAPPDMatching); + } + + return true; +} + +bool EBLoadRaw::LoadNextCTCData() +{ + Log("EBLoadRaw: Loading next CTCData entry " + std::to_string(CTCEntryNum) + " of " + std::to_string(CTCTotalEntries), v_warning, verbosityEBLoadRaw); + if (!ReadTriggerOverlap) + { + CTCData->GetEntry(CTCEntryNum); + CTCData->Get("TrigData", *TData); + Log("EBLoadRaw: Loaded CTCData entry " + std::to_string(CTCEntryNum), v_warning, verbosityEBLoadRaw); + } + else + { + if (CTCEntryNum != CTCTotalEntries - 1) + { + CTCData->GetEntry(CTCEntryNum); + CTCData->Get("TrigData", *TData); + m_data->CStore.Set("usingTriggerOverlap", false); + Log("EBLoadRaw: Loaded CTCData entry " + std::to_string(CTCEntryNum), v_warning, verbosityEBLoadRaw); + } + else + { + BoostStore TrigOverlapStore; + std::stringstream ss_trigoverlap; + ss_trigoverlap << "TrigOverlap_R" << RunNumber << "S" << SubRunNumber << "p" << PartFileNumber; + bool got_trig_o = TrigOverlapStore.Initialise(ss_trigoverlap.str().c_str()); + if (got_trig_o) + { + TrigOverlapStore.Get("TrigData", *TData); + m_data->CStore.Set("usingTriggerOverlap", true); + } + else + std::cout << "EBLoadRaw: Trigger Overlap data not found while loading" << std::endl; + } + m_data->CStore.Set("TrigData", TData); + + Log("EBLoadRaw: Loaded CTCData entry " + std::to_string(CTCEntryNum), v_warning, verbosityEBLoadRaw); + CTCEntryNum++; + } + return true; +} diff --git a/UserTools/EBLoadRaw/EBLoadRaw.h b/UserTools/EBLoadRaw/EBLoadRaw.h new file mode 100644 index 000000000..4d5059b53 --- /dev/null +++ b/UserTools/EBLoadRaw/EBLoadRaw.h @@ -0,0 +1,112 @@ +#ifndef EBLoadRaw_H +#define EBLoadRaw_H + +#include +#include + +#include "Tool.h" +#include "CardData.h" +#include "TriggerData.h" +#include "PsecData.h" +#include "BoostStore.h" +#include "Store.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBLoadRaw : public Tool +{ + +public: + EBLoadRaw(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + + bool LoadPMTData(); + bool LoadMRDData(); + bool LoadLAPPDData(); + bool LoadCTCData(); + bool LoadRunInfo(); + + bool LoadNextPMTData(); + bool LoadNextMRDData(); + bool LoadNextLAPPDData(); + bool LoadNextCTCData(); + + bool LoadNewFile(); + int RunCode(string fileName); + std::vector OrganizeRunParts(std::string FileList); + +private: + std::string CurrentFile = "NONE"; + std::string InputFile; + std::vector OrganizedFileList; + bool ReadTriggerOverlap; + int RunCodeToSave; + + bool LoadCTC; + bool LoadPMT; + bool LoadMRD; + bool LoadLAPPD; + + int PMTTotalEntries; + int MRDTotalEntries; + int LAPPDTotalEntries; + int CTCTotalEntries; + + int LoadedPMTTotalEntries; + int LoadedMRDTotalEntries; + int LoadedLAPPDTotalEntries; + int LoadedCTCTotalEntries; + + bool ProcessingComplete; + bool FileCompleted; + bool JumpBecauseLAPPD; + bool PMTEntriesCompleted; + bool MRDEntriesCompleted; + bool LAPPDEntriesCompleted; + bool CTCEntriesCompleted; + bool usingTriggerOverlap; + + int CTCEntryNum; + int PMTEntryNum; + int MRDEntryNum; + int LAPPDEntryNum; + int LoadingFileNumber; + + int RunNumber; + int SubRunNumber; + int PartFileNumber; + + bool PMTPaused; + bool MRDPaused; + bool LAPPDPaused; + bool CTCPaused; + + BoostStore *RawData = nullptr; + BoostStore *PMTData = nullptr; + BoostStore *MRDData = nullptr; + BoostStore *LAPPDData = nullptr; + BoostStore *CTCData = nullptr; + + std::vector *CData = nullptr; + TriggerData *TData = nullptr; + MRDOut *MData = nullptr; + PsecData *LData = nullptr; + + int verbosityEBLoadRaw; + + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; +}; + +#endif diff --git a/UserTools/EBLoadRaw/README.md b/UserTools/EBLoadRaw/README.md new file mode 100644 index 000000000..957f68e36 --- /dev/null +++ b/UserTools/EBLoadRaw/README.md @@ -0,0 +1,20 @@ +# EBLoadRaw + +EBLoadRaw tool is a part of Event Building version 2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 +It basically follows the logic of LoadRawData, but reorganized to a different format and abort the BuileType option. If you need to load PMT and CTC data flow, just choose LoadCTC = true and LoadPMT = true, and use false for others. + +## Data + +need a list of raw part file as input, set the loaded entry to CStore. +Check Load*Data functions for each data flow. + +## Configuration + +**InputFile** is the name of txt file which has the raw part file list in it. +**ReadTriggerOverlap** will control load the overlap file or not. It's necessary for beam runs, not really necessary for source runs because lost a few events is not unacceptable for source run. + +**LoadCTC, LoadPMT, LoadMRD, LoadLAPPD** These tells the tool to load the data flow or not. Usually true for all of them. + + diff --git a/UserTools/EBMRD/EBMRD.cpp b/UserTools/EBMRD/EBMRD.cpp new file mode 100644 index 000000000..a687fc4ac --- /dev/null +++ b/UserTools/EBMRD/EBMRD.cpp @@ -0,0 +1,244 @@ +#include "EBMRD.h" + +EBMRD::EBMRD() : Tool() {} + +bool EBMRD::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("verbosityEBMRD", verbosityEBMRD); + matchTargetTrigger = 8; + m_variables.Get("matchTargetTrigger", matchTargetTrigger); + matchTolerance_ns = 2000000; // default 2ms + m_variables.Get("matchTolerance_ns", matchTolerance_ns); + exePerMatch = 500; + m_variables.Get("exePerMatch", exePerMatch); + matchToAllTriggers = 0; + m_variables.Get("matchToAllTriggers", matchToAllTriggers); + + matchedMRDNumber = 0; + ForceMRDMatched = false; + + return true; +} + +bool EBMRD::Execute() +{ + m_data->CStore.Get("RunCode", currentRunCode); + + m_data->CStore.Get("MRDEvents", MRDEvents); + m_data->CStore.Get("MRDEventTriggerTypes", MRDEventTriggerTypes); + m_data->CStore.Get("MRDBeamLoopback", MRDBeamLoopback); + m_data->CStore.Get("MRDCosmicLoopback", MRDCosmicLoopback); + m_data->CStore.Get("NewMRDDataAvailable", NewMRDDataAvailable); + + m_data->CStore.Get("PairedMRDTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Get("PairedMRDTimeStamps", PairedMRDTimeStamps); + + Log("EBMRD: NewMRDDataAvailable = " + std::to_string(NewMRDDataAvailable) + ", Current loaded MRDEvents size is " + std::to_string(MRDEvents.size()), v_message, verbosityEBMRD); + Log("EBMRD: Current buffer size is " + std::to_string(MRDEventsBuffer.size()), v_message, verbosityEBMRD); + // loop the MRDEvents, save every event to MRDEventsBuffer if it's not already in the buffer + int newLoadedEvents = 0; + for (std::pair>> p : MRDEvents) + { + uint64_t MTCtime = p.first; + std::vector> WaveMap = p.second; + // if find the MTCtime in the PairedMRDTimeStamps, then skip + if (PairedMRDTimeStamps.size() > 0) + { + bool skip = false; + for (std::pair> pair : PairedMRDTimeStamps) + { + for (uint64_t t : pair.second) + { + if (t == MTCtime) + { + skip = true; + break; + } + } + if (skip) + break; + } + if (skip) + continue; + } + if (MRDEventsBuffer.find(MTCtime) == MRDEventsBuffer.end()) + { + MRDEventsBuffer.emplace(MTCtime, WaveMap); + newLoadedEvents++; + } + } + Log("EBMRD: Finished loading MRDEvents to buffer, Buffer_MRDEvents size is now " + std::to_string(MRDEventsBuffer.size()) + " new loaded events = " + std::to_string(newLoadedEvents), v_message, verbosityEBMRD); + + bool stopLoop = false; + m_data->vars.Get("StopLoop", stopLoop); + int runNum = thisRunNum; + m_data->vars.Get("RunNumber", thisRunNum); + bool ForceMRDMatching = false; + m_data->CStore.Get("ForceMRDMatching", ForceMRDMatching); + if(!ForceMRDMatching) + ForceMRDMatched = false; + + if (exeNum % exePerMatch == 0 || runNum != thisRunNum || stopLoop || (ForceMRDMatching && !ForceMRDMatched)) + { + if (ForceMRDMatching) + { + if (!ForceMRDMatched) + ForceMRDMatched = true; + } + Log("EBMRD: exeNum = " + std::to_string(exeNum) + ". Doing matching now", v_message, verbosityEBMRD); + if (matchToAllTriggers) + { + Matching(0, 0); + } + else + { + bool BeamTriggerGroupped = false; + m_data->CStore.Get("BeamTriggerGroupped", BeamTriggerGroupped); + bool CosmicTriggerGroupped = false; + m_data->CStore.Get("CosmicTriggerGroupped", CosmicTriggerGroupped); + bool NuMITriggerGroupped = false; + m_data->CStore.Get("NuMITriggerGroupped", NuMITriggerGroupped); + + if (BeamTriggerGroupped) + Matching(matchTargetTrigger, 14); + if (CosmicTriggerGroupped) + { + Matching(36, 36); + Matching(45, 46); + } + if (NuMITriggerGroupped) + Matching(42, 46); + + if (!BeamTriggerGroupped && !CosmicTriggerGroupped && !NuMITriggerGroupped) + Log("EBMRD: BeamTriggerGroupped and CosmicTriggerGroupped are false, no beam trigger groupped in the grouper, stop matching", v_message, verbosityEBMRD); + } + } + + m_data->CStore.Set("PairedMRDTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Set("PairedMRDTimeStamps", PairedMRDTimeStamps); + m_data->CStore.Set("PairedMRD_TriggerIndex", PairedMRD_TriggerIndex); + m_data->CStore.Set("MRDHitMapRunCode", MRDHitMapRunCode); + + exeNum++; + return true; +} + +bool EBMRD::Finalise() +{ + Log("\033[1;34mEBMRD: Finalising\033[0m", v_message, verbosityEBMRD); + Log("EBMRD: Matched MRD number = " + std::to_string(matchedMRDNumber), v_message, verbosityEBMRD); + Log("EBMRD: Unmatched MRD number = " + std::to_string(MRDEventsBuffer.size()), v_message, verbosityEBMRD); + return true; +} + +bool EBMRD::Matching(int targetTrigger, int matchToTrack) +{ + cout << "\033[1;34m******* EBMRD : Matching *******\033[0m" << endl; + std::map>> GroupedTriggersInTotal; // each map is a group of triggers, with the key is the target trigger word + m_data->CStore.Get("GroupedTriggersInTotal", GroupedTriggersInTotal); + + Log("EBMRD: Got GroupedTriggersInTotal[14] size: " + std::to_string(GroupedTriggersInTotal[14].size()), v_message, verbosityEBMRD); + + vector matchedMRDTimes; + std::map matchedNumberInTrack; + + // loop the MRDEventsBuffer keys, and loop all the grouped triggers + // in each group of trigger, find the target trigger word and it's time + // fine the minimum time difference, if smaller than matchTolerance_ns, then save the time to PairedCTCTimeStamps and PairedMRDTimeStamps + int loopNum = 0; + for (std::pair>> mrdpair : MRDEventsBuffer) + { + if (verbosityEBMRD > 11) + cout << "******************EBMRD: new MRD event: " << loopNum << endl; + uint64_t MTCtime = mrdpair.first; + std::vector> WaveMap = mrdpair.second; + // set minDT to 5 min + uint64_t minDT = 5 * 60 * 1e9; + uint64_t minDTTrigger = 0; + uint64_t dt = 0; + uint32_t matchedTrigWord = 0; + int matchedTrack = 0; + int matchedIndex = 0; + for (std::pair>> pair : GroupedTriggersInTotal) + { + int TrackTriggerWord = pair.first; + if (TrackTriggerWord != matchToTrack && !matchToAllTriggers) + { + Log("EBMRD: Skipping TrackTriggerWord " + std::to_string(TrackTriggerWord), v_debug, verbosityEBMRD); + continue; + } + if (matchedNumberInTrack.find(TrackTriggerWord) == matchedNumberInTrack.end()) + matchedNumberInTrack.emplace(TrackTriggerWord, 0); + + vector> groupedTriggers = pair.second; + + for (int i = 0; i < groupedTriggers.size(); i++) + { + map groupedTrigger = groupedTriggers.at(i); + // itearte over all the grouped triggers, if the value is target trigger, then calculate the time difference + for (std::pair p : groupedTrigger) + { + if (matchToAllTriggers || p.second == targetTrigger) + { + if (MTCtime > p.first) + { + dt = MTCtime - p.first; + } + else + { + dt = p.first - MTCtime; + } + if (dt < minDT) + { + minDT = dt; + minDTTrigger = p.first; + matchedTrigWord = p.second; + matchedIndex = p.second; + matchedTrack = TrackTriggerWord; + + // if(verbosityEBMRD > 11) cout<<"EBMRD: dt: "< pair : matchedNumberInTrack) + { + Log("EBMRD: Match finished, matched number in Track " + std::to_string(pair.first) + " is " + std::to_string(pair.second), v_message, verbosityEBMRD); + } + + return true; +} \ No newline at end of file diff --git a/UserTools/EBMRD/EBMRD.h b/UserTools/EBMRD/EBMRD.h new file mode 100644 index 000000000..d0f21f157 --- /dev/null +++ b/UserTools/EBMRD/EBMRD.h @@ -0,0 +1,65 @@ +#ifndef EBMRD_H +#define EBMRD_H + +#include +#include + +#include "Tool.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBMRD : public Tool +{ + +public: + EBMRD(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + bool Matching(int targetTrigger, int matchToTrack); + +private: + int verbosityEBMRD; + int matchTargetTrigger; + uint64_t matchTolerance_ns; + + int currentRunCode; + + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; + + int matchedMRDNumber = 0; + int exeNum = 0; + + std::map>> MRDEvents; // Key: {MTCTime}, value: "WaveMap" with key (CardID,ChannelID), value FinishedWaveform + std::map MRDEventTriggerTypes; // Key: {MTCTime}, value: string noting what type of trigger occured for the event + std::map MRDBeamLoopback; // Key: {MTCTime}, value: string noting what type of trigger occured for the event + std::map MRDCosmicLoopback; // KEY: {MTCTime}, value: Cosmic loopback TDC value + + std::map>> MRDEventsBuffer; + + bool NewMRDDataAvailable; + + std::map> PairedCTCTimeStamps; + std::map> PairedMRD_TriggerIndex; + std::map> PairedMRDTimeStamps; + std::map MRDHitMapRunCode; // Key: {MTCTime}, value: RunCode + + bool matchToAllTriggers; + + int thisRunNum; + int exePerMatch; + + bool ForceMRDMatched; +}; + +#endif diff --git a/UserTools/EBMRD/README.md b/UserTools/EBMRD/README.md new file mode 100644 index 000000000..3aed04355 --- /dev/null +++ b/UserTools/EBMRD/README.md @@ -0,0 +1,35 @@ +# EBMRD + +EBMRD tool is a part of Event Building version 2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 + +EBMRD match the MRD timestamp to grouped trigger, and save the matching results to CStore for EBSaver. + +## Data + + +**PairedCTCTimeStamps** +After matching, the matched trigger timestamp will be saved here. The key is the main trigger word for each run type. +Saved as PairedMRDTriggerTimestamp in CStore. + +**PairedMRDTimeStamps** +After matching, the matched MRD timestamp will be saved here. The key is the main trigger word for each run type. +This and PairedCTCTimeStamps have the same index. A little bit dangerous, but overall works well. +Saved as PairedMRDTimeStamps in CStore + + +## Configuration + +**matchTargetTrigger** +This gives which trigger word that the MRD timestamps should be matched to. + +**matchTolerance_ns** +This gives the maximum allowed time tolerance between the MRD timestmap and the target trigger timestamp. + +**exePerMatch** +This gives how many loops need to be past for one matching between MRD timestmaps and target trigger timestamps. +500 is generally fine with beam runs. 100 would be better for AmBe runs + +**matchToAllTriggers** +1 or 0. 1 means match MRD timestamps to all possible triggers, 0 means only match to the target trigger. diff --git a/UserTools/EBPMT/EBPMT.cpp b/UserTools/EBPMT/EBPMT.cpp new file mode 100644 index 000000000..641507833 --- /dev/null +++ b/UserTools/EBPMT/EBPMT.cpp @@ -0,0 +1,484 @@ +#include "EBPMT.h" + +EBPMT::EBPMT() : Tool() {} + +bool EBPMT::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("verbosityEBPMT", verbosityEBPMT); + matchTargetTrigger = 5; + m_variables.Get("matchTargetTrigger", matchTargetTrigger); + matchTolerance_ns = 200; // default 200ns + m_variables.Get("matchTolerance_ns", matchTolerance_ns); + exePerMatch = 500; + m_variables.Get("exePerMatch", exePerMatch); + matchToAllTriggers = false; + m_variables.Get("matchToAllTriggers", matchToAllTriggers); + + NumWavesInCompleteSet = 140; + + FinishedHits = new std::map> *>(); + RWMRawWaveforms = new std::map>(); + BRFRawWaveforms = new std::map>(); + + saveRWMWaveforms = true; + saveBRFWaveforms = true; + m_variables.Get("saveRWMWaveforms", saveRWMWaveforms); + m_variables.Get("saveBRFWaveforms", saveBRFWaveforms); + + return true; +} + +bool EBPMT::Execute() +{ + m_data->CStore.Get("RunCode", currentRunCode); + bool gotHits = m_data->CStore.Get("InProgressHits", InProgressHits); + bool gotChkey = m_data->CStore.Get("InProgressChkey", InProgressChkey); + + m_data->CStore.Get("RWMRawWaveforms", RWMRawWaveforms); + m_data->CStore.Get("BRFRawWaveforms", BRFRawWaveforms); + Log("EBPMT: Got RWMRawWaveforms size: " + std::to_string(RWMRawWaveforms->size()), v_message, verbosityEBPMT); + Log("EBPMT: Got BRFRawWaveforms size: " + std::to_string(BRFRawWaveforms->size()), v_message, verbosityEBPMT); + + if (exeNum % 80 == 0 && exeNum != 0) + { + // 80 is arbitrary, because 6*80 = 480 around, close, and smaller than the pairing exe number, exePerMatch default 500 + Log("EBPMT: exeNum: " + std::to_string(exeNum) + " Before loading, apply a VMEOffset correction", v_message, verbosityEBPMT); + Log("EBPMT: before apply the VME offset correction, the size of FinishedHits is " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + m_data->CStore.Get("InProgressHitsAux", InProgressHitsAux); + m_data->CStore.Get("InProgressRecoADCHits", InProgressRecoADCHits); + m_data->CStore.Get("InProgressRecoADCHitsAux", InProgressRecoADCHitsAux); + + CorrectVMEOffset(); + m_data->CStore.Set("InProgressHits", InProgressHits); + m_data->CStore.Set("InProgressChkey", InProgressChkey); + m_data->CStore.Set("InProgressHitsAux", InProgressHitsAux); + m_data->CStore.Set("InProgressRecoADCHits", InProgressRecoADCHits); + m_data->CStore.Set("InProgressRecoADCHitsAux", InProgressRecoADCHitsAux); + m_data->CStore.Set("RWMRawWaveforms", RWMRawWaveforms); + m_data->CStore.Set("BRFRawWaveforms", BRFRawWaveforms); + } + + m_data->CStore.Get("PairedPMTTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Get("PairedPMTTimeStamps", PairedPMTTimeStamps); + Log("EBPMT: Got PairedPMTTimeStamps size: " + std::to_string(PairedPMTTimeStamps.size()), v_message, verbosityEBPMT); + Log("EBPMT: Got PairedPMTTriggerTimestamp size: " + std::to_string(PairedCTCTimeStamps.size()), v_message, verbosityEBPMT); + + Log("EBPMT: gotHits = " + std::to_string(gotHits) + " gotChkey = " + std::to_string(gotChkey), v_message, verbosityEBPMT); + if (!gotHits || !gotChkey) + { + Log("EBPMT: No InProgressHits or InProgressChkey found", v_message, verbosityEBPMT); + return true; + } + + Log("EBPMT: got inprogress hits and chkey with size " + std::to_string(InProgressHits->size()) + " and " + std::to_string(InProgressChkey->size()), v_message, verbosityEBPMT); + + vector PMTEmplacedHitTimes; + vector RWMEmplacedTimes; + vector BRFEmplacedTimes; + + for (std::pair> *> p : *InProgressHits) + { + uint64_t PMTCounterTimeNs = p.first; + std::map> *hitMap = p.second; + vector ChannelKey = InProgressChkey->at(PMTCounterTimeNs); + + Log("EBPMT: PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs), v_debug, verbosityEBPMT); + Log("EBPMT: hitMap size: " + std::to_string(hitMap->size()), v_debug, verbosityEBPMT); + Log("EBPMT: ChannelKey vector size: " + std::to_string(ChannelKey.size()), v_debug, verbosityEBPMT); + Log("EBPMT: Current unfinished InProgressHits size: " + std::to_string(InProgressHits->size()), v_debug, verbosityEBPMT); + + if (static_cast(ChannelKey.size()) > MaxObservedNumWaves) + MaxObservedNumWaves = ChannelKey.size(); + if (InProgressHits->size() > 500 && MaxObservedNumWaves < NumWavesInCompleteSet && !max_waves_adapted && MaxObservedNumWaves >= 130) + { + NumWavesInCompleteSet = MaxObservedNumWaves; + max_waves_adapted = true; + Log("EBPMT: MaxObservedNumWaves = " + std::to_string(MaxObservedNumWaves), v_message, verbosityEBPMT); + Log("EBPMT: NumWavesInCompleteSet = " + std::to_string(NumWavesInCompleteSet), v_message, verbosityEBPMT); + } + + if (MaxObservedNumWaves > NumWavesInCompleteSet) + NumWavesInCompleteSet = MaxObservedNumWaves; + + if (ChannelKey.size() == (NumWavesInCompleteSet - 1)) + { + Log("EBPMT: ChannelKey.size() == (NumWavesInCompleteSet - 1), ChannelKey.size() = " + std::to_string(ChannelKey.size()) + " == NumWavesInCompleteSet - 1 = " + std::to_string(NumWavesInCompleteSet - 1), v_debug, verbosityEBPMT); + if (AlmostCompleteWaveforms.find(PMTCounterTimeNs) != AlmostCompleteWaveforms.end()) + { + Log("EBPMT: AlmostCompleteWaveforms size = " + std::to_string(AlmostCompleteWaveforms.size()), v_debug, verbosityEBPMT); + AlmostCompleteWaveforms[PMTCounterTimeNs]++; + } + else + AlmostCompleteWaveforms.emplace(PMTCounterTimeNs, 0); + Log("EBPMT: AlmostCompleteWaveforms adding PMTCounterTimeNs = " + std::to_string(PMTCounterTimeNs) + " to " + std::to_string(AlmostCompleteWaveforms[PMTCounterTimeNs]), v_debug, verbosityEBPMT); + } + + Log("EBPMT: ChannelKey.size() = " + std::to_string(ChannelKey.size()) + " >= NumWavesInCompleteSet = " + std::to_string(NumWavesInCompleteSet) + " or AlmostCompleteWaveforms.at(PMTCounterTimeNs) = " + std::to_string(AlmostCompleteWaveforms[PMTCounterTimeNs] >= 5), v_debug, verbosityEBPMT); + + if (ChannelKey.size() >= NumWavesInCompleteSet || ((ChannelKey.size() == NumWavesInCompleteSet - 1) && (AlmostCompleteWaveforms[PMTCounterTimeNs] >= 5))) + { + Log("EBPMT: Emplace hit map to FinishedHits, ChannelKey.size() = " + std::to_string(ChannelKey.size()) + " >= NumWavesInCompleteSet = " + std::to_string(NumWavesInCompleteSet) + " or AlmostCompleteWaveforms.at(PMTCounterTimeNs) = " + std::to_string(AlmostCompleteWaveforms.at(PMTCounterTimeNs) >= 5), v_debug, verbosityEBPMT); + + // check if the PMTCounterTimeNs is already in the FinishedHits, if not then add it + + if (FinishedHits->find(PMTCounterTimeNs) != FinishedHits->end()) + { + Log("EBPMT: PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs) + " already in FinishedHits", v_debug, verbosityEBPMT); + continue; + } + // if find PMTCounterTimeNs in PairedPMTTimeStamps, then skip this hit + if (PairedPMTTimeStamps.size() > 0) + { + bool skip = false; + for (std::pair> p : PairedPMTTimeStamps) + { + vector PMTTimeStamps = p.second; + for (uint64_t PMTTimeStamp : PMTTimeStamps) + { + if (PMTCounterTimeNs == PMTTimeStamp) + { + skip = true; + break; + } + } + if (skip) + break; + } + if (skip) + continue; + } + FinishedHits->emplace(PMTCounterTimeNs, hitMap); + + PMTEmplacedHitTimes.push_back(PMTCounterTimeNs); + + std::map, int> aWaveMapSampleSize; + + // Put PMT timestamp into the timestamp set for this run. + Log("EBPMT: waveset has clock counter: " + std::to_string(PMTCounterTimeNs), v_debug, verbosityEBPMT); + } + + if ((ChannelKey.size() == NumWavesInCompleteSet - 1)) + { + if (AlmostCompleteWaveforms.at(PMTCounterTimeNs) >= 5) + AlmostCompleteWaveforms.erase(PMTCounterTimeNs); + } + } + + Log("EBPMT: InProgressHits size: " + std::to_string(InProgressHits->size()) + " InProgressChkey size: " + std::to_string(InProgressChkey->size()), v_message, verbosityEBPMT); + Log("EBPMT: PMTEmplacedHitTimes size: " + std::to_string(PMTEmplacedHitTimes.size()), v_message, verbosityEBPMT); + /*for (uint64_t PMTCounterTimeNs : PMTEmplacedHitTimes) + { + InProgressHits->erase(PMTCounterTimeNs); + InProgressChkey->erase(PMTCounterTimeNs); + }*/ + Log("EBPMT: InProgressHits size: " + std::to_string(InProgressHits->size()) + " InProgressChkey size: " + std::to_string(InProgressChkey->size()), v_message, verbosityEBPMT); + + // If this InProgressTankEvent is too old, clear it + Log("EBPMT: Current number of unfinished hitmaps in InProgressHits: " + std::to_string(InProgressHits->size()), v_debug, verbosityEBPMT); + + Log("EBPMT: All finished, left size are, matchedHitNumber: " + std::to_string(matchedHitNumber) + " InProgressHits: " + std::to_string(InProgressHits->size()) + " FinishedHits: " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + + if (exeNum % 80 == 0) + { + Log("EBPMT: after apply the VME offset correction and loading, the size of FinishedHits is " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + } + + exeNum++; + + if (exeNum % 50 == 0) + { + Log("EBPMT: exeNum: " + std::to_string(exeNum), v_message, verbosityEBPMT); + } + + bool stopLoop = false; + m_data->vars.Get("StopLoop", stopLoop); + int runNum = thisRunNum; // run number saved in buffer as the previous run number + // m_data->vars.Get("RunNumber", thisRunNum); + m_data->CStore.Get("runNumber", thisRunNum); + + bool ForcePMTMatching = false; + m_data->CStore.Get("ForcePMTMatching", ForcePMTMatching); + + if (exeNum % exePerMatch == 0 || runNum != thisRunNum || stopLoop || ForcePMTMatching) + { + Log("EBPMT: exeNum: " + std::to_string(exeNum) + " Doing Matching", v_message, verbosityEBPMT); + if (matchToAllTriggers) + { + Matching(0, 0); + } + else + { + bool BeamTriggerGroupped = false; + m_data->CStore.Get("BeamTriggerGroupped", BeamTriggerGroupped); + if (BeamTriggerGroupped) + Matching(5, 14); + else + Log("EBPMT: BeamTriggerGroupped is false, no beam trigger groupped in the grouper, stop matching", v_message, verbosityEBPMT); + } + } + + m_data->CStore.Set("PairedPMTTriggerTimestamp", PairedCTCTimeStamps); + m_data->CStore.Set("PairedPMTTimeStamps", PairedPMTTimeStamps); + m_data->CStore.Set("PairedPMT_TriggerIndex", PairedPMT_TriggerIndex); + m_data->CStore.Set("PMTHitmapRunCode", PMTHitmapRunCode); + // everytime change the trigger group, also update the trigger index. + Log("EBPMT: Set PairedPMTTimeStamps size: " + std::to_string(PairedPMTTimeStamps.size()), v_message, verbosityEBPMT); + Log("EBPMT: Set PairedPMTTriggerTimestamp size: " + std::to_string(PairedCTCTimeStamps.size()), v_message, verbosityEBPMT); + + return true; +} + +bool EBPMT::Finalise() +{ + + Log("\033[1;34mEBPMT: Finalising\033[0m", v_message, verbosityEBPMT); + Log("EBPMT: Matched Hit Map Entry Number: " + std::to_string(matchedHitNumber), v_message, verbosityEBPMT); + Log("EBPMT: Unmatched Hit Map Entry Number left: " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + + return true; +} + +bool EBPMT::Matching(int targetTrigger, int matchToTrack) +{ + cout << "\033[1;34m******* EBPMT : Matching *******\033[0m" << endl; + std::map>> GroupedTriggersInTotal; // each map is a group of triggers, with the key is the target trigger word + m_data->CStore.Get("GroupedTriggersInTotal", GroupedTriggersInTotal); + + vector matchedHitTimes; + // loop over all the Hits, for each FinishedHits, loop all grouped triggers, if the time differencs<100 for trigger 5, + // matchedHitNumber ++, then remove the hit from the map + int loopNum = 0; + for (std::pair> *> pmtpair : *FinishedHits) + { + if (verbosityEBPMT > 11) + cout << "******************EBPMT: new hit" << endl; + uint64_t PMTCounterTimeNs = pmtpair.first; + std::map> *hitMap = pmtpair.second; + // set minDT to 5 min + uint64_t minDT = 5 * 60 * 1e9; + uint64_t minDTTrigger = 0; + uint64_t dt = 0; + uint32_t matchedTrigWord = 0; + int matchedTrack = 0; + int matchedIndex = 0; + // loop all tracks of GroupedTriggersInTotal + for (std::pair>> pair : GroupedTriggersInTotal) + { + int TrackTriggerWord = pair.first; + if (TrackTriggerWord != matchToTrack && !matchToAllTriggers) + continue; + + vector> groupedTriggers = pair.second; + + // loop all the grouped triggers, if the value is target trigger, then calculate the time difference + for (int i = 0; i < groupedTriggers.size(); i++) + { + map groupedTrigger = groupedTriggers.at(i); + // itearte over all the grouped triggers, if the value is target trigger, then calculate the time difference + for (std::pair p : groupedTrigger) + { + if (matchToAllTriggers || p.second == targetTrigger) + { + if (PMTCounterTimeNs > p.first) + { + dt = PMTCounterTimeNs - p.first; + } + else + { + dt = p.first - PMTCounterTimeNs; + } + if (dt < minDT) + { + minDT = dt; + minDTTrigger = p.first; + matchedTrigWord = p.second; + matchedTrack = TrackTriggerWord; + matchedIndex = i; + } + } + } + } + } + + Log("EBPMT: looping hit " + std::to_string(loopNum) + ", minDT: " + std::to_string(minDT) + ", minDTTrigger time: " + std::to_string(minDTTrigger) + " with word " + std::to_string(matchedTrigWord) + ", in trigger track " + std::to_string(matchedTrack), v_warning, verbosityEBPMT); + if (minDT < matchTolerance_ns) + { + PairedCTCTimeStamps[matchedTrack].push_back(minDTTrigger); + PairedPMTTimeStamps[matchedTrack].push_back(PMTCounterTimeNs); + PairedPMT_TriggerIndex[matchedTrack].push_back(matchedIndex); + + // the pmt hit map with timestmap PMTCounterTimeNs, match to trigger with timestamp minDTTrigger + // the matched trigger is at matchedIndex of that trigger track + + matchedHitNumber++; + matchedHitTimes.push_back(PMTCounterTimeNs); + // FinishedHits->erase(PMTCounterTimeNs); + Log("EBPMT: Matched Hit to trigger " + std::to_string(matchedTrigWord) + " at PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs) + " to TriggerTime: " + std::to_string(minDTTrigger) + " with minDT: " + std::to_string(minDT) + ", in trigger track " + std::to_string(matchedTrack) + ", in trigger index " + std::to_string(matchedIndex), v_message, verbosityEBPMT); + } + else + { + Log("EBPMT: Match failed, found min diff Hit to trigger " + std::to_string(matchedTrigWord) + " at PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs) + " to TriggerTime: " + std::to_string(minDTTrigger) + " with minDT: " + std::to_string(minDT) + ", in trigger track " + std::to_string(matchedTrack) + ", in trigger index " + std::to_string(matchedIndex), v_message, verbosityEBPMT); + } + loopNum++; + } + Log("EBPMT: total matchedHitNumber: " + std::to_string(matchedHitNumber), v_message, verbosityEBPMT); + Log("EBPMT: Current number of unfinished hitmaps after match in InProgressHits: " + std::to_string(InProgressHits->size()), v_message, verbosityEBPMT); + + Log("EBPMT: Found matched hits: " + std::to_string(matchedHitTimes.size()), v_message, verbosityEBPMT); + Log("EBPMT: before erase, left number of unfinished hitmaps in FinishedHits: " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + for (uint64_t PMTCounterTimeNs : matchedHitTimes) + { + FinishedHits->erase(PMTCounterTimeNs); + + if (saveRWMWaveforms) + { + // check does RWMRawWaveforms have key PMTCounterTimeNs, if not, print a log waring and skip + if (RWMRawWaveforms->find(PMTCounterTimeNs) == RWMRawWaveforms->end()) + { + Log("EBPMT: After matching, RWMRawWaveforms does not have key PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs), v_warning, verbosityEBPMT); + } + } + + if (saveBRFWaveforms) + { + // check does BRFRawWaveforms have key PMTCounterTimeNs, if not, print a log waring and skip + if (BRFRawWaveforms->find(PMTCounterTimeNs) == BRFRawWaveforms->end()) + { + Log("EBPMT: After matching, BRFRawWaveforms does not have key PMTCounterTimeNs: " + std::to_string(PMTCounterTimeNs), v_warning, verbosityEBPMT); + } + } + } + Log("EBPMT: after erase, left number of unfinished hitmaps in FinishedHits: " + std::to_string(FinishedHits->size()), v_message, verbosityEBPMT); + + return true; +} + +void EBPMT::CorrectVMEOffset() +{ + Log("EBPMT: Correcting VME Offset", v_message, verbosityEBPMT); + vector timestamps; // all current timestamps + std::map timestamps_to_shift; // timestamps need to be shifted + + // if InProgressHits size is 0, return + if (InProgressHits->size() == 0) + { + Log("EBPMT: InProgressHits size is 0, return", v_message, verbosityEBPMT); + return; + } + + // insert the key of std::map> *> *InProgressHits; to timestamps + for (std::pair> *> p : *InProgressHits) + { + timestamps.push_back(p.first); + } + + Log("EBPMT: Found " + std::to_string(timestamps.size()) + " timestamps", v_message, verbosityEBPMT); + + // loop timestamps,对于每一个时间戳,检查它与它之前的时间戳的差值是否是8或者16 + // 如果是,获得InProgressHits在这两个时间戳上的map的size + // 在timestamps_to_shift中记录pair,第一个时间戳是size较小的那个,第二个是较大的那个 + for (int i = 1; i < timestamps.size(); i++) + { + uint64_t dt = (timestamps[i] > timestamps[i - 1]) ? (timestamps[i] - timestamps[i - 1]) : (timestamps[i - 1] - timestamps[i]); + Log("EBPMT: Found two timestamps with difference = " + std::to_string(dt) + "ns", v_message, verbosityEBPMT); + Log("EBPMT: timestamps[i - 1] = " + std::to_string(timestamps[i - 1]) + " timestamps[i] = " + std::to_string(timestamps[i]), v_message, verbosityEBPMT); + if (dt == 8 || dt == 16) + { + uint64_t FirstMapSize = InProgressHits->at(timestamps[i - 1])->size(); + uint64_t SecondMapSize = InProgressHits->at(timestamps[i])->size(); + Log("EBPMT: Found two timestamps with 8 or 16ns difference, FirstMapSize: " + std::to_string(FirstMapSize) + " SecondMapSize: " + std::to_string(SecondMapSize), v_message, verbosityEBPMT); + if (FirstMapSize < SecondMapSize) + { + timestamps_to_shift.emplace(timestamps[i - 1], timestamps[i]); + } + else + { + timestamps_to_shift.emplace(timestamps[i], timestamps[i - 1]); + } + } + else if (dt < 1600) + { + Log("EBPMT: Found two timestamps with difference = " + std::to_string(dt) + "ns", v_message, verbosityEBPMT); + continue; + } + } + + int correctionApplied = 0; + Log("EBPMT: Found " + std::to_string(timestamps_to_shift.size()) + " timestamps to shift", v_message, verbosityEBPMT); + // go through timestamps_to_shift, for each pair, shift the hit map in the first smaller timestamp to the second larger timestamp + // apply on InProgressHits, InProgressHitsAux, InProgressChkey, InProgressRecoADCHits, InProgressRecoADCHitsAux + // also need to apply on RWMRawWaveforms and BRFRawWaveforms + if (InProgressHitsAux != NULL && InProgressRecoADCHitsAux != NULL) + { // InProgressHitsAux,InProgressRecoADCHitsAux may not exist yet + for (std::map::iterator it = timestamps_to_shift.begin(); it != timestamps_to_shift.end(); it++) + { + uint64_t SmallerMapTS = it->first; + uint64_t LargerMapTS = it->second; + Log("EBPMT::CorrectVMEOffset: Map Timestamp " + std::to_string(SmallerMapTS) + " to timestamp " + std::to_string(LargerMapTS), v_debug, verbosityEBPMT); + if (InProgressHits->count(SmallerMapTS) == 0 || InProgressHits->count(LargerMapTS) == 0) + { // map object at FirstTS, SecondTS may not exist yet + Log("EBPMT::CorrectVMEOffset: InProgressHits->count(FirstTS) == " + std::to_string(InProgressHits->count(SmallerMapTS)) + ", InProgressHits->count(SecondTS) == " + std::to_string(InProgressHits->count(LargerMapTS)), v_debug, verbosityEBPMT); + break; + } + // Get InProgress* {Hits, Chkey, and RecoADCHits} objects + std::map> *FirstTankHits = InProgressHits->at(SmallerMapTS); + std::map> *SecondTankHits = InProgressHits->at(LargerMapTS); + std::vector FirstChankey = InProgressChkey->at(SmallerMapTS); + std::vector SecondChankey = InProgressChkey->at(LargerMapTS); + std::map> *FirstTankHitsAux = InProgressHitsAux->at(SmallerMapTS); + std::map> *SecondTankHitsAux = InProgressHitsAux->at(LargerMapTS); + std::map>> FirstRecoADCHits = InProgressRecoADCHits->at(SmallerMapTS); + std::map>> SecondRecoADCHits = InProgressRecoADCHits->at(LargerMapTS); + std::map>> FirstRecoADCHitsAux = InProgressRecoADCHitsAux->at(SmallerMapTS); + std::map>> SecondRecoADCHitsAux = InProgressRecoADCHitsAux->at(LargerMapTS); + + SecondTankHits->insert(FirstTankHits->begin(), FirstTankHits->end()); + SecondChankey.insert(SecondChankey.end(), FirstChankey.begin(), FirstChankey.end()); + SecondTankHitsAux->insert(FirstTankHitsAux->begin(), FirstTankHitsAux->end()); + SecondRecoADCHits.insert(FirstRecoADCHits.begin(), FirstRecoADCHits.end()); + SecondRecoADCHitsAux.insert(FirstRecoADCHitsAux.begin(), FirstRecoADCHitsAux.end()); + + (*InProgressHits)[LargerMapTS] = SecondTankHits; + InProgressHits->erase(SmallerMapTS); + (*InProgressChkey)[LargerMapTS] = SecondChankey; + InProgressChkey->erase(SmallerMapTS); + (*InProgressHitsAux)[LargerMapTS] = SecondTankHitsAux; + InProgressHitsAux->erase(SmallerMapTS); + (*InProgressRecoADCHits)[LargerMapTS] = SecondRecoADCHits; + InProgressRecoADCHits->erase(SmallerMapTS); + (*InProgressRecoADCHitsAux)[LargerMapTS] = SecondRecoADCHitsAux; + InProgressRecoADCHitsAux->erase(SmallerMapTS); + + if (saveRWMWaveforms) + { + // if found SmallerMapTS in RWMRawWaveforms, then change it to LargerMapTS + if (RWMRawWaveforms->find(SmallerMapTS) != RWMRawWaveforms->end()) + { + (*RWMRawWaveforms)[LargerMapTS] = (*RWMRawWaveforms)[SmallerMapTS]; + RWMRawWaveforms->erase(SmallerMapTS); + } + } + if (saveBRFWaveforms) + { + // if found SmallerMapTS in BRFRawWaveforms, then change it to LargerMapTS + if (BRFRawWaveforms->find(SmallerMapTS) != BRFRawWaveforms->end()) + { + (*BRFRawWaveforms)[LargerMapTS] = (*BRFRawWaveforms)[SmallerMapTS]; + BRFRawWaveforms->erase(SmallerMapTS); + } + + correctionApplied++; + } + } + } + Log("EBPMT: Corrected VME Offset for " + std::to_string(correctionApplied) + " timestamps", v_message, verbosityEBPMT); +} \ No newline at end of file diff --git a/UserTools/EBPMT/EBPMT.h b/UserTools/EBPMT/EBPMT.h new file mode 100644 index 000000000..9065ef439 --- /dev/null +++ b/UserTools/EBPMT/EBPMT.h @@ -0,0 +1,78 @@ +#ifndef EBPMT_H +#define EBPMT_H + +#include +#include + +#include "Tool.h" +#include "Hit.h" +#include "ADCPulse.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBPMT : public Tool +{ + +public: + EBPMT(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + bool Matching(int targetTrigger, int matchToTrack); + void CorrectVMEOffset(); + +private: + int verbosityEBPMT; + int matchTargetTrigger; + uint64_t matchTolerance_ns; + + int currentRunCode; + + std::map> *> *FinishedHits; // Key: {MTCTime}, value: map of Hit distributions + std::map> *FinishedRWMWaveforms; // Key: {MTCTime}, value: RWM waveform + std::map> *FinishedBRFWaveforms; // Key: {MTCTime}, value: BRF waveform + + std::map AlmostCompleteWaveforms; + + std::map> *> *InProgressHits; // Key: {MTCTime}, value: map of Hit distributions + std::map> *InProgressChkey; // Key: {MTCTime}, value: vector of in progress chankeys + + // only used for VME offset correction + std::map> *> *InProgressHitsAux; // Key: {MTCTime}, value: map of Hit distributions + std::map>>> *InProgressRecoADCHits; // Key: {MTCTime}, value: map of found pulses + std::map>>> *InProgressRecoADCHitsAux; // Key: {MTCTime}, value: map of found pulses + std::map> *RWMRawWaveforms; // Key: MTCTime, Value: RWM waveform + std::map> *BRFRawWaveforms; // Key: MTCTime, Value: BRF waveform + + std::map> PairedCTCTimeStamps; + std::map> PairedPMT_TriggerIndex; + std::map> PairedPMTTimeStamps; + std::map PMTHitmapRunCode; // Key: {MTCTime}, value: RunCode + + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; + + int MaxObservedNumWaves = 0; + int NumWavesInCompleteSet = 140; + bool max_waves_adapted = false; + + int matchedHitNumber = 0; + int exeNum = 0; + int thisRunNum; + int exePerMatch = 500; + bool matchToAllTriggers; + + bool saveRWMWaveforms; + bool saveBRFWaveforms; +}; + +#endif diff --git a/UserTools/EBPMT/README.md b/UserTools/EBPMT/README.md new file mode 100644 index 000000000..cfb62496a --- /dev/null +++ b/UserTools/EBPMT/README.md @@ -0,0 +1,43 @@ +# EBPMT + +EBPMT tool is a part of Event Building version 2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 +EBPMT match the ADC timestamps to grouped trigger, and save the matching results to CStore for EBSaver. + + +## Data + +**FinishedHits** +The PMT hits on each PMT are decoded from the PMTDataDecoder. While there are enough number of PMT loaded for a (ADC) PMT timestamp, the timestamp will be pushed to FinishedHits. The name was taken from ANNIEEventBuilder. + + +**RWMRawWaveforms** +**BRFRawWaveforms** +These two behaves like FinishedHits, but for raw RWM and BRF waveforms. +The slides for BRF and RWM waveforms: https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5756 + + +**PairedCTCTimeStamps** +After matching, the matched trigger timestamp will be saved here. The key is the main trigger word for each run type. + +**PairedPMTTimeStamps** +After matching, the matched PMT timestamp will be saved here. The key is the main trigger word for each run type. +This and PairedCTCTimeStamps have the same index. A little bit dangerous, but overall works well. + + + +## Configuration + +**matchTargetTrigger** +This gives which trigger word that the PMT timestamps should be matched to. + +**matchTolerance_ns** +This gives the maximum allowed time tolerance between the PMT timestmap and the target trigger timestamp. + +**exePerMatch** +This gives how many loops need to be past for one matching between PMT timestmaps and target trigger timestamps. +500 is generally fine with beam runs + +**matchToAllTriggers** +1 or 0. 1 means match PMT timestamps to all possible triggers, 0 means only match to the target trigger. diff --git a/UserTools/EBSaver/EBSaver.cpp b/UserTools/EBSaver/EBSaver.cpp new file mode 100644 index 000000000..b07780d2c --- /dev/null +++ b/UserTools/EBSaver/EBSaver.cpp @@ -0,0 +1,1495 @@ +#include "EBSaver.h" + +EBSaver::EBSaver() : Tool() {} + +bool EBSaver::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("verbosityEBSaver", verbosityEBSaver); + savePath = ""; + m_variables.Get("savePath", savePath); + saveName = "ProcessedData_"; + m_variables.Get("saveName", saveName); + beamInfoFileName = "BeamInfo.root"; + m_variables.Get("beamInfoFileName", beamInfoFileName); + + saveTriggerGroups = true; + savePMT = true; + + saveAllTriggers = false; + m_variables.Get("saveAllTriggers", saveAllTriggers); + saveMRD = true; + m_variables.Get("saveMRD", saveMRD); + saveLAPPD = true; + m_variables.Get("saveLAPPD", saveLAPPD); + saveOrphan = true; + m_variables.Get("saveOrphan", saveOrphan); + saveBeamInfo = true; + m_variables.Get("saveBeamInfo", saveBeamInfo); + + saveRawBRFWaveform = true; + m_variables.Get("saveRawBRFWaveform", saveRawBRFWaveform); + saveRawRWMWaveform = true; + m_variables.Get("saveRawRWMWaveform", saveRawRWMWaveform); + + ANNIEEvent = new BoostStore(false, 2); + + exeNumber = 0; + savedTriggerGroupNumber = 0; + savedPMTHitMapNumber = 0; + savedMRDNumber = 0; + savedLAPPDNumber = 0; + + savePerExe = 2000; + + if (savePMT) + saveName += "PMT"; + if (saveMRD) + saveName += "MRD"; + if (saveLAPPD) + saveName += "LAPPD"; + + m_data->CStore.Get("BeamTriggerMain", BeamTriggerMain); + m_data->CStore.Get("LaserTriggerMain", LaserTriggerMain); + m_data->CStore.Get("CosmicTriggerMain", CosmicTriggerMain); + m_data->CStore.Get("LEDTriggerMain", LEDTriggerMain); + m_data->CStore.Get("AmBeTriggerMain", AmBeTriggerMain); + m_data->CStore.Get("PPSMain", PPSMain); + + InProgressHits = new std::map> *>; + InProgressChkey = new std::map>; + InProgressRecoADCHits = new std::map>>>; + InProgressRecoADCHitsAux = new std::map>>>; + InProgressHitsAux = new std::map> *>; + FinishedRawAcqSize = new std::map>>; + + RWMRawWaveforms = new std::map>; + BRFRawWaveforms = new std::map>; + + if (saveBeamInfo) + { + Log("EBSaver: saveBeamInfo is true, loading Beam Info", v_message, verbosityEBSaver); + LoadBeamInfo(); + } + + return true; +} + +bool EBSaver::Execute() +{ + + bool saveProcessedFile = false; + bool saveEverything = false; + m_data->CStore.Get("SaveProcessedFile", saveProcessedFile); + m_data->CStore.Get("SaveEverything", saveEverything); + if (!saveProcessedFile && !saveEverything) + { + Log("EBSaver: Not saving data in this exe", v_message, verbosityEBSaver); + return true; + } + cout << "\033[1;34m******* EBSaver : Start execute *******\033[0m" << endl; + + m_data->CStore.Get("RunCodeToSave", savingRunCode); + GotAllDataFromOriginalBuffer(); + + Log("EBSaver: Start saving data for run code " + std::to_string(savingRunCode), v_message, verbosityEBSaver); + + // clean the to remove buffer + GroupedTriggerIndexToRemove.clear(); + PMTRunCodeToRemove.clear(); + MRDRunCodeToRemove.clear(); + LAPPDRunCodeToRemove.clear(); + + PMTPairInfoToRemoveTime.clear(); + MRDPairInfoToRemoveTime.clear(); + LAPPDPairInfoToRemoveTime.clear(); + + // get the grouped trigger, save the grouped triggers with the same runcode + cout << "\033[1;34m******* EBSaver : Saving *******\033[0m" << endl; + m_data->CStore.Get("GroupedTriggersInTotal", GroupedTriggersInTotal); + m_data->CStore.Get("RunCodeInTotal", RunCodeInTotal); + + int savedEventNumber = 0; + // loop each track in the RunCodeInTotal; + for (auto const &track : RunCodeInTotal) + { + int triggerTrack = track.first; + std::vector RunCodeVector = track.second; + // check if the RunCodeInTotal[tragetTrigWord] has the same size with GroupedTriggersInTotal[tragetTrigWord] + Log("EBSaver: Looping trigger track " + std::to_string(triggerTrack) + " with RunCodeInTotal size " + std::to_string(RunCodeVector.size()) + " and GroupedTriggersInTotal size " + std::to_string(GroupedTriggersInTotal[triggerTrack].size()), v_message, verbosityEBSaver); + + if (RunCodeVector.size() != GroupedTriggersInTotal[triggerTrack].size()) + { + Log("EBSaver: RunCodeInTotal and GroupedTriggersInTotal size not match, RunCodeVector size " + std::to_string(RunCodeVector.size()) + " and GroupedTriggersInTotal size " + std::to_string(GroupedTriggersInTotal[triggerTrack].size()), v_warning, verbosityEBSaver); + continue; + } + // GroupedTriggersInTotal and RunCodeInTotal have the same size + // same index is the cooresponding data + for (int i = 0; i < RunCodeVector.size(); i++) + { + int runCode = RunCodeVector[i]; + // saving + // if save Everything, in case there might be some mis aligned events not saved to that processed part file correctly and left in buffer, save them to corresponding part file + if (runCode == savingRunCode) + { + Log("\033[1;34m ****EBSaver: Saving a new event with savedEventNumber = " + std::to_string(savedEventNumber) + " ****\033[0m", v_message, verbosityEBSaver); + + std::string saveFileName = savePath + saveName + "_R" + to_string(runCode / 100000) + "S" + to_string((runCode % 100000) / 10000 - 1) + "p" + to_string(runCode % 10000); + Log("EBSaver: Saving to " + saveFileName + " with run code " + std::to_string(runCode) + " at index " + std::to_string(i), v_message, verbosityEBSaver); + + // if in last exe, the runcode for that group of trigger equals to the saving RunCode, save to ANNIEEvent Processed File + SaveToANNIEEvent(saveFileName, runCode, triggerTrack, i); + savedEventNumber++; + } + } + } + + // remove the paired trigger and data timestamp at PairInfoToRemoveIndex from the buffer like PairedLAPPDTimeStamps + for (auto const &track : GroupedTriggerIndexToRemove) + { + int triggerTrack = track.first; + int groupIndex = track.second; + GroupedTriggersInTotal[triggerTrack].erase(GroupedTriggersInTotal[triggerTrack].begin() + groupIndex); + RunCodeInTotal[triggerTrack].erase(RunCodeInTotal[triggerTrack].begin() + groupIndex); + } + int PMTToRemove = 0; + int MRDToRemove = 0; + int LAPPDToRemove = 0; + for (auto const &track : PMTPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector times = track.second; + PMTToRemove += times.size(); + // print the size of times, and all elements in times + Log("EBSaver: PMT PairInfoToRemoveTime at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + cout << endl; + for (auto const &track : MRDPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector times = track.second; + MRDToRemove += times.size(); + Log("EBSaver: MRD PairInfoToRemoveTime at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + cout << endl; + for (auto const &track : LAPPDPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector times = track.second; + LAPPDToRemove += times.size(); + Log("EBSaver: LAPPD PairInfoToRemoveTime at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + cout << endl; + + Log("EBSaver: before remove from pair info buffer, going to remove PMT " + std::to_string(PMTToRemove) + ", MRD " + std::to_string(MRDToRemove) + ", LAPPD " + std::to_string(LAPPDToRemove), v_message, verbosityEBSaver); + + // print everything in PairedLAPPDTimeStamps for debug + for (auto const &track : PairedLAPPDTimeStamps) + { + int triggerTrack = track.first; + std::vector times = track.second; + Log("EBSaver: PairedLAPPDTimeStamps at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + // print everything in Buffer_LAPPDTimestamp_ns for debug + Log("EBSaver: Buffer_LAPPDTimestamp_ns size " + std::to_string(Buffer_LAPPDTimestamp_ns.size()), v_message, verbosityEBSaver); + for (int i = 0; i < Buffer_LAPPDTimestamp_ns.size(); i++) + cout << i << ": " << Buffer_LAPPDTimestamp_ns[i] << ", "; + cout << endl; + + // 删除 LAPPD 相关时间戳 + int removedLAPPD = 0; + for (auto const &track : LAPPDPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector indexes = track.second; + for (int i = 0; i < indexes.size(); i++) + { + int foundIndex = -1; + for (int j = 0; j < PairedLAPPDTimeStamps[triggerTrack].size(); j++) + { + if (PairedLAPPDTimeStamps[triggerTrack][j] == indexes[i]) + { + foundIndex = j; + break; + } + } + if (foundIndex != -1) + { + removedLAPPD++; + Log("EBSaver: Remove LAPPD data with LAPPDTime " + std::to_string(indexes[i]) + " at index " + std::to_string(foundIndex), v_message, verbosityEBSaver); + PairedLAPPDTimeStamps[triggerTrack].erase(PairedLAPPDTimeStamps[triggerTrack].begin() + foundIndex); + PairedLAPPDTriggerTimestamp[triggerTrack].erase(PairedLAPPDTriggerTimestamp[triggerTrack].begin() + foundIndex); + } + } + } + + // 删除 PMT 相关时间戳 + + for (auto const &track : PMTPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector indexes = track.second; + for (int i = 0; i < indexes.size(); i++) + { + int foundIndex = -1; + for (int j = 0; j < PairedPMTTimeStamps[triggerTrack].size(); j++) + { + if (PairedPMTTimeStamps[triggerTrack][j] == indexes[i]) + { + foundIndex = j; + break; + } + } + if (foundIndex != -1) + { + PairedPMTTimeStamps[triggerTrack].erase(PairedPMTTimeStamps[triggerTrack].begin() + foundIndex); + PairedPMTTriggerTimestamp[triggerTrack].erase(PairedPMTTriggerTimestamp[triggerTrack].begin() + foundIndex); + } + } + } + + // 删除 MRD 相关时间戳 + for (auto const &track : MRDPairInfoToRemoveTime) + { + int triggerTrack = track.first; + std::vector indexes = track.second; + for (int i = 0; i < indexes.size(); i++) + { + int foundIndex = -1; + for (int j = 0; j < PairedMRDTimeStamps[triggerTrack].size(); j++) + { + if (PairedMRDTimeStamps[triggerTrack][j] == indexes[i]) + { + foundIndex = j; + break; + } + } + if (foundIndex != -1) + { + PairedMRDTimeStamps[triggerTrack].erase(PairedMRDTimeStamps[triggerTrack].begin() + foundIndex); + PairedMRDTriggerTimestamp[triggerTrack].erase(PairedMRDTriggerTimestamp[triggerTrack].begin() + foundIndex); + } + } + } + + ANNIEEvent->Close(); + ANNIEEvent->Delete(); + delete ANNIEEvent; + ANNIEEvent = new BoostStore(false, 2); + + if (saveEverything) + { + Log("EBSaver: Save everything", v_message, verbosityEBSaver); + } + + // now save other data left in the data buffer to orphan + // loop the runcode buffer of each data store, find which run code we need to save + // then loop the run code vector, for each run code, loop all data buffers, save the left data with the save run code + + m_data->CStore.Set("GroupedTriggersInTotal", GroupedTriggersInTotal); + m_data->CStore.Set("RunCodeInTotal", RunCodeInTotal); + m_data->CStore.Set("PairedLAPPDTriggerTimestamp", PairedLAPPDTriggerTimestamp); + m_data->CStore.Set("PairedLAPPDTimeStamps", PairedLAPPDTimeStamps); + m_data->CStore.Set("PairedPMTTriggerTimestamp", PairedPMTTriggerTimestamp); + m_data->CStore.Set("PairedPMTTimeStamps", PairedPMTTimeStamps); + m_data->CStore.Set("PairedMRDTriggerTimestamp", PairedMRDTriggerTimestamp); + m_data->CStore.Set("PairedMRDTimeStamps", PairedMRDTimeStamps); + + Log("EBSaver: Execute finished, saved PMT " + std::to_string(savedPMTHitMapNumber) + ", MRD " + std::to_string(savedMRDNumber) + ", LAPPD " + std::to_string(savedLAPPDNumber) + ", trigger group " + std::to_string(savedTriggerGroupNumber), v_message, verbosityEBSaver); + + Log("EBSaver: Set PMT pairing information buffer PairedPMTTimeStamps size " + std::to_string(PairedPMTTimeStamps.size()), v_message, verbosityEBSaver); + // print size of each track + for (auto const &track : PairedPMTTimeStamps) + Log("EBSaver: track " + std::to_string(track.first) + " size " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + Log("EBSaver: Set MRD pairing information buffer PairedMRDTimeStamps size " + std::to_string(PairedMRDTimeStamps.size()), v_message, verbosityEBSaver); + for (auto const &track : PairedMRDTimeStamps) + Log("EBSaver: track " + std::to_string(track.first) + " size " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + Log("EBSaver: Set LAPPD pairing information buffer PairedLAPPDTimeStamps size " + std::to_string(PairedLAPPDTimeStamps.size()), v_message, verbosityEBSaver); + for (auto const &track : PairedLAPPDTimeStamps) + Log("EBSaver: track " + std::to_string(track.first) + " size " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + + SetDataObjects(); + cout << "\033[1;34m******* EBSaver : Finished *******\033[0m" << endl; + + return true; +} + +bool EBSaver::Finalise() +{ + Log("\033[1;34mEBSaver: Finalising\033[0m", v_message, verbosityEBSaver); + ANNIEEvent->Close(); + ANNIEEvent->Delete(); + delete ANNIEEvent; + + Log("EBSaver: Finished built " + std::to_string(TotalBuiltEventsNumber) + " events", v_message, verbosityEBSaver); + Log("EBSaver: Finished built " + std::to_string(savedTriggerGroupNumber) + " trigger groups", v_message, verbosityEBSaver); + Log("EBSaver: Finished built " + std::to_string(savedPMTHitMapNumber) + " PMT hit maps", v_message, verbosityEBSaver); + Log("EBSaver: Finished built " + std::to_string(savedMRDNumber) + " MRD events", v_message, verbosityEBSaver); + Log("EBSaver: Finished built " + std::to_string(savedLAPPDNumber) + " LAPPD events", v_message, verbosityEBSaver); + Log("EBSaver: matched but not built event number: ***********", v_message, verbosityEBSaver); + Log("\033[1;34mEBSaver: left PMT events in pairing info buffer " + std::to_string(PairedPMTTimeStamps.size()) + " \033[0m", v_message, verbosityEBSaver); + // also print the size of each track with track word + + for (auto const &track : PairedPMTTimeStamps) + { + Log("EBSaver: track " + std::to_string(track.first) + ", total left trigger number " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + if (verbosityEBSaver > 9) + { + // count how many events not built for each trigger word + std::map unbuiltEvents; + for (int i = 0; i < track.second.size(); i++) + { + if (PairedPMTTimeStamps[track.first][i] != 0) + unbuiltEvents[PairedPMTTimeStamps[track.first][i]]++; + } + for (auto const &event : unbuiltEvents) + Log("EBSaver: track " + std::to_string(track.first) + ", left trigger " + std::to_string(event.first) + " number " + std::to_string(event.second), v_message, verbosityEBSaver); + } + } + Log("\033[1;34mEBSaver: left MRD events in pairing info buffer " + std::to_string(PairedMRDTimeStamps.size()) + " \033[0m", v_message, verbosityEBSaver); + for (auto const &track : PairedMRDTimeStamps) + { + Log("EBSaver: track " + std::to_string(track.first) + ", left trigger number " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + if (verbosityEBSaver > 9) + { + // count how many events not built for each trigger word + std::map unbuiltEvents; + for (int i = 0; i < track.second.size(); i++) + { + if (PairedMRDTimeStamps[track.first][i] != 0) + unbuiltEvents[PairedMRDTimeStamps[track.first][i]]++; + } + for (auto const &event : unbuiltEvents) + Log("EBSaver: track " + std::to_string(track.first) + ", left trigger " + std::to_string(event.first) + " number " + std::to_string(event.second), v_message, verbosityEBSaver); + } + } + Log("\033[1;34mEBSaver: left LAPPD events in pairing info buffer " + std::to_string(PairedLAPPDTimeStamps.size()) + " \033[0m", v_message, verbosityEBSaver); + for (auto const &track : PairedLAPPDTimeStamps) + { + Log("EBSaver: track " + std::to_string(track.first) + ", left trigger number " + std::to_string(track.second.size()), v_message, verbosityEBSaver); + // count how many events not built for each trigger word + if (verbosityEBSaver > 9) + { + std::map unbuiltEvents; + for (int i = 0; i < track.second.size(); i++) + { + if (PairedLAPPDTimeStamps[track.first][i] != 0) + unbuiltEvents[PairedLAPPDTimeStamps[track.first][i]]++; + } + for (auto const &event : unbuiltEvents) + Log("EBSaver: track " + std::to_string(track.first) + ", left trigger " + std::to_string(event.first) + " number " + std::to_string(event.second), v_message, verbosityEBSaver); + } + } + Log("EBSaver: left event number: ***********", v_message, verbosityEBSaver); + Log("EBSaver: left PMT events in original data buffer " + std::to_string(InProgressHits->size()), v_message, verbosityEBSaver); + Log("EBSaver: left MRD events in original data buffer " + std::to_string(MRDEvents.size()), v_message, verbosityEBSaver); + Log("EBSaver: left LAPPD events in original data buffer " + std::to_string(Buffer_LAPPDTimestamp_ns.size()), v_message, verbosityEBSaver); + // print the size of each track of + + // add debug print for the left MRD, print TriggerTimeWithoutMRD and PairedMRDTimeStamps to two txt file + std::ofstream TriggerTimeWithoutMRDFile; + TriggerTimeWithoutMRDFile.open("EBdebug_TriggerTimeWithoutMRD.txt"); + for (auto const &track : TriggerTimeWithoutMRD) + { + TriggerTimeWithoutMRDFile << track.first << " " << track.second << endl; + } + TriggerTimeWithoutMRDFile.close(); + std::ofstream PairedMRDTimeStampsFile; + PairedMRDTimeStampsFile.open("EBdebug_PairedMRDTimeStamps.txt"); + for (auto const &track : PairedMRDTimeStamps) + { + for (int i = 0; i < track.second.size(); i++) + { + PairedMRDTimeStampsFile << track.first << " " << track.second[i] << endl; + } + } + + return true; +} + +bool EBSaver::SaveToANNIEEvent(string saveFileName, int runCode, int triggerTrack, int trackIndex) +{ + SaveRunInfo(runCode); + std::map DataStreams; + DataStreams.emplace("Tank", 0); + DataStreams.emplace("MRD", 0); + DataStreams.emplace("CTC", 1); + DataStreams.emplace("LAPPD", 0); + + SaveGroupedTriggers(triggerTrack, trackIndex); + + bool PMTSaved = false; // incase of multiple 14 found in one group + bool MRDSaved = false; + bool LAPPDSaved = false; + bool beamInfoSaved = false; + + std::map GroupedTrigger = GroupedTriggersInTotal[triggerTrack][trackIndex]; + // For each element in GroupedTrigger, find is it appear in PairedPMTTriggerTimestamp[triggerTrack], + // if yes, got the index, access the same index at PairedPMTTimeStamps[triggerTrack], that uint64_t is the PMTTime + for (auto &trigger : GroupedTrigger) + { + uint64_t triggerTime = trigger.first; + uint32_t triggerType = trigger.second; + if (triggerType == 14) + { + Log("EBSaver: Found undelayed beam trigger with time " + std::to_string(triggerTime) + " in GroupedTrigger", v_debug, verbosityEBSaver); + if (!beamInfoSaved) + { + SaveBeamInfo(triggerTime); + beamInfoSaved = true; + } + } + + if (PairedPMTTriggerTimestamp.find(triggerTrack) != PairedPMTTriggerTimestamp.end()) + { + for (int i = 0; i < PairedPMTTriggerTimestamp.at(triggerTrack).size(); i++) + { + if (PairedPMTTriggerTimestamp.at(triggerTrack).at(i) == triggerTime) + { + uint64_t PMTTime = PairedPMTTimeStamps.at(triggerTrack).at(i); + Log("EBSaver: Found trigger with time " + std::to_string(triggerTime) + " in PairedPMTTriggerTimestamp " + std::to_string(i) + " match with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + + bool saved = SavePMTData(PMTTime); + PMTSaved = saved; + DataStreams["Tank"] = 1; + if (saved) + PMTPairInfoToRemoveTime[triggerTrack].push_back(PMTTime); + Log("EBSaver: Saved " + std::to_string(savedPMTHitMapNumber) + " PMT data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + // break; + } + } + } + + // check if PairedMRDTriggerTimestamp has element with key = triggerTrack + if (!MRDSaved) + { + Log("Finding trigger track = " + std::to_string(triggerTrack) + " in PairedMRDTriggerTimestamp", v_debug, verbosityEBSaver); + // print PairedMRDTriggerTimestamp with track number and size + for (auto const &track : PairedMRDTriggerTimestamp) + { + Log("EBSaver: in PairedMRDTriggerTimestamp track " + std::to_string(track.first) + ", left trigger number " + std::to_string(track.second.size()), v_debug, verbosityEBSaver); + } + for (auto const &track : PairedMRDTimeStamps) + { + Log("EBSaver: in PairedMRDTimeStamps track " + std::to_string(track.first) + ", left trigger number " + std::to_string(track.second.size()), v_debug, verbosityEBSaver); + } + if (PairedMRDTriggerTimestamp.find(triggerTrack) != PairedMRDTriggerTimestamp.end()) + { + if (triggerTime > PairedMRDTriggerTimestamp.at(triggerTrack).at(0) && triggerTime < PairedMRDTriggerTimestamp.at(triggerTrack).at(PairedMRDTriggerTimestamp.at(triggerTrack).size() - 1)) + { + uint64_t minDiff = 100 * 60 * 1e9; + Log("Found trigger track = " + std::to_string(triggerTrack) + " in PairedMRDTriggerTimestamp with current searching trigger type = " + std::to_string(triggerType) + " and trigger time = " + std::to_string(triggerTime), v_debug, verbosityEBSaver); + // print the size of PairedMRDTriggerTimestamp.at(triggerTrack), print the first and the last timestamp + Log("EBSaver: PairedMRDTriggerTimestamp size " + std::to_string(PairedMRDTriggerTimestamp.at(triggerTrack).size()), v_debug, verbosityEBSaver); + if (PairedMRDTriggerTimestamp.at(triggerTrack).size() > 0) + Log("EBSaver: PairedMRDTriggerTimestamp first " + std::to_string(PairedMRDTriggerTimestamp.at(triggerTrack).at(0)) + ", last " + std::to_string(PairedMRDTriggerTimestamp.at(triggerTrack).at(PairedMRDTriggerTimestamp.at(triggerTrack).size() - 1)), v_debug, verbosityEBSaver); + + for (int i = 0; i < PairedMRDTriggerTimestamp.at(triggerTrack).size(); i++) + { + uint64_t diff = (PairedMRDTriggerTimestamp.at(triggerTrack).at(i) > triggerTime) ? PairedMRDTriggerTimestamp.at(triggerTrack).at(i) - triggerTime : triggerTime - PairedMRDTriggerTimestamp.at(triggerTrack).at(i); + if (diff < minDiff) + minDiff = diff; + + if (PairedMRDTriggerTimestamp.at(triggerTrack).at(i) == triggerTime || (diff < 1e6)) + { + if (diff < 1e6) + { + Log("EBSaver: diff<1e6, is " + std::to_string(diff), v_debug, verbosityEBSaver); + TriggerTimeWithoutMRD.emplace(PairedMRDTriggerTimestamp.at(triggerTrack).at(i), static_cast(diff)); + } + uint64_t MRDTime = PairedMRDTimeStamps.at(triggerTrack).at(i); + bool saved = SaveMRDData(MRDTime); + MRDSaved = saved; + DataStreams["MRD"] = 1; + if (MRDSaved) + MRDPairInfoToRemoveTime[triggerTrack].push_back(MRDTime); + Log("EBSaver: Saved " + std::to_string(savedMRDNumber) + " MRD data with MRDTime " + std::to_string(MRDTime), v_debug, verbosityEBSaver); + Log("EBSaver: Found trigger with time " + std::to_string(triggerTime) + " in PairedMRDTriggerTimestamp " + std::to_string(i) + " match with MRDTime " + std::to_string(MRDTime), v_debug, verbosityEBSaver); + // break; + Log("EBSaver: While saving MRD data, use trigger time " + std::to_string(triggerTime) + " with minDiff " + std::to_string(minDiff), v_debug, verbosityEBSaver); + } + } + } + // Log("EBSaver: MRDData saved", 8, verbosityEBSaver); + } + } + + if (PairedLAPPDTriggerTimestamp.find(triggerTrack) != PairedLAPPDTriggerTimestamp.end()) + { + for (int i = 0; i < PairedLAPPDTriggerTimestamp.at(triggerTrack).size(); i++) + { + if (PairedLAPPDTriggerTimestamp.at(triggerTrack).at(i) == triggerTime) + { + uint64_t LAPPDTime = PairedLAPPDTimeStamps.at(triggerTrack).at(i); + bool saved = SaveLAPPDData(LAPPDTime); + LAPPDSaved = saved; + DataStreams["LAPPD"] = 1; + if (LAPPDSaved) + LAPPDPairInfoToRemoveTime[triggerTrack].push_back(LAPPDTime); + Log("EBSaver: Saved " + std::to_string(savedLAPPDNumber) + " LAPPD data with LAPPDTime " + std::to_string(LAPPDTime), v_debug, verbosityEBSaver); + Log("EBSaver: Found trigger with time " + std::to_string(triggerTime) + " in PairedLAPPDTriggerTimestamp " + std::to_string(i) + " match with LAPPDTime " + std::to_string(LAPPDTime), v_debug, verbosityEBSaver); + // break; + } + } + // Log("EBSaver: LAPPDData saved", 8, verbosityEBSaver); + } + } + + ANNIEEvent->Set("DataStreams", DataStreams); + + // if Datastream is not built, save a default empty data for that into the event + if (DataStreams["Tank"] == 0) + BuildEmptyPMTData(); + if (DataStreams["MRD"] == 0) + { + BuildEmptyMRDData(); + if (triggerTrack == 14) + { + // find the time of trigger 8 in current group + uint64_t triggerTime = 0; + for (auto &trigger : GroupedTrigger) + { + if (trigger.second == 8) + { + triggerTime = trigger.first; + break; + } + } + TriggerTimeWithoutMRD.emplace(triggerTime, triggerTrack); + } + else if (triggerTrack == 36) + { + // find the time of trigger 8 in current group + uint64_t triggerTime = 0; + for (auto &trigger : GroupedTrigger) + { + if (trigger.second == 36) + { + triggerTime = trigger.first; + break; + } + } + TriggerTimeWithoutMRD.emplace(triggerTime, triggerTrack); + } + } + + if (DataStreams["LAPPD"] == 0) + BuildEmptyLAPPDData(); + + Log("EBSaver: Print ANNIEEvent, Saving to " + saveFileName, v_debug, verbosityEBSaver); + if (verbosityEBSaver > 8) + ANNIEEvent->Print(false); + ANNIEEvent->Save(saveFileName); + TotalBuiltEventsNumber++; + ANNIEEvent->Delete(); + + return true; +} + +bool EBSaver::SaveRunInfo(int runCode) +{ + int RunNumber = runCode / 100000; + int SubRunNumber = (runCode % 100000) / 10000 - 1; + int PartFileNumber = runCode % 10000; + + ANNIEEvent->Set("RunNumber", RunNumber); + ANNIEEvent->Set("SubRunNumber", SubRunNumber); + ANNIEEvent->Set("PartNumber", PartFileNumber); + Log("EBSaver: Saving run info with RunNumber " + std::to_string(RunNumber) + " SubRunNumber " + std::to_string(SubRunNumber) + " PartFileNumber " + std::to_string(PartFileNumber), v_debug, verbosityEBSaver); + return true; +} + +bool EBSaver::SaveGroupedTriggers(int triggerTrack, int groupIndex) +{ + Log("EBSaver: Saving grouped triggers for trigger track " + std::to_string(triggerTrack) + " with group index " + std::to_string(groupIndex), v_debug, verbosityEBSaver); + std::map GroupedTrigger = GroupedTriggersInTotal[triggerTrack][groupIndex]; + GroupedTriggerIndexToRemove.emplace(triggerTrack, groupIndex); + + ANNIEEvent->Set("GroupedTrigger", GroupedTrigger); + int matchTriggerType = triggerTrack; + ANNIEEvent->Set("PrimaryTriggerWord", matchTriggerType); + if (matchTriggerType != 14) + { + ANNIEEvent->Set("TriggerWord", matchTriggerType); + } + else + { + ANNIEEvent->Set("TriggerWord", 5); + } + + // find the triggertrack trigger time in GroupedTrigger + uint64_t primaryTrigTime = 0; + for (auto &trigger : GroupedTrigger) + { + if (trigger.second == triggerTrack) + { + primaryTrigTime = trigger.first; + break; + } + } + + ANNIEEvent->Set("PrimaryTriggerTime", primaryTrigTime); + ANNIEEvent->Set("CTCTimestamp", primaryTrigTime); + + bool NCExtended = false; + bool CCExtended = false; + std::string TriggerType = ""; + int CTCWordExtended = 0; + uint64_t ExtendedTriggerTime = 0; + + if (triggerTrack == BeamTriggerMain) + { + TriggerType = "Beam"; + // if found 40 in values of GroupedTrigger, set NCExtended to true + // put the data at that index to ExtendedTriggerTime + for (auto &trigger : GroupedTrigger) + { + if (trigger.second == 41) + { + NCExtended = true; + ExtendedTriggerTime = trigger.first; + CTCWordExtended = 1; + break; + } + } + for (auto &trigger : GroupedTrigger) + { + if (trigger.second == 40) + { + CCExtended = true; + ExtendedTriggerTime = trigger.first; + CTCWordExtended = 2; + break; + } + } + } + else if (triggerTrack == LaserTriggerMain) + TriggerType = "Laser"; + else if (triggerTrack == CosmicTriggerMain) + TriggerType = "Cosmic"; + else if (triggerTrack == LEDTriggerMain) + TriggerType = "LED"; + else if (triggerTrack == AmBeTriggerMain) + TriggerType = "AmBe"; + else if (triggerTrack == PPSMain) + TriggerType = "PPS"; + + ANNIEEvent->Set("NCExtended", NCExtended); + ANNIEEvent->Set("CCExtended", CCExtended); + ANNIEEvent->Set("TriggerType", TriggerType); + ANNIEEvent->Set("TriggerExtended", CTCWordExtended); // 0: normal, 1: NC extended, 2: CC extended + // Notice, in the V1 eventbuilder, there is a requirement that the matched trigger time - extended trigger time <5000, if not the extended will be 0 + // we don't have it here because the PMT was not matched to a single trigger, but a group. + // you may need to select the events based on the time difference in the grouped trigger + + TimeClass TriggerTime(primaryTrigTime); + TriggerClass TriggerData(TriggerType, matchTriggerType, CTCWordExtended, true, TriggerTime); + ANNIEEvent->Set("TriggerData", TriggerData); + + savedTriggerGroupNumber++; + Log("EBSaver: Saved trigger group with trigger type " + TriggerType + " and trigger time " + std::to_string(primaryTrigTime), v_debug, verbosityEBSaver); + return true; +} + +bool EBSaver::SavePMTData(uint64_t PMTTime) +{ + Log("EBSaver: Saving PMT data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + // find PMTTime in InProgressHits, if not found, return false + if (InProgressHits->find(PMTTime) == InProgressHits->end()) + { + Log("EBSaver: PMT data with PMTTime " + std::to_string(PMTTime) + " not found in InProgressHits", v_debug, verbosityEBSaver); + return false; + } + ANNIEEvent->Set("EventTimeTank", PMTTime); + + std::map> *PMTHits = InProgressHits->at(PMTTime); + std::map>> PMTRecoADCHits = InProgressRecoADCHits->at(PMTTime); + std::map> *PMTHitsAux = InProgressHitsAux->at(PMTTime); + std::map>> PMTRecoADCHitsAux = InProgressRecoADCHitsAux->at(PMTTime); + std::map> PMTRawAcqSize = FinishedRawAcqSize->at(PMTTime); + + Log("EBSaver: Got PMT data, saving", v_debug, verbosityEBSaver); + + // check does the ANNIEEvent already have the key "Hits", if yes, print the size of the vector of each key + // also print the size of the vector of each key in new PMTHits + // Then Merger the two maps + std::map> *OldPMTHits = new std::map>; + bool gotHits = ANNIEEvent->Get("Hits", OldPMTHits); + if (gotHits) + { + Log("EBSaver: ANNIEEvent already has key Hits, size " + std::to_string(OldPMTHits->size()), v_debug, verbosityEBSaver); + for (auto const &time : *OldPMTHits) + Log("EBSaver: OldPMTHits old time " + std::to_string(time.first) + " size " + std::to_string(time.second.size()), v_debug, verbosityEBSaver); + for (auto const &time : *PMTHits) + Log("EBSaver: PMTHits new time " + std::to_string(time.first) + " size " + std::to_string(time.second.size()), v_debug, verbosityEBSaver); + for (auto const &time : *OldPMTHits) + { + if (PMTHits->count(time.first) == 0) + { + PMTHits->emplace(time.first, time.second); + } + else + { + for (auto const &hit : time.second) + { + PMTHits->at(time.first).push_back(hit); + } + } + } + Log("EBSaver: Merged PMT data, PMTHits size " + std::to_string(PMTHits->size()), v_debug, verbosityEBSaver); + } + + ANNIEEvent->Set("Hits", PMTHits, true); + ANNIEEvent->Set("RecoADCData", PMTRecoADCHits); + ANNIEEvent->Set("AuxHits", PMTHitsAux, true); + ANNIEEvent->Set("RecoAuxADCData", PMTRecoADCHitsAux); + ANNIEEvent->Set("RawAcqSize", PMTRawAcqSize); + + if(saveRawRWMWaveform) + { + //find PMTTime as key in RWMRawWaveforms, if found, save it, if not, save an empty vector + if (RWMRawWaveforms->find(PMTTime) != RWMRawWaveforms->end() && RWMRawWaveforms->at(PMTTime).size() > 0) + { + std::vector RWMRawWaveform = RWMRawWaveforms->at(PMTTime); + ANNIEEvent->Set("RWMRawWaveform", RWMRawWaveform); + Log("EBSaver: Saved RWM data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + RWMRawWaveforms->erase(PMTTime); + } + else + { + std::vector RWMRawWaveform; + ANNIEEvent->Set("RWMRawWaveform", RWMRawWaveform); + Log("EBSaver: Saved empty RWM data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + } + } + if(saveRawBRFWaveform) + { + //find PMTTime as key in BRFRawWaveforms, if found, save it, if not, save an empty vector + if (BRFRawWaveforms->find(PMTTime) != BRFRawWaveforms->end() && BRFRawWaveforms->at(PMTTime).size() > 0) + { + std::vector BRFRawWaveform = BRFRawWaveforms->at(PMTTime); + ANNIEEvent->Set("BRFRawWaveform", BRFRawWaveform); + Log("EBSaver: Saved BRF data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + BRFRawWaveforms->erase(PMTTime); + } + else + { + std::vector BRFRawWaveform; + ANNIEEvent->Set("BRFRawWaveform", BRFRawWaveform); + Log("EBSaver: Saved empty BRF data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + } + } + + savedPMTHitMapNumber++; + + // erase the built data from original data buffer + InProgressHits->erase(PMTTime); + InProgressRecoADCHits->erase(PMTTime); + InProgressHitsAux->erase(PMTTime); + InProgressRecoADCHitsAux->erase(PMTTime); + FinishedRawAcqSize->erase(PMTTime); + + Log("EBSaver: Saved PMT data with PMTTime " + std::to_string(PMTTime), v_debug, verbosityEBSaver); + return true; +} + +bool EBSaver::SaveMRDData(uint64_t MRDTime) +{ + Log("EBSaver: Saving MRD data with MRDTime " + std::to_string(MRDTime), v_debug, verbosityEBSaver); + // find MRDTime in MRDEvents, if not found, return false + if (MRDEvents.find(MRDTime) == MRDEvents.end()) + { + Log("EBSaver: not found MRD data with MRDTime " + std::to_string(MRDTime) + " in MRDEvents", v_debug, verbosityEBSaver); + return false; + } + + // find the index of the MRDTime in PairedMRDTimeStamps + std::vector> MRDHits = MRDEvents.at(MRDTime); + std::string MRDTriggerType = MRDEventTriggerTypes.at(MRDTime); + int beam_tdc = MRDBeamLoopback.at(MRDTime); + int cosmic_tdc = MRDCosmicLoopback.at(MRDTime); + + std::map> *TDCData = new std::map>; + + for (unsigned int i_value = 0; i_value < MRDHits.size(); i_value++) + { + unsigned long channelkey = MRDHits.at(i_value).first; + int hitTimeADC = MRDHits.at(i_value).second; + double hitTime = 4000. - 4. * static_cast(hitTimeADC); + + if (TDCData->count(channelkey) == 0) + { + std::vector newhitvector; + newhitvector.push_back(Hit(0, hitTime, 1.)); + TDCData->emplace(channelkey, newhitvector); + } + else + { + TDCData->at(channelkey).push_back(Hit(0, hitTime, 1.)); + } + } + + std::map mrd_loopback_tdc; + mrd_loopback_tdc.emplace("BeamLoopbackTDC", beam_tdc); + mrd_loopback_tdc.emplace("CosmicLoopbackTDC", cosmic_tdc); + + Log("EBSaver: TDCdata size: " + std::to_string(TDCData->size()), v_warning, verbosityEBSaver); + + ANNIEEvent->Set("TDCData", TDCData, true); + TimeClass t(MRDTime); + ANNIEEvent->Set("EventTimeMRD", t); + ANNIEEvent->Set("MRDTriggerType", MRDTriggerType); + ANNIEEvent->Set("MRDLoopbackTDC", mrd_loopback_tdc); + + savedMRDNumber++; + + // erase the built data from original data buffer + MRDEvents.erase(MRDTime); + MRDEventTriggerTypes.erase(MRDTime); + MRDBeamLoopback.erase(MRDTime); + MRDCosmicLoopback.erase(MRDTime); + + Log("EBSaver: Saved MRD data with MRDTime " + std::to_string(MRDTime), v_debug, verbosityEBSaver); + return true; +} + +bool EBSaver::SaveLAPPDData(uint64_t LAPPDTime) +{ + Log("EBSaver: Saving LAPPD data with LAPPDTime " + std::to_string(LAPPDTime), v_debug, verbosityEBSaver); + // find LAPPDTime in Buffer_LAPPDTimestamp_ns, if not found, return false + if (std::find(Buffer_LAPPDTimestamp_ns.begin(), Buffer_LAPPDTimestamp_ns.end(), LAPPDTime) == Buffer_LAPPDTimestamp_ns.end()) + { + Log("EBSaver: LAPPD data with LAPPDTime " + std::to_string(LAPPDTime) + " not found in Buffer_LAPPDTimestamp_ns", v_debug, verbosityEBSaver); + return false; + } + + // find the index of the LAPPDTime in PairedLAPPDTimeStamps + int index = -1; + for (int i = 0; i < Buffer_LAPPDTimestamp_ns.size(); i++) + { + if (Buffer_LAPPDTimestamp_ns.at(i) == LAPPDTime) + { + index = i; + break; + } + } + + // save the data at index i to ANNIE event, then remove that index from buffer + if (index != -1) + { + std::map LAPPDDataMap; + std::map LAPPDBeamgate_ns; + std::map LAPPDTimeStamps_ns; // data and key are the same + std::map LAPPDTimeStampsRaw; + std::map LAPPDBeamgatesRaw; + std::map LAPPDOffsets; + std::map LAPPDTSCorrection; + std::map LAPPDBGCorrection; + std::map LAPPDOSInMinusPS; + std::map LAPPDBG_PPSBefore; + std::map LAPPDBG_PPSAfter; + std::map LAPPDBG_PPSDiff; + std::map LAPPDBG_PPSMissing; + std::map LAPPDTS_PPSBefore; + std::map LAPPDTS_PPSAfter; + std::map LAPPDTS_PPSDiff; + std::map LAPPDTS_PPSMissing; + + bool gotMap = ANNIEEvent->Get("LAPPDDataMap", LAPPDDataMap); + bool gotBeamgates_ns = ANNIEEvent->Get("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + bool gotTimeStamps_ns = ANNIEEvent->Get("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + bool gotTimeStampsRaw = ANNIEEvent->Get("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + bool gotBeamgatesRaw = ANNIEEvent->Get("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + bool gotOffsets = ANNIEEvent->Get("LAPPDOffsets", LAPPDOffsets); + bool gotTSCorrection = ANNIEEvent->Get("LAPPDTSCorrection", LAPPDTSCorrection); + bool gotDBGCorrection = ANNIEEvent->Get("LAPPDBGCorrection", LAPPDBGCorrection); + bool gotOSInMinusPS = ANNIEEvent->Get("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + bool gotBG_PPSBefore = ANNIEEvent->Get("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + bool gotBG_PPSAfter = ANNIEEvent->Get("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + bool gotBG_PPSDiff = ANNIEEvent->Get("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + bool gotBG_PPSMissing = ANNIEEvent->Get("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + bool gotTS_PPSBefore = ANNIEEvent->Get("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + bool gotTS_PPSAfter = ANNIEEvent->Get("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + bool gotTS_PPSDiff = ANNIEEvent->Get("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + bool gotTS_PPSMissing = ANNIEEvent->Get("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); + + LAPPDDataMap.emplace(LAPPDTime, Buffer_LAPPDData.at(index)); + LAPPDBeamgate_ns.emplace(LAPPDTime, Buffer_LAPPDBeamgate_ns.at(index)); + LAPPDTimeStamps_ns.emplace(LAPPDTime, Buffer_LAPPDTimestamp_ns.at(index)); + LAPPDTimeStampsRaw.emplace(LAPPDTime, Buffer_LAPPDTimestamp_Raw.at(index)); + LAPPDBeamgatesRaw.emplace(LAPPDTime, Buffer_LAPPDBeamgate_Raw.at(index)); + LAPPDOffsets.emplace(LAPPDTime, Buffer_LAPPDOffset.at(index)); + LAPPDTSCorrection.emplace(LAPPDTime, Buffer_LAPPDTSCorrection.at(index)); + LAPPDBGCorrection.emplace(LAPPDTime, Buffer_LAPPDBGCorrection.at(index)); + LAPPDOSInMinusPS.emplace(LAPPDTime, Buffer_LAPPDOffset_minus_ps.at(index)); + LAPPDBG_PPSBefore.emplace(LAPPDTime, Buffer_LAPPDBG_PPSBefore.at(index)); + LAPPDBG_PPSAfter.emplace(LAPPDTime, Buffer_LAPPDBG_PPSAfter.at(index)); + LAPPDBG_PPSDiff.emplace(LAPPDTime, Buffer_LAPPDBG_PPSDiff.at(index)); + LAPPDBG_PPSMissing.emplace(LAPPDTime, Buffer_LAPPDBG_PPSMissing.at(index)); + LAPPDTS_PPSBefore.emplace(LAPPDTime, Buffer_LAPPDTS_PPSBefore.at(index)); + LAPPDTS_PPSAfter.emplace(LAPPDTime, Buffer_LAPPDTS_PPSAfter.at(index)); + LAPPDTS_PPSDiff.emplace(LAPPDTime, Buffer_LAPPDTS_PPSDiff.at(index)); + LAPPDTS_PPSMissing.emplace(LAPPDTime, Buffer_LAPPDTS_PPSMissing.at(index)); + + if(Buffer_LAPPDTS_PPSMissing.at(index)!= Buffer_LAPPDBG_PPSMissing.at(index)) + { + Log("EBSaver: LAPPDTS_PPSMissing is different from LAPPDBG_PPSMissing, LAPPDTS_PPSMissing " + std::to_string(Buffer_LAPPDTS_PPSMissing.at(index)) + " LAPPDBG_PPSMissing " + std::to_string(Buffer_LAPPDBG_PPSMissing.at(index)), v_message, verbosityEBSaver); + } + + ANNIEEvent->Set("LAPPDDataMap", LAPPDDataMap); + ANNIEEvent->Set("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + ANNIEEvent->Set("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + ANNIEEvent->Set("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + ANNIEEvent->Set("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + ANNIEEvent->Set("LAPPDOffsets", LAPPDOffsets); + ANNIEEvent->Set("LAPPDTSCorrection", LAPPDTSCorrection); + ANNIEEvent->Set("LAPPDBGCorrection", LAPPDBGCorrection); + ANNIEEvent->Set("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + ANNIEEvent->Set("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + ANNIEEvent->Set("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + ANNIEEvent->Set("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + ANNIEEvent->Set("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + ANNIEEvent->Set("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + ANNIEEvent->Set("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + ANNIEEvent->Set("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + ANNIEEvent->Set("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); + + savedLAPPDNumber++; + + // erase the built data from original data buffer + Buffer_LAPPDData.erase(Buffer_LAPPDData.begin() + index); + Buffer_LAPPDBeamgate_ns.erase(Buffer_LAPPDBeamgate_ns.begin() + index); + Buffer_LAPPDTimestamp_ns.erase(Buffer_LAPPDTimestamp_ns.begin() + index); + Buffer_LAPPDTimestamp_Raw.erase(Buffer_LAPPDTimestamp_Raw.begin() + index); + Buffer_LAPPDBeamgate_Raw.erase(Buffer_LAPPDBeamgate_Raw.begin() + index); + Buffer_LAPPDOffset.erase(Buffer_LAPPDOffset.begin() + index); + Buffer_LAPPDTSCorrection.erase(Buffer_LAPPDTSCorrection.begin() + index); + Buffer_LAPPDBGCorrection.erase(Buffer_LAPPDBGCorrection.begin() + index); + Buffer_LAPPDOffset_minus_ps.erase(Buffer_LAPPDOffset_minus_ps.begin() + index); + Buffer_LAPPDBG_PPSBefore.erase(Buffer_LAPPDBG_PPSBefore.begin() + index); + Buffer_LAPPDBG_PPSAfter.erase(Buffer_LAPPDBG_PPSAfter.begin() + index); + Buffer_LAPPDBG_PPSDiff.erase(Buffer_LAPPDBG_PPSDiff.begin() + index); + Buffer_LAPPDBG_PPSMissing.erase(Buffer_LAPPDBG_PPSMissing.begin() + index); + Buffer_LAPPDTS_PPSBefore.erase(Buffer_LAPPDTS_PPSBefore.begin() + index); + Buffer_LAPPDTS_PPSAfter.erase(Buffer_LAPPDTS_PPSAfter.begin() + index); + Buffer_LAPPDTS_PPSDiff.erase(Buffer_LAPPDTS_PPSDiff.begin() + index); + Buffer_LAPPDTS_PPSMissing.erase(Buffer_LAPPDTS_PPSMissing.begin() + index); + + Log("EBSaver: Saved LAPPD data with LAPPDTime " + std::to_string(LAPPDTime), v_debug, verbosityEBSaver); + return true; + } + else + { + Log("EBSaver: Failed to find LAPPD data with LAPPDTime " + std::to_string(LAPPDTime), v_debug, verbosityEBSaver); + + return false; + } +} + +bool EBSaver::SaveOrphan(int runCode) +{ + // loop everything in the data buffer, save + SaveOrphanPMT(runCode); + SaveOrphanMRD(runCode); + SaveOrphanLAPPD(runCode); + SaveOrphanCTC(runCode); + return true; +} + +bool EBSaver::SaveOrphanPMT(int runCode) +{ + + return true; +} + +bool EBSaver::SaveOrphanMRD(int runCode) +{ + + return true; +} + +bool EBSaver::SaveOrphanCTC(int runCode) +{ + + return true; +} + +bool EBSaver::SaveOrphanLAPPD(int runCode) +{ + + return true; +} + +bool EBSaver::GotAllDataFromOriginalBuffer() +{ + // got PMT data + bool gotPMTHits = m_data->CStore.Get("InProgressHits", InProgressHits); + bool gotPMTChkey = m_data->CStore.Get("InProgressChkey", InProgressChkey); + bool gotIPRecoADCHits = m_data->CStore.Get("InProgressRecoADCHits", InProgressRecoADCHits); + bool gotIPHitsAux = m_data->CStore.Get("InProgressHitsAux", InProgressHitsAux); + bool gotIPRADCH = m_data->CStore.Get("InProgressRecoADCHitsAux", InProgressRecoADCHitsAux); + bool gotFRAS = m_data->CStore.Get("FinishedRawAcqSize", FinishedRawAcqSize); // Filled in PhaseIIADCCalibrator + bool gotRWM = m_data->CStore.Get("RWMRawWaveforms", RWMRawWaveforms); + bool gotBRF = m_data->CStore.Get("BRFRawWaveforms", BRFRawWaveforms); + + if (!gotPMTHits || !gotPMTChkey || !gotIPRecoADCHits || !gotIPHitsAux || !gotIPRADCH || !gotFRAS) + { + Log("EBSaver: Failed to get some PMT data from buffer", v_message, verbosityEBSaver); + // print which one was failed + if (!gotPMTHits) + Log("EBSaver: Failed to get PMT hits from buffer", v_message, verbosityEBSaver); + if (!gotPMTChkey) + Log("EBSaver: Failed to get PMT chkey from buffer", v_message, verbosityEBSaver); + if (!gotIPRecoADCHits) + Log("EBSaver: Failed to get PMT recoADCHits from buffer", v_message, verbosityEBSaver); + if (!gotIPHitsAux) + Log("EBSaver: Failed to get PMT hits aux from buffer", v_message, verbosityEBSaver); + if (!gotIPRADCH) + Log("EBSaver: Failed to get PMT recoADCHits aux from buffer", v_message, verbosityEBSaver); + if (!gotFRAS) + Log("EBSaver: Failed to get PMT raw acq size from buffer", v_message, verbosityEBSaver); + } + // got PMT match info + bool gotPairedPMTTriggerTimestamp = m_data->CStore.Get("PairedPMTTriggerTimestamp", PairedPMTTriggerTimestamp); + bool gotPairedPMTTimeStamps = m_data->CStore.Get("PairedPMTTimeStamps", PairedPMTTimeStamps); + bool gotPairedPMT_TriggerIndex = m_data->CStore.Get("PairedPMT_TriggerIndex", PairedPMT_TriggerIndex); + bool gotPMTHitmapRunCode = m_data->CStore.Get("PMTHitmapRunCode", PMTHitmapRunCode); + if (!gotPairedPMTTriggerTimestamp || !gotPairedPMTTimeStamps || !gotPairedPMT_TriggerIndex || !gotPMTHitmapRunCode) + { + Log("EBSaver: Failed to get PMT match info from buffer", v_message, verbosityEBSaver); + // print which one was failed + if (!gotPairedPMTTriggerTimestamp) + Log("EBSaver: Failed to get PairedPMTTriggerTimestamp", v_message, verbosityEBSaver); + if (!gotPairedPMTTimeStamps) + Log("EBSaver: Failed to get PairedPMTTimeStamps", v_message, verbosityEBSaver); + if (!gotPairedPMT_TriggerIndex) + Log("EBSaver: Failed to get PairedPMT_TriggerIndex", v_message, verbosityEBSaver); + if (!gotPMTHitmapRunCode) + Log("EBSaver: Failed to get PMTHitmapRunCode", v_message, verbosityEBSaver); + } + // + // got MRD data + bool gotMRDEvents = m_data->CStore.Get("MRDEvents", MRDEvents); + bool gotMRDEventTriggerTypes = m_data->CStore.Get("MRDEventTriggerTypes", MRDEventTriggerTypes); + bool gotMRDBeamLoopback = m_data->CStore.Get("MRDBeamLoopback", MRDBeamLoopback); + bool gotMRDCosmicLoopback = m_data->CStore.Get("MRDCosmicLoopback", MRDCosmicLoopback); + if (!gotMRDEvents || !gotMRDEventTriggerTypes || !gotMRDBeamLoopback || !gotMRDCosmicLoopback) + Log("EBSaver: Failed to get some MRD data from buffer", v_message, verbosityEBSaver); + // got MRD match info + bool gotPairedMRDTriggerTimestamp = m_data->CStore.Get("PairedMRDTriggerTimestamp", PairedMRDTriggerTimestamp); + bool gotPairedMRDTimeStamps = m_data->CStore.Get("PairedMRDTimeStamps", PairedMRDTimeStamps); + bool gotPairedMRD_TriggerIndex = m_data->CStore.Get("PairedMRD_TriggerIndex", PairedMRD_TriggerIndex); + bool gotMRDHitMapRunCode = m_data->CStore.Get("MRDHitMapRunCode", MRDHitMapRunCode); + if (!gotPairedMRDTriggerTimestamp || !gotPairedMRDTimeStamps || !gotPairedMRD_TriggerIndex || !gotMRDHitMapRunCode) + Log("EBSaver: Failed to get MRD match info from buffer", v_message, verbosityEBSaver); + // + // got LAPPD data + bool gotBuffer_LAPPDTimestamp_ns = m_data->CStore.Get("Buffer_LAPPDTimestamp_ns", Buffer_LAPPDTimestamp_ns); + bool gotBuffer_LAPPDData = m_data->CStore.Get("Buffer_LAPPDData", Buffer_LAPPDData); + bool gotBuffer_LAPPDBeamgate_ns = m_data->CStore.Get("Buffer_LAPPDBeamgate_ns", Buffer_LAPPDBeamgate_ns); + bool gotBuffer_LAPPDOffset = m_data->CStore.Get("Buffer_LAPPDOffset", Buffer_LAPPDOffset); + bool gotBuffer_LAPPDBeamgate_Raw = m_data->CStore.Get("Buffer_LAPPDBeamgate_Raw", Buffer_LAPPDBeamgate_Raw); + bool gotBuffer_LAPPDTimestamp_Raw = m_data->CStore.Get("Buffer_LAPPDTimestamp_Raw", Buffer_LAPPDTimestamp_Raw); + bool gotBuffer_LAPPDBGCorrection = m_data->CStore.Get("Buffer_LAPPDBGCorrection", Buffer_LAPPDBGCorrection); + bool gotBuffer_LAPPDTSCorrection = m_data->CStore.Get("Buffer_LAPPDTSCorrection", Buffer_LAPPDTSCorrection); + bool gotBuffer_LAPPDOffset_minus_ps = m_data->CStore.Get("Buffer_LAPPDOffset_minus_ps", Buffer_LAPPDOffset_minus_ps); + if (!gotBuffer_LAPPDTimestamp_ns || !gotBuffer_LAPPDData || !gotBuffer_LAPPDBeamgate_ns || !gotBuffer_LAPPDOffset || !gotBuffer_LAPPDBeamgate_Raw || !gotBuffer_LAPPDTimestamp_Raw || !gotBuffer_LAPPDBGCorrection || !gotBuffer_LAPPDTSCorrection || !gotBuffer_LAPPDOffset_minus_ps) + Log("EBSaver: Failed to get some LAPPD data from buffer", v_message, verbosityEBSaver); + bool gotBuffer_LAPPDBG_PPSBefore = m_data->CStore.Get("Buffer_LAPPDBG_PPSBefore", Buffer_LAPPDBG_PPSBefore); + bool gotBuffer_LAPPDBG_PPSAfter = m_data->CStore.Get("Buffer_LAPPDBG_PPSAfter", Buffer_LAPPDBG_PPSAfter); + bool gotBuffer_LAPPDBG_PPSDiff = m_data->CStore.Get("Buffer_LAPPDBG_PPSDiff", Buffer_LAPPDBG_PPSDiff); + bool gotBuffer_LAPPDBG_PPSMissing = m_data->CStore.Get("Buffer_LAPPDBG_PPSMissing", Buffer_LAPPDBG_PPSMissing); + bool gotBuffer_LAPPDTS_PPSBefore = m_data->CStore.Get("Buffer_LAPPDTS_PPSBefore", Buffer_LAPPDTS_PPSBefore); + bool gotBuffer_LAPPDTS_PPSAfter = m_data->CStore.Get("Buffer_LAPPDTS_PPSAfter", Buffer_LAPPDTS_PPSAfter); + bool gotBuffer_LAPPDTS_PPSDiff = m_data->CStore.Get("Buffer_LAPPDTS_PPSDiff", Buffer_LAPPDTS_PPSDiff); + bool gotBuffer_LAPPDTS_PPSMissing = m_data->CStore.Get("Buffer_LAPPDTS_PPSMissing", Buffer_LAPPDTS_PPSMissing); + if(!gotBuffer_LAPPDBG_PPSBefore || !gotBuffer_LAPPDBG_PPSAfter || !gotBuffer_LAPPDBG_PPSDiff || !gotBuffer_LAPPDBG_PPSMissing || !gotBuffer_LAPPDTS_PPSBefore || !gotBuffer_LAPPDTS_PPSAfter || !gotBuffer_LAPPDTS_PPSDiff || !gotBuffer_LAPPDTS_PPSMissing) + Log("EBSaver: Failed to get LAPPD PPS data from buffer", v_message, verbosityEBSaver); + + // got LAPPD match info + bool gotPairedLAPPDTriggerTimestamp = m_data->CStore.Get("PairedLAPPDTriggerTimestamp", PairedLAPPDTriggerTimestamp); + bool gotPairedLAPPDTimeStamps = m_data->CStore.Get("PairedLAPPDTimeStamps", PairedLAPPDTimeStamps); + bool gotPairedLAPPD_TriggerIndex = m_data->CStore.Get("PairedLAPPD_TriggerIndex", PairedLAPPD_TriggerIndex); + bool gotLAPPDRunCode = m_data->CStore.Get("Buffer_LAPPDRunCode", Buffer_LAPPDRunCode); + if (!gotPairedLAPPDTriggerTimestamp || !gotPairedLAPPDTimeStamps || !gotPairedLAPPD_TriggerIndex || !gotLAPPDRunCode) + { + Log("EBSaver: Failed to get LAPPD match info from buffer", v_message, verbosityEBSaver); + // print which one was failed + if (!gotPairedLAPPDTriggerTimestamp) + Log("EBSaver: Failed to get PairedLAPPDTriggerTimestamp", v_message, verbosityEBSaver); + if (!gotPairedLAPPDTimeStamps) + Log("EBSaver: Failed to get PairedLAPPDTimeStamps", v_message, verbosityEBSaver); + if (!gotPairedLAPPD_TriggerIndex) + Log("EBSaver: Failed to get PairedLAPPD_TriggerIndex", v_message, verbosityEBSaver); + if (!gotLAPPDRunCode) + Log("EBSaver: Failed to get LAPPDRunCode", v_message, verbosityEBSaver); + } + + Log("EBSaver: got PMT pairing information buffer PairedPMTTimeStamps size " + std::to_string(PairedPMTTimeStamps.size()), v_message, verbosityEBSaver); + Log("EBSaver: got MRD pairing information buffer PairedMRDTimeStamps size " + std::to_string(PairedMRDTimeStamps.size()), v_message, verbosityEBSaver); + for (auto const &track : PairedMRDTimeStamps) + { + int triggerTrack = track.first; + std::vector times = track.second; + Log("EBSaver: PairedMRDTimeStamps at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + cout << endl; + + Log("EBSaver: got LAPPD pairing information buffer PairedLAPPDTimeStamps size " + std::to_string(PairedLAPPDTimeStamps.size()), v_message, verbosityEBSaver); + for (auto const &track : PairedLAPPDTimeStamps) + { + int triggerTrack = track.first; + std::vector times = track.second; + Log("EBSaver: PairedLAPPDTimeStamps at track " + std::to_string(triggerTrack) + " size " + std::to_string(times.size()), v_message, verbosityEBSaver); + for (int i = 0; i < times.size(); i++) + cout << i << ": " << times[i] << ", "; + } + cout << endl; + + // print PairedLAPPD_TriggerIndex + Log("EBSaver: got LAPPD pairing information buffer PairedLAPPD_TriggerIndex size " + std::to_string(PairedLAPPD_TriggerIndex.size()), v_message, verbosityEBSaver); + for (auto const &track : PairedLAPPD_TriggerIndex) + { + int triggerTrack = track.first; + std::vector indexes = track.second; + Log("EBSaver: PairedLAPPD_TriggerIndex at track " + std::to_string(triggerTrack) + " size " + std::to_string(indexes.size()), v_message, verbosityEBSaver); + for (int i = 0; i < indexes.size(); i++) + cout << i << ": " << indexes[i] << ", "; + } + cout << endl; + + // print Buffer_LAPPDBeamgate_ns + Log("EBSaver: got LAPPD pairing information buffer Buffer_LAPPDBeamgate_ns size " + std::to_string(Buffer_LAPPDBeamgate_ns.size()), v_message, verbosityEBSaver); + for (int i = 0; i < Buffer_LAPPDBeamgate_ns.size(); i++) + cout << i << ": " << Buffer_LAPPDBeamgate_ns[i] << ", "; + cout << endl; + + return true; +} + +void EBSaver::SetDataObjects() +{ + // after erase those data, set them back to CStore + // set PMT data + m_data->CStore.Set("InProgressHits", InProgressHits); + m_data->CStore.Set("InProgressChkey", InProgressChkey); + m_data->CStore.Set("InProgressRecoADCHits", InProgressRecoADCHits); + m_data->CStore.Set("InProgressHitsAux", InProgressHitsAux); + m_data->CStore.Set("InProgressRecoADCHitsAux", InProgressRecoADCHitsAux); + m_data->CStore.Set("FinishedRawAcqSize", FinishedRawAcqSize); + m_data->CStore.Set("RWMRawWaveforms", RWMRawWaveforms); + m_data->CStore.Set("BRFRawWaveforms", BRFRawWaveforms); + // set PMT match info + m_data->CStore.Set("PairedPMTTriggerTimestamp", PairedPMTTriggerTimestamp); + m_data->CStore.Set("PairedPMTTimeStamps", PairedPMTTimeStamps); + m_data->CStore.Set("PairedPMT_TriggerIndex", PairedPMT_TriggerIndex); + m_data->CStore.Set("PMTHitmapRunCode", PMTHitmapRunCode); + // set MRD data + m_data->CStore.Set("MRDEvents", MRDEvents); + m_data->CStore.Set("MRDEventTriggerTypes", MRDEventTriggerTypes); + m_data->CStore.Set("MRDBeamLoopback", MRDBeamLoopback); + m_data->CStore.Set("MRDCosmicLoopback", MRDCosmicLoopback); + // set MRD match info + m_data->CStore.Set("PairedMRDTriggerTimestamp", PairedMRDTriggerTimestamp); + m_data->CStore.Set("PairedMRDTimeStamps", PairedMRDTimeStamps); + m_data->CStore.Set("PairedMRD_TriggerIndex", PairedMRD_TriggerIndex); + m_data->CStore.Set("MRDHitMapRunCode", MRDHitMapRunCode); + // set LAPPD data + m_data->CStore.Set("Buffer_LAPPDTimestamp_ns", Buffer_LAPPDTimestamp_ns); + m_data->CStore.Set("Buffer_LAPPDData", Buffer_LAPPDData); + m_data->CStore.Set("Buffer_LAPPDBeamgate_ns", Buffer_LAPPDBeamgate_ns); + m_data->CStore.Set("Buffer_LAPPDOffset", Buffer_LAPPDOffset); + m_data->CStore.Set("Buffer_LAPPDBeamgate_Raw", Buffer_LAPPDBeamgate_Raw); + m_data->CStore.Set("Buffer_LAPPDTimestamp_Raw", Buffer_LAPPDTimestamp_Raw); + m_data->CStore.Set("Buffer_LAPPDBGCorrection", Buffer_LAPPDBGCorrection); + m_data->CStore.Set("Buffer_LAPPDTSCorrection", Buffer_LAPPDTSCorrection); + m_data->CStore.Set("Buffer_LAPPDOffset_minus_ps", Buffer_LAPPDOffset_minus_ps); + m_data->CStore.Set("Buffer_LAPPDBG_PPSBefore", Buffer_LAPPDBG_PPSBefore); + m_data->CStore.Set("Buffer_LAPPDBG_PPSAfter", Buffer_LAPPDBG_PPSAfter); + m_data->CStore.Set("Buffer_LAPPDBG_PPSDiff", Buffer_LAPPDBG_PPSDiff); + m_data->CStore.Set("Buffer_LAPPDBG_PPSMissing", Buffer_LAPPDBG_PPSMissing); + m_data->CStore.Set("Buffer_LAPPDTS_PPSBefore", Buffer_LAPPDTS_PPSBefore); + m_data->CStore.Set("Buffer_LAPPDTS_PPSAfter", Buffer_LAPPDTS_PPSAfter); + m_data->CStore.Set("Buffer_LAPPDTS_PPSDiff", Buffer_LAPPDTS_PPSDiff); + m_data->CStore.Set("Buffer_LAPPDTS_PPSMissing", Buffer_LAPPDTS_PPSMissing); + // set LAPPD match info + m_data->CStore.Set("PairedLAPPDTriggerTimestamp", PairedLAPPDTriggerTimestamp); + m_data->CStore.Set("PairedLAPPDTimeStamps", PairedLAPPDTimeStamps); + m_data->CStore.Set("PairedLAPPD_TriggerIndex", PairedLAPPD_TriggerIndex); + m_data->CStore.Set("Buffer_LAPPDRunCode", Buffer_LAPPDRunCode); +} + +void EBSaver::BuildEmptyPMTData() +{ + std::map> *PMTHits = new std::map>; + std::map>> PMTRecoADCHits; + std::map> *PMTHitsAux = new std::map>; + std::map>> PMTRecoADCHitsAux; + std::map> PMTRawAcqSize; + + ANNIEEvent->Set("Hits", PMTHits, true); + ANNIEEvent->Set("RecoADCData", PMTRecoADCHits); + ANNIEEvent->Set("AuxHits", PMTHitsAux, true); + ANNIEEvent->Set("RecoAuxADCData", PMTRecoADCHitsAux); + ANNIEEvent->Set("RawAcqSize", PMTRawAcqSize); +} + +void EBSaver::BuildEmptyMRDData() +{ + std::map> *TDCData = new std::map>; + std::string MRDTriggerType = ""; + std::map mrd_loopback_tdc; + + ANNIEEvent->Set("TDCData", TDCData, true); + TimeClass t(0); + ANNIEEvent->Set("EventTimeMRD", t); + ANNIEEvent->Set("MRDTriggerType", MRDTriggerType); + ANNIEEvent->Set("MRDLoopbackTDC", mrd_loopback_tdc); +} + +void EBSaver::BuildEmptyLAPPDData() +{ + std::map LAPPDDataMap; + std::map LAPPDBeamgate_ns; + std::map LAPPDTimeStamps_ns; // data and key are the same + std::map LAPPDTimeStampsRaw; + std::map LAPPDBeamgatesRaw; + std::map LAPPDOffsets; + std::map LAPPDTSCorrection; + std::map LAPPDBGCorrection; + std::map LAPPDOSInMinusPS; + std::map LAPPDBG_PPSBefore; + std::map LAPPDBG_PPSAfter; + std::map LAPPDBG_PPSDiff; + std::map LAPPDBG_PPSMissing; + std::map LAPPDTS_PPSBefore; + std::map LAPPDTS_PPSAfter; + std::map LAPPDTS_PPSDiff; + std::map LAPPDTS_PPSMissing; + + ANNIEEvent->Set("LAPPDDataMap", LAPPDDataMap); + ANNIEEvent->Set("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + ANNIEEvent->Set("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + ANNIEEvent->Set("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + ANNIEEvent->Set("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + ANNIEEvent->Set("LAPPDOffsets", LAPPDOffsets); + ANNIEEvent->Set("LAPPDTSCorrection", LAPPDTSCorrection); + ANNIEEvent->Set("LAPPDBGCorrection", LAPPDBGCorrection); + ANNIEEvent->Set("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + ANNIEEvent->Set("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + ANNIEEvent->Set("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + ANNIEEvent->Set("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + ANNIEEvent->Set("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + ANNIEEvent->Set("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + ANNIEEvent->Set("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + ANNIEEvent->Set("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + ANNIEEvent->Set("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); +} + +void EBSaver::LoadBeamInfo() +{ + TFile *file = new TFile(beamInfoFileName.c_str(), "READ"); + TTree *tree; + file->GetObject("BeamTree", tree); + + if (!tree) + { + cout << "EBSaver: Failed to load beam info from file with name: " << beamInfoFileName << endl; + return; + } + + // copy from IFBeamDBInterfaceV2.cpp + // Here's some documentation for some of the parameters stored in the beam + // database. It's taken from the MicroBooNE operations wiki: + // http://tinyurl.com/z3c4mxs + // + // The status page shows the present reading of beamline instrumentation. All + // of this data is being stored to IF beam Database. The "IF Beam DB + // dashboard":http://dbweb4.fnal.gov:8080/ifbeam/app/BNBDash/index provides + // another view of beam data. Some of it is redundant to the status page, but + // it verifies that the data is being stored in the database. At present the + // page shows following devices: + // * TOR860, TOR875 - two toroids in BNB measuring beam intensity. TOR860 is + // at the beginning of the beamline, and TOR875 is at the end. + // * THCURR - horn current + // * HWTOUT - horn water temperature coming out of the horn. + // * BTJT2 - target temperature + // * HP875, VP875 - beam horizontal and vertical positions at the 875 + // location, about 4.5 m upstream of the target center. + // * HPTG1, VPTG1 - beam horizontal and vertical positions immediately + // (about 2.5 m) upstream of the target center. + // * HPTG2, VPTG2 - beam horizontal and vertical positions more immediately + // (about 1.5 m) upstream of the target center. + // * Because there are no optics between H/VP875 and H/VPTG2, the movements + // on these monitors should scale with the difference in distances. + // * BTJT2 - target air cooling temperature. Four RTD measure the return + // temperature of the cooling air. This is the one closest to the target. + // * BTH2T2 - target air cooling temperature. This is the temperature of the + // air going into the horn. + + // additionally, the unit of E_TOR860 and E_TOR875 is E12 + + uint64_t timestamp; + double E_TOR860, E_TOR875, THCURR, BTJT2, HP875, VP875, HPTG1, VPTG1, HPTG2, VPTG2, BTH2T2; + + tree->SetBranchAddress("Timestamp", ×tamp); + tree->SetBranchAddress("E_TOR860", &E_TOR860); + tree->SetBranchAddress("E_TOR875", &E_TOR875); + tree->SetBranchAddress("E_THCURR", &THCURR); + tree->SetBranchAddress("E_BTJT2", &BTJT2); + tree->SetBranchAddress("E_HP875", &HP875); + tree->SetBranchAddress("E_VP875", &VP875); + tree->SetBranchAddress("E_HPTG1", &HPTG1); + tree->SetBranchAddress("E_VPTG1", &VPTG1); + tree->SetBranchAddress("E_HPTG2", &HPTG2); + tree->SetBranchAddress("E_VPTG2", &VPTG2); + tree->SetBranchAddress("E_BTH2T2", &BTH2T2); + + Long64_t nentries = tree->GetEntries(); + Log("EBSaver: Loading beam infor, total entries in beam info file: " + std::to_string(nentries), v_message, verbosityEBSaver); + for (Long64_t i = 0; i < nentries; ++i) + { + tree->GetEntry(i); + if (i % (static_cast(nentries / 10)) == 0) + Log("EBSaver: Loading beam info, processed " + std::to_string(i) + " entries", v_message, verbosityEBSaver); + BeamInfoTimestamps.push_back(timestamp); + E_TOR860_map.emplace(timestamp, E_TOR860); + E_TOR875_map.emplace(timestamp, E_TOR875); + THCURR_map.emplace(timestamp, THCURR); + BTJT2_map.emplace(timestamp, BTJT2); + HP875_map.emplace(timestamp, HP875); + VP875_map.emplace(timestamp, VP875); + HPTG1_map.emplace(timestamp, HPTG1); + VPTG1_map.emplace(timestamp, VPTG1); + HPTG2_map.emplace(timestamp, HPTG2); + VPTG2_map.emplace(timestamp, VPTG2); + BTH2T2_map.emplace(timestamp, BTH2T2); + } + + Log("EBSaver: Loaded number of E_TOR860 entries: " + std::to_string(E_TOR860_map.size()), v_message, verbosityEBSaver); + + Log("EBSaver: Finished loading beam info from " + beamInfoFileName, v_message, verbosityEBSaver); + + return; +} + +bool EBSaver::SaveBeamInfo(uint64_t TriggerTime) +{ + double E_TOR860, E_TOR875, THCURR, BTJT2, HP875, VP875, HPTG1, VPTG1, HPTG2, VPTG2, BTH2T2; + // find the closest timestamp in vector BeamInfoTimestamps + + uint64_t closestTimestamp = 0; + double minDiff = 60 * 60 * 1e9; // 60 minutes + int minIndex = -1; + + for (int i = 0; i < BeamInfoTimestamps.size(); i++) + { + uint64_t timestamp = BeamInfoTimestamps.at(i) * 1e6; + double diff = (timestamp > TriggerTime) ? timestamp - TriggerTime : TriggerTime - timestamp; + if (i == 0) + Log("EBSaver: First beam info timestamp is " + std::to_string(timestamp) + " with diff = " + std::to_string(diff), v_warning, verbosityEBSaver); + else if (i == BeamInfoTimestamps.size() - 1) + Log("EBSaver: Last beam info timestamp is " + std::to_string(timestamp) + " with diff = " + std::to_string(diff), v_warning, verbosityEBSaver); + + if (diff < minDiff) + { + minDiff = diff; + minIndex = i; + } + } + + if (minIndex == -1) + { + Log("EBSaver: Failed to find the closest beam info timestamp to trigger time", v_message, verbosityEBSaver); + + uint64_t beamInfoTime_long = 0; + int64_t timeDiff = -9999; + double defaultVal = -9999.; + int beam_good = 0; + ANNIEEvent->Set("BeamInfoTime", beamInfoTime_long); + ANNIEEvent->Set("BeamInfoTimeToTriggerDiff", timeDiff); + ANNIEEvent->Set("beam_E_TOR860", defaultVal); + ANNIEEvent->Set("beam_E_TOR875", defaultVal); + ANNIEEvent->Set("beam_THCURR", defaultVal); + ANNIEEvent->Set("beam_BTJT2", defaultVal); + ANNIEEvent->Set("beam_HP875", defaultVal); + ANNIEEvent->Set("beam_VP875", defaultVal); + ANNIEEvent->Set("beam_HPTG1", defaultVal); + ANNIEEvent->Set("beam_VPTG1", defaultVal); + ANNIEEvent->Set("beam_HPTG2", defaultVal); + ANNIEEvent->Set("beam_VPTG2", defaultVal); + ANNIEEvent->Set("beam_BTH2T2", defaultVal); + ANNIEEvent->Set("beam_good", beam_good); + + Log("EBSaver: Saved beam info with time " + std::to_string(0) + ", pot E_TOR860 = " + std::to_string(-9999) + ", beam_good = " + std::to_string(-9999), v_message, verbosityEBSaver); + } + else + { + Log("Found the closest beam info timestamp to trigger time at index " + std::to_string(minIndex) + " with time " + std::to_string(BeamInfoTimestamps.at(minIndex)) + " and dt = " + std::to_string(minDiff), v_message, verbosityEBSaver); + + // get the precise difference + uint64_t beamInfoTime = BeamInfoTimestamps.at(minIndex); + ULong64_t beamInfoTime_long = beamInfoTime * 1e6; + int64_t timeDiff = beamInfoTime_long - TriggerTime; + + // check if the map has the key + E_TOR860 = E_TOR860_map.at(beamInfoTime); + E_TOR875 = E_TOR875_map.at(beamInfoTime); + THCURR = THCURR_map.at(beamInfoTime); + BTJT2 = BTJT2_map.at(beamInfoTime); + HP875 = HP875_map.at(beamInfoTime); + VP875 = VP875_map.at(beamInfoTime); + HPTG1 = HPTG1_map.at(beamInfoTime); + VPTG1 = VPTG1_map.at(beamInfoTime); + HPTG2 = HPTG2_map.at(beamInfoTime); + VPTG2 = VPTG2_map.at(beamInfoTime); + BTH2T2 = BTH2T2_map.at(beamInfoTime); + + ANNIEEvent->Set("BeamInfoTime", beamInfoTime); + ANNIEEvent->Set("BeamInfoTimeToTriggerDiff", timeDiff); + + ANNIEEvent->Set("beam_E_TOR860", E_TOR860); + ANNIEEvent->Set("beam_E_TOR875", E_TOR875); + ANNIEEvent->Set("beam_THCURR", THCURR); + ANNIEEvent->Set("beam_BTJT2", BTJT2); + ANNIEEvent->Set("beam_HP875", HP875); + ANNIEEvent->Set("beam_VP875", VP875); + ANNIEEvent->Set("beam_HPTG1", HPTG1); + ANNIEEvent->Set("beam_VPTG1", VPTG1); + ANNIEEvent->Set("beam_HPTG2", HPTG2); + ANNIEEvent->Set("beam_VPTG2", VPTG2); + ANNIEEvent->Set("beam_BTH2T2", BTH2T2); + + int beam_good = 0; + + if (THCURR > 172 && THCURR < 176) + { + if (E_TOR860 > 0.5 && E_TOR860 < 8 && E_TOR875 > 0.5 && E_TOR875 < 8 && (E_TOR875 - E_TOR860) / E_TOR860 < 0.05) + beam_good = 1; + } + + ANNIEEvent->Set("beam_good", beam_good); + + Log("EBSaver: Saved beam info with time " + std::to_string(beamInfoTime) + ", pot E_TOR860 = " + std::to_string(E_TOR860) + ", beam_good = " + std::to_string(beam_good), v_message, verbosityEBSaver); + } + + return true; +} \ No newline at end of file diff --git a/UserTools/EBSaver/EBSaver.h b/UserTools/EBSaver/EBSaver.h new file mode 100644 index 000000000..57a960f7d --- /dev/null +++ b/UserTools/EBSaver/EBSaver.h @@ -0,0 +1,202 @@ +#ifndef EBSaver_H +#define EBSaver_H + +#include +#include + +#include "Tool.h" +#include "BoostStore.h" +#include "PsecData.h" +#include "TimeClass.h" +#include "TriggerClass.h" +#include "Waveform.h" +#include "ANNIEalgorithms.h" +#include "ADCPulse.h" +#include "CalibratedADCWaveform.h" +#include "BeamStatus.h" +#include "TFile.h" +#include "TTree.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBSaver : public Tool +{ + +public: + EBSaver(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + + bool GotAllDataFromOriginalBuffer(); + void SetDataObjects(); + + bool SaveToANNIEEvent(string saveFileName, int runCode, int triggerTrack, int trackIndex); // save the data to the ANNIEEvent, include all other saving functions. + bool SaveRunInfo(int runCode); // get run numbers from the RunCode in trigger grouper + bool SaveGroupedTriggers(int triggerTrack, int groupIndex); + // use the targetTrigWord to get the trigger track, use the groupIndex to get the group of triggers in that track + // save triggers from std::map>> GroupedTriggersInTotal; //each map is a group of triggers, with the key is the target trigger word + + bool SavePMTData(uint64_t PMTTime); + bool SaveMRDData(uint64_t MRDTime); + bool SaveLAPPDData(uint64_t LAPPDTime); + bool SaveBeamInfo(uint64_t TriggerTime); + + bool SaveOrphan(int runCode); + bool SaveOrphanPMT(int runCode); + bool SaveOrphanMRD(int runCode); + bool SaveOrphanCTC(int runCode); + bool SaveOrphanLAPPD(int runCode); + + void BuildEmptyPMTData(); + void BuildEmptyMRDData(); + void BuildEmptyLAPPDData(); + + void LoadBeamInfo(); + +private: + int saveRunNumber; + int saveSubrunNumber; + int savePartFileNumber; + int savingRunCode; + + bool saveTriggerGroups = true; + bool saveAllTriggers; + bool savePMT = true; + bool saveMRD; + bool saveLAPPD; + bool saveOrphan; + bool saveBeamInfo; + + bool saveRawRWMWaveform; + bool saveRawBRFWaveform; + + string savePath; + string saveName; + + string beamInfoFileName; + + int verbosityEBSaver; + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; + + BoostStore *ANNIEEvent; + + int exeNumber; + int savedTriggerGroupNumber; + int savedPMTHitMapNumber; + int savedMRDNumber; + int savedLAPPDNumber; + + std::map TriggerTimeWithoutMRD; // trigger time, 8 or 36 + + int thisRunNum; + int thisSubrunNum; + int thisPartFileNum; + + int savePerExe; + + int TotalBuiltEventsNumber; + int TotalBuiltPMTNumber; + int TotalBuiltMRDNumber; + int TotalBuiltLAPPDNumber; + int TotalBuiltTriggerGroupNumber; + + std::map PMTRunCodeToRemove; + std::map MRDRunCodeToRemove; + std::map LAPPDRunCodeToRemove; + std::map GroupedTriggerIndexToRemove; + + std::map> PMTPairInfoToRemoveTime; + std::map> MRDPairInfoToRemoveTime; + std::map> LAPPDPairInfoToRemoveTime; + + std::map>> GroupedTriggersInTotal; // each map is a group of triggers, with the key is the target trigger word + std::map> RunCodeInTotal; + + int BeamTriggerMain; + int LaserTriggerMain; + int CosmicTriggerMain; + int LEDTriggerMain; + int AmBeTriggerMain; + int PPSMain; + + // PMT related data object + std::map> *> *InProgressHits; // Key: {MTCTime}, value: map of Hit distributions + std::map> *InProgressChkey; // Key: {MTCTime}, value: vector of in progress chankeys + std::map>>> *InProgressRecoADCHits; // Key: {MTCTime}, value: map of found pulses + std::map>>> *InProgressRecoADCHitsAux; // Key: {MTCTime}, value: map of found pulses + std::map> *> *InProgressHitsAux; // Key: {MTCTime}, value: map of Hit distributions + std::map>> *FinishedRawAcqSize; // Key: {MTCTime}, value: map of acquisition time window sizes + + std::map> *RWMRawWaveforms; // Key: MTCTime, Value: RWM waveform + std::map> *BRFRawWaveforms; // Key: MTCTime, Value: BRF waveform + + std::map> PairedPMTTriggerTimestamp; + std::map> PairedPMT_TriggerIndex; + std::map> PairedPMTTimeStamps; + std::map PMTHitmapRunCode; // Key: {MTCTime}, value: RunCode + + // MRD related data object + std::map>> MRDEvents; // Key: {MTCTime}, value: "WaveMap" with key (CardID,ChannelID), value FinishedWaveform + std::map MRDEventTriggerTypes; // Key: {MTCTime}, value: string noting what type of trigger occured for the event + std::map MRDBeamLoopback; // Key: {MTCTime}, value: string noting what type of trigger occured for the event + std::map MRDCosmicLoopback; // KEY: {MTCTime}, value: Cosmic loopback TDC value + + std::map> PairedMRDTriggerTimestamp; + std::map> PairedMRD_TriggerIndex; + std::map> PairedMRDTimeStamps; + std::map MRDHitMapRunCode; // Key: {MTCTime}, value: RunCode + + // LAPPD related data object + vector Buffer_IndexOfData; // index of unpaired data + vector Buffer_LAPPDTimestamp_ns; // used to match + + vector Buffer_LAPPDData; + vector Buffer_LAPPDBeamgate_ns; + vector Buffer_LAPPDOffset; + vector Buffer_LAPPDBeamgate_Raw; + vector Buffer_LAPPDTimestamp_Raw; + vector Buffer_LAPPDBGCorrection; + vector Buffer_LAPPDTSCorrection; + vector Buffer_LAPPDOffset_minus_ps; + vector Buffer_LAPPDBG_PPSBefore; + vector Buffer_LAPPDBG_PPSAfter; + vector Buffer_LAPPDBG_PPSDiff; + vector Buffer_LAPPDBG_PPSMissing; + vector Buffer_LAPPDTS_PPSBefore; + vector Buffer_LAPPDTS_PPSAfter; + vector Buffer_LAPPDTS_PPSDiff; + vector Buffer_LAPPDTS_PPSMissing; + + vector Buffer_LAPPDRunCode; + + std::map> PairedLAPPDTriggerTimestamp; + std::map> PairedLAPPD_TriggerIndex; + std::map> PairedLAPPDTimeStamps; + + // beam info related objects + vector BeamInfoTimestamps; + std::map E_TOR860_map; + std::map E_TOR875_map; + std::map THCURR_map; + std::map BTJT2_map; + std::map HP875_map; + std::map VP875_map; + std::map HPTG1_map; + std::map VPTG1_map; + std::map HPTG2_map; + std::map VPTG2_map; + std::map BTH2T2_map; +}; + +#endif diff --git a/UserTools/EBSaver/README.md b/UserTools/EBSaver/README.md new file mode 100644 index 000000000..a05a2dc7c --- /dev/null +++ b/UserTools/EBSaver/README.md @@ -0,0 +1,29 @@ +# EBSaver + +EBSaver is a part of Event Building version 2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 + +For a group of trigger with it's main trigger in part file x, that event will be saved as processed file x. +There shouldn't be any error if the file is correctly processed, the stat info will be printed out at Finalise. +Processing one part file usually just take a few minutes. The time of processing multiple files will be increased quick because of the trigger grouping. There is a limit but more than 7 beam files are not recommended. + + +## Data + +EBSaver take four cataogeies of inputs +1. Beam Info. (From beam fetcher) +2. Grouped triggers. (from EBTriggerGrouper) + GroupedTriggersInTotal +3. Data from subsystems. (PMT, MRD, LAPPD, from data decoders) + In GotAllDataFromOriginalBuffer function +4. Matched pairs of data timestamps and grouped triggers. (from EBPMT, EBMRD, EBLAPPD) + Also in GotAllDataFromOriginalBuffer function + + +## Configuration + +beamInfoFileName: name of the beam info file generated by beam fetcher V2 + +Other configs are set by defalut +Save Orphan is not implemented right now. \ No newline at end of file diff --git a/UserTools/EBTriggerGrouper/EBTriggerGrouper.cpp b/UserTools/EBTriggerGrouper/EBTriggerGrouper.cpp new file mode 100644 index 000000000..afd2b0946 --- /dev/null +++ b/UserTools/EBTriggerGrouper/EBTriggerGrouper.cpp @@ -0,0 +1,745 @@ +#include "EBTriggerGrouper.h" + +EBTriggerGrouper::EBTriggerGrouper() : Tool() {} + +bool EBTriggerGrouper::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("verbosityEBTG", verbosityEBTG); + savePath = ""; + m_variables.Get("savePath", savePath); + m_variables.Get("GroupMode", GroupMode); + m_variables.Get("GroupTolerance", GroupTolerance); + m_variables.Get("GroupTrigWord", GroupTrigWord); + + TimeToTriggerWordMap = new std::map>; + TimeToTriggerWordMapComplete = new std::map>; + + groupBeam = true; + m_variables.Get("groupBeam", groupBeam); + groupCosmic = false; + m_variables.Get("groupCosmic", groupCosmic); + groupLaser = true; + m_variables.Get("groupLaser", groupLaser); + groupLED = false; + m_variables.Get("groupLED", groupLED); + groupAmBe = false; + m_variables.Get("groupAmBe", groupAmBe); + groupPPS = false; + m_variables.Get("groupPPS", groupPPS); + groupNuMI = true; + m_variables.Get("groupNuMI", groupNuMI); + + BeamTriggerMain = 14; + BeamTolerance = 3000000; // use 3 ms here, the spill time difference is 66ms + m_variables.Get("BeamTolerance", BeamTolerance); + BeamTriggers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 37, 38, 40, 41, 46}; + m_data->CStore.Set("BeamTriggersUsedForGroupping", BeamTriggers); + m_data->CStore.Set("BeamTriggerMain", BeamTriggerMain); + + LaserTriggerMain = 47; + m_variables.Get("LaserTriggerMain", LaserTriggerMain); + LaserTolerance = 1000; // 1us + m_variables.Get("LaserTolerance", LaserTolerance); + LaserTriggers = {47, 46}; // 47 first, then 46, (~232ns in run 4692 data) + m_data->CStore.Set("LaserTriggersUsedForGroupping", LaserTriggers); + + PPSTriggerMain = 32; + PPSTolerance = 30000; // 30 us + m_variables.Get("PPSTolerance", PPSTolerance); + PPSTriggers = {32, 34}; // 32 first, then 34, (~20us in run 4802 data) + m_data->CStore.Set("PPSTriggersUsedForGroupping", PPSTriggers); + + CosmicTriggerMain = 45; // TODO need to check + m_variables.Get("CosmicTriggerMain", CosmicTriggerMain); + CosmicTolerance = 100; // 330000ns, TODO + m_variables.Get("CosmicTolerance", CosmicTolerance); + CosmicTriggers = {44, 45, 36, 27, 28, 29, 30, 46}; // TODO: check the trigger words in cosmic run + m_data->CStore.Set("CosmicTriggersUsedForGroupping", CosmicTriggers); + + LEDTriggerMain = 31; // need to check + m_variables.Get("LEDTriggerMain", LEDTriggerMain); + LEDTolerance = 1000; // 1ms 440ns in LED run 4792 + m_variables.Get("LEDTolerance", LEDTolerance); + LEDTriggers = {33, 22, 31, 43, 46}; // in run 4792 [[22, 33], [4160001224, 4160001664]] + m_data->CStore.Set("LEDTriggersUsedForGroupping", LEDTriggers); + + AmBeTriggerMain = 11; // TODO: need to check + m_variables.Get("AmBeTriggerMain", AmBeTriggerMain); + AmBeTolerance = 5000; // 2336 in Ambe run 4707 + m_variables.Get("AmBeTolerance", AmBeTolerance); + AmBeTriggers = {11, 12, 15, 19, 46}; // in run 4707 [[19, 12, 15, 11], [21275647928, 21275647936, 21275647952, 21275650264]] + m_data->CStore.Set("AmBeTriggersUsedForGroupping", AmBeTriggers); + + NuMITriggerMain = 42; + m_variables.Get("NuMITriggerMain", NuMITriggerMain); + NuMITolerance = 100; // 100ns + m_variables.Get("NuMITolerance", NuMITolerance); + NuMITriggers = {42, 46}; // + m_data->CStore.Set("NuMITriggersUsedForGroupping", NuMITriggers); + + StoreTotalEntry = 0; + + maxNumAllowedInBuffer = 10000; + m_variables.Get("maxNumAllowedInBuffer", maxNumAllowedInBuffer); + Log("EBTG: maxNumAllowedInBuffer = " + std::to_string(maxNumAllowedInBuffer), v_message, verbosityEBTG); + + return true; +} + +bool EBTriggerGrouper::Execute() +{ + bool NewCTCDataAvailable = false; + m_data->CStore.Get("NewCTCDataAvailable", NewCTCDataAvailable); + Log("EBTG: NewCTCDataAvailable = " + std::to_string(NewCTCDataAvailable), v_message, verbosityEBTG); + bool FileProcessingComplete = false; + m_data->CStore.Get("FileProcessingComplete", FileProcessingComplete); + if (FileProcessingComplete) + { + Log("EBTG: FileProcessingComplete = " + std::to_string(FileProcessingComplete), v_message, verbosityEBTG); + return true; + } + if (!NewCTCDataAvailable) + { + Log("EBTG: No new CTC data avaliable", v_message, verbosityEBTG); + return true; + } + Log("EBTG: Get Run information", v_message, verbosityEBTG); + m_data->CStore.Get("RunNumber", CurrentRunNum); + m_data->CStore.Get("SubRunNumber", CurrentSubrunNum); + int CurrentUsingPartNum = CurrentPartNum; + m_data->CStore.Get("PartFileNumber", CurrentPartNum); + m_data->CStore.Get("RunCode", currentRunCode); + + m_data->CStore.Get("usingTriggerOverlap", usingTriggerOverlap); + if (usingTriggerOverlap) + { + CurrentPartNum -= 1; + Log("EBTG: usingTriggerOverlap, CurrentPartNum was minused 1 to be " + std::to_string(CurrentPartNum), v_message, verbosityEBTG); + } + + /* + if (CurrentPartNum != CurrentUsingPartNum) + { + Log("EBTG: PartFileNumber changed from " + std::to_string(CurrentUsingPartNum) + " to " + std::to_string(CurrentPartNum) + " Clear buffer with size " + std::to_string(TrigTimeForGroup.size()), v_message, verbosityEBTG); + TrigTimeForGroup.clear(); + TrigWordForGroup.clear(); + }*/ + + Log("EBTG: Accessing new Trigger data in CStore", v_message, verbosityEBTG); + m_data->CStore.Get("TimeToTriggerWordMap", TimeToTriggerWordMap); + m_data->CStore.Get("TimeToTriggerWordMapComplete", TimeToTriggerWordMapComplete); + + // do grouping in the TimeToTriggerWordMap, remove the groupped triggers from both of them + // 1. load the trigger from TimeToTriggerWordMap to local buffer TrigTimeForGroup and TrigWordForGroup, clean it + // 2. group the triggers in buffer, save to GroupedTriggers, and remove grouped trigger from buffer + // 2.1 group trigger based on trigger word selection or time Tolerance relative to the target trigger + // 2.2 for left triggers, pair them with the grouped trigger using the same Tolerance fo cover triggers before the target trigger + // 2.3 run for different trigger tracks. like pps + + // Finally we should have: + // 1. GroupedTriggers: mutiple grouped trigger tracks + // 2. buffer: left triggers in buffer, not grouped + + vector TriggerToRemove; + for (auto it = TimeToTriggerWordMap->begin(); it != TimeToTriggerWordMap->end(); ++it) + { + uint64_t timestamp = it->first; + std::vector triggers = it->second; + bool stopLoading = false; + + // if found the target trigger in the trigger vector, stop loading to buffer. + if (usingTriggerOverlap) + { + for (auto trig = triggers.begin(); trig != triggers.end(); ++trig) + { + if (*trig == GroupTrigWord) + stopLoading = true; + Log("EBTG: when using TriggerOverlap, met the new target trigger " + std::to_string(GroupTrigWord) + ", stop loading to buffer", v_message, verbosityEBTG); + } + } + if (stopLoading) + break; + + for (auto trig = triggers.begin(); trig != triggers.end(); ++trig) + { + TrigTimeForGroup.push_back(timestamp); + TrigWordForGroup.push_back(*trig); + TriggerToRemove.push_back(timestamp); + StoreTotalEntry++; + if (verbosityEBTG > 11) + cout << "EBTG: TrigTimeForGroup: " << timestamp << " TrigWordForGroup: " << *trig << endl; + } + } + Log("EBTG: finish loading trigger from TimeToTriggerWordMap, buffer TrigTimeForGroup size = " + std::to_string(TrigTimeForGroup.size()) + ", loaded TimeToTriggerWordMap size = " + std::to_string(TimeToTriggerWordMap->size()), v_message, verbosityEBTG); + Log("EBTG: Start erase triggers from TimeToTriggerWordMap and TimeToTriggerWordMapComplete, TimeToTriggerWordMap and TimeToTriggerWordMapComplete size = " + std::to_string(TimeToTriggerWordMap->size()) + ", " + std::to_string(TimeToTriggerWordMapComplete->size()), v_message, verbosityEBTG); + for (int i = 0; i < TriggerToRemove.size(); i++) + { + TimeToTriggerWordMap->erase(TriggerToRemove[i]); + TimeToTriggerWordMapComplete->erase(TriggerToRemove[i]); + } + Log("EBTG: Finish erase triggers from TimeToTriggerWordMap and TimeToTriggerWordMapComplete, TimeToTriggerWordMap and TimeToTriggerWordMapComplete size = " + std::to_string(TimeToTriggerWordMap->size()) + ", " + std::to_string(TimeToTriggerWordMapComplete->size()), v_message, verbosityEBTG); + + /*{ + //TODO: this should be removed after later changes was made + Log("EBTG: Start grouping based on trigger word " + std::to_string(GroupTrigWord), v_message, verbosityEBTG); + + GroupByTolerance(); // remove grouped trigger in the function + FillByTolerance(); + //CleanBuffer(); + + Log("EBTG: grouping and filling finishes, buffer size is " + std::to_string(TrigTimeForGroup.size()) + ", now save to CStore", v_message, verbosityEBTG); + + m_data->CStore.Set("GroupedTriggers", GroupedTriggers); + }*/ + + m_data->CStore.Set("TrigTimeForGroup", TrigTimeForGroup); + m_data->CStore.Set("TrigWordForGroup", TrigWordForGroup); + + Log("EBTG: Start grouping for different trigger tracks", v_message, verbosityEBTG); + if (groupBeam) + { + Log("EBTG: Grouping Beam Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(BeamTriggerMain, BeamTriggers, BeamTolerance); + int fillNum = FillByTrigWord(BeamTriggerMain, BeamTriggers, BeamTolerance); + Log("EBTG: Found Beam Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("BeamTriggerGroupped", true); + } + else + { + m_data->CStore.Set("BeamTriggerGroupped", false); + } + + if (groupCosmic) + { + Log("EBTG: Grouping Cosmic Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(CosmicTriggerMain, CosmicTriggers, CosmicTolerance); + int fillNum = FillByTrigWord(CosmicTriggerMain, CosmicTriggers, CosmicTolerance); + Log("EBTG: Found Cosmic Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("CosmicTriggerGroupped", true); + } + else + { + m_data->CStore.Set("CosmicTriggerGroupped", false); + } + + if (groupLaser) + { + Log("EBTG: Grouping Laser Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(LaserTriggerMain, LaserTriggers, LaserTolerance); + int fillNum = FillByTrigWord(LaserTriggerMain, LaserTriggers, LaserTolerance); + Log("EBTG: Found Laser Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("LaserTriggerGroupped", true); + } + else + { + m_data->CStore.Set("LaserTriggerGroupped", false); + } + + if (groupLED) + { + Log("EBTG: Grouping LED Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(LEDTriggerMain, LEDTriggers, LEDTolerance); + int fillNum = FillByTrigWord(LEDTriggerMain, LEDTriggers, LEDTolerance); + Log("EBTG: Found LED Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("LEDTriggerGroupped", true); + } + else + { + m_data->CStore.Set("LEDTriggerGroupped", false); + } + + if (groupAmBe) + { + Log("EBTG: Grouping AmBe Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(AmBeTriggerMain, AmBeTriggers, AmBeTolerance); + int fillNum = FillByTrigWord(AmBeTriggerMain, AmBeTriggers, AmBeTolerance); + Log("EBTG: Found AmBe Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("AmBeTriggerGroupped", true); + } + else + { + m_data->CStore.Set("AmBeTriggerGroupped", false); + } + + if (groupPPS) + { + Log("EBTG: Grouping PPS Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(PPSTriggerMain, PPSTriggers, PPSTolerance); + int fillNum = FillByTrigWord(PPSTriggerMain, PPSTriggers, PPSTolerance); + Log("EBTG: Found PPS Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("PPSTriggerGroupped", true); + } + else + { + m_data->CStore.Set("PPSTriggerGroupped", false); + } + + if (groupNuMI) + { + Log("EBTG: Grouping NuMI Triggers", v_message, verbosityEBTG); + int groupNum = GroupByTrigWord(NuMITriggerMain, NuMITriggers, NuMITolerance); + int fillNum = FillByTrigWord(NuMITriggerMain, NuMITriggers, NuMITolerance); + Log("EBTG: Found NuMI Trigger group: " + std::to_string(groupNum) + ". Fill additional triggers to group: " + std::to_string(fillNum), v_message, verbosityEBTG); + m_data->CStore.Set("NuMITriggerGroupped", true); + } + else + { + m_data->CStore.Set("NuMITriggerGroupped", false); + } + + Log("EBTG: Grouping for different trigger tracks finishes, save to CStore", v_message, verbosityEBTG); + m_data->CStore.Set("GroupedTriggersInTotal", GroupedTriggersInTotal); + m_data->CStore.Set("RunCodeInTotal", RunCodeInTotal); + + int removedTriggerNumber = CleanTriggerBuffer(); + Log("EBTG: CleanTriggerBuffer finishes, removed " + std::to_string(removedTriggerNumber) + " triggers from buffer, buffer size = " + std::to_string(TrigTimeForGroup.size()), v_message, verbosityEBTG); + + return true; +} + +bool EBTriggerGrouper::Finalise() +{ + Log("\033[1;34mEBTG: Finalising\033[0m", v_message, verbosityEBTG); + Log("EBTG: GroupedTriggersInTotal track number = " + std::to_string(GroupedTriggersInTotal.size()), v_message, verbosityEBTG); + for (auto it = GroupedTriggersInTotal.begin(); it != GroupedTriggersInTotal.end(); ++it) + { + Log("EBTG: GroupedTriggersInTotal track " + std::to_string(it->first) + " size = " + std::to_string(it->second.size()), v_message, verbosityEBTG); + } + Log("EBTG: In configfile, set left trigger number = " + std::to_string(maxNumAllowedInBuffer), v_message, verbosityEBTG); + Log("EBTG: Left Total loaded trigger number to buffer = " + std::to_string(StoreTotalEntry), v_message, verbosityEBTG); + Log("EBTG: Ungrouped triggers in buffer size = " + std::to_string(TrigTimeForGroup.size()), v_message, verbosityEBTG); + // calculate which trigger word left in TrigWordForGroup, and print them + std::map triggerWordCount; + for (int i = 0; i < TrigWordForGroup.size(); i++) + { + triggerWordCount[TrigWordForGroup[i]]++; + } + for (auto it = triggerWordCount.begin(); it != triggerWordCount.end(); ++it) + { + Log("EBTG: Trigger word " + std::to_string(it->first) + " left in buffer " + std::to_string(it->second) + " times", v_message, verbosityEBTG); + } + Log("EBTG: Ungrouped triggers in TimeToTriggerWordMap size = " + std::to_string(TimeToTriggerWordMap->size()), v_message, verbosityEBTG); + Log("EBTG: Ungrouped triggers in TimeToTriggerWordMapComplete size = " + std::to_string(TimeToTriggerWordMapComplete->size()), v_message, verbosityEBTG); + + // print first 10000 triggers to a txt for debug + Log("EBTG: Save first 2000 triggers in each track of GroupedTriggersInTotal to TrigDebugGrouped.txt", v_message, verbosityEBTG); + ofstream trigDebugGrouped; + trigDebugGrouped.open("TrigDebugGrouped.txt"); + trigDebugGrouped << "trackTargetTrigger groupIndex triggerTime triggerWord" << endl; + for (auto it = GroupedTriggersInTotal.begin(); it != GroupedTriggersInTotal.end(); ++it) + { + int i = 0; + for (int j = 0; j < it->second.size(); j++) + { + for (auto trig = it->second[j].begin(); trig != it->second[j].end(); ++trig) + { + if (i > 2000) + break; + trigDebugGrouped << it->first << " " << j << " " << trig->first << " " << trig->second << endl; + i++; + } + if (i > 2000) + break; + } + } + trigDebugGrouped.close(); + Log("EBTG: Save first 10000 triggers in TrigTimeForGroup to TrigDebugBufferLeft.txt", v_message, verbosityEBTG); + ofstream trigDebugBufferLeft; + trigDebugBufferLeft.open("TrigDebugBufferLeft.txt"); + for (int i = 0; i < TrigTimeForGroup.size(); i++) + { + if (i > 10000) + break; + trigDebugBufferLeft << i << " " << TrigTimeForGroup[i] << " " << TrigWordForGroup[i] << endl; + } + Log("EBTG: Save first 2000 triggers in TimeToTriggerWordMap to TrigDebug.txt", v_message, verbosityEBTG); + ofstream trigDebug; + trigDebug.open("TrigDebug.txt"); + int i = 0; + for (auto it = TimeToTriggerWordMap->begin(); it != TimeToTriggerWordMap->end(); ++it) + { + if (i > 2000) + break; + trigDebug << it->first << " "; + for (auto trig = it->second.begin(); trig != it->second.end(); ++trig) + { + trigDebug << *trig << " "; + } + trigDebug << endl; + i++; + } + trigDebug.close(); + + Log("EBTG: Printing SkippedDuplicateTriggers", v_message, verbosityEBTG); + int totalSkipped = 0; + for (auto it = SkippedDuplicateTriggers.begin(); it != SkippedDuplicateTriggers.end(); ++it) + { + Log("EBTG: Skipped " + std::to_string(it->second) + " groups of triggers for trigger track " + std::to_string(it->first), v_message, verbosityEBTG); + totalSkipped += it->second; + } + Log("EBTG: Total skipped groups of triggers = " + std::to_string(totalSkipped), v_message, verbosityEBTG); + + return true; +} + +bool EBTriggerGrouper::GroupByTolerance() +{ + Log("EBTG: GroupByTolerance()", v_warning, verbosityEBTG); + Log("EBTG: Grouping by Tolerance: " + std::to_string(GroupTolerance), v_warning, verbosityEBTG); + Log("EBTG: size of time buffer before grouping is " + std::to_string(TrigTimeForGroup.size()) + ", size of word buffer is " + std::to_string(TrigWordForGroup.size()), v_warning, verbosityEBTG); + bool found = false; + uint64_t prev_target_time = 0; + std::map ThisGroup; + vector toRemove; + int totalGroupedTriggerNumber = 0; + for (int i = 0; i < TrigTimeForGroup.size(); i++) + { + uint64_t dt = 0; + if (TrigTimeForGroup[i] > prev_target_time) + dt = TrigTimeForGroup[i] - prev_target_time; + else if (TrigTimeForGroup[i] < prev_target_time) + dt = prev_target_time - TrigTimeForGroup[i]; + else if (TrigTimeForGroup[i] == prev_target_time) + dt = 0; + + if (!found && TrigWordForGroup[i] == GroupTrigWord) + { + found = true; + ThisGroup.clear(); + prev_target_time = TrigTimeForGroup[i]; + ThisGroup.insert(std::pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + toRemove.push_back(i); + } + else if (found && dt < GroupTolerance) + { + + ThisGroup.insert(std::pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + toRemove.push_back(i); + if (TrigWordForGroup[i] == 10 || TrigWordForGroup[i] == 40 || TrigWordForGroup[i] == 41) + { + ThisGroup.insert(std::pair(TrigTimeForGroup[i] + 1, TrigWordForGroup[i])); + } + ///!!! attention, the trigger word 10 always come with 8 with the same time, so it won't be inserted to the map + // Therefore we add another 1ns to it, but it's not real + } + else if (found && dt > GroupTolerance) + { + if (verbosityEBTG > 9) + { + // print all triggers in this group + cout << "EBTG: GroupByTolerance: ThisGroup size = " << ThisGroup.size() << endl; + for (auto it = ThisGroup.begin(); it != ThisGroup.end(); ++it) + { + cout << it->first << " - " << it->second << ", "; + } + cout << endl; + } + GroupedTriggers.push_back(ThisGroup); + totalGroupedTriggerNumber += ThisGroup.size(); + ThisGroup.clear(); + found = false; + } + } + int totalToRemoveTriggerNumber = toRemove.size(); + // from end to beginning, remove the triggers in buffer based on toRemove index + for (int i = toRemove.size() - 1; i >= 0; i--) + { + TrigTimeForGroup.erase(TrigTimeForGroup.begin() + toRemove[i]); + TrigWordForGroup.erase(TrigWordForGroup.begin() + toRemove[i]); + } + Log("EBTG: GroupByTolerance Finished, accumulated saved " + std::to_string(GroupedTriggers.size()) + " group of triggers", v_warning, verbosityEBTG); + Log("EBTG: buffer TriggersForGroup after grouping size = " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + Log("EBTG: totalGroupedTriggerNumber in this grouping step is: " + std::to_string(totalGroupedTriggerNumber) + ", totalToRemoveTriggerNumber = " + std::to_string(totalToRemoveTriggerNumber), v_warning, verbosityEBTG); + + return true; +} + +bool EBTriggerGrouper::FillByTolerance() +{ + Log("EBTG: FillByTolerance()", v_warning, verbosityEBTG); + Log("EBTG: Fill by Tolerance: " + std::to_string(GroupTolerance), v_warning, verbosityEBTG); + Log("EBTG: size of time buffer before refilling is " + std::to_string(TrigTimeForGroup.size()) + ", size of word buffer is " + std::to_string(TrigWordForGroup.size()), v_warning, verbosityEBTG); + + int addedTriggerNumber = 0; + + for (int i = TrigTimeForGroup.size() - 1; i >= 0; i--) + { + for (int j = 0; j < GroupedTriggers.size(); j++) + { + + for (auto it = GroupedTriggers[j].begin(); it != GroupedTriggers[j].end(); ++it) + { + if (it->second == GroupTrigWord) + { + uint64_t dt = (TrigTimeForGroup[i] > it->first) ? (TrigTimeForGroup[i] - it->first) : (it->first - TrigTimeForGroup[i]); + if (dt < GroupTolerance) + { + GroupedTriggers[j].insert(std::make_pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + TrigTimeForGroup.erase(TrigTimeForGroup.begin() + i); + TrigWordForGroup.erase(TrigWordForGroup.begin() + i); + addedTriggerNumber++; + break; + } + } + } + } + } + + Log("EBTG: FillByTolerance Finished, addedTriggerNumber = " + std::to_string(addedTriggerNumber), v_warning, verbosityEBTG); + Log("EBTG: buffer TriggersForGroup after refilling size = " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + + return true; +} + +bool EBTriggerGrouper::CleanBuffer() +{ + Log("EBTG: CleanBuffer()", v_warning, verbosityEBTG); + Log("EBTG: size of time buffer before cleaning is " + std::to_string(TrigTimeForGroup.size()) + ", size of word buffer is " + std::to_string(TrigWordForGroup.size()), v_warning, verbosityEBTG); + // check is there any target trigger word in the buffer + // if yes, print a warning message + // only leave the last 100 triggers in the buffer + int numberOfTargetTriggers = 0; + for (int i = 0; i < TrigWordForGroup.size(); i++) + { + if (TrigWordForGroup[i] == GroupTrigWord) + { + numberOfTargetTriggers++; + } + } + if (numberOfTargetTriggers > 0) + { + Log("EBTG: CleanBuffer: Warning: there are " + std::to_string(numberOfTargetTriggers) + " target trigger words in the buffer", v_warning, verbosityEBTG); + } + else + { + Log("EBTG: CleanBuffer: no target trigger words left in the buffer.", v_warning, verbosityEBTG); + } + if (TrigTimeForGroup.size() > 100) + { + TrigTimeForGroup.erase(TrigTimeForGroup.begin(), TrigTimeForGroup.end() - 100); + TrigWordForGroup.erase(TrigWordForGroup.begin(), TrigWordForGroup.end() - 100); + } + Log("EBTG: CleanBuffer Finished, buffer size = " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + return true; +} + +int EBTriggerGrouper::GroupByTrigWord(uint32_t mainTrigWord, vector TrigWords, int tolerance) +{ + Log("EBTG: GroupByTrigWord()", v_warning, verbosityEBTG); + Log("EBTG: Grouping by TrigWord: " + std::to_string(mainTrigWord), v_warning, verbosityEBTG); + Log("EBTG: size of time buffer before grouping is " + std::to_string(TrigTimeForGroup.size()) + ", size of word buffer is " + std::to_string(TrigWordForGroup.size()), v_warning, verbosityEBTG); + bool found = false; + uint64_t prev_target_time = 0; + std::map ThisGroup; + vector toRemove; + int totalGroupedTriggerNumber = 0; + uint64_t trackTriggerTime = 0; + uint32_t trackTriggerWord = 0; + + for (int i = 0; i < TrigTimeForGroup.size(); i++) + { + uint64_t dt = 0; + if (TrigTimeForGroup[i] > prev_target_time) + dt = TrigTimeForGroup[i] - prev_target_time; + else if (TrigTimeForGroup[i] < prev_target_time) + dt = prev_target_time - TrigTimeForGroup[i]; + else if (TrigTimeForGroup[i] == prev_target_time) + dt = 0; + + if (!found && TrigWordForGroup[i] == mainTrigWord) + { + found = true; + ThisGroup.clear(); + prev_target_time = TrigTimeForGroup[i]; + ThisGroup.insert(std::pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + trackTriggerTime = TrigTimeForGroup[i]; + trackTriggerWord = TrigWordForGroup[i]; + toRemove.push_back(i); + } + else if (found && dt < tolerance) + { + // if found TrigWordForGroup in TrigWords, insert to ThisGroup + if (std::find(TrigWords.begin(), TrigWords.end(), TrigWordForGroup[i]) != TrigWords.end()) + { + ThisGroup.insert(std::pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + toRemove.push_back(i); + if (mainTrigWord == 14 && (TrigWordForGroup[i] == 10 || TrigWordForGroup[i] == 40 || TrigWordForGroup[i] == 41)) + { + ThisGroup.insert(std::pair(TrigTimeForGroup[i] + 1, TrigWordForGroup[i])); + } + ///!!! attention, the trigger word 10 always come with 8 with the same time, so it won't be inserted to the map + // Therefore we add another 1ns to it, but it's not real + } + } + else if (found && dt > tolerance) + { + if (verbosityEBTG > 9) + { + // print all triggers in this group + cout << "EBTG: GroupByTrigWord: ThisGroup size = " << ThisGroup.size() << endl; + for (auto it = ThisGroup.begin(); it != ThisGroup.end(); ++it) + { + cout << it->first << " - " << it->second << ", "; + } + cout << endl; + } + // check is the current track trigger already exist in GroupedTriggersInTotal, if so, don't add it + // find trackTriggerTime in each element in GroupedTriggersInTotal[mainTrigWord] + bool trackTriggerExist = false; + for (int j = 0; j < GroupedTriggersInTotal[mainTrigWord].size(); j++) + { + for (auto it = GroupedTriggersInTotal[mainTrigWord][j].begin(); it != GroupedTriggersInTotal[mainTrigWord][j].end(); ++it) + { + if (it->first == trackTriggerTime && it->second == trackTriggerWord) + { + trackTriggerExist = true; + break; + } + } + } + if (!trackTriggerExist) + { + GroupedTriggersInTotal[mainTrigWord].push_back(ThisGroup); + } + else + { + // in it's track of SkippedDuplicateTriggers, plus one. if found it, ++, if not, emplace 1 + if (SkippedDuplicateTriggers.find(mainTrigWord) != SkippedDuplicateTriggers.end()) + { + SkippedDuplicateTriggers[mainTrigWord]++; + } + else + { + SkippedDuplicateTriggers.emplace(mainTrigWord, 1); + } + + Log("EBTG: Found a duplicated main trigger with word " + std::to_string(mainTrigWord) + " and time " + std::to_string(trackTriggerTime), v_message, verbosityEBTG); + } + + if (verbosityEBTG > 9) + cout << "EBTG: saving grouped trigger with currentRunCode = " << currentRunCode << endl; + if (!trackTriggerExist) + RunCodeInTotal[mainTrigWord].push_back(currentRunCode); + else + Log("EBTG: Found a duplicated main trigger with word " + std::to_string(mainTrigWord) + " and time " + std::to_string(trackTriggerTime) + ", so skip adding run code vector", v_message, verbosityEBTG); + totalGroupedTriggerNumber += ThisGroup.size(); + ThisGroup.clear(); + found = false; + } + } + int totalToRemoveTriggerNumber = toRemove.size(); + // from end to beginning, remove the triggers in buffer based on toRemove index + for (int i = toRemove.size() - 1; i >= 0; i--) + { + TrigTimeForGroup.erase(TrigTimeForGroup.begin() + toRemove[i]); + TrigWordForGroup.erase(TrigWordForGroup.begin() + toRemove[i]); + } + Log("EBTG: GroupByTrigWord Finished, accumulated saved " + std::to_string(GroupedTriggers.size()) + " group of triggers", v_warning, verbosityEBTG); + Log("EBTG: buffer TriggersForGroup after grouping size = " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + Log("EBTG: totalGroupedTriggerNumber in this grouping step is: " + std::to_string(totalGroupedTriggerNumber) + ", totalToRemoveTriggerNumber = " + std::to_string(totalToRemoveTriggerNumber), v_warning, verbosityEBTG); + + return totalToRemoveTriggerNumber; +} + +int EBTriggerGrouper::FillByTrigWord(uint32_t mainTrigWord, vector TrigWords, int tolerance) +{ + // Fill the trigger maps at GroupedTriggersInTotal[mainTrigWord] + // for all triggers in the buffer, if the trigger word is in the vector, and in the range of main TrigWord - the tolerance + // push the trigger into the map + + Log("EBTG: FillByTrigWord()", v_warning, verbosityEBTG); + Log("EBTG: Fill by TrigWord: " + std::to_string(mainTrigWord), v_warning, verbosityEBTG); + Log("EBTG: size of time buffer before refilling is " + std::to_string(TrigTimeForGroup.size()) + ", size of word buffer is " + std::to_string(TrigWordForGroup.size()), v_warning, verbosityEBTG); + + int addedTriggerNumber = 0; + vector indexToRemove; + + for (int i = TrigTimeForGroup.size() - 1; i >= 0; i--) + { + if (verbosityEBTG > 11) + cout << "EBTG: FillByTrigWord: mainTrigWord = " << mainTrigWord << ", TrigWordForGroup[i] = " << TrigWordForGroup[i] << ", TrigTimeForGroup[i] = " << TrigTimeForGroup[i] << ", tolerance = " << tolerance << endl; + // check is current trigger word in TrigWords + if (std::find(TrigWords.begin(), TrigWords.end(), TrigWordForGroup[i]) == TrigWords.end()) + continue; + bool triggerToAdd = false; + int insertTrack = 0; + int insertGroupIndex = 0; + uint64_t insertedDT = tolerance; + for (int j = 0; j < GroupedTriggersInTotal[mainTrigWord].size(); j++) + { + for (auto it = GroupedTriggersInTotal[mainTrigWord][j].begin(); it != GroupedTriggersInTotal[mainTrigWord][j].end(); ++it) + { + if (it->second == mainTrigWord) + { + uint64_t dt = (TrigTimeForGroup[i] > it->first) ? (TrigTimeForGroup[i] - it->first) : (it->first - TrigTimeForGroup[i]); + if (dt < tolerance && dt < insertedDT) + { + insertedDT = dt; + insertTrack = mainTrigWord; + insertGroupIndex = j; + triggerToAdd = true; + Log("EBTG: FillByTrigWord: Found trigger to add, insertTrack = " + std::to_string(insertTrack) + ", insertGroupIndex = " + std::to_string(insertGroupIndex) + ", insert DT = " + std::to_string(insertedDT), 9, verbosityEBTG); + break; + } + } + } + } + if (triggerToAdd) + { + GroupedTriggersInTotal[mainTrigWord][insertGroupIndex].insert(std::make_pair(TrigTimeForGroup[i], TrigWordForGroup[i])); + indexToRemove.push_back(i); + if (verbosityEBTG > 11) + cout << "EBTG: FillByTrigWord: add this trigger: " << TrigTimeForGroup[i] << " - " << TrigWordForGroup[i] << endl; + addedTriggerNumber++; + } + } + Log("EBTG: FillByTrigWord Finished, addedTriggerNumber = " + std::to_string(addedTriggerNumber), v_warning, verbosityEBTG); + Log("EBTG: indexToRemove size = " + std::to_string(indexToRemove.size()) + ", buffer size before remove is " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + + // sort indexToRemove from large to small, then remove the triggers in buffer based on toRemove index + std::sort(indexToRemove.begin(), indexToRemove.end(), std::greater()); + + if (verbosityEBTG > 11) + { + // print all index to remove + cout << "EBTG: FillByTrigWord: indexToRemove: "; + for (int i = 0; i < indexToRemove.size(); i++) + { + cout << indexToRemove[i] << ", "; + } + } + + for (int i = 0; i < indexToRemove.size(); i++) + { + TrigTimeForGroup.erase(TrigTimeForGroup.begin() + indexToRemove[i]); + TrigWordForGroup.erase(TrigWordForGroup.begin() + indexToRemove[i]); + } + Log("EBTG: buffer TriggersForGroup after refilling and removing size = " + std::to_string(TrigTimeForGroup.size()), v_warning, verbosityEBTG); + + return addedTriggerNumber; +} + +int EBTriggerGrouper::CleanTriggerBuffer() +{ + // remove very early trigger in TrigTimeForGroup and TrigWordForGroup + // only leave the latest maxNumAllowedInBuffer elements + int removedNumber = 0; + if (TrigTimeForGroup.size() > maxNumAllowedInBuffer) + { + removedNumber = TrigTimeForGroup.size() - maxNumAllowedInBuffer; + removedTriggerInBuffer += removedNumber; + Log("EBTG: CleanTriggerBuffer, will remove the earliest " + std::to_string(TrigTimeForGroup.size() - maxNumAllowedInBuffer) + " triggers in buffer", v_message, verbosityEBTG); + TrigTimeForGroup.erase(TrigTimeForGroup.begin(), TrigTimeForGroup.end() - maxNumAllowedInBuffer); + TrigWordForGroup.erase(TrigWordForGroup.begin(), TrigWordForGroup.end() - maxNumAllowedInBuffer); + } + return removedNumber; +} \ No newline at end of file diff --git a/UserTools/EBTriggerGrouper/EBTriggerGrouper.h b/UserTools/EBTriggerGrouper/EBTriggerGrouper.h new file mode 100644 index 000000000..3d573259b --- /dev/null +++ b/UserTools/EBTriggerGrouper/EBTriggerGrouper.h @@ -0,0 +1,124 @@ +#ifndef EBTriggerGrouper_H +#define EBTriggerGrouper_H + +#include +#include + +#include "Tool.h" + +/** + * \class EBPMT + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ + +class EBTriggerGrouper : public Tool +{ + +public: + EBTriggerGrouper(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + + bool GroupByTolerance(); + bool FillByTolerance(); + bool SaveGroupedTriggers(); + bool CleanBuffer(); + + int GroupByTrigWord(uint32_t mainTrigWord, vector TrigWords, int tolerance); + // group and save triggers to GroupedTriggersInTotal and RunCodeInTotal + // input a vector of trigger words in that combination, and a tolerance + // during grouping, select based on the main TrigWord + the tolerance + // in that range, if the trigger word is in the vector, group them together + // push the grouped trigger map into the vector at GroupedTriggersInTotal[mainTrigWord] + + int FillByTrigWord(uint32_t mainTrigWord, vector TrigWords, int tolerance); + // Fill the trigger maps at GroupedTriggersInTotal[mainTrigWord] + // for all triggers in the buffer, if the trigger word is in the vector, and in the range of main TrigWord - the tolerance + // push the trigger into the map + + int CleanTriggerBuffer(); // remove very early trigger in TrigTimeForGroup and TrigWordForGroup + // only leave the latest maxNumAllowedInBuffer elements + +private: + string savePath; + string GroupMode; // beam, Tolerance + double GroupTolerance; + int GroupTrigWord; + + std::map> *TimeToTriggerWordMap; + std::map> *TimeToTriggerWordMapComplete; // Info about all triggerwords + + vector TrigTimeForGroup; + vector TrigWordForGroup; + vector RunCodeBuffer; + + std::vector> GroupedTriggers; // each map is a group of triggers, for the main target trigger + vector RunCode; //!! RunCode goes with each group, always modify them together + + std::map>> GroupedTriggersInTotal; // each map is a group of triggers, with the key is the target trigger word + std::map> RunCodeInTotal; //!! RunCode goes with each group, always modify them together + + std::map SkippedDuplicateTriggers; // if the trigger was duplicated in multiple entries, skip it. this record the skipped number of groups + + int verbosityEBTG; + + int v_message = 1; + int v_warning = 2; + int v_error = 3; + int v_debug = 4; + + int ANNIEEventNum; + int CurrentRunNum; + int CurrentSubrunNum; + int CurrentPartNum; + int currentRunCode; + bool usingTriggerOverlap; + + int StoreTotalEntry; + + int maxNumAllowedInBuffer; + int removedTriggerInBuffer; + + bool groupBeam; + bool groupCosmic; + bool groupLaser; + bool groupLED; + bool groupAmBe; + bool groupPPS; + bool groupNuMI; + + int BeamTriggerMain; + double BeamTolerance; + vector BeamTriggers; + + int CosmicTriggerMain; + double CosmicTolerance; + vector CosmicTriggers; + + int LaserTriggerMain; + double LaserTolerance; + vector LaserTriggers; + + int LEDTriggerMain; + double LEDTolerance; + vector LEDTriggers; + + int AmBeTriggerMain; + double AmBeTolerance; + vector AmBeTriggers; + + int PPSTriggerMain; + double PPSTolerance; + vector PPSTriggers; + + int NuMITriggerMain; + double NuMITolerance; + vector NuMITriggers; +}; + +#endif diff --git a/UserTools/EBTriggerGrouper/README.md b/UserTools/EBTriggerGrouper/README.md new file mode 100644 index 000000000..3f84b6468 --- /dev/null +++ b/UserTools/EBTriggerGrouper/README.md @@ -0,0 +1,32 @@ +# EBTriggerGrouper + +EBTriggerGrouper is a part of the Event Builder V2 tool chain. +For reference slides, see: +https://annie-docdb.fnal.gov/cgi-bin/sso/ShowDocument?docid=5633 + + +This tool take TimeToTriggerWordMap from the trigger data decoder as input, push the triggers and trigger words into TrigTimeForGroup and TrigWordForGroup, then use the pre defined trigger groups like BeamTriggers to group the triggers based on time tolorance. Finally save the grouped triggers to GroupedTriggersInTotal in CStore. + +## Data + +**TimeToTriggerWordMap** `std::map>` +**TimeToTriggerWordMapComplete** `std::map>` +Take from TriggerDataDecoder. This tool will push the info to + +**TrigTimeForGroup** `vector` +**TrigWordForGroup** `vector` +Buffer for timestamps. Only be used in this tool. + + +**GroupedTriggersInTotal** `std::map>>` +Groupped triggers, will be passed to other tools for matching. + +## Configuration +For one group type, you need one option, and two configs from the config file, one config hard coded in the cpp file. +groupBeam: tell the tool group this run type or not +BeamTriggerMain: the main trigger of a run type. For instance, main beam trigger is 14 +BeamTolerance: the time tolerance that you allow other triggers in this run type to be paired with a main trigger. +BeamTriggers: hard coded in the cpp file for safety. This vector contains all trigger word that allowed to be grouped as beam. +They are sent to GroupByTrigWord function for each run type. In case there will be more run types in the future. + + diff --git a/UserTools/Factory/Factory.cpp b/UserTools/Factory/Factory.cpp index d94a2e18b..3c6aa49a8 100644 --- a/UserTools/Factory/Factory.cpp +++ b/UserTools/Factory/Factory.cpp @@ -169,5 +169,14 @@ if (tool=="PlotsTrackLengthAndEnergy") ret=new PlotsTrackLengthAndEnergy; if (tool=="SaveConfigInfo") ret=new SaveConfigInfo; if (tool=="ReadConfigInfo") ret=new ReadConfigInfo; if (tool=="BackTracker") ret=new BackTracker; +if (tool=="EBLoadRaw") ret=new EBLoadRaw; +if (tool=="EBTriggerGrouper") ret=new EBTriggerGrouper; +if (tool=="EBLAPPD") ret=new EBLAPPD; +if (tool=="EBPMT") ret=new EBPMT; +if (tool=="EBMRD") ret=new EBMRD; +if (tool=="EBSaver") ret=new EBSaver; +if (tool=="LAPPDLoadStore") ret=new LAPPDLoadStore; +if (tool=="LAPPDTreeMaker") ret=new LAPPDTreeMaker; +if (tool=="ANNIEEventTreeMaker") ret=new ANNIEEventTreeMaker; return ret; } diff --git a/UserTools/LAPPDLoadStore/LAPPDLoadStore.cpp b/UserTools/LAPPDLoadStore/LAPPDLoadStore.cpp new file mode 100644 index 000000000..92edebf4d --- /dev/null +++ b/UserTools/LAPPDLoadStore/LAPPDLoadStore.cpp @@ -0,0 +1,1612 @@ +#include "LAPPDLoadStore.h" + +LAPPDLoadStore::LAPPDLoadStore() : Tool() {} + +bool LAPPDLoadStore::Initialise(std::string configfile, DataModel &data) +{ + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + // Control variables + // Control variables used in this tool + retval = 0; + eventNo = 0; + CLOCK_to_NSEC = 3.125; // 3.125 ns per clock cycle + errorEventsNumber = 0; + // Control variables that you get from the config file, for this tool + m_variables.Get("ReadStore", ReadStore); + m_variables.Get("Nboards", Nboards); + m_variables.Get("StorePedinputfile", PedFileName); + m_variables.Get("PedinputfileTXT", PedFileNameTXT); + m_variables.Get("DoPedSubtraction", DoPedSubtract); + m_variables.Get("LAPPDStoreReadInVerbosity", LAPPDStoreReadInVerbosity); + m_variables.Get("num_vector_data", num_vector_data); + m_variables.Get("num_vector_pps", num_vector_pps); + m_variables.Get("SelectSingleLAPPD", SelectSingleLAPPD); + m_variables.Get("SelectedLAPPD", SelectedLAPPD); + mergingModeReadIn = false; + m_variables.Get("mergingModeReadIn", mergingModeReadIn); + ReadStorePdeFile = false; + m_variables.Get("ReadStorePdeFile", ReadStorePdeFile); + MultiLAPPDMap = false; + m_variables.Get("MultiLAPPDMap", MultiLAPPDMap); + loadPSEC = true; + m_variables.Get("loadPSEC", loadPSEC); + loadPPS = false; + m_variables.Get("loadPPS", loadPPS); + loadOffsets = false; + m_variables.Get("loadOffsets", loadOffsets); + LoadBuiltPPSInfo = true; + m_variables.Get("LoadBuiltPPSInfo", LoadBuiltPPSInfo); + loadFromStoreDirectly = false; + m_variables.Get("loadFromStoreDirectly", loadFromStoreDirectly); + // Control variables in this tool, initialized in this tool + NonEmptyEvents = 0; + NonEmptyDataEvents = 0; + PPSnumber = 0; + mergedEvent = false; + isFiltered = false; + isBLsub = false; + isCFD = false; + // Global Control variables that you get from the config file + m_variables.Get("stopEntries", stopEntries); + m_variables.Get("PsecReceiveMode", PsecReceiveMode); + m_variables.Get("RawDataOutputWavLabel", OutputWavLabel); + m_variables.Get("RawDataInputWavLabel", InputWavLabel); + m_variables.Get("NChannels", NChannels); + m_variables.Get("Nsamples", Nsamples); + m_variables.Get("TrigChannel", TrigChannel); + m_variables.Get("SampleSize", SampleSize); + m_variables.Get("LAPPDchannelOffset", LAPPDchannelOffset); + // Data variables + // Data variables you get from other tools (it not initialized in execute) + // Data variables you use in this tool + m_variables.Get("PSECinputfile", NewFileName); + // Verbosity + // Details on channels, samples and max vector sizes and trigger channel + m_variables.Get("Nsamples", Nsamples); + m_variables.Get("TrigChannel", TrigChannel); + + runNumber = 0; + subRunNumber = 0; + partFileNumber = 0; + eventNumberInPF = 0; + + ReadStore = 0; + + // get data file + /* + if (ReadStore == 1) + { + // get data from a StoreFile in ANNIEEvent format + m_data->Stores["ANNIEEvent"] = new BoostStore(false, 2); + m_data->Stores["ANNIEEvent"]->Initialise(NewFileName); + cout << "LAPPDStoreReadIn Reading new ANNIEevent from " << NewFileName << endl; + } + else if (ReadStore == 0) + { // get data from previous chain, or m_data + cout << "LAPPDStoreReadIn Using ANNIEevent or CStore" << endl; + }*/ + // Grab all pedestal files and prepare the map channel|pedestal-vector for substraction + if (DoPedSubtract == 1) + { + PedestalValues = new std::map>; + /*if (ReadStorePdeFile) + { + m_data->Stores["PedestalFile"] = new BoostStore(false, 2); + bool ret = false; + if (FILE *file = fopen(PedFileName.c_str(), "r")) + { + fclose(file); + ret = true; + cout << "Using Store Pedestal File" << endl; + } + if (ret) + { + m_data->Stores["PedestalFile"]->Initialise(PedFileName); + long Pedentries; + m_data->Stores["PedestalFile"]->Header->Get("TotalEntries", Pedentries); + if (LAPPDStoreReadInVerbosity > 0) + cout << PedFileName << " got " << Pedentries << endl; + m_data->Stores["PedestalFile"]->Get("PedestalMap", PedestalValues); + } + } + else*/ + { + for (int i = 0; i < Nboards; i++) + { + if (LAPPDStoreReadInVerbosity > 0) + cout << "Reading Pedestal File " << PedFileNameTXT << " " << i << endl; + ReadPedestals(i); + } + } + if (LAPPDStoreReadInVerbosity > 0) + cout << "PEDSIZES: " << PedestalValues->size() << " " << PedestalValues->at(0).size() << " " << PedestalValues->at(4).at(5) << endl; + } + + // set some control variables for later tools + m_data->CStore.Set("SelectSingleLAPPD", SelectSingleLAPPD); + m_data->Stores["ANNIEEvent"]->Set("Nsamples", Nsamples); + m_data->Stores["ANNIEEvent"]->Set("NChannels", NChannels); + m_data->Stores["ANNIEEvent"]->Set("TrigChannel", TrigChannel); + m_data->Stores["ANNIEEvent"]->Set("LAPPDchannelOffset", LAPPDchannelOffset); + m_data->Stores["ANNIEEvent"]->Set("SampleSize", SampleSize); + m_data->Stores["ANNIEEvent"]->Set("isFiltered", isFiltered); + m_data->Stores["ANNIEEvent"]->Set("isBLsubtracted", isBLsub); + m_data->Stores["ANNIEEvent"]->Set("isCFD", isCFD); + + if (loadOffsets) + LoadOffsetsAndCorrections(); + if (LAPPDStoreReadInVerbosity > 11) + debugStoreReadIn.open("debugStoreReadIn.txt"); + + return true; +} + +void LAPPDLoadStore::CleanDataObjects() +{ + LAPPD_ID = -9999; + Raw_buffer.clear(); + Parse_buffer.clear(); + ReadBoards.clear(); + data.clear(); + meta.clear(); + pps.clear(); + LAPPDWaveforms.clear(); + EventType = -9999; + LAPPDana = false; + ParaBoards.clear(); + meta.clear(); + LAPPDWaveforms.clear(); + data.clear(); + Parse_buffer.clear(); + // LAPPDDataMap.clear(); + // DataStreams.clear(); + runInfoLoaded = false; + + LAPPD_IDs.clear(); + LAPPDLoadedTimeStampsRaw.clear(); + LAPPDLoadedBeamgatesRaw.clear(); + LAPPDLoadedOffsets.clear(); + LAPPDLoadedTSCorrections.clear(); + LAPPDLoadedBGCorrections.clear(); + LAPPDLoadedOSInMinusPS.clear(); +} + +bool LAPPDLoadStore::Execute() +{ + // 1. clean data variables + // 2. decide loading data or not, load the data from PsecData dat to tool + // 3. parse and pass data to later tools + + CleanDataObjects(); + m_data->CStore.Set("LAPPD_new_event", false); + + if (MultiLAPPDMap) + { + bool gotDataStream = m_data->Stores["ANNIEEvent"]->Get("DataStreams", DataStreams); + bool getMap = m_data->Stores["ANNIEEvent"]->Get("LAPPDDataMap", LAPPDDataMap); + if (getMap && DataStreams["LAPPD"] == true && LAPPDDataMap.size() > 0) + { + // cout << "Outside, size of LAPPDDatamap = " << LAPPDDataMap.size() << endl; + bool gotBeamgates_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + bool gotTimeStamps_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + bool gotTimeStampsRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + bool gotBeamgatesRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + bool gotOffsets = m_data->Stores["ANNIEEvent"]->Get("LAPPDOffsets", LAPPDOffsets); + bool gotTSCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDTSCorrection", LAPPDTSCorrection); + bool gotDBGCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDBGCorrection", LAPPDBGCorrection); + bool gotOSInMinusPS = m_data->Stores["ANNIEEvent"]->Get("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + if (LoadBuiltPPSInfo) + { + bool gotBG_PPSBefore = m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + bool gotBG_PPSAfter = m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + bool gotBG_PPSDiff = m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + bool gotBG_PPSMissing = m_data->Stores["ANNIEEvent"]->Get("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + bool gotTS_PPSBefore = m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + bool gotTS_PPSAfter = m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + bool gotTS_PPSDiff = m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + bool gotTS_PPSMissing = m_data->Stores["ANNIEEvent"]->Get("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); + if (LAPPDStoreReadInVerbosity > 3) + { + cout << "LAPPDLoadStore: gotOffsets = " << gotOffsets << ", gotBG_PPSBefore = " << gotBG_PPSBefore << ", gotTS_PPSBefore = " << gotTS_PPSBefore << endl; + cout << "Size of LAPPDDataMap = " << LAPPDDataMap.size() << ", LAPPDOffsets = " << LAPPDOffsets.size() << ", LAPPDBG_PPSBefore = " << LAPPDBG_PPSBefore.size() << ", LAPPDTS_PPSBefore = " << LAPPDTS_PPSBefore.size() << endl; + + cout << "gotBG_PPSBefore = " << gotBG_PPSBefore << ", gotBG_PPSAfter = " << gotBG_PPSAfter << ", gotBG_PPSDiff = " << gotBG_PPSDiff << ", gotBG_PPSMissing = " << gotBG_PPSMissing << endl; + cout << "gotTS_PPSBefore = " << gotTS_PPSBefore << ", gotTS_PPSAfter = " << gotTS_PPSAfter << ", gotTS_PPSDiff = " << gotTS_PPSDiff << ", gotTS_PPSMissing = " << gotTS_PPSMissing << endl; + } + } + } + else + { + return true; + } + } + + // decide loading data or not, set to LAPPDana for later tools + LAPPDana = LoadData(); + m_data->CStore.Set("LAPPDana", LAPPDana); + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDana for loading was set to " << LAPPDana << endl; + if (!LAPPDana) + { + // not loading data, return + return true; + } + + if (!MultiLAPPDMap) + { + // parse and pass data to later tools + int frametype = static_cast(Raw_buffer.size() / ReadBoards.size()); + if (frametype != num_vector_data && frametype != num_vector_pps) + { + cout << "Problem identifying the frametype, size of raw vector was " << Raw_buffer.size() << endl; + cout << "It was expected to be either " << num_vector_data * ReadBoards.size() << " or " << num_vector_pps * ReadBoards.size() << endl; + cout << "Please check manually!" << endl; + LAPPDana = false; + m_data->CStore.Set("LAPPDana", LAPPDana); + m_data->CStore.Set("LAPPDPPShere", LAPPDana); + return true; + } + + if (frametype == num_vector_pps && loadPPS) + { + // if it's PPS, don't to anything relate to merging + m_data->CStore.Set("LAPPDanaData", false); + // set LAPPDana to false + LAPPDana = false; + m_data->CStore.Set("LAPPDana", LAPPDana); + ParsePPSData(); + m_data->CStore.Set("LAPPD_ID", LAPPD_ID); + m_data->Stores["ANNIEEvent"]->Set("LAPPD_ID", LAPPD_ID); + m_data->CStore.Set("LoadingPPS", true); + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: PPS data loaded, LAPPDanaData is false, set LAPPDana to false" << endl; + return true; + } + + if (frametype == num_vector_data && loadPSEC) + { + m_data->CStore.Set("LAPPDanaData", true); + bool parsData = ParsePSECData(); + LoadRunInfo(); + runInfoLoaded = true; + LAPPDana = parsData; + m_data->CStore.Set("LAPPDana", LAPPDana); + m_data->CStore.Set("LoadingPPS", false); + + if (!parsData) + { + cout << "LAPPDStoreReadIn: PSEC data parsing failed, set LAPPDana to false and return" << endl; + + return true; + } + NonEmptyDataEvents += 1; + } + + // parsing finished, do pedestal subtraction + DoPedestalSubtract(); + // save some timestamps relate to this event, for later using + SaveTimeStamps(); + + vector ReadedBoards; + vector ACDCReadedLAPPDID; + for (auto it = ReadBoards.begin(); it != ReadBoards.end(); it++) + { + ReadedBoards.push_back(*it); + ACDCReadedLAPPDID.push_back(LAPPD_ID); + // cout << "ReadedBoards loaded with " << *it << endl; + } + + if (LAPPDStoreReadInVerbosity > 0) + cout << "*************************END LAPPDStoreReadIn************************************" << endl; + m_data->CStore.Set("LAPPD_ID", LAPPD_ID); + m_data->Stores["ANNIEEvent"]->Set("LAPPD_ID", LAPPD_ID); + m_data->Stores["ANNIEEvent"]->Set("RawLAPPDData", LAPPDWaveforms); // leave this only for the merger tool + m_data->Stores["ANNIEEvent"]->Set("MergeLAPPDPsec", LAPPDWaveforms); + m_data->Stores["ANNIEEvent"]->Set("ACDCmetadata", meta); + m_data->Stores["ANNIEEvent"]->Set("ACDCboards", ReadBoards); + m_data->Stores["ANNIEEvent"]->Set("SortedBoards", ParaBoards); + m_data->Stores["ANNIEEvent"]->Set("TriggerChannelBase", TrigChannel); + m_data->Stores["ANNIEEvent"]->Set("ACDCReadedLAPPDID", ACDCReadedLAPPDID); + m_data->Stores["ANNIEEvent"]->Set("ReadedBoards", ReadedBoards); + + m_data->CStore.Set("NewLAPPDDataAvailable", true); + if (LAPPDStoreReadInVerbosity > 11) + debugStoreReadIn << " Set NewLAPPDDataAvailable to true" << endl; + + NonEmptyEvents += 1; + eventNo++; + if (LAPPDStoreReadInVerbosity > 2) + { + cout << "Finish LAPPDStoreReadIn, Printing the ANNIEEvent" << endl; + m_data->Stores["ANNIEEvent"]->Print(false); + } + } + else + { + // if we are reading multiple LAPPD data from one ANNIEEvent + // assume we only have PSEC data in ANNIEEvent, no PPS event. + // loop the map, for each PSEC data, do the same loading and parsing. + // load the waveform by using LAPPD_ID * board_number * channel_number as the key + + // data was already loaded in the LoadData() + + vector ReadedBoards; + vector ACDCReadedLAPPDID; + + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: LAPPDDataMap has " << LAPPDDataMap.size() << " LAPPD PSEC data " << endl; + bool ValidDataLoaded = false; + std::map::iterator it; + for (it = LAPPDDataMap.begin(); it != LAPPDDataMap.end(); it++) + { + ParaBoards.clear(); + uint64_t time = it->first; + PsecData dat = it->second; + ReadBoards = dat.BoardIndex; // From the data, board index is not related to the LAPPD_ID! WHY use this way? + Raw_buffer = dat.RawWaveform; + LAPPD_ID = dat.LAPPD_ID; + if (LAPPD_ID != SelectedLAPPD && SelectSingleLAPPD) + continue; + + if (Raw_buffer.size() == 0 || ReadBoards.size() == 0) + { + m_data->CStore.Set("LAPPDana", false); + cout << "LAPPD Load Store, find Raw buffer size == 0 or ReadBoards size == 0" << endl; + continue; + // return true; + } + + if (LAPPDStoreReadInVerbosity > 0) + { + // print ReadBoards + cout << "LAPPD ID " << LAPPD_ID << " ReadBoards size is " << ReadBoards.size() << ", data: " << endl; + for (auto it = ReadBoards.begin(); it != ReadBoards.end(); it++) + { + cout << ", " << *it; + } + cout << endl; + } + + // push all elements in ReadBoards to ReadedBoards + for (auto it = ReadBoards.begin(); it != ReadBoards.end(); it++) + { + ReadedBoards.push_back(*it); + ACDCReadedLAPPDID.push_back(LAPPD_ID); + // cout << "ReadedBoards loaded with " << *it << endl; + } + + int frametype = static_cast(Raw_buffer.size() / ReadBoards.size()); + if (frametype != num_vector_data) + { + cout << "LAPPDStoreReadIn: For LAPPD_ID " << LAPPD_ID << " frametype is not num_vector_data, skip this LAPPD" << endl; + continue; + } + m_data->CStore.Set("LAPPDanaData", true); + if (LAPPDStoreReadInVerbosity > 3) + { + cout << "Before parsing data, printing size and element in ReadBoards, ReadedBoards, ParaBoards" << endl; + cout << "ReadBoards size is " << ReadBoards.size() << endl; + for (auto it = ReadBoards.begin(); it != ReadBoards.end(); it++) + { + cout << ", " << *it; + } + cout << endl; + cout << "ReadedBoards size is " << ReadedBoards.size() << endl; + for (auto it = ReadedBoards.begin(); it != ReadedBoards.end(); it++) + { + cout << ", " << *it; + } + cout << endl; + cout << "ParaBoards size is " << ParaBoards.size() << endl; + for (auto it = ParaBoards.begin(); it != ParaBoards.end(); it++) + { + cout << ", " << *it; + } + cout << endl; + } + bool parsData = ParsePSECData(); // TODO: now assuming all boards just has 30 channels. Need to be changed for gen 2 + if (parsData) + { + ValidDataLoaded = true; + if (LAPPDStoreReadInVerbosity > 2) + cout << "LAPPDLoadStore: Loaded LAPPD data for LAPPD_ID " << LAPPD_ID << " at time " << time << endl; + LAPPDLoadedTimeStamps.push_back(time); + LAPPD_IDs.push_back(LAPPD_ID); + // print the size of LAPPDTimeStampsRaw, print all keys in it + if (LAPPDStoreReadInVerbosity > 0) + { + cout << "LAPPDTimeStampsRaw size is " << LAPPDTimeStampsRaw.size() << endl; + for (auto it = LAPPDTimeStampsRaw.begin(); it != LAPPDTimeStampsRaw.end(); it++) + { + cout << "LAPPDTimeStampsRaw key is " << it->first << endl; + } + } + // print the size of LAPPDOffsets, print all keys in it + if (LAPPDStoreReadInVerbosity > 0) + { + cout << "LAPPDOffsets size is " << LAPPDOffsets.size() << endl; + for (auto it = LAPPDOffsets.begin(); it != LAPPDOffsets.end(); it++) + { + cout << "LAPPDOffsets key is " << it->first << endl; + } + } + + LAPPDLoadedTimeStampsRaw.push_back(LAPPDTimeStampsRaw.at(time)); + LAPPDLoadedBeamgatesRaw.push_back(LAPPDBeamgatesRaw.at(time)); + LAPPDLoadedOffsets.push_back(LAPPDOffsets.at(time)); + LAPPDLoadedTSCorrections.push_back(LAPPDTSCorrection.at(time)); + LAPPDLoadedBGCorrections.push_back(LAPPDBGCorrection.at(time)); + LAPPDLoadedOSInMinusPS.push_back(LAPPDOSInMinusPS.at(time)); + + if (LAPPDStoreReadInVerbosity > 2) + cout << "parsing finished for LAPPD_ID " << LAPPD_ID << " at time " << time << endl; + + if (LoadBuiltPPSInfo) + { + LAPPDLoadedBG_PPSBefore.push_back(LAPPDBG_PPSBefore.at(time)); + LAPPDLoadedBG_PPSAfter.push_back(LAPPDBG_PPSAfter.at(time)); + LAPPDLoadedBG_PPSDiff.push_back(LAPPDBG_PPSDiff.at(time)); + LAPPDLoadedBG_PPSMissing.push_back(LAPPDBG_PPSMissing.at(time)); + LAPPDLoadedTS_PPSBefore.push_back(LAPPDTS_PPSBefore.at(time)); + LAPPDLoadedTS_PPSAfter.push_back(LAPPDTS_PPSAfter.at(time)); + LAPPDLoadedTS_PPSDiff.push_back(LAPPDTS_PPSDiff.at(time)); + LAPPDLoadedTS_PPSMissing.push_back(LAPPDTS_PPSMissing.at(time)); + + if (LAPPDTS_PPSMissing.at(time) != LAPPDBG_PPSMissing.at(time) && ((LAPPDTS_PPSMissing.at(time) > -100 && LAPPDTS_PPSMissing.at(time) < 100) || (LAPPDBG_PPSMissing.at(time) > -100 && LAPPDBG_PPSMissing.at(time) < 100))) + { + cout << "LAPPDLoadStore: PPS missing number is not the same on BG and TS for LAPPD_ID " << LAPPD_ID << " at time " << time << ", BG: " << LAPPDBG_PPSMissing.at(time) << ", TS: " << LAPPDTS_PPSMissing.at(time) << endl; + cout << "LAPPDLoadStore: BG_PPSDiff: " << LAPPDBG_PPSDiff.at(time) << ", TS_PPSDiff: " << LAPPDTS_PPSDiff.at(time) << endl; + } + } + } + NonEmptyEvents += 1; + NonEmptyDataEvents += 1; + } + eventNo++; + LAPPDana = ValidDataLoaded; + m_data->CStore.Set("LAPPDana", LAPPDana); + DoPedestalSubtract(); + + m_data->Stores["ANNIEEvent"]->Set("RawLAPPDData", LAPPDWaveforms); // leave this only for the merger tool + m_data->Stores["ANNIEEvent"]->Set("LAPPD_IDs", LAPPD_IDs); + m_data->Stores["ANNIEEvent"]->Set("LAPPDLoadedTimeStamps", LAPPDLoadedTimeStamps); + m_data->Stores["ANNIEEvent"]->Set("ACDCboards", ReadedBoards); + m_data->Stores["ANNIEEvent"]->Set("ACDCReadedLAPPDID", ACDCReadedLAPPDID); + m_data->Stores["ANNIEEvent"]->Set("ACDCmetadata", meta); + + m_data->Stores["ANNIEEvent"]->Set("LAPPDDataMap", LAPPDDataMap); + + m_data->Stores["ANNIEEvent"]->Set("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + m_data->Stores["ANNIEEvent"]->Set("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + m_data->Stores["ANNIEEvent"]->Set("LAPPDOffsets", LAPPDOffsets); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTSCorrection", LAPPDTSCorrection); + m_data->Stores["ANNIEEvent"]->Set("LAPPDBGCorrection", LAPPDBGCorrection); + m_data->Stores["ANNIEEvent"]->Set("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + if (LoadBuiltPPSInfo) + { + m_data->Stores["ANNIEEvent"]->Set("LAPPDBG_PPSBefore", LAPPDBG_PPSBefore); + m_data->Stores["ANNIEEvent"]->Set("LAPPDBG_PPSAfter", LAPPDBG_PPSAfter); + m_data->Stores["ANNIEEvent"]->Set("LAPPDBG_PPSDiff", LAPPDBG_PPSDiff); + m_data->Stores["ANNIEEvent"]->Set("LAPPDBG_PPSMissing", LAPPDBG_PPSMissing); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTS_PPSBefore", LAPPDTS_PPSBefore); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTS_PPSAfter", LAPPDTS_PPSAfter); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTS_PPSDiff", LAPPDTS_PPSDiff); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTS_PPSMissing", LAPPDTS_PPSMissing); + } + // TODO: save other timestamps, variables and metadata for later use + + if (eventNo % 100 == 0) + { + cout << "LAPPDLoadStore: Loaded " << eventNo << " events, " << NonEmptyDataEvents << " non empty LAPPD PSEC data loaded from all LAPPDs" << endl; + } + } + + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDLoadStore: Finished loading LAPPD data" << endl; + + return true; +} + +bool LAPPDLoadStore::Finalise() +{ + cout << "\033[1;34mLAPPDLoadStore: Finalising\033[0m" << endl; + cout << "LAPPDLoadStore: Got pps event in total: " << PPSnumber << endl; + cout << "LAPPDLoadStore: Got error data or PPS events in total: " << errorEventsNumber << endl; + cout << "LAPPDLoadStore: Got non empty data and PPS events in total: " << NonEmptyEvents << endl; + cout << "LAPPDLoadStore: Got non empty data events in total: " << NonEmptyDataEvents << endl; + cout << "LAPPDLoadStore: End at event number: " << eventNo << endl; + return true; +} + +bool LAPPDLoadStore::ReadPedestals(int boardNo) +{ + + if (LAPPDStoreReadInVerbosity > 0) + cout << "Getting Pedestals " << boardNo << endl; + + std::string LoadName = PedFileNameTXT; + string nextLine; // temp line to parse + double finalsampleNo; + std::string ext = std::to_string(boardNo); + ext += ".txt"; + LoadName += ext; + PedFile.open(LoadName); // final name: PedFileNameTXT + boardNo + .txt + if (!PedFile.is_open()) + { + cout << "Failed to open " << LoadName << "!" << endl; + return false; + } + if (LAPPDStoreReadInVerbosity > 0) + cout << "Opened file: " << LoadName << endl; + + int sampleNo = 0; // sample number + while (getline(PedFile, nextLine)) + { + istringstream iss(nextLine); // copies the current line in the file + int location = -1; // counts the current perameter in the line + string stempValue; // current string in the line + int tempValue; // current int in the line + unsigned long channelNo = boardNo * 30; // channel number + // cout<<"NEW BOARD "<> stempValue) + { + location++; + int tempValue = stoi(stempValue, 0, 10); + if (sampleNo == 0) + { + vector tempPed; + tempPed.push_back(tempValue); + // cout<<"First time: "<insert(pair>(channelNo, tempPed)); + if (LAPPDStoreReadInVerbosity > 0) + cout << "Inserting pedestal at channelNo " << channelNo << endl; + // newboard=false; + } + else + { + // cout<<"Following time: "<count(channelNo)<find(channelNo))->second)).push_back(tempValue); + } + + channelNo++; + } + sampleNo++; + } + if (LAPPDStoreReadInVerbosity > 0) + cout << "FINAL SAMPLE NUMBER: " << PedestalValues->size() << " " << (((PedestalValues->find(0))->second)).size() << endl; + PedFile.close(); + return true; +} + +bool LAPPDLoadStore::MakePedestals() +{ + + // Empty for now... + // should be moved to ASCII readin? + + return true; +} + +int LAPPDLoadStore::getParsedMeta(std::vector buffer, int BoardId) +{ + // Catch empty buffers + if (buffer.size() == 0) + { + std::cout << "You tried to parse ACDC data without pulling/setting an ACDC buffer" << std::endl; + return -1; + } + + // Prepare the Metadata vector + // meta.clear(); + + // Helpers + int chip_count = 0; + + // Indicator words for the start/end of the metadata + const unsigned short startword = 0xBA11; + unsigned short endword = 0xFACE; + unsigned short endoffile = 0x4321; + + // Empty metadata map for each Psec chip + map> PsecInfo; + + // Empty trigger metadata map for each Psec chip + map> PsecTriggerInfo; + unsigned short CombinedTriggerRateCount; + + // Empty vector with positions of aboves startword + vector start_indices = + { + 1539, 3091, 4643, 6195, 7747}; + + // Fill the psec info map + vector::iterator bit; + for (int i : start_indices) + { + // Write the first word after the startword + bit = buffer.begin() + (i + 1); + + // As long as the endword isn't reached copy metadata words into a vector and add to map + vector InfoWord; + while (*bit != endword && *bit != endoffile && InfoWord.size() < 14) + { + InfoWord.push_back(*bit); + ++bit; + } + PsecInfo.insert(pair>(chip_count, InfoWord)); + chip_count++; + } + + // Fill the psec trigger info map + for (int chip = 0; chip < NUM_PSEC; chip++) + { + for (int ch = 0; ch < NUM_CH / NUM_PSEC; ch++) + { + if (LAPPDStoreReadInVerbosity > 10) + cout << "parsing meta step1-1" << endl; + // Find the trigger data at begin + last_metadata_start + 13_info_words + 1_end_word + 1 + bit = buffer.begin() + start_indices[4] + 13 + 1 + 1 + ch + (chip * (NUM_CH / NUM_PSEC)); + if (LAPPDStoreReadInVerbosity > 10) + cout << "parsing meta step1-2" << endl; + PsecTriggerInfo[chip].push_back(*bit); + } + } + + if (LAPPDStoreReadInVerbosity > 10) + cout << "parsing meta step1.5" << endl; + // Fill the combined trigger + CombinedTriggerRateCount = buffer[7792]; + + //---------------------------------------------------------- + // Start the metadata parsing + + meta.push_back(BoardId); + for (int CHIP = 0; CHIP < NUM_PSEC; CHIP++) + { + meta.push_back((0xDCB0 | CHIP)); + // cout<<"size of info word is "< 10) + cout << "parsing meta step2-1 infoword " << INFOWORD << endl; + if (PsecInfo[CHIP].size() < 13) + { + NonEmptyEvents = NonEmptyEvents - 1; + NonEmptyDataEvents = NonEmptyDataEvents - 1; + cout << "meta data parsing wrong! PsecInfo[CHIP].size() < 13" << endl; + m_data->CStore.Set("LAPPDana", false); + return 1; + } + + try + { + meta.push_back(PsecInfo[CHIP][INFOWORD]); + } + catch (...) + { + NonEmptyEvents = NonEmptyEvents - 1; + NonEmptyDataEvents = NonEmptyDataEvents - 1; + cout << "meta data parsing wrong! meta.push_back(PsecInfo[CHIP][INFOWORD]);" << endl; + m_data->CStore.Set("LAPPDana", false); + return 1; + } + } + for (int TRIGGERWORD = 0; TRIGGERWORD < 6; TRIGGERWORD++) + { + if (LAPPDStoreReadInVerbosity > 10) + cout << "parsing meta step2-2 trigger word" << endl; + + if (PsecTriggerInfo[CHIP].size() < 6) + { + NonEmptyEvents = NonEmptyEvents - 1; + NonEmptyDataEvents = NonEmptyDataEvents - 1; + cout << "meta data parsing wrong! PsecTriggerInfo[CHIP].size() < 6" << endl; + m_data->CStore.Set("LAPPDana", false); + return 1; + } + + try + { + meta.push_back(PsecTriggerInfo[CHIP][TRIGGERWORD]); + } + catch (...) + { + NonEmptyEvents = NonEmptyEvents - 1; + NonEmptyDataEvents = NonEmptyDataEvents - 1; + cout << "meta data parsing wrong! meta.push_back(PsecTriggerInfo[CHIP][TRIGGERWORD]);" << endl; + m_data->CStore.Set("LAPPDana", false); + return 1; + } + } + } + + meta.push_back(CombinedTriggerRateCount); + meta.push_back(0xeeee); + return 0; +} + +int LAPPDLoadStore::getParsedData(std::vector buffer, int ch_start) +{ + // Catch empty buffers + if (buffer.size() == 0) + { + std::cout << "You tried to parse ACDC data without pulling/setting an ACDC buffer" << std::endl; + return -1; + } + + // Helpers + int DistanceFromZero; + int channel_count = 0; + + // Indicator words for the start/end of the metadata + const unsigned short startword = 0xF005; + unsigned short endword = 0xBA11; + unsigned short endoffile = 0x4321; + + // Empty vector with positions of aboves startword + vector start_indices = + { + 2, 1554, 3106, 4658, 6210}; + + // Fill data map + vector::iterator bit; + for (int i : start_indices) + { + // Write the first word after the startword + bit = buffer.begin() + (i + 1); + + // As long as the endword isn't reached copy metadata words into a vector and add to map + vector InfoWord; + while (*bit != endword && *bit != endoffile) + { + InfoWord.push_back((unsigned short)*bit); + if (InfoWord.size() == NUM_SAMP) + { + data.insert(pair>(ch_start + channel_count, InfoWord)); + if (LAPPDStoreReadInVerbosity > 5) + cout << "inserted data to channel " << ch_start + channel_count << endl; + InfoWord.clear(); + channel_count++; + } + ++bit; + } + } + + return 0; +} + +bool LAPPDLoadStore::LoadData() +{ + // TODO: when looping in Stores["ANNIEEvent"], the multiple PSEC data will be saved in std::map LAPPDDatas; + // so we need to loop the map to get all data and waveforms, using the LAPPD_ID, board number, channel number to form a global channel-waveform map + // then loop all waveforms based on channel number + + if (loadFromStoreDirectly) + m_data->Stores["ANNIEEvent"]->GetEntry(eventNo); + if (LAPPDStoreReadInVerbosity > 2) + cout << "Got eventNo " << eventNo << endl; + + // if loaded enough events, stop the loop and return false + if (NonEmptyEvents == stopEntries || NonEmptyEvents > stopEntries || NonEmptyDataEvents == stopEntries || NonEmptyDataEvents > stopEntries) + { + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: NonEmptyEvents is " << NonEmptyEvents << ", NonEmptyDataEvents is " << NonEmptyDataEvents << ", stopEntries is " << stopEntries << ", stop the loop" << endl; + m_data->vars.Set("StopLoop", 1); + return false; + } + + // if (mergedEvent) + // DataStreams["LAPPD"] = true; + + // print the load information: DataStreams["LAPPD"] value, PsecReceiveMode, MultiLAPPDMap + if (LAPPDStoreReadInVerbosity > 0) + { + cout << "LAPPDStoreReadIn: DataStreams[LAPPD] is " << DataStreams["LAPPD"] << ", PsecReceiveMode is " << PsecReceiveMode << ", MultiLAPPDMap is " << MultiLAPPDMap << endl; + } + + if (loadPSEC || loadPPS) + { // if load any kind of data + // if there is no LAPPD data in event store, and not getting data from CStore, return false, don't load + if (!DataStreams["LAPPD"] && PsecReceiveMode == 0 && !MultiLAPPDMap) // if doesn't have datastream, not reveive data from raw data store (PsecReceiveMode), not loading multiple LAPPD map from processed data + { + return false; + } + else if (PsecReceiveMode == 1 && !MultiLAPPDMap) // no LAPPD data in event store, but load from CStore (for merging LAPPD to ANNIEEvent) + { // only get PSEC object from CStore + // if loading from raw data, and the loading was set to pause, return false + bool LAPPDRawLoadingPaused = false; + m_data->CStore.Get("PauseLAPPDDecoding", LAPPDRawLoadingPaused); + if (LAPPDRawLoadingPaused) + { + m_data->CStore.Set("NewLAPPDDataAvailable", false); + return false; + } + + PsecData dat; + bool getData = m_data->CStore.Get("LAPPDData", dat); + if (getData) + { + m_data->CStore.Set("StoreLoadedLAPPDData", dat); + } + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: getting LAPPDData from CStore" << endl; + bool mergingLoad; + // if in merging mode, but no LAPPD data in CStore, return false, don't load + m_data->CStore.Get("LAPPDanaData", mergingLoad); + if (!mergingLoad && mergingModeReadIn) + { + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: mergingMode is true but LAPPDanaData is false, set LAPPDana to false" << endl; + return false; + } + if (getData) + { + vector errorcodes = dat.errorcodes; + if (errorcodes.size() == 1 && errorcodes[0] == 0x00000000) + { + if (LAPPDStoreReadInVerbosity > 1) + printf("No errorcodes found all good: 0x%08x\n", errorcodes[0]); + } + else + { + printf("When Loading PPS: Errorcodes found: %li\n", errorcodes.size()); + for (unsigned int k = 0; k < errorcodes.size(); k++) + { + printf("Errorcode: 0x%08x\n", errorcodes[k]); + } + errorEventsNumber++; + return false; + } + ReadBoards = dat.BoardIndex; + Raw_buffer = dat.RawWaveform; + if(Raw_buffer.size() == 0 || ReadBoards.size() == 0) + { + cout << "LAPPD Load Store, find Raw buffer size == 0 or ReadBoards size == 0" << endl; + return false; + } + LAPPD_ID = dat.LAPPD_ID; + if (LAPPD_ID != SelectedLAPPD && SelectSingleLAPPD) + return false; + m_data->CStore.Set("PsecTimestamp", dat.Timestamp); + if (LAPPDStoreReadInVerbosity > 2) + { + cout << " Got Data " << endl; + dat.Print(); + } + int frameType = static_cast(Raw_buffer.size() / ReadBoards.size()); + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn: got Data from CStore, frame type is " << frameType << endl; + if (loadPSEC) + { + if (frameType == num_vector_data) + { + m_data->CStore.Set("LoadingPPS", false); + return true; + } + } + if (loadPPS) + { + if (frameType == num_vector_pps) + { + m_data->CStore.Set("LoadingPPS", true); + return true; + } + } + return false; + } + else + { + return false; + } + } + else if (DataStreams["LAPPD"] && PsecReceiveMode == 0 && !MultiLAPPDMap) // if load single lappd data at ID 0, require Datastream, not receive from cstore, not in multiLAPPDMap mode + { + PsecData dat; + m_data->Stores["ANNIEEvent"]->Get("LAPPDData", dat); + ReadBoards = dat.BoardIndex; + Raw_buffer = dat.RawWaveform; + LAPPD_ID = dat.LAPPD_ID; + if (LAPPD_ID != SelectedLAPPD && SelectSingleLAPPD) + return false; + m_data->CStore.Set("PsecTimestamp", dat.Timestamp); + + if (Raw_buffer.size() != 0 || ReadBoards.size() != 0) + { + if (LAPPDStoreReadInVerbosity > 0) + { + cout << "Getting data length format" << static_cast(Raw_buffer.size() / ReadBoards.size()) << ", psec timestamp is " << dat.Timestamp << endl; + cout << "ReadBoards size " << ReadBoards.size() << " Raw_buffer size " << Raw_buffer.size() << " LAPPD_ID " << LAPPD_ID << endl; + } + } + else + { + cout << "LAPPDStoreReadIn: loading data with raw buffer size 0 or ReadBoards size 0, skip loading" << endl; + cout << "ReadBoards size " << ReadBoards.size() << " Raw_buffer size " << Raw_buffer.size() << " LAPPD_ID " << LAPPD_ID << endl; + + return false; + } + return true; + } + else if (DataStreams["LAPPD"] && PsecReceiveMode == 0 && MultiLAPPDMap) // if not receive from cstore, and load multi lappd map + { + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDLoadStore: Loading multiple LAPPD data from ANNIEEvent" << "Inside, size of LAPPDDatamap = " << LAPPDDataMap.size() << endl; + + if (LAPPDDataMap.size() == 0) + { + cout << "what happened?" << endl; + return false; + } + + return true; + } + } + return false; // if not any of the above, return false +} + +void LAPPDLoadStore::ParsePPSData() +{ + if (LAPPDStoreReadInVerbosity > 0) + cout << "Loading PPS frame size " << pps.size() << endl; + std::vector pps = Raw_buffer; + std::vector pps_vector; + std::vector pps_count_vector; + + unsigned long pps_timestamp = 0; + unsigned long ppscount = 0; + for (int s = 0; s < ReadBoards.size(); s++) + { + unsigned short pps_63_48 = pps.at(2 + 16 * s); + unsigned short pps_47_32 = pps.at(3 + 16 * s); + unsigned short pps_31_16 = pps.at(4 + 16 * s); + unsigned short pps_15_0 = pps.at(5 + 16 * s); + std::bitset<16> bits_pps_63_48(pps_63_48); + std::bitset<16> bits_pps_47_32(pps_47_32); + std::bitset<16> bits_pps_31_16(pps_31_16); + std::bitset<16> bits_pps_15_0(pps_15_0); + unsigned long pps_63_0 = (static_cast(pps_63_48) << 48) + (static_cast(pps_47_32) << 32) + (static_cast(pps_31_16) << 16) + (static_cast(pps_15_0)); + if (LAPPDStoreReadInVerbosity > 0) + std::cout << "pps combined: " << pps_63_0 << std::endl; + std::bitset<64> bits_pps_63_0(pps_63_0); + // pps_timestamp = pps_63_0 * (CLOCK_to_NSEC); // NOTE: Don't do convert to ns because of the precision, do this in later tools + pps_timestamp = pps_63_0; + // LAPPDPPS->push_back(pps_timestamp); + if (LAPPDStoreReadInVerbosity > 0) + std::cout << "Adding timestamp " << pps_timestamp << " to LAPPDPPS" << std::endl; + pps_vector.push_back(pps_timestamp); + + unsigned short ppscount_31_16 = pps.at(8 + 16 * s); + unsigned short ppscount_15_0 = pps.at(9 + 16 * s); + std::bitset<16> bits_ppscount_31_16(ppscount_31_16); + std::bitset<16> bits_ppscount_15_0(ppscount_15_0); + unsigned long ppscount_31_0 = (static_cast(ppscount_31_16) << 16) + (static_cast(ppscount_15_0)); + if (LAPPDStoreReadInVerbosity > 0) + std::cout << "pps count combined: " << ppscount_31_0 << std::endl; + std::bitset<32> bits_ppscount_31_0(ppscount_31_0); + ppscount = ppscount_31_0; + pps_count_vector.push_back(ppscount); + + if (LAPPDStoreReadInVerbosity > 8) + { + // Print the bitsets + cout << "******************************" << endl; + std::cout << "printing ACDC " << s << ": " << endl; + std::cout << "bits_pps_63_48: " << bits_pps_63_48 << std::endl; + std::cout << "bits_pps_47_32: " << bits_pps_47_32 << std::endl; + std::cout << "bits_pps_31_16: " << bits_pps_31_16 << std::endl; + std::cout << "bits_pps_15_0: " << bits_pps_15_0 << std::endl; + // Print the unsigned shorts + std::cout << "pps_63_48: " << pps_63_48 << std::endl; + std::cout << "pps_47_32: " << pps_47_32 << std::endl; + std::cout << "pps_31_16: " << pps_31_16 << std::endl; + std::cout << "pps_15_0: " << pps_15_0 << std::endl; + std::cout << "pps_63_0: " << pps_63_0 << std::endl; + std::cout << "pps_63_0 after conversion in double: " << pps_timestamp << endl; + + for (int x = 0; x < 16; x++) + { + std::bitset<16> bit_pps_here(pps.at(x + 16 * s)); + cout << "unsigned short at " << x << " : " << pps.at(x + 16 * s) << ", bit at " << x << " is: " << bit_pps_here << endl; + ; + } + } + } + + // double ppsDiff = static_cast(pps_vector.at(0)) - static_cast(pps_vector.at(1)); + unsigned long ppsDiff = pps_vector.at(0) - pps_vector.at(1); + m_data->CStore.Set("LAPPDPPScount0", pps_count_vector.at(0)); + m_data->CStore.Set("LAPPDPPScount1", pps_count_vector.at(1)); + m_data->CStore.Set("LAPPDPPScount", pps_count_vector); + m_data->CStore.Set("LAPPDPPSDiff0to1", ppsDiff); + m_data->CStore.Set("LAPPDPPSVector", pps_vector); + + m_data->CStore.Set("LAPPDPPStimestamp0", pps_vector.at(0)); + m_data->CStore.Set("LAPPDPPStimestamp1", pps_vector.at(1)); + m_data->CStore.Set("LAPPDPPShere", true); + m_data->CStore.Set("LAPPD_ID", LAPPD_ID); + + PPSnumber++; +} + +bool LAPPDLoadStore::ParsePSECData() +{ + if (LAPPDStoreReadInVerbosity > 0) + std::cout << "PSEC Data Frame was read! Starting the parsing!" << std::endl; + + // while loading single PsecData Object, parse the data by LAPPDID and number of boards on each LAPPD and channel on each board + // Create a vector of paraphrased board indices + // the board indices goes with LAPPD ID. For example, LAPPD ID = 2, we will have board = 4,5 + // this need to be converted to 0,1 + int nbi = ReadBoards.size(); + if (LAPPDStoreReadInVerbosity > 0 && nbi != 2) + cout << "Number of board is " << nbi << endl; + if (nbi == 0) + { + cout << "LAPPDStoreReadIn: error here! number of board is 0" << endl; + errorEventsNumber++; + return false; + } + if (nbi % 2 != 0) + { + errorEventsNumber++; + cout << "LAPPDStoreReadIn: uneven number of boards in this event" << endl; + if (nbi == 1) + { + ParaBoards.push_back(ReadBoards[0]); + } + else + { + return false; + } + } + else + { + for (int cbi = 0; cbi < nbi; cbi++) + { + ParaBoards.push_back(cbi); + if (LAPPDStoreReadInVerbosity > 2) + cout << "Board " << cbi << " is added to the list of boards to be parsed!" << endl; + } + } + // loop all boards, 0, 1 + if (LAPPDStoreReadInVerbosity > 2) + { + cout << "ParaBoards size is " << ParaBoards.size() << endl; + for (int i = 0; i < ParaBoards.size(); i++) + { + cout << "ParaBoards " << i << " is " << ParaBoards[i] << endl; + } + } + for (int i = 0; i < ParaBoards.size(); i++) + { + int bi = ParaBoards.at(i) % 2; + Parse_buffer.clear(); + if (LAPPDStoreReadInVerbosity > 2) + std::cout << "Parsing board with ReadBoards ID" << ReadBoards[bi] << std::endl; + // Go over all ACDC board data frames by seperating them + int frametype = static_cast(Raw_buffer.size() / ReadBoards.size()); + for (int c = bi * frametype; c < (bi + 1) * frametype; c++) + { + Parse_buffer.push_back(Raw_buffer[c]); + } + if (LAPPDStoreReadInVerbosity > 2) + std::cout << "Data for " << i << "_th board with board number = " << ReadBoards[bi] << " was grabbed!" << std::endl; + + // Grab the parsed data and give it to a global variable 'data' + // insert the data start with channel number 30*ReadBoards[bi] + // for instance, when bi=0 , LAPPD ID = 2, ReadBoards[bi] = 4, insert to channel number start with 120, to 150 + int channelShift = bi * NUM_CH + LAPPD_ID * NUM_CH * 2; + retval = getParsedData(Parse_buffer, channelShift); //(because there are only 2 boards, so it's 0*30 or 1*30). Inserting the channel number start from this then ++ to 30 + if (retval == 0) + { + if (LAPPDStoreReadInVerbosity > 2) + std::cout << "Data for board with number = " << ReadBoards[bi] << " was parsed with channel shift " << channelShift << endl; + // Grab the parsed metadata and give it to a global variable 'meta' + retval = getParsedMeta(Parse_buffer, bi + LAPPD_ID * 2); + if (retval != 0) + { + std::cout << "Meta parsing went wrong! " << retval << endl; + return false; + } + else + { + if (LAPPDStoreReadInVerbosity > 2) + std::cout << "Meta for board " << ReadBoards[bi] << " was parsed!" << std::endl; + } + } + else + { + std::cout << "Parsing went wrong! " << retval << endl; + return false; + } + } + if (LAPPDStoreReadInVerbosity > 2) + cout << "Parsed all boards for this event finished" << endl; + return true; +} + +bool LAPPDLoadStore::DoPedestalSubtract() +{ + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDLoadStore::DoPedestalSubtract()" << endl; + Waveform tmpWave; + vector> VecTmpWave; + int pedval, val; + if (LAPPDStoreReadInVerbosity > 3) + { + // print the size of data and all keys, and the size of PedestalValues and all keys + cout << "Size of data is " << data.size() << endl; + for (std::map>::iterator it = data.begin(); it != data.end(); ++it) // looping over the data map by channel number, from 0 to 60 + { + cout << it->first << ", "; + } + cout << endl; + cout << "Size of PedestalValues is " << PedestalValues->size() << endl; + for (auto it = PedestalValues->begin(); it != PedestalValues->end(); ++it) // looping over the data map by channel number, from 0 to 60 + { + cout << it->first << ", "; + } + cout << endl; + } + // Loop over data stream + for (std::map>::iterator it = data.begin(); it != data.end(); ++it) // looping over the data map by channel number, from 0 to 60 + { + int wrongPedChannel = 0; + if (LAPPDStoreReadInVerbosity > 5) + cout << "Do Pedestal sub at Channel " << it->first; + + for (int kvec = 0; kvec < it->second.size(); kvec++) + { // loop all data point in this channel + if (DoPedSubtract == 1) + { + auto iter = PedestalValues->find((it->first)); + if (kvec == 0 && LAPPDStoreReadInVerbosity > 5) + cout << std::fixed << ", found PedestalValues for channel " << it->first << " with value = " << iter->second.at(0); + if (iter != PedestalValues->end() && iter->second.size() > kvec) + { + pedval = iter->second.at(kvec); + } + else + { + pedval = 0; + wrongPedChannel = (it->first); + } + } + else + { + pedval = 0; + } + val = it->second.at(kvec); + tmpWave.PushSample(0.3 * (double)(val - pedval)); + if (LAPPDStoreReadInVerbosity > 5 && kvec < 10) + cout << ", " << val << "-" << pedval << "=" << 0.3 * (double)(val - pedval); + } + if (wrongPedChannel != 0) + cout << "Pedestal value not found for channel " << wrongPedChannel << "with it->first channel" << it->first << ", LAPPD channel shift " << LAPPD_ID * 60 << endl; + + VecTmpWave.push_back(tmpWave); + + unsigned long pushChannelNo = (unsigned long)it->first; + LAPPDWaveforms.insert(pair>>(pushChannelNo, VecTmpWave)); + // cout<<", Pushed to LAPPDWaveforms with channel number "< bits_beamgate_63_48(beamgate_63_48); + std::bitset<16> bits_beamgate_47_32(beamgate_47_32); + std::bitset<16> bits_beamgate_31_16(beamgate_31_16); + std::bitset<16> bits_beamgate_15_0(beamgate_15_0); + unsigned long beamgate_63_0 = (static_cast(beamgate_63_48) << 48) + (static_cast(beamgate_47_32) << 32) + (static_cast(beamgate_31_16) << 16) + (static_cast(beamgate_15_0)); + std::bitset<64> bits_beamgate_63_0(beamgate_63_0); + unsigned long beamgate_timestamp = beamgate_63_0 * (CLOCK_to_NSEC); + m_data->CStore.Set("LAPPDbeamgate", beamgate_timestamp); + m_data->CStore.Set("LAPPDBeamgate_Raw", beamgate_63_0); + + unsigned long BGTruncation = beamgate_63_0 % 8; + unsigned long BGTruncated = beamgate_63_0 - BGTruncation; + unsigned long BGInt = BGTruncated / 8 * 25; + unsigned long BGIntTruncation = BGTruncation * 3; + // save these two to CStore + double BGFloat = BGTruncation * 0.125; + unsigned long BGIntCombined = BGInt + BGIntTruncation; + m_data->CStore.Set("LAPPDBGIntCombined", BGIntCombined); + m_data->CStore.Set("LAPPDBGFloat", BGFloat); + + unsigned short timestamp_63_48 = meta.at(70); + unsigned short timestamp_47_32 = meta.at(50); + unsigned short timestamp_31_16 = meta.at(30); + unsigned short timestamp_15_0 = meta.at(10); + std::bitset<16> bits_timestamp_63_48(timestamp_63_48); + std::bitset<16> bits_timestamp_47_32(timestamp_47_32); + std::bitset<16> bits_timestamp_31_16(timestamp_31_16); + std::bitset<16> bits_timestamp_15_0(timestamp_15_0); + unsigned long timestamp_63_0 = (static_cast(timestamp_63_48) << 48) + (static_cast(timestamp_47_32) << 32) + (static_cast(timestamp_31_16) << 16) + (static_cast(timestamp_15_0)); + unsigned long lappd_timestamp = timestamp_63_0 * (CLOCK_to_NSEC); + m_data->CStore.Set("LAPPDtimestamp", lappd_timestamp); + m_data->CStore.Set("LAPPDTimestamp_Raw", timestamp_63_0); + + unsigned long TSTruncation = timestamp_63_0 % 8; + unsigned long TSTruncated = timestamp_63_0 - TSTruncation; + unsigned long TSInt = TSTruncated / 8 * 25; + unsigned long TSIntTruncation = TSTruncation * 3; + // save these two to CStore + double TSFloat = TSTruncation * 0.125; + unsigned long TSIntCombined = TSInt + TSIntTruncation; + m_data->CStore.Set("LAPPDTSIntCombined", TSIntCombined); + m_data->CStore.Set("LAPPDTSFloat", TSFloat); + + m_data->Stores["ANNIEEvent"]->Set("LAPPDbeamgate", beamgate_timestamp); // in ns + m_data->Stores["ANNIEEvent"]->Set("LAPPDtimestamp", lappd_timestamp); // in ns + m_data->Stores["ANNIEEvent"]->Set("LAPPDBeamgate_Raw", beamgate_63_0); + m_data->Stores["ANNIEEvent"]->Set("LAPPDTimestamp_Raw", timestamp_63_0); + + if (LAPPDStoreReadInVerbosity > 11) + debugStoreReadIn << eventNo << " LAPPDStoreReadIn, Saving timestamps, beamgate_timestamp: " << beamgate_63_0 << ", lappd_timestamp: " << timestamp_63_0 << endl; + + if (loadOffsets && runInfoLoaded) + { + // run number + sub run number + partfile number + LAPPD_ID to make a string key + // TODO: need to add a reset number here after got everything work + // search it in the maps, then load + SaveOffsets(); + } + m_data->CStore.Set("LAPPD_new_event", true); +} + +void LAPPDLoadStore::SaveOffsets() +{ + + std::string key = std::to_string(runNumber) + "_" + std::to_string(subRunNumber) + "_" + std::to_string(partFileNumber) + "_" + std::to_string(LAPPD_ID); + + int LAPPDBGCorrection = 0; + int LAPPDTSCorrection = 0; + int LAPPDOffset_minus_ps = 0; + uint64_t LAPPDOffset = 0; + + uint64_t BG_PPSBefore = 0; + uint64_t BG_PPSAfter = 0; + uint64_t BG_PPSDiff = 0; + uint64_t TS_PPSBefore = 0; + uint64_t TS_PPSAfter = 0; + uint64_t TS_PPSDiff = 0; + int BG_PPSMissing = 0; + int TS_PPSMissing = 0; + + // Check if the key exists and the index is within range for BGCorrections + if (BGCorrections.find(key) != BGCorrections.end() && eventNumberInPF < BGCorrections[key].size()) + { + LAPPDBGCorrection = BGCorrections[key][eventNumberInPF]; + } + else + { + if (BGCorrections.find(key) == BGCorrections.end()) + { + std::cerr << "Error: Key not found in BGCorrections: " << key << std::endl; + } + else + { + std::cerr << "Error: eventNumberInPF out of range for BGCorrections with key: " << key << std::endl; + } + } + + // Repeat the checks for TSCorrections, Offsets_minus_ps, and Offsets + if (TSCorrections.find(key) != TSCorrections.end() && eventNumberInPF < TSCorrections[key].size()) + { + LAPPDTSCorrection = TSCorrections[key][eventNumberInPF]; + } + else + { + if (TSCorrections.find(key) == TSCorrections.end()) + { + std::cerr << "Error: Key not found in TSCorrections: " << key << std::endl; + } + else + { + std::cerr << "Error: eventNumberInPF out of range for TSCorrections with key: " << key << std::endl; + } + } + + if (Offsets_minus_ps.find(key) != Offsets_minus_ps.end() && eventNumberInPF < Offsets_minus_ps[key].size()) + { + LAPPDOffset_minus_ps = Offsets_minus_ps[key][eventNumberInPF]; + } + else + { + if (Offsets_minus_ps.find(key) == Offsets_minus_ps.end()) + { + std::cerr << "Error: Key not found in Offsets_minus_ps: " << key << std::endl; + } + else + { + std::cerr << "Error: eventNumberInPF out of range for Offsets_minus_ps with key: " << key << std::endl; + } + } + + if (Offsets.find(key) != Offsets.end() && eventNumberInPF < Offsets[key].size()) + { + LAPPDOffset = Offsets[key][eventNumberInPF]; + } + else + { + if (Offsets.find(key) == Offsets.end()) + { + std::cerr << "Error: Key not found in Offsets: " << key << std::endl; + } + else + { + std::cerr << "Error: eventNumberInPF out of range for Offsets with key: " << key << std::endl; + } + } + + if (BG_PPSBefore_loaded.find(key) != BG_PPSBefore_loaded.end() && eventNumberInPF < BG_PPSBefore_loaded[key].size()) + { + BG_PPSBefore = BG_PPSBefore_loaded[key][eventNumberInPF]; + } + else + { + if (BG_PPSBefore_loaded.find(key) == BG_PPSBefore_loaded.end()) + std::cerr << "Error: Key not found in BG_PPSBefore_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for BG_PPSBefore_loaded with key: " << key << std::endl; + } + + if (BG_PPSAfter_loaded.find(key) != BG_PPSAfter_loaded.end() && eventNumberInPF < BG_PPSAfter_loaded[key].size()) + { + BG_PPSAfter = BG_PPSAfter_loaded[key][eventNumberInPF]; + } + else + { + if (BG_PPSAfter_loaded.find(key) == BG_PPSAfter_loaded.end()) + std::cerr << "Error: Key not found in BG_PPSAfter_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for BG_PPSAfter_loaded with key: " << key << std::endl; + } + + if (BG_PPSDiff_loaded.find(key) != BG_PPSDiff_loaded.end() && eventNumberInPF < BG_PPSDiff_loaded[key].size()) + { + BG_PPSDiff = BG_PPSDiff_loaded[key][eventNumberInPF]; + } + else + { + if (BG_PPSDiff_loaded.find(key) == BG_PPSDiff_loaded.end()) + std::cerr << "Error: Key not found in BG_PPSDiff_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for BG_PPSDiff_loaded with key: " << key << std::endl; + } + + if (BG_PPSMissing_loaded.find(key) != BG_PPSMissing_loaded.end() && eventNumberInPF < BG_PPSMissing_loaded[key].size()) + { + BG_PPSMissing = BG_PPSMissing_loaded[key][eventNumberInPF]; + } + else + { + if (BG_PPSMissing_loaded.find(key) == BG_PPSMissing_loaded.end()) + std::cerr << "Error: Key not found in BG_PPSMissing_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for BG_PPSMissing_loaded with key: " << key << std::endl; + } + + if (TS_PPSBefore_loaded.find(key) != TS_PPSBefore_loaded.end() && eventNumberInPF < TS_PPSBefore_loaded[key].size()) + { + TS_PPSBefore = TS_PPSBefore_loaded[key][eventNumberInPF]; + } + else + { + if (TS_PPSBefore_loaded.find(key) == TS_PPSBefore_loaded.end()) + std::cerr << "Error: Key not found in TS_PPSBefore_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for TS_PPSBefore_loaded with key: " << key << std::endl; + } + + if (TS_PPSAfter_loaded.find(key) != TS_PPSAfter_loaded.end() && eventNumberInPF < TS_PPSAfter_loaded[key].size()) + { + TS_PPSAfter = TS_PPSAfter_loaded[key][eventNumberInPF]; + } + else + { + if (TS_PPSAfter_loaded.find(key) == TS_PPSAfter_loaded.end()) + std::cerr << "Error: Key not found in TS_PPSAfter_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for TS_PPSAfter_loaded with key: " << key << std::endl; + } + + if (TS_PPSDiff_loaded.find(key) != TS_PPSDiff_loaded.end() && eventNumberInPF < TS_PPSDiff_loaded[key].size()) + { + TS_PPSDiff = TS_PPSDiff_loaded[key][eventNumberInPF]; + } + else + { + if (TS_PPSDiff_loaded.find(key) == TS_PPSDiff_loaded.end()) + std::cerr << "Error: Key not found in TS_PPSDiff_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for TS_PPSDiff_loaded with key: " << key << std::endl; + } + + if (TS_PPSMissing_loaded.find(key) != TS_PPSMissing_loaded.end() && eventNumberInPF < TS_PPSMissing_loaded[key].size()) + { + TS_PPSMissing = TS_PPSMissing_loaded[key][eventNumberInPF]; + } + else + { + if (TS_PPSMissing_loaded.find(key) == TS_PPSMissing_loaded.end()) + std::cerr << "Error: Key not found in TS_PPSMissing_loaded: " << key << std::endl; + else + std::cerr << "Error: eventNumberInPF out of range for TS_PPSMissing_loaded with key: " << key << std::endl; + } + + // start to fill data + m_data->CStore.Set("LAPPDBGCorrection", LAPPDBGCorrection); + m_data->CStore.Set("LAPPDTSCorrection", LAPPDTSCorrection); + m_data->CStore.Set("LAPPDOffset", LAPPDOffset); + m_data->CStore.Set("LAPPDOffset_minus_ps", LAPPDOffset_minus_ps); + + m_data->CStore.Set("BG_PPSBefore", BG_PPSBefore); + m_data->CStore.Set("BG_PPSAfter", BG_PPSAfter); + m_data->CStore.Set("BG_PPSDiff", BG_PPSDiff); + m_data->CStore.Set("BG_PPSMissing", BG_PPSMissing); + m_data->CStore.Set("TS_PPSBefore", TS_PPSBefore); + m_data->CStore.Set("TS_PPSAfter", TS_PPSAfter); + m_data->CStore.Set("TS_PPSDiff", TS_PPSDiff); + m_data->CStore.Set("TS_PPSMissing", TS_PPSMissing); + + if (TS_PPSMissing != BG_PPSMissing) + { + cout << "LAPPDLoadStore: BG_PPSMissing != TS_PPSMissing, BG_PPSMissing: " << BG_PPSMissing << ", TS_PPSMissing: " << TS_PPSMissing << endl; + } + + // cout << "LAPPDStoreReadIn, Saving offsets and corrections, key: " << key << ", LAPPDOffset: " << LAPPDOffset << ", LAPPDOffset_minus_ps: " << LAPPDOffset_minus_ps << ", LAPPDBGCorrection: " << LAPPDBGCorrection << ", LAPPDTSCorrection: " << LAPPDTSCorrection << ", BG_PPSBefore: " << BG_PPSBefore << ", BG_PPSAfter: " << BG_PPSAfter << ", BG_PPSDiff: " << BG_PPSDiff << ", BG_PPSMissing: " << BG_PPSMissing << ", TS_PPSBefore: " << TS_PPSBefore << ", TS_PPSAfter: " << TS_PPSAfter << ", TS_PPSDiff: " << TS_PPSDiff << ", TS_PPSMissing: " << TS_PPSMissing << endl; + + if (LAPPDStoreReadInVerbosity > 11) + debugStoreReadIn << eventNo << "+LAPPDStoreReadIn, Saving offsets and corrections, key: " << key << ", LAPPDOffset: " << LAPPDOffset << ", LAPPDOffset_minus_ps: " << LAPPDOffset_minus_ps << ", LAPPDBGCorrection: " << LAPPDBGCorrection << ", LAPPDTSCorrection: " << LAPPDTSCorrection << endl; +} + +void LAPPDLoadStore::LoadOffsetsAndCorrections() +{ + // load here from the root tree to: + /* + std::map> Offsets; //Loaded offset, use string = run number + sub run number + partfile number as key. + std::map> Offsets_minus_ps; //offset in ps, use offset - this/1e3 as the real offset + std::map> BGCorrections; //Loaded BGcorrections, same key as Offsets, but offset saved on event by event basis in that part file, in unit of ticks + std::map> TSCorrections; //TS corrections, in unit of ticks + */ + + TFile *file = new TFile("offsetFitResult.root", "READ"); + TTree *tree; + file->GetObject("Events", tree); + + if (!tree) + { + std::cerr << "LAPPDStoreReadIn Loading offsets, Tree not found!" << std::endl; + return; + } + + int runNumber, subRunNumber, partFileNumber, LAPPD_ID; + ULong64_t final_offset_ns_0, final_offset_ps_negative_0, EventIndex; + ULong64_t BGCorrection_tick, TSCorrection_tick; + + ULong64_t BG_PPSBefore_tick; + ULong64_t BG_PPSAfter_tick; + ULong64_t BG_PPSDiff_tick; + ULong64_t BG_PPSMissing_tick; + ULong64_t TS_PPSBefore_tick; + ULong64_t TS_PPSAfter_tick; + ULong64_t TS_PPSDiff_tick; + ULong64_t TS_PPSMissing_tick; + ULong64_t TS_driftCorrection_ns; + ULong64_t BG_driftCorrection_ns; + + tree->SetBranchAddress("runNumber", &runNumber); + tree->SetBranchAddress("subRunNumber", &subRunNumber); + tree->SetBranchAddress("partFileNumber", &partFileNumber); + tree->SetBranchAddress("LAPPD_ID", &LAPPD_ID); + tree->SetBranchAddress("EventIndex", &EventIndex); + tree->SetBranchAddress("final_offset_ns_0", &final_offset_ns_0); + tree->SetBranchAddress("final_offset_ps_negative_0", &final_offset_ps_negative_0); + tree->SetBranchAddress("BGCorrection_tick", &BGCorrection_tick); + tree->SetBranchAddress("TSCorrection_tick", &TSCorrection_tick); + tree->SetBranchAddress("BG_PPSBefore_tick", &BG_PPSBefore_tick); + tree->SetBranchAddress("BG_PPSAfter_tick", &BG_PPSAfter_tick); + tree->SetBranchAddress("BG_PPSDiff_tick", &BG_PPSDiff_tick); + tree->SetBranchAddress("BG_PPSMissing_tick", &BG_PPSMissing_tick); + tree->SetBranchAddress("TS_PPSBefore_tick", &TS_PPSBefore_tick); + tree->SetBranchAddress("TS_PPSAfter_tick", &TS_PPSAfter_tick); + tree->SetBranchAddress("TS_PPSDiff_tick", &TS_PPSDiff_tick); + tree->SetBranchAddress("TS_PPSMissing_tick", &TS_PPSMissing_tick); + tree->SetBranchAddress("TS_driftCorrection_ns", &TS_driftCorrection_ns); + tree->SetBranchAddress("BG_driftCorrection_ns", &BG_driftCorrection_ns); + + + Long64_t nentries = tree->GetEntries(); + cout << "LAPPDStoreReadIn Loading offsets and corrections, total entries: " << nentries << endl; + for (Long64_t i = 0; i < nentries; ++i) + { + tree->GetEntry(i); + + std::string key = std::to_string(runNumber) + "_" + std::to_string(subRunNumber) + "_" + std::to_string(partFileNumber) + "_" + std::to_string(LAPPD_ID); + + // Prepare the vector sizes for each map + if (Offsets[key].size() <= EventIndex) + { + Offsets[key].resize(EventIndex + 1); + Offsets_minus_ps[key].resize(EventIndex + 1); + BGCorrections[key].resize(EventIndex + 1); + TSCorrections[key].resize(EventIndex + 1); + BG_PPSBefore_loaded[key].resize(EventIndex + 1); + BG_PPSAfter_loaded[key].resize(EventIndex + 1); + BG_PPSDiff_loaded[key].resize(EventIndex + 1); + BG_PPSMissing_loaded[key].resize(EventIndex + 1); + TS_PPSBefore_loaded[key].resize(EventIndex + 1); + TS_PPSAfter_loaded[key].resize(EventIndex + 1); + TS_PPSDiff_loaded[key].resize(EventIndex + 1); + TS_PPSMissing_loaded[key].resize(EventIndex + 1); + } + + // Now using EventIndex to place each event correctly + Offsets[key][EventIndex] = final_offset_ns_0 + TS_driftCorrection_ns; + Offsets_minus_ps[key][EventIndex] = static_cast(final_offset_ps_negative_0); + BGCorrections[key][EventIndex] = static_cast(BGCorrection_tick) - 1000; + TSCorrections[key][EventIndex] = static_cast(TSCorrection_tick) - 1000; + + BG_PPSBefore_loaded[key][EventIndex] = BG_PPSBefore_tick; + BG_PPSAfter_loaded[key][EventIndex] = BG_PPSAfter_tick; + BG_PPSDiff_loaded[key][EventIndex] = BG_PPSDiff_tick; + BG_PPSMissing_loaded[key][EventIndex] = static_cast(BG_PPSMissing_tick) - 1000; + TS_PPSBefore_loaded[key][EventIndex] = TS_PPSBefore_tick; + TS_PPSAfter_loaded[key][EventIndex] = TS_PPSAfter_tick; + TS_PPSDiff_loaded[key][EventIndex] = TS_PPSDiff_tick; + TS_PPSMissing_loaded[key][EventIndex] = static_cast(TS_PPSMissing_tick) - 1000; + + if (nentries > 10 && i % (static_cast(nentries / 10)) == 0) + { + cout << "LAPPDStoreReadIn Loading offsets and corrections, " << i << " entries loaded" << endl; + cout << "Printing key: " << key << ", EventIndex: " << EventIndex << ", final_offset_ns_0: " << final_offset_ns_0 << ", final_offset_ps_negative_0: " << final_offset_ps_negative_0 << ", BGCorrection_tick: " << BGCorrection_tick << ", TSCorrection_tick: " << TSCorrection_tick << ", BG_PPSMissing_tick: " << BG_PPSMissing_tick << ", TS_PPSMissing_tick: " << TS_PPSMissing_tick << ", TS_driftCorrection_ns: " << TS_driftCorrection_ns << ", BG_driftCorrection_ns: " << BG_driftCorrection_ns << endl; + } + } + + file->Close(); + delete file; + + // The data structures are now correctly filled and can be used as needed. +} + +void LAPPDLoadStore::LoadRunInfo() +{ + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn, Loading run info" << endl; + int PFNumberBeforeGet = partFileNumber; + m_data->CStore.Get("rawFileNumber", partFileNumber); + m_data->CStore.Get("runNumber", runNumber); + m_data->CStore.Get("subrunNumber", subRunNumber); + + if (partFileNumber != PFNumberBeforeGet) + { + eventNumberInPF = 0; + } + else + { + eventNumberInPF++; + } + if (LAPPDStoreReadInVerbosity > 0) + cout << "LAPPDStoreReadIn, Loaded run info, runNumber: " << runNumber << ", subRunNumber: " << subRunNumber << ", partFileNumber: " << partFileNumber << ", eventNumberInPF: " << eventNumberInPF << endl; +} diff --git a/UserTools/LAPPDLoadStore/LAPPDLoadStore.h b/UserTools/LAPPDLoadStore/LAPPDLoadStore.h new file mode 100644 index 000000000..e9a6fd7d4 --- /dev/null +++ b/UserTools/LAPPDLoadStore/LAPPDLoadStore.h @@ -0,0 +1,179 @@ +#ifndef LAPPDLoadStore_H +#define LAPPDLoadStore_H + +#include +#include +#include +#include +#include +#include "Tool.h" +#include "PsecData.h" +#include "TFile.h" +#include "TTree.h" + +#define NUM_CH 30 +#define NUM_PSEC 5 +#define NUM_SAMP 256 + +using namespace std; +/** + * \class LAPPDLoadStore + * + * Load LAPPD PSEC data and PPS data from BoostStore. + * + * $Author: Yue Feng $ + * $Date: 2024/04 $ + * Contact: yuef@iaistate.edu + * + */ +class LAPPDLoadStore : public Tool +{ + +public: + LAPPDLoadStore(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + bool ReadPedestals(int boardNo); ///< Read in the Pedestal Files + bool MakePedestals(); ///< Make a Pedestal File + + int getParsedData(vector buffer, int ch_start); + int getParsedMeta(vector buffer, int BoardId); + + void CleanDataObjects(); + bool LoadData(); + bool ParsePSECData(); + void ParsePPSData(); + bool DoPedestalSubtract(); + void SaveTimeStamps(); // save some timestamps relate to this event + void LoadOffsetsAndCorrections(); + void LoadRunInfo(); + void SaveOffsets(); + +private: + // This tool, control variables (only used in this tool, every thing that is not an data object) + // Variables that you get from the config file + int ReadStore; // read data from a StoreFile (tool chain start with this tool rather than LoadANNIEEvent) + int Nboards; // total number of boards to load pedestal file, LAPPD number * 2 + string PedFileName; // store format pedestal file name + string PedFileNameTXT; // txt format pedestal file name + int DoPedSubtract; // 1: do pedestal subtraction, 0: don't do pedestal subtraction + int LAPPDStoreReadInVerbosity; + int num_vector_data; + int num_vector_pps; + bool SelectSingleLAPPD; + int SelectedLAPPD; + bool mergingModeReadIn; + bool ReadStorePdeFile; + bool MultiLAPPDMap; // loading map of multiple LAPPDs from ANNIEEvent + bool loadOffsets; + bool LoadBuiltPPSInfo; + bool loadFromStoreDirectly; + // Variables that you need in the tool + int retval; // track the data parsing and meta parsing status + int eventNo; + double CLOCK_to_NSEC; + int errorEventsNumber; + bool runInfoLoaded; + + // LAPPD tool chain, control variables (Will be shared in multiple LAPPD tools to show the state of the tool chain in each loop) + // Variables that you get from the config file + int stopEntries; // stop tool chain after loading this number of PSEC data events + int NonEmptyEvents; // count how many non empty data events were loaded + int NonEmptyDataEvents; // count how many non empty data events were loaded + bool PsecReceiveMode; // Get PSEC data from CStore or Stores["ANNIEEvent"]. 1: CStore, 0: Stores["ANNIEEvent"] + string OutputWavLabel; + string InputWavLabel; + int NChannels; + int Nsamples; + int TrigChannel; + double SampleSize; + int LAPPDchannelOffset; + int PPSnumber; + bool loadPPS; + bool loadPSEC; + bool mergedEvent; // in some merged Event, the LAPPD events was merged to ANNIEEvent, but the data stream was not changed to be true. use this = 1 to read it + bool LAPPDana; // run other LAPPD tools + // Variables that you need in the tool + bool isCFD; + bool isBLsub; + bool isFiltered; + int EventType; // 0: PSEC, 1: PPS + // LAPPD tool chain, data variables. (Will be used in multiple LAPPD tools) + // everything you get or set to Store, which means it may be used in other tools or it's from other tools + int LAPPD_ID; + vector LAPPD_IDs; + vector LAPPDLoadedTimeStamps; + vector LAPPDLoadedTimeStampsRaw; + vector LAPPDLoadedBeamgatesRaw; + vector LAPPDLoadedOffsets; + vector LAPPDLoadedTSCorrections; + vector LAPPDLoadedBGCorrections; + vector LAPPDLoadedOSInMinusPS; + vector LAPPDLoadedBG_PPSBefore; + vector LAPPDLoadedBG_PPSAfter; + vector LAPPDLoadedBG_PPSDiff; + vector LAPPDLoadedBG_PPSMissing; + vector LAPPDLoadedTS_PPSBefore; + vector LAPPDLoadedTS_PPSAfter; + vector LAPPDLoadedTS_PPSDiff; + vector LAPPDLoadedTS_PPSMissing; + + vector ParaBoards; // save the board index for this PsecData + std::map>> LAPPDWaveforms; + + // This tool, data variables (only used in this tool, every thing that is an data object) + ifstream PedFile; // stream for reading in the Pedestal Files + string NewFileName; // name of the new Data File + std::map> *PedestalValues; + std::vector Raw_buffer; + std::vector Parse_buffer; + std::vector ReadBoards; + std::map> data; + vector meta; + vector pps; + vector LAPPD_ID_Channel; // for each LAPPD, how many channels on it's each board + vector LAPPD_ID_BoardNumber; // for each LAPPD, how many boards with it + std::map LAPPDDataMap; + std::map LAPPDBeamgate_ns; + std::map LAPPDTimeStamps_ns; // data and key are the same + std::map LAPPDTimeStampsRaw; + std::map LAPPDBeamgatesRaw; + std::map LAPPDOffsets; + std::map LAPPDTSCorrection; + std::map LAPPDBGCorrection; + std::map LAPPDOSInMinusPS; + std::map DataStreams; + // save PPS info for the second order correction + std::map LAPPDBG_PPSBefore; + std::map LAPPDBG_PPSAfter; + std::map LAPPDBG_PPSDiff; + std::map LAPPDBG_PPSMissing; + std::map LAPPDTS_PPSBefore; + std::map LAPPDTS_PPSAfter; + std::map LAPPDTS_PPSDiff; + std::map LAPPDTS_PPSMissing; + + // data variables don't need to be cleared in each loop + // these are loaded offset for event building + std::map> Offsets; // Loaded offset, use string = run number + sub run number + partfile number as key. + std::map> Offsets_minus_ps; // offset in ps, use offset - this/1e3 as the real offset + std::map> BGCorrections; // Loaded BGcorrections, same key as Offsets, but offset saved on event by event basis in that part file, in unit of ticks + std::map> TSCorrections; // TS corrections, in unit of ticks + std::map> BG_PPSBefore_loaded; // BG PPS before, in unit of ticks + std::map> BG_PPSAfter_loaded; // BG PPS after, in unit of ticks + std::map> BG_PPSDiff_loaded; // BG PPS Diff + std::map> BG_PPSMissing_loaded; // BG PPS Missing + std::map> TS_PPSBefore_loaded; // TS PPS before, in unit of ticks + std::map> TS_PPSAfter_loaded; // TS PPS after, in unit of ticks + std::map> TS_PPSDiff_loaded; // TS PPS Diff + std::map> TS_PPSMissing_loaded; // TS PPS Missing + + int runNumber; + int subRunNumber; + int partFileNumber; + int eventNumberInPF; + std::ofstream debugStoreReadIn; +}; + +#endif diff --git a/UserTools/LAPPDLoadStore/README.md b/UserTools/LAPPDLoadStore/README.md new file mode 100644 index 000000000..67581ceaf --- /dev/null +++ b/UserTools/LAPPDLoadStore/README.md @@ -0,0 +1,24 @@ +# LAPPDLoadStore + +LAPPDLoadStore will load LAPPD PsecData objects from boost store. + +## Data + +**PedFileNameTXT** +Load the Pedestal file in TXT format, based on LAPPD ID and board index. +The board indexes are reorganized based on LAPPD ID, i.e. LAPPD ID 0 will use board 0, 1, ID 2 will use board 4, 5. +Therefore, the input name should be like ~/Pedestal_0.txt, ~/Pedestal_1.txt, and PedFileNameTXT should be set as ~/Pedestal_ + + + +## Configuration + +**MultiLAPPDMap** True if load the LAPPD map for multi LAPPD data +**loadPSEC** true if load PsedData +**loadPPS** true if load PPS events +**loadOffsets** true if load the offset fitting result from the fitting scripts + +**PsecReceiveMode** true if receive data from raw data store + +**DoPedSubtract** true if do pedestal subtraction + diff --git a/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.cpp b/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.cpp new file mode 100644 index 000000000..3091f508f --- /dev/null +++ b/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.cpp @@ -0,0 +1,1093 @@ +#include "LAPPDTreeMaker.h" + +LAPPDTreeMaker::LAPPDTreeMaker() : Tool() {} + +bool LAPPDTreeMaker::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if (configfile != "") + m_variables.Initialise(configfile); // loading config file + // m_variables.Print(); + + m_data = &data; // assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + m_variables.Get("treeMakerVerbosity", treeMakerVerbosity); + m_variables.Get("treeMakerInputPulseLabel", treeMakerInputPulseLabel); + m_variables.Get("treeMakerInputHitLabel", treeMakerInputHitLabel); + treeMakerOutputFileName = "LAPPDTree.root"; + m_variables.Get("treeMakerOutputFileName", treeMakerOutputFileName); + + LoadPulse = false; + m_variables.Get("LoadPulse", LoadPulse); + LoadHit = false; + m_variables.Get("LoadHit", LoadHit); + LoadWaveform = false; + m_variables.Get("LoadWaveform", LoadWaveform); + LoadLAPPDDataTimeStamp = false; + m_variables.Get("LoadLAPPDDataTimeStamp", LoadLAPPDDataTimeStamp); + LoadPPSTimestamp = false; + m_variables.Get("LoadPPSTimestamp", LoadPPSTimestamp); + LoadRunInfoRaw = false; + m_variables.Get("LoadRunInfoRaw", LoadRunInfoRaw); + LoadRunInfoANNIEEvent = false; + m_variables.Get("LoadRunInfoANNIEEvent", LoadRunInfoANNIEEvent); + LoadTriggerInfo = false; + m_variables.Get("LoadTriggerInfo", LoadTriggerInfo); + LoadGroupedTriggerInfo = false; + m_variables.Get("LoadGroupedTriggerInfo", LoadGroupedTriggerInfo); + if (!LoadTriggerInfo) + LoadGroupedTriggerInfo = false; // if not loading trigger, don't fill grouped trigger + LoadGroupOption = "beam"; + m_variables.Get("LoadGroupOption", LoadGroupOption); + MultiLAPPDMapTreeMaker = false; + m_variables.Get("MultiLAPPDMapTreeMaker", MultiLAPPDMapTreeMaker); + + TString filename = treeMakerOutputFileName; + file = new TFile(filename, "RECREATE"); + fPulse = new TTree("Pulse", "Pulse"); + fHit = new TTree("Hit", "Hit"); + fWaveform = new TTree("Waveform", "Waveform"); + fTimeStamp = new TTree("TimeStamp", "TimeStamp"); + fTrigger = new TTree("Trig", "Trig"); + fGroupedTrigger = new TTree("GTrig", "GTrig"); + + fPulse->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fPulse->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fPulse->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fPulse->Branch("EventNumber", &EventNumber, "EventNumber/I"); + fPulse->Branch("LAPPD_ID", &LAPPD_ID, "LAPPD_ID/I"); + fPulse->Branch("LAPPDDataTimeStampUL", &LAPPDDataTimeStampUL, "LAPPDDataTimeStampUL/l"); + fPulse->Branch("LAPPDDataBeamgateUL", &LAPPDDataBeamgateUL, "LAPPDDataBeamgateUL/l"); + fPulse->Branch("ChannelID", &ChannelID, "ChannelID/I"); + fPulse->Branch("StripNumber", &StripNumber, "StripNumber/I"); + fPulse->Branch("PeakTime", &PeakTime, "PeakTime/D"); + fPulse->Branch("Charge", &Charge, "Charge/D"); + fPulse->Branch("PeakAmp", &PeakAmp, "PeakAmp/D"); + fPulse->Branch("PulseStart", &PulseStart, "PulseStart/D"); + fPulse->Branch("PulseEnd", &PulseEnd, "PulseEnd/D"); + fPulse->Branch("PulseSize", &PulseSize, "PulseSize/D"); + fPulse->Branch("PulseSide", &PulseSide, "PulseSide/I"); + fPulse->Branch("PulseThreshold", &PulseThreshold, "PulseThreshold/D"); + fPulse->Branch("PulseBaseline", &PulseBaseline, "PulseBaseline/D"); + if (MultiLAPPDMapTreeMaker) + { + fPulse->Branch("LTSRaw", <SRaw, "LTSRaw/l"); + fPulse->Branch("LBGRaw", &LBGRaw, "LBGRaw/l"); + fPulse->Branch("LOffset_ns", &LOffset_ns, "LOffset_ns/l"); + fPulse->Branch("LTSCorrection", <SCorrection, "LTSCorrection/I"); + fPulse->Branch("LBGCorrection", &LBGCorrection, "LBGCorrection/I"); + fPulse->Branch("LOSInMinusPS", &LOSInMinusPS, "LOSInMinusPS/I"); + fPulse->Branch("CTCPrimeTriggerTime", &CTCPrimeTriggerTime, "CTCPrimeTriggerTime/l"); + } + + fHit->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fHit->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fHit->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fHit->Branch("EventNumber", &EventNumber, "EventNumber/I"); + fHit->Branch("LAPPD_ID", &LAPPD_ID, "LAPPD_ID/I"); + fHit->Branch("LAPPDDataTimeStampUL", &LAPPDDataTimeStampUL, "LAPPDDataTimeStampUL/l"); + fHit->Branch("LAPPDDataBeamgateUL", &LAPPDDataBeamgateUL, "LAPPDDataBeamgateUL/l"); + fHit->Branch("StripNumber", &StripNumber, "StripNumber/I"); + fHit->Branch("HitTime", &HitTime, "HitTime/D"); + fHit->Branch("HitAmp", &HitAmp, "HitAmp/D"); + fHit->Branch("XPosTank", &XPosTank, "XPosTank/D"); + fHit->Branch("YPosTank", &YPosTank, "YPosTank/D"); + fHit->Branch("ZPosTank", &ZPosTank, "ZPosTank/D"); + fHit->Branch("ParallelPos", &ParallelPos, "ParallelPos/D"); + fHit->Branch("TransversePos", &TransversePos, "TransversePos/D"); + fHit->Branch("Pulse1StartTime", &Pulse1StartTime, "Pulse1StartTime/D"); + fHit->Branch("Pulse2StartTime", &Pulse2StartTime, "Pulse2StartTime/D"); + fHit->Branch("Pulse1LastTime", &Pulse1LastTime, "Pulse1LastTime/D"); + fHit->Branch("Pulse2LastTime", &Pulse2LastTime, "Pulse2LastTime/D"); + if (MultiLAPPDMapTreeMaker) + { + fHit->Branch("LTSRaw", <SRaw, "LTSRaw/l"); + fHit->Branch("LBGRaw", &LBGRaw, "LBGRaw/l"); + fHit->Branch("LOffset_ns", &LOffset_ns, "LOffset_ns/l"); + fHit->Branch("LTSCorrection", <SCorrection, "LTSCorrection/I"); + fHit->Branch("LBGCorrection", &LBGCorrection, "LBGCorrection/I"); + fHit->Branch("LOSInMinusPS", &LOSInMinusPS, "LOSInMinusPS/I"); + fHit->Branch("CTCPrimeTriggerTime", &CTCPrimeTriggerTime, "CTCPrimeTriggerTime/l"); + } + + fWaveform->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fWaveform->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fWaveform->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fWaveform->Branch("EventNumber", &EventNumber, "EventNumber/I"); + fWaveform->Branch("LAPPD_ID", &LAPPD_ID, "LAPPD_ID/I"); + fWaveform->Branch("LAPPDDataTimeStampUL", &LAPPDDataTimeStampUL, "LAPPDDataTimeStampUL/l"); + fWaveform->Branch("LAPPDDataBeamgateUL", &LAPPDDataBeamgateUL, "LAPPDDataBeamgateUL/l"); + fWaveform->Branch("StripNumber", &StripNumber, "StripNumber/I"); + fWaveform->Branch("PulseSide", &PulseSide, "PulseSide/I"); + fWaveform->Branch("WaveformMax", &waveformMaxValue, "WaveformMax/D"); + fWaveform->Branch("WaveformRMS", &waveformRMSValue, "WaveformRMS/D"); + fWaveform->Branch("WaveformMaxTimeBin", &waveformMaxTimeBinValue, "WaveformMaxTimeBin/I"); + fWaveform->Branch("waveformMaxFoundNear", &waveformMaxFoundNear, "waveformMaxFoundNear/O"); // O is boolean + fWaveform->Branch("WaveformMaxNearing", &waveformMaxNearingValue, "WaveformMaxNearing/D"); + if (MultiLAPPDMapTreeMaker) + { + fWaveform->Branch("LTSRaw", <SRaw, "LTSRaw/l"); + fWaveform->Branch("LBGRaw", &LBGRaw, "LBGRaw/l"); + fWaveform->Branch("LOffset_ns", &LOffset_ns, "LOffset_ns/l"); + fWaveform->Branch("LTSCorrection", <SCorrection, "LTSCorrection/I"); + fWaveform->Branch("LBGCorrection", &LBGCorrection, "LBGCorrection/I"); + fWaveform->Branch("LOSInMinusPS", &LOSInMinusPS, "LOSInMinusPS/I"); + fWaveform->Branch("CTCPrimeTriggerTime", &CTCPrimeTriggerTime, "CTCPrimeTriggerTime/l"); + } + + fTimeStamp->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fTimeStamp->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fTimeStamp->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fTimeStamp->Branch("EventNumber", &EventNumber, "EventNumber/I"); + fTimeStamp->Branch("LAPPD_ID", &LAPPD_ID, "LAPPD_ID/I"); + fTimeStamp->Branch("LAPPDDataTimeStampUL", &LAPPDDataTimeStampUL, "LAPPDDataTimeStampUL/l"); + fTimeStamp->Branch("LAPPDDataBeamgateUL", &LAPPDDataBeamgateUL, "LAPPDDataBeamgateUL/l"); + fTimeStamp->Branch("LAPPDDataTimestamp", &LAPPDDataTimestampPart1, "LAPPDDataTimestamp/l"); + fTimeStamp->Branch("LAPPDDataBeamgate", &LAPPDDataBeamgatePart1, "LAPPDDataBeamgate/l"); + fTimeStamp->Branch("LAPPDDataTimestampFloat", &LAPPDDataTimestampPart2, "LAPPDDataTimestampFloat/D"); + fTimeStamp->Branch("LAPPDDataBeamgateFloat", &LAPPDDataBeamgatePart2, "LAPPDDataBeamgateFloat/D"); + fTimeStamp->Branch("ppsDiff", &ppsDiff, "ppsDiff/L"); + fTimeStamp->Branch("ppsCount0", &ppsCount0, "ppsCount0/l"); + fTimeStamp->Branch("ppsCount1", &ppsCount1, "ppsCount1/l"); + fTimeStamp->Branch("ppsTime0", &ppsTime0, "ppsTime0/l"); + fTimeStamp->Branch("ppsTime1", &ppsTime1, "ppsTime1/l"); + + // trigger trees have no related to LAPPD data or PPS, so don't need event number + fTrigger->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fTrigger->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fTrigger->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fTrigger->Branch("CTCTimeStamp", &CTCTimeStamp, "CTCTimeStamp/l"); + fTrigger->Branch("CTCTriggerWord", &CTCTriggerWord); + fTrigger->Branch("trigNumInMap", &trigNumInThisMap, "trigNumInMap/I"); + fTrigger->Branch("trigIndexInMap", &trigIndexInThisMap, "trigNumInMap/I"); + + fGroupedTrigger->Branch("RunNumber", &RunNumber, "RunNumber/I"); + fGroupedTrigger->Branch("SubRunNumber", &SubRunNumber, "SubRunNumber/I"); + fGroupedTrigger->Branch("PartFileNumber", &PartFileNumber, "PartFileNumber/I"); + fGroupedTrigger->Branch("gTrigWord", &groupedTriggerWords); + fGroupedTrigger->Branch("gTrigTime", &groupedTriggerTimestamps); + fGroupedTrigger->Branch("gTrigType", &groupedTriggerType, "gTrigType/I"); + fGroupedTrigger->Branch("gTrigNum", &TriggerGroupNumInThisEvent, "gTrigNum/I"); + + TriggerWordMap = new std::map>; + m_data->Stores["ANNIEEvent"]->Header->Get("AnnieGeometry", _geom); + EventNumber = 0; + + return true; +} + +bool LAPPDTreeMaker::Execute() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute()" << endl; + CleanVariables(); + + m_data->CStore.Get("LoadingPPS", LoadingPPS); + if (treeMakerVerbosity > 0) + cout << "LoadingPPS: " << LoadingPPS << endl; + + m_data->CStore.Get("LAPPDana", LAPPDana); + if (treeMakerVerbosity > 0) + cout << "LAPPDana: " << LAPPDana << endl; + + if (LoadRunInfoRaw) + LoadRunInfoFromRaw(); + + if (LoadRunInfoANNIEEvent) + LoadRunInfoFromANNIEEvent(); + + bool loadTriggerPaused = false; + m_data->CStore.Get("PauseCTCDecoding", loadTriggerPaused); + if (treeMakerVerbosity > 0) + cout << "loadTriggerPaused: " << loadTriggerPaused << endl; + if (!loadTriggerPaused) + { + if (LoadTriggerInfo) + { + bool getTrig = m_data->CStore.Get("TimeToTriggerWordMap", TriggerWordMap); + if (!getTrig) + cout << "Error in getting trigger word map" << endl; + if (getTrig) + { + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker:: TimeToTriggerWordMap size: " << TriggerWordMap->size() << endl; + FillTriggerTree(); + } + } + } + + if (LoadGroupedTriggerInfo) + FillGroupedTriggerTree(); + + if (MultiLAPPDMapTreeMaker && LAPPDana) + { + m_data->Stores["ANNIEEvent"]->Get("PrimaryTriggerTime", CTCPrimeTriggerTime); + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute() MultiLAPPDMapTreeMaker" << endl; + LoadLAPPDMapInfo(); + bool getMap = m_data->Stores["ANNIEEvent"]->Get("LAPPDDataMap", LAPPDDataMap); + bool gotBeamgates_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + bool gotTimeStamps_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + bool gotTimeStampsRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + bool gotBeamgatesRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + bool gotOffsets = m_data->Stores["ANNIEEvent"]->Get("LAPPDOffsets", LAPPDOffsets); + bool gotTSCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDTSCorrection", LAPPDTSCorrection); + bool gotDBGCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDBGCorrection", LAPPDBGCorrection); + bool gotOSInMinusPS = m_data->Stores["ANNIEEvent"]->Get("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute() MultiLAPPDMapTreeMaker get map = " << getMap << endl; + if (getMap) + { + if (treeMakerVerbosity > 0) + cout << "map size: " << LAPPDDataMap.size() << endl; + for (auto &item : LAPPDDataMap) + { + PsecData thisData = item.second; + int thisLAPPD_ID = thisData.LAPPD_ID; + + uint64_t thisDataTime = item.first; + uint64_t thisTSRaw = LAPPDTimeStampsRaw.at(thisDataTime); + uint64_t thisBGRaw = LAPPDBeamgatesRaw.at(thisDataTime); + uint64_t thisOffset = LAPPDOffsets.at(thisDataTime); + int thisTSCorr = LAPPDTSCorrection.at(thisDataTime); + int thisDBGCorr = LAPPDBGCorrection.at(thisDataTime); + int thisOSInMinusPS = LAPPDOSInMinusPS.at(thisDataTime); + + if (treeMakerVerbosity > 0) + cout << "outside tree maker, Got LAPPD ID: " << thisLAPPD_ID << ", time stamp: " << thisDataTime << ", TSraw " << thisTSRaw << ", BGraw " << thisBGRaw << ", offset " << thisOffset << ", TSCorr " << thisTSCorr << ", DBGCorr " << thisDBGCorr << ", OSInMinusPS " << thisOSInMinusPS << endl; + + LAPPD_IDs.push_back(thisLAPPD_ID); + LAPPDMapTimeStampRaw.push_back(thisTSRaw); + LAPPDMapBeamgateRaw.push_back(thisBGRaw); + LAPPDMapOffsets.push_back(thisOffset); + LAPPDMapTSCorrections.push_back(thisTSCorr); + LAPPDMapBGCorrections.push_back(thisDBGCorr); + LAPPDMapOSInMinusPS.push_back(thisOSInMinusPS); + + if (treeMakerVerbosity > 0) + cout << "outside size of LAPPD_IDs: " << LAPPD_IDs.size() << endl; + } + } + else + { + cout << "outside LAPPDTreeMaker::LoadLAPPDMapInfo, no LAPPDDataMap found" << endl; + } + + if (treeMakerVerbosity > 0) + { + cout << "LAPPDMapTimeStampRaw: "; + for (auto &item : LAPPDMapTimeStampRaw) + cout << item << " "; + cout << "LAPPDTreeMaker::Execute() MultiLAPPDMapTreeMaker finished " << endl; + } + } + + if (LoadPPSTimestamp && LoadingPPS) + { + bool gotPPSTimestamp = m_data->CStore.Get("LAPPDPPSVector", pps_vector); + bool gotPPSCounter = m_data->CStore.Get("LAPPDPPScount", pps_count_vector); + if (!gotPPSTimestamp) + cout << "Error in getting PPS timestamp" << endl; + if (!gotPPSCounter) + cout << "Error in getting PPS counter" << endl; + if (gotPPSTimestamp && gotPPSCounter) + FillPPSTimestamp(); + } + + if (LoadLAPPDDataTimeStamp && !LoadingPPS) + { + bool newDataEvent; + m_data->CStore.Get("LAPPD_new_event", newDataEvent); + if (newDataEvent) + FillLAPPDDataTimeStamp(); + m_data->CStore.Set("LAPPD_new_event", true); + } + + if (LoadPulse && LAPPDana) + { + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute() LoadPulse" << endl; + bool gotPulse = m_data->Stores["ANNIEEvent"]->Get(treeMakerInputPulseLabel, lappdPulses); + if (!gotPulse) + cout << "Error in getting LAPPD pulses" << endl; + if (gotPulse) + FillPulseTree(); + } + + if (LoadHit && LAPPDana) + { + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute() LoadHit" << endl; + bool gotHit = m_data->Stores["ANNIEEvent"]->Get(treeMakerInputHitLabel, lappdHits); + if (!gotHit) + cout << "Error in getting LAPPD hits" << endl; + if (gotHit) + FillHitTree(); + } + + if (LoadWaveform && LAPPDana) + { + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::Execute() LoadWaveform" << endl; + bool gotWaveformMax = m_data->Stores["ANNIEEvent"]->Get("waveformMax", waveformMax); + if (!gotWaveformMax) + cout << "Error in getting waveform max" << endl; + bool gotWaveformRMS = m_data->Stores["ANNIEEvent"]->Get("waveformRMS", waveformRMS); + if (!gotWaveformRMS) + cout << "Error in getting waveform RMS" << endl; + bool gotWaveformMaxLast = m_data->Stores["ANNIEEvent"]->Get("waveformMaxLast", waveformMaxLast); + if (!gotWaveformMaxLast) + cout << "Error in getting waveform max last" << endl; + bool gotWaveformMaxNearing = m_data->Stores["ANNIEEvent"]->Get("waveformMaxNearing", waveformMaxNearing); + if (!gotWaveformMaxNearing) + cout << "Error in getting waveform max nearing" << endl; + bool gotWaveformMaxTimeBin = m_data->Stores["ANNIEEvent"]->Get("waveformMaxTimeBin", waveformMaxTimeBin); + if (!gotWaveformMaxTimeBin) + cout << "Error in getting waveform max time bin" << endl; + + if (gotWaveformMax && gotWaveformRMS && gotWaveformMaxLast && gotWaveformMaxNearing && gotWaveformMaxTimeBin) + FillWaveformTree(); + } + + if (LAPPDana) + EventNumber++; + + if (TriggerWordMap != nullptr) + TriggerWordMap->clear(); + + return true; +} + +bool LAPPDTreeMaker::Finalise() +{ + file->cd(); + fPulse->Write(); + fHit->Write(); + fWaveform->Write(); + fTimeStamp->Write(); + fTrigger->Write(); + fGroupedTrigger->Write(); + file->Close(); + return true; +} + +void LAPPDTreeMaker::CleanVariables() +{ + LAPPDana = false; + + RunNumber = -9999; + SubRunNumber = -9999; + PartFileNumber = -9999; + + lappdPulses.clear(); + lappdHits.clear(); + lappdData.clear(); + waveformMax.clear(); + waveformRMS.clear(); + waveformMaxLast.clear(); + waveformMaxNearing.clear(); + waveformMaxTimeBin.clear(); + pps_vector.clear(); + pps_count_vector.clear(); + + LAPPD_ID = -9999; + ChannelID = -9999; + PeakTime = -9999; + Charge = -9999; + PeakAmp = -9999; + PulseStart = -9999; + PulseEnd = -9999; + PulseSize = -9999; + PulseSide = -9999; + PulseThreshold = -9999; + PulseBaseline = -9999; + + HitTime = -9999; + HitAmp = -9999; + XPosTank = -9999; + YPosTank = -9999; + ZPosTank = -9999; + ParallelPos = -9999; + TransversePos = -9999; + Pulse1StartTime = -9999; + Pulse2StartTime = -9999; + Pulse1LastTime = -9999; + Pulse2LastTime = -9999; + + LAPPDDataTimeStampUL = 0; + LAPPDDataBeamgateUL = 0; + LAPPDDataTimestampPart1 = 0; + LAPPDDataBeamgatePart1 = 0; + LAPPDDataTimestampPart2 = -9999; + LAPPDDataBeamgatePart2 = -9999; + + ppsDiff = -9999; + ppsCount0 = 0; + ppsCount1 = 0; + ppsTime0 = 0; + ppsTime1 = 0; + + CTCTimeStamp = 0; + CTCTriggerWord.clear(); + trigNumInThisMap = -9999; + trigIndexInThisMap = 0; + + groupedTriggerWordsVector.clear(); + groupedTriggerTimestampsVector.clear(); + groupedTriggerWords.clear(); + groupedTriggerTimestamps.clear(); + groupedTriggerByType.clear(); + groupedTriggerType = -9999; + TriggerGroupNumInThisEvent = 0; // start from 0 + groupedTriggerType = -9999; + + LAPPD_IDs.clear(); + LAPPDMapTimeStampRaw.clear(); + LAPPDMapBeamgateRaw.clear(); + LAPPDMapOffsets.clear(); + LAPPDMapTSCorrections.clear(); + LAPPDMapBGCorrections.clear(); + LAPPDMapOSInMinusPS.clear(); + + LAPPDDataMap.clear(); + LAPPDBeamgate_ns.clear(); + LAPPDTimeStamps_ns.clear(); + LAPPDTimeStampsRaw.clear(); + LAPPDBeamgatesRaw.clear(); + LAPPDOffsets.clear(); + LAPPDTSCorrection.clear(); + LAPPDBGCorrection.clear(); + LAPPDOSInMinusPS.clear(); +} + +bool LAPPDTreeMaker::LoadRunInfoFromRaw() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::LoadRunInfoFromRaw" << endl; + m_data->CStore.Get("runNumber", RunNumber); + m_data->CStore.Get("rawFileNumber", PartFileNumber); + m_data->CStore.Get("subrunNumber", SubRunNumber); + return true; +} + +bool LAPPDTreeMaker::LoadRunInfoFromANNIEEvent() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::LoadRunInfoFromANNIEEvent" << endl; + m_data->Stores["ANNIEEvent"]->Get("RunNumber", RunNumber); + m_data->Stores["ANNIEEvent"]->Get("SubRunNumber", SubRunNumber); + m_data->Stores["ANNIEEvent"]->Get("PartNumber", PartFileNumber); + if (treeMakerVerbosity > 0) + cout << "RunNumber: " << RunNumber << ", SubRunNumber: " << SubRunNumber << ", PartFileNumber: " << PartFileNumber << endl; + return true; +} + +bool LAPPDTreeMaker::FillPulseTree() +{ + // LAPPDPulse thisPulse(LAPPD_ID, channel, peakBin*(25./256.), Q, peakAmp, pulseStart, pulseStart+pulseSize); + std::map>>::iterator it; + int foundPulseNum = 0; + if (lappdPulses.size() == 0) + { + if (treeMakerVerbosity > 0) + cout << "No pulses found" << endl; + return true; + } + for (it = lappdPulses.begin(); it != lappdPulses.end(); it++) + { + int stripno = it->first; + vector> stripPulses = it->second; + vector pulse0 = stripPulses.at(0); + vector pulse1 = stripPulses.at(1); + for (int i = 0; i < pulse0.size(); i++) + { + PulseSide = 0; + LAPPDPulse thisPulse = pulse0.at(i); + LAPPD_ID = thisPulse.GetTubeId(); + ChannelID = thisPulse.GetChannelID(); + StripNumber = stripno; + PeakTime = thisPulse.GetTime(); + Charge = thisPulse.GetCharge(); + PeakAmp = thisPulse.GetPeak(); + PulseStart = thisPulse.GetLowRange(); + PulseEnd = thisPulse.GetHiRange(); + PulseSize = PulseEnd - PulseStart; + // cout << " tree maker, this pulse0 LAPPD ID is " << LAPPD_ID << endl; + // TODO save threshold and baseline + if (MultiLAPPDMapTreeMaker) + { + // find the LAPPD_ID in LAPPD_IDs, get the index + // use that index to get the timestamp and beamgate + // if not found, set them to zero + int index = std::distance(LAPPD_IDs.begin(), std::find(LAPPD_IDs.begin(), LAPPD_IDs.end(), LAPPD_ID)); + if (index < LAPPDMapTimeStampRaw.size()) + { + LTSRaw = LAPPDMapTimeStampRaw.at(index); + LBGRaw = LAPPDMapBeamgateRaw.at(index); + LOffset_ns = LAPPDMapOffsets.at(index); + LTSCorrection = LAPPDMapTSCorrections.at(index); + LBGCorrection = LAPPDMapBGCorrections.at(index); + LOSInMinusPS = LAPPDMapOSInMinusPS.at(index); + } + else + { + LTSRaw = 0; + LBGRaw = 0; + LOffset_ns = 0; + LTSCorrection = 0; + LBGCorrection = 0; + LOSInMinusPS = 0; + } + } + + fPulse->Fill(); + foundPulseNum++; + } + for (int i = 0; i < pulse1.size(); i++) + { + PulseSide = 1; + LAPPDPulse thisPulse = pulse1.at(i); + LAPPD_ID = thisPulse.GetTubeId(); + ChannelID = thisPulse.GetChannelID(); + StripNumber = stripno; + PeakTime = thisPulse.GetTime(); + Charge = thisPulse.GetCharge(); + PeakAmp = thisPulse.GetPeak(); + PulseStart = thisPulse.GetLowRange(); + PulseEnd = thisPulse.GetHiRange(); + PulseSize = PulseEnd - PulseStart; + /*cout << " this pulse1 LAPPD ID is " << LAPPD_ID << endl; + cout << "ThresReco pulse1 got LAPPD_IDs: "; + for (int i = 0; i < LAPPD_IDs.size(); i++) + { + cout << LAPPD_IDs.at(i) << " "; + }*/ + // TODO save threshold and baseline + if (MultiLAPPDMapTreeMaker) + { + // find the index of LAPPD_ID in LAPPD_IDs, use that index to assign the timestamlUL and beam gate UL, if not found set them to zero + int index = std::distance(LAPPD_IDs.begin(), std::find(LAPPD_IDs.begin(), LAPPD_IDs.end(), LAPPD_ID)); + if (index < LAPPDMapTimeStampRaw.size()) + { + LTSRaw = LAPPDMapTimeStampRaw.at(index); + LBGRaw = LAPPDMapBeamgateRaw.at(index); + LOffset_ns = LAPPDMapOffsets.at(index); + LTSCorrection = LAPPDMapTSCorrections.at(index); + LBGCorrection = LAPPDMapBGCorrections.at(index); + LOSInMinusPS = LAPPDMapOSInMinusPS.at(index); + } + else + { + LTSRaw = 0; + LBGRaw = 0; + LOffset_ns = 0; + LTSCorrection = 0; + LBGCorrection = 0; + LOSInMinusPS = 0; + } + } + fPulse->Fill(); + foundPulseNum++; + } + } + if (treeMakerVerbosity > 0) + cout << "Found and saved " << foundPulseNum << " pulses" << endl; + return true; +} + +bool LAPPDTreeMaker::FillHitTree() +{ + // LAPPDHit hit(tubeID, averageTimeLow, averageAmp, positionInTank, positionOnLAPPD, pulse1LastTime, pulse2LastTime, pulse1StartTime, pulse2StartTime); + int foundHitNum = 0; + if (lappdHits.size() == 0) + { + if (treeMakerVerbosity > 0) + cout << "No hits found" << endl; + return true; + } + std::map>::iterator it; + for (it = lappdHits.begin(); it != lappdHits.end(); it++) + { + int stripno = it->first; + vector stripHits = it->second; + for (int i = 0; i < stripHits.size(); i++) + { + LAPPDHit thisHit = stripHits.at(i); + LAPPD_ID = thisHit.GetTubeId(); + StripNumber = stripno; + HitTime = thisHit.GetTime(); + HitAmp = thisHit.GetCharge(); + vector position = thisHit.GetPosition(); + XPosTank = position.at(0); + YPosTank = position.at(1); + ZPosTank = position.at(2); + vector localPosition = thisHit.GetLocalPosition(); + ParallelPos = localPosition.at(0); + TransversePos = localPosition.at(1); + Pulse1StartTime = thisHit.GetPulse1StartTime(); + Pulse2StartTime = thisHit.GetPulse2StartTime(); + Pulse1LastTime = thisHit.GetPulse1LastTime(); + Pulse2LastTime = thisHit.GetPulse2LastTime(); + if (treeMakerVerbosity > 0) + { + cout << " this hit LAPPD ID is " << LAPPD_ID << endl; + cout << "ThresReco hit got LAPPD_IDs: "; + for (int i = 0; i < LAPPD_IDs.size(); i++) + { + cout << LAPPD_IDs.at(i) << " "; + } + } + if (MultiLAPPDMapTreeMaker) + { + // find the LAPPD_ID in LAPPD_IDs, get the index + // use that index to get the timestamp and beamgate + // if not found, set them to zero + int index = std::distance(LAPPD_IDs.begin(), std::find(LAPPD_IDs.begin(), LAPPD_IDs.end(), LAPPD_ID)); + if (index < LAPPDMapTimeStampRaw.size()) + { + LTSRaw = LAPPDMapTimeStampRaw.at(index); + LBGRaw = LAPPDMapBeamgateRaw.at(index); + LOffset_ns = LAPPDMapOffsets.at(index); + LTSCorrection = LAPPDMapTSCorrections.at(index); + LBGCorrection = LAPPDMapBGCorrections.at(index); + LOSInMinusPS = LAPPDMapOSInMinusPS.at(index); + } + else + { + LTSRaw = 0; + LBGRaw = 0; + LOffset_ns = 0; + LTSCorrection = 0; + LBGCorrection = 0; + LOSInMinusPS = 0; + } + } + fHit->Fill(); + foundHitNum++; + } + } + if (treeMakerVerbosity > 0) + cout << "Found and saved " << foundHitNum << " hits" << endl; + return true; +} + +bool LAPPDTreeMaker::FillWaveformTree() +{ + if (waveformMax.size() == 0) + { + if (treeMakerVerbosity > 0) + cout << "No waveforms found" << endl; + return true; + } + std::map>::iterator it; + for (it = waveformMax.begin(); it != waveformMax.end(); it++) + { + int key = it->first; + LAPPD_ID = static_cast(key / 60); + int stripSide = static_cast((key - LAPPD_ID * 60) / 30); + StripNumber = key - LAPPD_ID * 60 - stripSide * 30; + // cout << " this waveform LAPPD ID is " << LAPPD_ID << endl; + + for (int side = 0; side < 2; side++) + { + PulseSide = side; + waveformMaxValue = waveformMax.at(key).at(side); + waveformRMSValue = waveformRMS.at(key).at(side); + waveformMaxFoundNear = waveformMaxLast.at(key).at(side); + waveformMaxNearingValue = waveformMaxNearing.at(key).at(side); + waveformMaxTimeBinValue = waveformMaxTimeBin.at(key).at(side); + /*cout << " LAPPDTreeMaker fill waveform tree, LAPPD ID is " << LAPPD_ID << endl; + cout << "ThresReco got LAPPD_IDs: "; + for (int i = 0; i < LAPPD_IDs.size(); i++) + { + cout << LAPPD_IDs.at(i) << " "; + }*/ + if (MultiLAPPDMapTreeMaker) + { + // find the LAPPD_ID in LAPPD_IDs, get the index + // use that index to get the timestamp and beamgate + // if not found, set them to zero + int index = std::distance(LAPPD_IDs.begin(), std::find(LAPPD_IDs.begin(), LAPPD_IDs.end(), LAPPD_ID)); + if (index < LAPPDMapTimeStampRaw.size()) + { + LTSRaw = LAPPDMapTimeStampRaw.at(index); + LBGRaw = LAPPDMapBeamgateRaw.at(index); + LOffset_ns = LAPPDMapOffsets.at(index); + LTSCorrection = LAPPDMapTSCorrections.at(index); + LBGCorrection = LAPPDMapBGCorrections.at(index); + LOSInMinusPS = LAPPDMapOSInMinusPS.at(index); + } + else + { + LTSRaw = 0; + LBGRaw = 0; + LOffset_ns = 0; + LTSCorrection = 0; + LBGCorrection = 0; + LOSInMinusPS = 0; + } + } + fWaveform->Fill(); + } + } + if (treeMakerVerbosity > 0) + cout << "Found and saved " << waveformMax.size() << " waveforms" << endl; + return true; +} + +bool LAPPDTreeMaker::FillPPSTimestamp() +{ + ppsTime0 = pps_vector.at(0); + ppsTime1 = pps_vector.at(1); + ppsCount0 = pps_count_vector.at(0); + ppsCount1 = pps_count_vector.at(1); + ppsDiff = ppsTime1 - ppsTime0; + m_data->CStore.Get("LAPPD_ID", LAPPD_ID); + if (treeMakerVerbosity > 0) + cout << "LAPPD_ID: " << LAPPD_ID << ", ppsDiff: " << ppsDiff << ", ppsTime0: " << ppsTime0 << ", ppsTime1: " << ppsTime1 << ", ppsCount0: " << ppsCount0 << ", ppsCount1: " << ppsCount1 << endl; + fTimeStamp->Fill(); + return true; +} + +bool LAPPDTreeMaker::FillLAPPDDataTimeStamp() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::FillLAPPDDataTimeStamp. Before fill: LAPPDDataTimeStampUL: " << LAPPDDataTimeStampUL << ", LAPPDDataBeamgateUL: " << LAPPDDataBeamgateUL << ", LAPPDDataTimestampPart1: " << LAPPDDataTimestampPart1 << ", LAPPDDataBeamgatePart1: " << LAPPDDataBeamgatePart1 << ", LAPPDDataTimestampPart2: " << LAPPDDataTimestampPart2 << ", LAPPDDataBeamgatePart2: " << LAPPDDataBeamgatePart2 << endl; + if (!MultiLAPPDMapTreeMaker) + { + m_data->CStore.Get("LAPPDBeamgate_Raw", LAPPDDataBeamgateUL); + m_data->CStore.Get("LAPPDTimestamp_Raw", LAPPDDataTimeStampUL); + m_data->CStore.Get("LAPPDBGIntCombined", LAPPDDataBeamgatePart1); + m_data->CStore.Get("LAPPDBGFloat", LAPPDDataBeamgatePart2); + m_data->CStore.Get("LAPPDTSIntCombined", LAPPDDataTimestampPart1); + m_data->CStore.Get("LAPPDTSFloat", LAPPDDataTimestampPart2); + m_data->CStore.Get("LAPPD_ID", LAPPD_ID); + fTimeStamp->Fill(); + } + else + { + for (int i = 0; i < LAPPD_IDs.size(); i++) + { + LAPPD_ID = LAPPD_IDs.at(i); + LAPPDDataBeamgateUL = LAPPDMapBeamgateRaw.at(i); + LAPPDDataTimeStampUL = LAPPDMapTimeStampRaw.at(i); + fTimeStamp->Fill(); + } + } + if (treeMakerVerbosity > 0) + cout << "LAPPDDataTimeStampUL: " << LAPPDDataTimeStampUL << ", LAPPDDataBeamgateUL: " << LAPPDDataBeamgateUL << ", LAPPDDataTimestampPart1: " << LAPPDDataTimestampPart1 << ", LAPPDDataBeamgatePart1: " << LAPPDDataBeamgatePart1 << ", LAPPDDataTimestampPart2: " << LAPPDDataTimestampPart2 << ", LAPPDDataBeamgatePart2: " << LAPPDDataBeamgatePart2 << endl; + return true; +} + +bool LAPPDTreeMaker::FillTriggerTree() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::FillTriggerTree" << endl; + + trigNumInThisMap = TriggerWordMap->size(); + for (const auto &item : *TriggerWordMap) + { + CTCTimeStamp = item.first; + CTCTriggerWord = item.second; + fTrigger->Fill(); + trigIndexInThisMap++; + } + if (treeMakerVerbosity > 0) + cout << "FillTriggerTree: " << trigNumInThisMap << " triggers filled" << endl; + + return true; +} + +bool LAPPDTreeMaker::FillGroupedTriggerTree() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::FillGroupedTriggerTree" << endl; + + // fill new triggers from the map to ungrouped trigger buffer + for (const auto &item : *TriggerWordMap) + { + CTCTimeStamp = item.first; + CTCTriggerWord = item.second; + + for (const auto &trigw : CTCTriggerWord) + { + unGroupedTriggerTimestamps.push_back(CTCTimeStamp); + unGroupedTriggerWords.push_back(trigw); + } + } + + if (LoadGroupOption == "beam") + GroupTriggerByBeam(); + else if (LoadGroupOption == "laser") + GroupTriggerByLaser(); + + GroupPPSTrigger(); + + for (int i = 0; i < groupedTriggerWordsVector.size(); i++) + { + groupedTriggerWords = groupedTriggerWordsVector.at(i); + groupedTriggerTimestamps = groupedTriggerTimestampsVector.at(i); + groupedTriggerType = groupedTriggerByType.at(i); + fGroupedTrigger->Fill(); + TriggerGroupNumInThisEvent += 1; + } + + CleanTriggers(); + + return true; +} + +bool LAPPDTreeMaker::GroupTriggerByBeam() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::GroupTriggerByBeam" << endl; + + vector removeIndex; + bool beamNow = false; + bool trigger2ed = false; + bool trigger14ed = false; + bool trigger1ed = false; + int beamConfirm = 0; + vector thisTGroup; + vector thisTTimestamp; + bool ppsNow = false; + + for (int i = 0; i < unGroupedTriggerWords.size(); i++) + { + uint32_t tWord = unGroupedTriggerWords.at(i); + unsigned long tTime = unGroupedTriggerTimestamps.at(i); + bool pushedToBuffer = false; + if (!beamNow) + { + // not in a beam group + if (tWord == 3) + { + beamNow = true; + beamConfirm = 0; + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + pushedToBuffer = true; + trigger2ed = false; + trigger14ed = false; + trigger1ed = false; + } + } + else + { // while in a group + if (beamConfirm <= 2 && tWord == 3) + { + // in grouping mode, meet a new start, but haven't got enough trigger 14 and 2 + // clear buffer, restart the grouping from this t 3 + thisTGroup.clear(); + thisTTimestamp.clear(); + beamNow = true; + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + pushedToBuffer = true; + trigger2ed = false; + trigger14ed = false; + trigger1ed = false; + } + + if (beamConfirm > 2 && tWord == 10) + { + // if beam confirmed and meet a trigger 10, save the grouped triggers + // 10 always come with 8, which is delayed trigger to MRD + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + pushedToBuffer = true; + // if found trigger 14 and 2, save the grouped triggers + if ((std::find(thisTGroup.begin(), thisTGroup.end(), 14) != thisTGroup.end()) && (std::find(thisTGroup.begin(), thisTGroup.end(), 2) != thisTGroup.end())) + { + groupedTriggerWordsVector.push_back(thisTGroup); + groupedTriggerTimestampsVector.push_back(thisTTimestamp); + groupedTriggerByType.push_back(14); + } + thisTGroup.clear(); + thisTTimestamp.clear(); + beamNow = false; + trigger14ed = false; + trigger2ed = false; + trigger1ed = false; + beamConfirm = 0; + } + + if (!pushedToBuffer && tWord != 32 && tWord != 34 && tWord != 36) + { + if (tWord == 2) + { + trigger2ed = true; + beamConfirm++; + } + + if (tWord != 14) + { + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + } + else if (!trigger14ed) + { + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + trigger14ed = true; + beamConfirm++; + } + pushedToBuffer = true; + } + } + + if (pushedToBuffer) + { + removeIndex.push_back(i); + } + } + + vector unRemovedTriggerWords; + vector unRemovedTriggerTimestamps; + for (int i = 0; i < unGroupedTriggerWords.size(); i++) + { + if (std::find(removeIndex.begin(), removeIndex.end(), i) == removeIndex.end()) + { + unRemovedTriggerWords.push_back(unGroupedTriggerWords.at(i)); + unRemovedTriggerTimestamps.push_back(unGroupedTriggerTimestamps.at(i)); + } + } + unGroupedTriggerTimestamps = unRemovedTriggerTimestamps; + unGroupedTriggerWords = unRemovedTriggerWords; + + return true; +} + +bool LAPPDTreeMaker::GroupPPSTrigger() +{ + if (treeMakerVerbosity > 0) + cout << "LAPPDTreeMaker::GroupPPSTrigger" << endl; + + vector removeIndex; + vector thisTGroup; + vector thisTTimestamp; + bool ppsNow = false; + for (int i = 0; i < unGroupedTriggerWords.size(); i++) + { + uint32_t tWord = unGroupedTriggerWords.at(i); + unsigned long tTime = unGroupedTriggerTimestamps.at(i); + bool pushedToBuffer = false; + if (!ppsNow) + { + if (tWord == 32) + { + ppsNow = true; + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + pushedToBuffer = true; + } + } + else + { + if (tWord == 34) + { + thisTGroup.push_back(tWord); + thisTTimestamp.push_back(tTime); + pushedToBuffer = true; + groupedTriggerWordsVector.push_back(thisTGroup); + groupedTriggerTimestampsVector.push_back(thisTTimestamp); + groupedTriggerByType.push_back(32); + thisTGroup.clear(); + thisTTimestamp.clear(); + ppsNow = false; + } + } + + if (pushedToBuffer) + { + removeIndex.push_back(i); + } + } + + vector unRemovedTriggerWords; + vector unRemovedTriggerTimestamps; + for (int i = 0; i < unGroupedTriggerWords.size(); i++) + { + if (std::find(removeIndex.begin(), removeIndex.end(), i) == removeIndex.end()) + { + unRemovedTriggerWords.push_back(unGroupedTriggerWords.at(i)); + unRemovedTriggerTimestamps.push_back(unGroupedTriggerTimestamps.at(i)); + } + } + unGroupedTriggerTimestamps = unRemovedTriggerTimestamps; + unGroupedTriggerWords = unRemovedTriggerWords; + return true; +} + +bool LAPPDTreeMaker::GroupTriggerByLaser() +{ + // waiting for implementation + return true; +} + +void LAPPDTreeMaker::CleanTriggers() +{ + // only keep the last 1000 triggers + // create new vector to store the last 1000 triggers + if (unGroupedTriggerWords.size() > 1000) + { + std::vector lastTrigWords(unGroupedTriggerWords.end() - 1000, unGroupedTriggerWords.end()); + unGroupedTriggerWords = lastTrigWords; + std::vector lastTrigTimestamps(unGroupedTriggerTimestamps.end() - 1000, unGroupedTriggerTimestamps.end()); + unGroupedTriggerTimestamps = lastTrigTimestamps; + } +} + +void LAPPDTreeMaker::LoadLAPPDMapInfo() +{ + // cout << "LAPPDTreeMaker::LoadLAPPDMapInfo" << endl; + bool getMap = m_data->Stores["ANNIEEvent"]->Get("LAPPDDataMap", LAPPDDataMap); + bool gotBeamgates_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgate_ns", LAPPDBeamgate_ns); + bool gotTimeStamps_ns = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStamps_ns", LAPPDTimeStamps_ns); + bool gotTimeStampsRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDTimeStampsRaw", LAPPDTimeStampsRaw); + bool gotBeamgatesRaw = m_data->Stores["ANNIEEvent"]->Get("LAPPDBeamgatesRaw", LAPPDBeamgatesRaw); + bool gotOffsets = m_data->Stores["ANNIEEvent"]->Get("LAPPDOffsets", LAPPDOffsets); + bool gotTSCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDTSCorrection", LAPPDTSCorrection); + bool gotDBGCorrection = m_data->Stores["ANNIEEvent"]->Get("LAPPDBGCorrection", LAPPDBGCorrection); + bool gotOSInMinusPS = m_data->Stores["ANNIEEvent"]->Get("LAPPDOSInMinusPS", LAPPDOSInMinusPS); + // cout << "LAPPDTreeMaker::LoadLAPPDMapInfo() get map = " << getMap << endl; + + if (getMap) + { + if (treeMakerVerbosity > 0) + cout << "map size: " << LAPPDDataMap.size() << endl; + for (auto &item : LAPPDDataMap) + { + PsecData thisData = item.second; + int thisLAPPD_ID = thisData.LAPPD_ID; + + uint64_t thisDataTime = item.first; + uint64_t thisTSRaw = LAPPDTimeStampsRaw.at(thisDataTime); + uint64_t thisBGRaw = LAPPDBeamgatesRaw.at(thisDataTime); + uint64_t thisOffset = LAPPDOffsets.at(thisDataTime); + int thisTSCorr = LAPPDTSCorrection.at(thisDataTime); + int thisDBGCorr = LAPPDBGCorrection.at(thisDataTime); + int thisOSInMinusPS = LAPPDOSInMinusPS.at(thisDataTime); + + if (treeMakerVerbosity > 0) + cout << "tree maker, Got LAPPD ID: " << thisLAPPD_ID << ", time stamp: " << thisDataTime << ", TSraw " << thisTSRaw << ", BGraw " << thisBGRaw << ", offset " << thisOffset << ", TSCorr " << thisTSCorr << ", DBGCorr " << thisDBGCorr << ", OSInMinusPS " << thisOSInMinusPS << endl; + + LAPPD_IDs.push_back(thisLAPPD_ID); + LAPPDMapTimeStampRaw.push_back(thisTSRaw); + LAPPDMapBeamgateRaw.push_back(thisBGRaw); + LAPPDMapOffsets.push_back(thisOffset); + LAPPDMapTSCorrections.push_back(thisTSCorr); + LAPPDMapBGCorrections.push_back(thisDBGCorr); + LAPPDMapOSInMinusPS.push_back(thisOSInMinusPS); + + if (treeMakerVerbosity > 0) + cout << "size of LAPPD_IDs: " << LAPPD_IDs.size() << endl; + } + } + else + { + cout << "LAPPDTreeMaker::LoadLAPPDMapInfo, no LAPPDDataMap found" << endl; + } +} \ No newline at end of file diff --git a/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.h b/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.h new file mode 100644 index 000000000..9285df8e2 --- /dev/null +++ b/UserTools/LAPPDTreeMaker/LAPPDTreeMaker.h @@ -0,0 +1,184 @@ +#ifndef LAPPDTreeMaker_H +#define LAPPDTreeMaker_H + +#include +#include + +#include "Tool.h" +#include "TTree.h" +#include "TFile.h" +#include "TString.h" +#include "LAPPDPulse.h" +#include "LAPPDHit.h" +#include "Geometry.h" +#include "Position.h" +#include "PsecData.h" + +/** + * \class LAPPDTreeMaker + * + * + * $Author: Yue Feng $ + * $Date: 2024/02/03 16:10:00 $ + * Contact: yuef@iastate.edu + */ +class LAPPDTreeMaker : public Tool +{ + +public: + LAPPDTreeMaker(); ///< Simple constructor + bool Initialise(std::string configfile, DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + void CleanVariables(); + bool FillPulseTree(); + bool FillHitTree(); + bool FillWaveformTree(); + bool FillPPSTimestamp(); + bool FillLAPPDDataTimeStamp(); + bool LoadRunInfoFromRaw(); + bool LoadRunInfoFromANNIEEvent(); + bool GroupTriggerByBeam(); + bool GroupTriggerByLaser(); + bool GroupPPSTrigger(); + bool FillTriggerTree(); + bool FillGroupedTriggerTree(); + void CleanTriggers(); + void LoadLAPPDMapInfo(); + +private: + TFile *file; + TTree *fPulse; + TTree *fHit; + TTree *fWaveform; + TTree *fTimeStamp; + TTree *fTrigger; + TTree *fGroupedTrigger; + + int treeMakerVerbosity; + bool LAPPDana; + bool LoadingPPS; + + bool LoadPulse; + bool LoadHit; + bool LoadWaveform; + bool LoadLAPPDDataTimeStamp; + bool LoadPPSTimestamp; + bool LoadRunInfoRaw; + bool LoadRunInfoANNIEEvent; + bool LoadTriggerInfo; + bool LoadGroupedTriggerInfo; + string LoadGroupOption; // using beam, or laser, or other. + + std::map>> lappdData; + std::map> waveformMax; // strip number+30*side, value + std::map> waveformRMS; + std::map> waveformMaxLast; + std::map> waveformMaxNearing; + std::map> waveformMaxTimeBin; + + map> *TriggerWordMap; + unsigned long CTCTimeStamp; + std::vector CTCTriggerWord; + int trigNumInThisMap; + int trigIndexInThisMap; + int TriggerGroupNumInThisEvent; + int groupedTriggerType; + + vector unGroupedTriggerWords; + vector unGroupedTriggerTimestamps; + vector> groupedTriggerWordsVector; + vector> groupedTriggerTimestampsVector; + vector groupedTriggerByType; + vector groupedTriggerWords; + vector groupedTriggerTimestamps; + + double waveformMaxValue; + double waveformRMSValue; + bool waveformMaxFoundNear; + double waveformMaxNearingValue; + int waveformMaxTimeBinValue; + + std::map>> lappdPulses; + std::map> lappdHits; + Geometry *_geom; + string treeMakerInputPulseLabel; + string treeMakerInputHitLabel; + string treeMakerOutputFileName; + + int EventNumber; // this is for LAPPD relate event number, data or PPS, not trigger!! + int StripNumber; + + int LAPPD_ID; + int ChannelID; + double PeakTime; + double Charge; + double PeakAmp; + double PulseStart; + double PulseEnd; + double PulseSize; + int PulseSide; + double PulseThreshold; + double PulseBaseline; + + double HitTime; + double HitAmp; + double XPosTank; + double YPosTank; + double ZPosTank; + double ParallelPos; + double TransversePos; + double Pulse1StartTime; + double Pulse2StartTime; + double Pulse1LastTime; + double Pulse2LastTime; + + unsigned long LAPPDDataTimeStampUL; + unsigned long LAPPDDataBeamgateUL; + unsigned long LAPPDDataTimestampPart1; + unsigned long LAPPDDataBeamgatePart1; + double LAPPDDataTimestampPart2; + double LAPPDDataBeamgatePart2; + + vector pps_vector; + vector pps_count_vector; + Long64_t ppsDiff; + unsigned long ppsCount0; + unsigned long ppsCount1; + unsigned long ppsTime0; // in clock tick, without 3.125ns + unsigned long ppsTime1; // in clock tick, without 3.125ns + + int RunNumber; + int SubRunNumber; + int PartFileNumber; + + bool MultiLAPPDMapTreeMaker; + vector LAPPD_IDs; + vector LAPPDMapTimeStampRaw; + vector LAPPDMapBeamgateRaw; + vector LAPPDMapOffsets; + vector LAPPDMapTSCorrections; + vector LAPPDMapBGCorrections; + vector LAPPDMapOSInMinusPS; + + std::map LAPPDDataMap; + std::map LAPPDBeamgate_ns; + std::map LAPPDTimeStamps_ns; // data and key are the same + std::map LAPPDTimeStampsRaw; + std::map LAPPDBeamgatesRaw; + std::map LAPPDOffsets; + std::map LAPPDTSCorrection; + std::map LAPPDBGCorrection; + std::map LAPPDOSInMinusPS; + + + uint64_t LTSRaw; + uint64_t LBGRaw; + uint64_t LOffset_ns; + int LTSCorrection; + int LBGCorrection; + int LOSInMinusPS; + uint64_t CTCPrimeTriggerTime; +}; + +#endif diff --git a/UserTools/LAPPDTreeMaker/README.md b/UserTools/LAPPDTreeMaker/README.md new file mode 100644 index 000000000..4d54da112 --- /dev/null +++ b/UserTools/LAPPDTreeMaker/README.md @@ -0,0 +1,9 @@ +# LAPPDTreeMaker + +LAPPDTreeMaker is the end tool for LAPPD_EB, LAPPDProcessedAna, LAPPDAsciiAna tool chains. It will use the the objects generated by other tools and generate a root file with multiple root trees, which contains LAPPD waveform, pulse, hit, timestamp, and CTC trigger, grouped CTC trigger information. + +## Data + + +## Configuration +There are multiple load options, please check LAPPDProcessedAna tool chain for more details diff --git a/UserTools/Unity.h b/UserTools/Unity.h index 8b4e74769..8459002e1 100644 --- a/UserTools/Unity.h +++ b/UserTools/Unity.h @@ -177,3 +177,13 @@ #include "SaveConfigInfo.h" #include "ReadConfigInfo.h" #include "BackTracker.h" +#include "LAPPDLoadStore.h" +#include "EBLoadRaw.h" +#include "EBTriggerGrouper.h" +#include "EBLAPPD.h" +#include "EBPMT.h" +#include "EBMRD.h" +#include "EBSaver.h" +#include "LAPPDTreeMaker.h" +#include "ANNIEEventTreeMaker.h" + diff --git a/offsetFit_MultipleLAPPD.cpp b/offsetFit_MultipleLAPPD.cpp new file mode 100644 index 000000000..769023467 --- /dev/null +++ b/offsetFit_MultipleLAPPD.cpp @@ -0,0 +1,1272 @@ +// This is a script for offset fitting, use it on the output LAPPDTree.root +// This script require all LAPPD events appear in sequence, and all CTC events appear in sequence +/* procedure: + 1. load LAPPDTree.root (TODO: or use LAPPDTree_runNumber.root) + 2. load TimeStamp tree, get run number and part file number + 3. for each unique run number and part file number, do fit: + 4. in this file, for each LAPPD ID: + 5. loop TimeStamp tree + load data timestamp + load data beamgate + load PPS for board 0 and board 1 + 6. loop Trig (or GTrig) tree + load CTC PPS (word = 32) + load target trigger word + + 7. Find the number of resets in LAPPD PPS: + There must be at least one event in each reset. + Based on the event index order, only fit before the reset which doesn't have data event. + Save the data event and PPS index order. + + 8. Use the target trigger word, fit the offset + 9. save the offset for this LAPPD ID, run number, part file number, index, reset number. + 10. Print info to txt file + +Laser trigger word: 47 +Undelayed beam trigger word: 14 + +root -l -q 'offsetFit_MultipleLAPPD.cpp("LAPPDTree.root", 14, 1, 10, 0)' +root -l -q 'offsetFit_MultipleLAPPD.cpp("LAPPDTree.root", 47, 0, 10, 0)' +*/ +#include +#include +#include +#include +#include +#include +#include "TFile.h" +#include "TTree.h" +#include "TH2D.h" +#include "TH1D.h" +#include "TString.h" + +vector> fitInThisReset( + const std::vector &LAPPDDataTimeStampUL, + const std::vector &LAPPDDataBeamgateUL, + const std::vector &LAPPD_PPS, + const int fitTargetTriggerWord, + const std::vector &CTCTrigger, + const std::vector &CTCPPS, + const ULong64_t PPSDeltaT) +{ + cout << "***************************************" << endl; + cout << "Fitting in this reset with:" << endl; + cout << "LAPPDDataTimeStampUL size: " << LAPPDDataTimeStampUL.size() << endl; + cout << "LAPPDDataBeamgateUL size: " << LAPPDDataBeamgateUL.size() << endl; + cout << "LAPPD_PPS size: " << LAPPD_PPS.size() << endl; + cout << "CTCTrigger size: " << CTCTrigger.size() << endl; + cout << "CTCPPS size: " << CTCPPS.size() << endl; + cout << "PPSDeltaT: " << PPSDeltaT << endl; // in ps + // for this input PPS, fit an offset + // return the offset and other information in order + // precedure: + // 1. check drift + // 2. shift the timestmap and beamgate based on drift + // 3. fit the offset + + std::vector PPSInterval_ACDC; + + for (int i = 1; i < LAPPD_PPS.size(); i++) + { + + double diff = static_cast(LAPPD_PPS[i] - LAPPD_PPS[i - 1]); + cout< 2 microseconds + cout<<"PPSInterval_ACDC["< 2) + { + h->Fill(PPSInterval_ACDC[i]); // fill in microseconds + cout << "Fill histogram: PPSInterval_ACDC[" << i << "]: " << PPSInterval_ACDC[i] << endl; + } + } + + TF1 *gausf = new TF1("gausf", "gaus", 0, 1E3); + h->Fit(gausf, "Q"); // Q for quiet mode + ULong64_t drift = static_cast(gausf->GetParameter(1) * 1E3 * 1E3); // drift in ps + ULong64_t trueInterval = PPSDeltaT - drift; + std::cout << "Gaussian Drift in ps is " << drift << std::endl; + std::cout << "True PPS interval in ps is " << trueInterval << std::endl; + delete gausf; + delete h; + // initialize variables need for fitting + int orphanCount = 0; // count the number that how many data event timestamp doesn't matched to a target trigger within an interval. + std::map>> DerivationMap; + cout << "LAPPD_PPS.size() " << LAPPD_PPS.size() << " CTCPPS.size() " << CTCPPS.size() << endl; + for (int i = 0; i < LAPPD_PPS.size(); i++) + { + if (i > 5) + { + if (i % static_cast(LAPPD_PPS.size() / 5) == 0) + cout << "Fitting PPS " << i << " of " << LAPPD_PPS.size() << endl; + } + ULong64_t LAPPD_PPS_ns = LAPPD_PPS.at(i) / 1000; + ULong64_t LAPPD_PPS_truncated_ps = LAPPD_PPS.at(i) % 1000; + + for (int j = 0; j < CTCPPS.size(); j++) + { + + vector diffSum; + ULong64_t offsetNow_ns = 0; + if (drift == 0) + { + offsetNow_ns = CTCPPS.at(j) - LAPPD_PPS_ns; + } + else + { + double LAPPD_PPS_ns_dd = static_cast(LAPPD_PPS_ns); + double driftScaling = LAPPD_PPS_ns_dd / (trueInterval / 1000); + ULong64_t totalDriftedClock = static_cast(drift * driftScaling / 1000); + offsetNow_ns = CTCPPS.at(j) - (LAPPD_PPS_ns + totalDriftedClock); + if (i < 3 && j < 3) + cout<<"totalDriftedClock in ns = "< notOrphanIndex; + vector ctcPairedIndex; + vector ctcOrphanPairedIndex; + + for (int lappdb = 0; lappdb < LAPPDDataBeamgateUL.size(); lappdb++) + { + ULong64_t TS_ns = LAPPDDataTimeStampUL.at(lappdb) / 1000; + ULong64_t TS_truncated_ps = LAPPDDataTimeStampUL.at(lappdb) % 1000; + // if fit for the undelayed beam trigger, use BG + if (fitTargetTriggerWord == 14) + { + TS_ns = LAPPDDataBeamgateUL.at(lappdb) / 1000; + TS_truncated_ps = LAPPDDataBeamgateUL.at(lappdb) % 1000; + } + + ULong64_t driftCorrectionForTS = 0; + if (drift != 0) + { + double TS_ns_dd = static_cast(TS_ns); + double driftScaling = TS_ns_dd / (trueInterval / 1000); + driftCorrectionForTS = static_cast(drift * driftScaling / 1000); + if(lappdb<3 && i<3 && j<3) + cout<::max(); + bool useThisValue = true; + int minPairIndex = 0; + string reason = "none"; + Long64_t first_derivation = 0; + int minIndex = 0; + double useValue = true; + + // find the best match of target trigger to this TS, in ns level. + for (int ctcb = 0; ctcb < CTCTrigger.size(); ctcb++) + { + ULong64_t CTCTrigger_ns = CTCTrigger.at(ctcb); + Long64_t diff = CTCTrigger_ns - DriftCorrectedTS_ns; + if (diff < 0) + diff = -diff; + + if (diff < minMatchDiff) + { + minMatchDiff = diff; + minPairIndex = ctcb; + } + + Long64_t LastBound = diff - minMatchDiff; + if (LastBound < 0) + LastBound = -LastBound; + Long64_t FirstBound = diff - first_derivation; + if (FirstBound < 0) + FirstBound = -FirstBound; + + // save the dt for the first matching to determin the matching position in range. + if (ctcb == 0) + first_derivation = diff; + + if (ctcb == CTCTrigger.size() - 1 && LastBound / 1E9 < 0.01) + { + useValue = false; + reason = "When matching the last TS, this diff is too close to (or even is) the minMatchDiff at index " + std::to_string(minPairIndex) + " in " + std::to_string(CTCTrigger.size()) + ". All LAPPD TS is out of the end of CTC trigger range"; + } + if (ctcb == CTCTrigger.size() - 1 && FirstBound / 1E9 < 0.01) + { + useValue = false; + reason = "When matching the last TS, this diff is too close to (or even is) the first_derivation at index " + std::to_string(minPairIndex) + " in " + std::to_string(CTCTrigger.size()) + ". All LAPPD TS is out of the beginning of CTC trigger range"; + } + } + + if (useValue) + { + diffSum.push_back(minMatchDiff); + double minAllowedDiff = 0; + double maxAllowedDiff = 100E3; + if (fitTargetTriggerWord == 14) + { + minAllowedDiff = 322E3; + maxAllowedDiff = 326E3; + } + if (minMatchDiff > maxAllowedDiff || minMatchDiff < minAllowedDiff) + { + // TODO: adjust the limit for laser. + orphanCount += 1; + ctcOrphanPairedIndex.push_back(minPairIndex); + } + else + { + notOrphanIndex.push_back(lappdb); + ctcPairedIndex.push_back(minPairIndex); + } + } + else + { + orphanCount += 1; + } + } + + double mean_dev = 0; + for (int k = 0; k < diffSum.size(); k++) + { + mean_dev += diffSum[k]; + } + if (diffSum.size() > 0) + mean_dev = mean_dev / diffSum.size(); + + double mean_dev_noOrphan = 0; + for (int k = 0; k < notOrphanIndex.size(); k++) + { + if (fitTargetTriggerWord == 14) + { + if (diffSum.at(k) > 322E3 && diffSum.at(k) < 326E3) + mean_dev_noOrphan += diffSum[notOrphanIndex[k]]; + } + else + { + mean_dev_noOrphan += diffSum[notOrphanIndex[k]]; + } + } + if ((diffSum.size() - orphanCount) != 0) + { + mean_dev_noOrphan = mean_dev_noOrphan / (diffSum.size() - orphanCount); + } + else + { + mean_dev_noOrphan = -1; // if all timestamps are out of the range, set it to -1 + } + + bool increMean_dev = false; + int maxAttempts = 1000; + int attemptCount = 0; + + if (mean_dev > 0) + { + int increament_dev = 0; + while (true) + { + // TODO + auto iter = DerivationMap.find(mean_dev); + if (iter == DerivationMap.end() || iter->second.empty()) + { + vector Info = {i, j, orphanCount, static_cast(mean_dev_noOrphan * 1000), increament_dev}; + DerivationMap[mean_dev].push_back(Info); + DerivationMap[mean_dev].push_back(notOrphanIndex); + DerivationMap[mean_dev].push_back(ctcPairedIndex); + DerivationMap[mean_dev].push_back(ctcOrphanPairedIndex); + break; + } + else + { + increament_dev += 1; + mean_dev += 0.001; // if the mean_dev is already in the map, increase it by 1ps + attemptCount += 1; + if (attemptCount > maxAttempts) + break; + } + } + } + } + } + // finish matching, found the minimum mean_dev in the map, extract the matching information + double min_mean_dev = std::numeric_limits::max(); + int final_i = 0; + int final_j = 0; + int gotOrphanCount = 0; + double gotMin_mean_dev_noOrphan = 0; + double increament_times = 0; + vector final_notOrphanIndex; + vector final_ctcPairedIndex; + vector final_ctcOrphanIndex; + for (const auto &minIter : DerivationMap) + { + if (minIter.first > 10 && minIter.first < min_mean_dev) + { + min_mean_dev = minIter.first; + final_i = minIter.second[0][0]; + final_j = minIter.second[0][1]; + gotOrphanCount = minIter.second[0][2]; + gotMin_mean_dev_noOrphan = static_cast(minIter.second[0][3] / 1000); + increament_times = minIter.second[0][4]; + final_notOrphanIndex = minIter.second[1]; + final_ctcPairedIndex = minIter.second[2]; + final_ctcOrphanIndex = minIter.second[3]; + } + } + + ULong64_t final_offset_ns = 0; + ULong64_t final_offset_ps_negative = 0; + if (drift == 0) + { + final_offset_ns = CTCPPS.at(final_j) - (LAPPD_PPS.at(final_i) / 1000); + final_offset_ps_negative = LAPPD_PPS.at(final_i) % 1000; + } + else + { + ULong64_t LAPPD_PPS_ns = LAPPD_PPS.at(final_i) / 1000; + ULong64_t LAPPD_PPS_truncated_ps = LAPPD_PPS.at(final_i) % 1000; + double driftScaling = static_cast(LAPPD_PPS_ns) / (trueInterval / 1000); // this is the same drift scaling as in the matching loop + ULong64_t totalDriftedClock = static_cast(drift * driftScaling / 1000); + cout< TimeStampRaw; + vector BeamGateRaw; + vector TimeStamp_ns; + vector BeamGate_ns; + vector TimeStamp_ps; + vector BeamGate_ps; + vector EventIndex; + vector EventDeviation_ns; + vector CTCTriggerIndex; + vector CTCTriggerTimeStamp_ns; + vector BeamGate_correction_tick; + vector TimeStamp_correction_tick; + vector PPS_tick_correction; // if timestamp falls in between of PPS i and i+1, corrected timestamp = timestamp + PPS_tick_correction[i] + vector LAPPD_PPS_missing_ticks; + vector LAPPD_PPS_interval_ticks; + + vector BG_PPSBefore; + vector BG_PPSAfter; + vector BG_PPSDiff; + vector BG_PPSMiss; + vector TS_PPSBefore; + vector TS_PPSAfter; + vector TS_PPSDiff; + vector TS_PPSMiss; + + vector TS_driftCorrection_ns; + vector BG_driftCorrection_ns; + + // calculate the missing ticks for each LAPPD PPS + PPS_tick_correction.push_back(0); + LAPPD_PPS_missing_ticks.push_back(0); + LAPPD_PPS_interval_ticks.push_back(0); + ULong64_t intervalTicks = 320000000 * (PPSDeltaT / 1000 / 1E9); + for (int i = 1; i < LAPPD_PPS.size(); i++) + { + ULong64_t thisPPS = LAPPD_PPS.at(i) / 3125; + ULong64_t prevPPS = LAPPD_PPS.at(i - 1) / 3125; + long long thisInterval = thisPPS - prevPPS; + long long thisMissingTicks = intervalTicks - thisInterval; + LAPPD_PPS_interval_ticks.push_back(thisInterval); + + // if the difference between this PPS and previous PPS is > intervalTicks-20 and < intervalTicks+5, + // the missed value is thisInterval - intervalTicks + // push this value plus the sum of previous missing ticks to the vector + // else just push the sum of previous missing ticks + long long sumOfPreviousMissingTicks = 0; + for (int j = 0; j < LAPPD_PPS_missing_ticks.size(); j++) + { + sumOfPreviousMissingTicks += LAPPD_PPS_missing_ticks.at(j); + } + + if (thisMissingTicks > -20 && thisMissingTicks < 20) + { + LAPPD_PPS_missing_ticks.push_back(thisMissingTicks); + PPS_tick_correction.push_back(thisMissingTicks + sumOfPreviousMissingTicks); + } + else + { + // some time one pps might be wired, but the combination of two is ok. + bool combined = false; + // if there are missing PPS, interval is like 22399999990 % 3200000000 = 3199999990 + long long pInterval = thisInterval % intervalTicks; + long long missingPTicks = 0; + if (intervalTicks - pInterval < 30) + missingPTicks = intervalTicks - pInterval; + else if (pInterval < 30) + missingPTicks = -pInterval; + ////// + if (missingPTicks == 1 || missingPTicks == -1) + { + cout << "Found missing tick is " << missingPTicks << ",continue." << endl; + LAPPD_PPS_missing_ticks.push_back(0); + PPS_tick_correction.push_back(sumOfPreviousMissingTicks); + continue; + } + + if (missingPTicks != 0) + { + LAPPD_PPS_missing_ticks.push_back(missingPTicks); + PPS_tick_correction.push_back(missingPTicks + sumOfPreviousMissingTicks); + combined = true; + cout << "Pushing PPS correction " << i << ", this PPS interval tick is " << thisInterval << ", missing ticks: " << thisMissingTicks << ", push missing " << LAPPD_PPS_missing_ticks.at(i) << ", push correction " << PPS_tick_correction.at(i) << endl; + continue; + } + + // if one PPS is not recoreded correctly, like one interval is 1574262436, followed by a 4825737559 + // then 1574262436 + 4825737559 = 6399999995 = 3200000000 * 2 - 5 + long long nextInterval = 0; + if (i < LAPPD_PPS.size() - 1) + { + nextInterval = LAPPD_PPS.at(i + 1) / 3125 - thisPPS; + long long combinedMissingTicks = intervalTicks - (nextInterval + thisInterval) % intervalTicks; + if (combinedMissingTicks > -30 && combinedMissingTicks < 30) + { + LAPPD_PPS_missing_ticks.push_back(combinedMissingTicks); + PPS_tick_correction.push_back(combinedMissingTicks + sumOfPreviousMissingTicks); + combined = true; + cout << "Pushing PPS correction " << i << ", this PPS interval tick is " << thisInterval << ", missing ticks: " << thisMissingTicks << ", push missing " << LAPPD_PPS_missing_ticks.at(i) << ", push correction " << PPS_tick_correction.at(i) << endl; + continue; + } + } + + if (!combined) + { + LAPPD_PPS_missing_ticks.push_back(0); + PPS_tick_correction.push_back(sumOfPreviousMissingTicks); + } + } + cout << "Pushing PPS correction " << i << ", this PPS interval tick is " << thisInterval << ", missing ticks: " << thisMissingTicks << ", push missing " << LAPPD_PPS_missing_ticks.at(i) << ", push correction " << PPS_tick_correction.at(i) << endl; + } + + // loop all data events, plus the offset, save the event time and beamgate time + // fing the closest CTC trigger, also save all information + cout << "Start saving results. PPS size: " << LAPPD_PPS.size() << ", beamgate size: " << LAPPDDataBeamgateUL.size() << endl; + cout << "First PPS: " << LAPPD_PPS.at(0) / 3125 << ", Last PPS: " << LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 << endl; + cout << "First BG: " << LAPPDDataBeamgateUL.at(0) / 3125 << ", Last BG: " << LAPPDDataBeamgateUL.at(LAPPDDataBeamgateUL.size() - 1) / 3125 << endl; + cout << "First TS: " << LAPPDDataTimeStampUL.at(0) / 3125 << ", Last TS: " << LAPPDDataTimeStampUL.at(LAPPDDataTimeStampUL.size() - 1) / 3125 << endl; + + for (int l = 0; l < LAPPDDataTimeStampUL.size(); l++) + { + ULong64_t TS_ns = LAPPDDataTimeStampUL.at(l) / 1000; + ULong64_t TS_truncated_ps = LAPPDDataTimeStampUL.at(l) % 1000; + ULong64_t BG_ns = LAPPDDataBeamgateUL.at(l) / 1000; + ULong64_t BG_truncated_ps = LAPPDDataBeamgateUL.at(l) % 1000; + ULong64_t driftCorrectionForTS = 0; + ULong64_t driftCorrectionForBG = 0; + if (drift != 0) + { + + double driftScaling = static_cast(TS_ns) / (trueInterval / 1000); + driftCorrectionForTS = static_cast(drift/ 1000 * driftScaling ); + double driftScalingBG = static_cast(BG_ns) / (trueInterval / 1000); + driftCorrectionForBG = static_cast(drift/ 1000 * driftScalingBG ); + cout<<"drift = "< LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125) + { + BeamGate_correction_tick.push_back(PPS_tick_correction.at(LAPPD_PPS.size() - 1) + 1000); + cout << "BGraw = " << LAPPDDataBeamgateUL.at(l) / 3125 << ", pps = " << LAPPD_PPS.at(LAPPD_PPS.size() - 1) << ", pps/3125 = " << LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 << endl; + BGFound = true; + } + if (!BGFound && LAPPDDataBeamgateUL.at(l) / 3125 < LAPPD_PPS.at(0) / 3125) + { + BeamGate_correction_tick.push_back(0 + 1000); + cout << "BGraw less than pps0" << endl; + BGFound = true; + } + if (!TSFound || !BGFound) + { + cout << "Error: PPS not found for event " << l << ", TSFound: " << TSFound << ", BGFound: " << BGFound << endl; + } + /* + cout << "******Found result:" << endl; + cout << "LAPPDDataTimeStampUL.at(" << l << "): " << LAPPDDataTimeStampUL.at(l)/3125 << endl; + cout << "LAPPDDataBeamgateUL.at(" << l << "): " << LAPPDDataBeamgateUL.at(l)/3125 << endl; + cout << "TS_ns: " << TS_ns << endl; + cout << "BG_ns: " << BG_ns << endl; + cout << "final_offset_ns: " << final_offset_ns << endl; + cout << "drift: " << drift << endl; + cout << "TS driftscaling: " << TS_ns / trueInterval / 1000 << endl; + cout << "DriftCorrectedTS_ns: " << DriftCorrectedTS_ns << endl; + cout << "TS_truncated_ps: " << TS_truncated_ps << endl; + cout << "DriftCorrectedBG_ns: " << DriftCorrectedBG_ns << endl; + cout << "BG_truncated_ps: " << BG_truncated_ps << endl; + cout << "Found min_mean_dev_match: " << min_mean_dev_match << endl; + cout << "MatchedIndex: " << matchedIndex << endl; + cout << "CTCTrigger.at(" << matchedIndex << "): " << CTCTrigger.at(matchedIndex) << endl; + cout << "BeamGate_correction_tick at " << l << ": " << BeamGate_correction_tick.at(l) << endl; + cout << "TimeStamp_correction_tick at " << l << ": " << TimeStamp_correction_tick.at(l) << endl; + */ + + // for this LAPPDDataBeamgateUL.at(l), in the LAPPD_PPS vector, find it's closest PPS before and after, and also calculate the time difference between them, and the missing tick between them. + // save as BG_PPSBefore_tick, BG_PPSAfter_tick, BG_PPSDiff_tick, BG_PPSMissing_tick + // Do the same thing for LAPPDDataTimeStampUL.at(l), save as TS_PPSBefore_tick, TS_PPSAfter_tick, TS_PPSDiff_tick, TS_PPSMissing_tick + + ULong64_t BG_PPSBefore_tick = 0; + ULong64_t BG_PPSAfter_tick = 0; + ULong64_t BG_PPSDiff_tick = 0; + ULong64_t BG_PPSMissing_tick = 0; + + ULong64_t TS_PPSBefore_tick = 0; + ULong64_t TS_PPSAfter_tick = 0; + ULong64_t TS_PPSDiff_tick = 0; + ULong64_t TS_PPSMissing_tick = 0; + // if the first PPS is later than beamgate, then set before = 0, after is the first, diff is the first, missing is the first + + cout << "Start finding PPS before and after the beamgate" << endl; + + if ((LAPPD_PPS.at(0) / 3125 > LAPPDDataBeamgateUL.at(l) / 3125) || (LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 < LAPPDDataBeamgateUL.at(l) / 3125)) + { + if (LAPPD_PPS.at(0) / 3125 > LAPPDDataBeamgateUL.at(l) / 3125) + { + BG_PPSBefore_tick = 0; + BG_PPSAfter_tick = LAPPD_PPS.at(0) / 3125; + BG_PPSDiff_tick = LAPPD_PPS.at(0) / 3125; + BG_PPSMissing_tick = LAPPD_PPS.at(0) / 3125; + cout << "First PPS is later than beamgate, before is 0, after is the first, diff is the first, missing is the first" << endl; + } + // if the last PPS is earlier than beamgate, then set before is the last, after = 0, diff is the last, missing is the last + if (LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 < LAPPDDataBeamgateUL.at(l) / 3125) + { + BG_PPSBefore_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + BG_PPSAfter_tick = 0; + BG_PPSDiff_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + BG_PPSMissing_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + cout << "Last PPS is earlier than beamgate, before is the last, after is 0, diff is the last, missing is the last" << endl; + } + } + else + { + // if the first PPS is earlier than beamgate, and the last PPS is later than beamgate, then find the closest PPS before and after + for (int i = 0; i < LAPPD_PPS.size() - 1; i++) + { + if (LAPPD_PPS.at(i) / 3125 < LAPPDDataBeamgateUL.at(l) / 3125 && LAPPD_PPS.at(i + 1) / 3125 > LAPPDDataBeamgateUL.at(l) / 3125) + { + BG_PPSBefore_tick = LAPPD_PPS.at(i) / 3125; + BG_PPSAfter_tick = LAPPD_PPS.at(i + 1) / 3125; + BG_PPSDiff_tick = LAPPD_PPS.at(i + 1) / 3125 - LAPPD_PPS.at(i) / 3125; + ULong64_t DiffTick = (LAPPD_PPS.at(i + 1) - LAPPD_PPS.at(i)) / 3125 - 1000; + BG_PPSMissing_tick = 3200000000 - DiffTick; + cout << "Found PPS before and after the beamgate, before: " << BG_PPSBefore_tick << ", after: " << BG_PPSAfter_tick << ", diff: " << BG_PPSDiff_tick << ", missing: " << BG_PPSMissing_tick << endl; + break; + } + } + } + + // do the samething for timestamp + cout << "Start finding PPS before and after the timestamp" << endl; + + if ((LAPPD_PPS.at(0) / 3125 > LAPPDDataTimeStampUL.at(l) / 3125) || (LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 < LAPPDDataTimeStampUL.at(l) / 3125)) + { + if (LAPPD_PPS.at(0) / 3125 > LAPPDDataTimeStampUL.at(l) / 3125) + { + TS_PPSBefore_tick = 0; + TS_PPSAfter_tick = LAPPD_PPS.at(0) / 3125; + TS_PPSDiff_tick = LAPPD_PPS.at(0) / 3125; + TS_PPSMissing_tick = LAPPD_PPS.at(0) / 3125; + cout << "First PPS is later than timestamp, before is 0, after is the first, diff is the first, missing is the first" << endl; + } + if (LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125 < LAPPDDataTimeStampUL.at(l) / 3125) + { + TS_PPSBefore_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + TS_PPSAfter_tick = 0; + TS_PPSDiff_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + TS_PPSMissing_tick = LAPPD_PPS.at(LAPPD_PPS.size() - 1) / 3125; + cout << "Last PPS is earlier than timestamp, before is the last, after is 0, diff is the last, missing is the last" << endl; + } + } + else + { + for (int i = 0; i < LAPPD_PPS.size() - 1; i++) + { + if (LAPPD_PPS.at(i) / 3125 < LAPPDDataTimeStampUL.at(l) / 3125 && LAPPD_PPS.at(i + 1) / 3125 > LAPPDDataTimeStampUL.at(l) / 3125) + { + TS_PPSBefore_tick = LAPPD_PPS.at(i) / 3125; + TS_PPSAfter_tick = LAPPD_PPS.at(i + 1) / 3125; + TS_PPSDiff_tick = LAPPD_PPS.at(i + 1) / 3125 - LAPPD_PPS.at(i) / 3125; + ULong64_t DiffTick = (LAPPD_PPS.at(i + 1) - LAPPD_PPS.at(i)) / 3125 - 1000; + TS_PPSMissing_tick = 3200000000 - DiffTick; + cout << "Found PPS before and after the timestamp, before: " << TS_PPSBefore_tick << ", after: " << TS_PPSAfter_tick << ", diff: " << TS_PPSDiff_tick << ", missing: " << TS_PPSMissing_tick << endl; + break; + } + } + } + + TimeStampRaw.push_back(LAPPDDataTimeStampUL.at(l) / 3125); + BeamGateRaw.push_back(LAPPDDataBeamgateUL.at(l) / 3125); + TimeStamp_ns.push_back(DriftCorrectedTS_ns); + BeamGate_ns.push_back(DriftCorrectedBG_ns); + TimeStamp_ps.push_back(TS_truncated_ps); + BeamGate_ps.push_back(BG_truncated_ps); + EventIndex.push_back(l); + EventDeviation_ns.push_back(min_mean_dev_match); + // to get ps, should minus the TS_truncated_ps + CTCTriggerIndex.push_back(matchedIndex); + CTCTriggerTimeStamp_ns.push_back(CTCTrigger.at(matchedIndex)); + + BG_PPSBefore.push_back(BG_PPSBefore_tick); + BG_PPSAfter.push_back(BG_PPSAfter_tick); + BG_PPSDiff.push_back(BG_PPSDiff_tick); + BG_PPSMiss.push_back(BG_PPSMissing_tick); + TS_PPSBefore.push_back(TS_PPSBefore_tick); + TS_PPSAfter.push_back(TS_PPSAfter_tick); + TS_PPSDiff.push_back(TS_PPSDiff_tick); + TS_PPSMiss.push_back(TS_PPSMissing_tick); + + TS_driftCorrection_ns.push_back(driftCorrectionForTS); + BG_driftCorrection_ns.push_back(driftCorrectionForBG); + } + ULong64_t totalEventNumber = LAPPDDataTimeStampUL.size(); + ULong64_t gotOrphanCount_out = gotOrphanCount; + ULong64_t gotMin_mean_dev_noOrphan_out = gotMin_mean_dev_noOrphan; + ULong64_t increament_times_out = increament_times; + ULong64_t min_mean_dev_out = min_mean_dev; + ULong64_t final_i_out = final_i; + ULong64_t final_j_out = final_j; + ULong64_t drift_out = drift; + + vector FitInfo = {final_offset_ns, final_offset_ps_negative, gotOrphanCount_out, gotMin_mean_dev_noOrphan_out, increament_times_out, min_mean_dev_out, final_i_out, final_j_out, totalEventNumber, drift_out}; + + vector> Result = {FitInfo, TimeStampRaw, BeamGateRaw, TimeStamp_ns, BeamGate_ns, TimeStamp_ps, BeamGate_ps, EventIndex, EventDeviation_ns, CTCTriggerIndex, CTCTriggerTimeStamp_ns, BeamGate_correction_tick, TimeStamp_correction_tick, LAPPD_PPS_interval_ticks, BG_PPSBefore, BG_PPSAfter, BG_PPSDiff, BG_PPSMiss, TS_PPSBefore, TS_PPSAfter, TS_PPSDiff, TS_PPSMiss, TS_driftCorrection_ns, BG_driftCorrection_ns}; + return Result; +} + +vector> fitInPartFile(TTree *lappdTree, TTree *triggerTree, int runNumber, int subRunNumber, int partFileNumber, int LAPPD_ID, int fitTargetTriggerWord, bool triggerGrouped, int intervalInSecond) +{ + cout << "***************************************" << endl; + cout << "Fitting in run " << runNumber << ", sub run " << subRunNumber << ", part file " << partFileNumber << " for LAPPD ID " << LAPPD_ID << endl; + + vector LAPPD_PPS0; + vector LAPPD_PPS1; + vector LAPPDDataTimeStampUL; + vector LAPPDDataBeamgateUL; + + vector CTCTargetTimeStamp; + vector CTCPPSTimeStamp; + + int LAPPD_ID_inTree; + int runNumber_inTree; + int subRunNumber_inTree; + int partFileNumber_inTree; + + ULong64_t ppsTime0; + ULong64_t ppsTime1; + ULong64_t LAPPDTimeStampUL; + ULong64_t LAPPDBeamgateUL; + ULong64_t LAPPDDataTimestamp; + ULong64_t LAPPDDataBeamgate; + double LAPPDDataTimestampFloat; + double LAPPDDataBeamgateFloat; + + vector *CTCTriggerWord = nullptr; + ULong64_t CTCTimeStamp; + vector *groupedTriggerWords = nullptr; + vector *groupedTriggerTimestamps = nullptr; + + lappdTree->SetBranchAddress("RunNumber", &runNumber_inTree); + lappdTree->SetBranchAddress("SubRunNumber", &subRunNumber_inTree); + lappdTree->SetBranchAddress("PartFileNumber", &partFileNumber_inTree); + lappdTree->SetBranchAddress("LAPPD_ID", &LAPPD_ID_inTree); + lappdTree->SetBranchAddress("LAPPDDataTimeStampUL", &LAPPDTimeStampUL); + lappdTree->SetBranchAddress("LAPPDDataBeamgateUL", &LAPPDBeamgateUL); + lappdTree->SetBranchAddress("LAPPDDataTimestamp", &LAPPDDataTimestamp); + lappdTree->SetBranchAddress("LAPPDDataBeamgate", &LAPPDDataBeamgate); + lappdTree->SetBranchAddress("LAPPDDataTimestampFloat", &LAPPDDataTimestampFloat); + lappdTree->SetBranchAddress("LAPPDDataBeamgateFloat", &LAPPDDataBeamgateFloat); + lappdTree->SetBranchAddress("ppsTime0", &ppsTime0); + lappdTree->SetBranchAddress("ppsTime1", &ppsTime1); + + // triggerTree->Print(); + triggerTree->SetBranchAddress("RunNumber", &runNumber_inTree); + triggerTree->SetBranchAddress("SubRunNumber", &subRunNumber_inTree); + triggerTree->SetBranchAddress("PartFileNumber", &partFileNumber_inTree); + if (triggerGrouped) + { + triggerTree->SetBranchAddress("gTrigWord", &groupedTriggerWords); + triggerTree->SetBranchAddress("gTrigTime", &groupedTriggerTimestamps); + } + else + { + triggerTree->SetBranchAddress("CTCTriggerWord", &CTCTriggerWord); + triggerTree->SetBranchAddress("CTCTimeStamp", &CTCTimeStamp); + } + + int l_nEntries = lappdTree->GetEntries(); + int t_nEntries = triggerTree->GetEntries(); + int repeatedPPSNumber0 = -1; + int repeatedPPSNumber1 = -1; + + // 5. loop TimeStamp tree + for (int i = 0; i < l_nEntries; i++) + { + lappdTree->GetEntry(i); + // if(i<100) + // cout<<"LAPPD_ID_inTree: "<(LAPPDTimeStampUL * 1000 / 8 * 25) / 1E9 / 1000 << ", Beamgate: " << static_cast(LAPPDBeamgateUL * 1000 / 8 * 25) / 1E9 / 1000 << endl; + LAPPDDataTimeStampUL.push_back(LAPPDTimeStampUL * 1000 / 8 * 25); + LAPPDDataBeamgateUL.push_back(LAPPDBeamgateUL * 1000 / 8 * 25); + /* + cout << "LAPPDDataTimestamp: " << LAPPDDataTimestamp << ", LAPPDDataBeamgate: " << LAPPDDataBeamgate << endl; + cout << "LAPPDDataTimestampFloat: " << LAPPDDataTimestampFloat << ", LAPPDDataBeamgateFloat: " << LAPPDDataBeamgateFloat << endl; + ULong64_t ULTS = LAPPDTimeStampUL*1000/8*25; + double DTS = static_cast(LAPPDDataTimestamp); + double plusDTS = DTS + LAPPDDataTimestampFloat; + ULong64_t ULBG = LAPPDBeamgateUL*1000/8*25; + double DBG = static_cast(LAPPDDataBeamgate); + double plusDBG = DBG + LAPPDDataBeamgateFloat; + cout << std::fixed << " ULTS: " << ULTS << ", DTS: " << DTS << ", plusDTS: " << plusDTS << endl; + cout << std::fixed << " ULBG: " << ULBG << ", DBG: " << DBG << ", plusDBG: " << plusDBG << endl; + cout << endl; + */ + } + else if (LAPPDTimeStampUL == 0) + { + // cout << "ppsTime0: " << ppsTime0 << ", ppsTime1: " << ppsTime1 << endl; + if (LAPPD_PPS0.size() == 0) + LAPPD_PPS0.push_back(ppsTime0 * 1000 / 8 * 25); + if (LAPPD_PPS1.size() == 0) + LAPPD_PPS1.push_back(ppsTime1 * 1000 / 8 * 25); + if (LAPPD_PPS0.size() > 0 && ppsTime0 * 1000 / 8 * 25 != LAPPD_PPS0.at(LAPPD_PPS0.size() - 1)) + LAPPD_PPS0.push_back(ppsTime0 * 1000 / 8 * 25); + else + repeatedPPSNumber0 += 1; + if (LAPPD_PPS1.size() > 0 && ppsTime1 * 1000 / 8 * 25 != LAPPD_PPS1.at(LAPPD_PPS1.size() - 1)) + LAPPD_PPS1.push_back(ppsTime1 * 1000 / 8 * 25); + else + repeatedPPSNumber1 += 1; + } + } + } + cout << "repeatedPPSNumber0: " << repeatedPPSNumber0 << ", loaded PPS0 size: " << LAPPD_PPS0.size() << endl; + cout << "repeatedPPSNumber1: " << repeatedPPSNumber1 << ", loaded PPS1 size: " << LAPPD_PPS1.size() << endl; + + // 6. loop Trig (or GTrig) tree + for (int i = 0; i < t_nEntries; i++) + { + triggerTree->GetEntry(i); + if (runNumber_inTree == runNumber && subRunNumber_inTree == subRunNumber && partFileNumber_inTree == partFileNumber) + { + // cout<<"triggerGrouped: "<size(); j++) + { + // cout<<"At j = "<at(j)<<", fitTargetTriggerWord: "<at(j) == fitTargetTriggerWord) + CTCTargetTimeStamp.push_back(groupedTriggerTimestamps->at(j)); + if (groupedTriggerWords->at(j) == 32) + CTCPPSTimeStamp.push_back(groupedTriggerTimestamps->at(j)); + } + } + else + { + for (int j = 0; j < CTCTriggerWord->size(); j++) + { + if (CTCTriggerWord->at(j) == fitTargetTriggerWord) + CTCTargetTimeStamp.push_back(CTCTimeStamp); + if (CTCTriggerWord->at(j) == 32) + CTCPPSTimeStamp.push_back(CTCTimeStamp); + } + } + } + } + cout << "Vector for partfile " << partFileNumber << " for LAPPD ID " << LAPPD_ID << " loaded." << endl; + cout << "LAPPDDataTimeStampUL in ps size: " << LAPPDDataTimeStampUL.size() << endl; + cout << "LAPPDDataBeamgateUL in ps size: " << LAPPDDataBeamgateUL.size() << endl; + cout << "LAPPD_PPS0 size: " << LAPPD_PPS0.size() << endl; + cout << "LAPPD_PPS1 size: " << LAPPD_PPS1.size() << endl; + cout << "CTCTargetTimeStamp size: " << CTCTargetTimeStamp.size() << endl; + cout << "CTCPPSTimeStamp size: " << CTCPPSTimeStamp.size() << endl; + // 7. Find the number of resets in LAPPD PPS: + int LAPPDDataFitStopIndex = 0; + int resetNumber = 0; + // first check is there a reset, if no, set the LAPPDDataFitStopIndex to the size of LAPPDDataTimeStampUL + // if all PPS in this part file was increamented, then there is no reset + for (int i = 1; i < LAPPD_PPS0.size(); i++) + { + if (LAPPD_PPS0[i] < LAPPD_PPS0[i - 1]) + { + resetNumber += 1; + cout << "For LAPPD ID " << LAPPD_ID << ", run number " << runNumber << ", sub run number " << subRunNumber << ", part file number " << partFileNumber << ", reset " + << " found at PPS_ACDC0 index " << i << endl; + break; + } + } + for (int i = 1; i < LAPPD_PPS1.size(); i++) + { + if (LAPPD_PPS1[i] < LAPPD_PPS1[i - 1]) + { + resetNumber += 1; + cout << "For LAPPD ID " << LAPPD_ID << ", run number " << runNumber << ", sub run number " << subRunNumber << ", part file number " << partFileNumber << ", reset " + << " found at PPS_ACDC1 index " << i << endl; + break; + } + } + if (resetNumber == 0) + cout << "For LAPPD ID " << LAPPD_ID << ", run number " << runNumber << ", sub run number " << subRunNumber << ", part file number " << partFileNumber << ", no reset found." << endl; + + // if reset found, loop the timestamp in order to find the LAPPDDataFitStopIndex + // + if (resetNumber != 0) + { + for (int i = 1; i < LAPPDDataTimeStampUL.size(); i++) + { + if (LAPPDDataTimeStampUL[i] < LAPPDDataTimeStampUL[i - 1]) + { + LAPPDDataFitStopIndex = i - 1; + break; + } + } + // TODO: extend this to later offsets + } + // 8. Use the target trigger word, fit the offset + // TODO: fit for each reset + vector> ResultTotal; + if (LAPPDDataTimeStampUL.size() == LAPPDDataBeamgateUL.size()) + { + if (LAPPD_PPS0.size() == 0 || LAPPD_PPS1.size() == 0) + { + cout << "Error: PPS0 or PPS1 is empty, return empty result." << endl; + return ResultTotal; + } + vector> ResultACDC0 = fitInThisReset(LAPPDDataTimeStampUL, LAPPDDataBeamgateUL, LAPPD_PPS0, fitTargetTriggerWord, CTCTargetTimeStamp, CTCPPSTimeStamp, intervalInSecond * 1E9 * 1000); + vector> ResultACDC1 = fitInThisReset(LAPPDDataTimeStampUL, LAPPDDataBeamgateUL, LAPPD_PPS1, fitTargetTriggerWord, CTCTargetTimeStamp, CTCPPSTimeStamp, intervalInSecond * 1E9 * 1000); + + // 9. save the offset for this LAPPD ID, run number, part file number, index, reset number. + + cout << "Fitting in part file " << partFileNumber << " for LAPPD ID " << LAPPD_ID << " done." << endl; + + // Combine ResultACDC0 and ResultACDC1 to ResultTotal + for (int i = 0; i < ResultACDC0.size(); i++) + { + ResultTotal.push_back(ResultACDC0[i]); + } + for (int i = 0; i < ResultACDC1.size(); i++) + { + ResultTotal.push_back(ResultACDC1[i]); + } + } + return ResultTotal; +} + +void offsetFit_MultipleLAPPD(string fileName, int fitTargetTriggerWord, bool triggerGrouped, int intervalInSecond, int processPFNumber) +{ + // 1. load LAPPDTree.root + const string file = fileName; + TFile *f = new TFile(file.c_str(), "READ"); + if (!f->IsOpen()) + { + std::cerr << "Error: cannot open file " << file << std::endl; + return; + } + + std::cout << "Opened file " << file << std::endl; + + std::ofstream outputOffset("offset.txt"); + + outputOffset << "runNumber" + << "\t" + << "subRunNumber" + << "\t" + << "partFileNumber" + << "\t" + << "resetNumber" + << "\t" + << "LAPPD_ID" + << "\t" + << "offset_ACDC0_ns" + << "\t" + << "offset_ACDC1_ns" + << "\t" + << "offset_ACDC0_ps_negative" + << "\t" + << "offset_ACDC1_ps_negative" + << "\t" + << "gotOrphanCount_ACDC0" + << "\t" + << "gotOrphanCount_ACDC1" + << "\t" + << "EventNumInThisPartFile" + << "\t" + << "min_mean_dev_noOrphan_ACDC0" + << "\t" + << "min_mean_dev_noOrphan_ACDC1" + << "\t" + << "increament_times_ACDC0" + << "\t" + << "increament_times_ACDC1" + << "\t" + << "min_mean_dev_ACDC0" + << "\t" + << "min_mean_dev_ACDC1" + << std::endl; + + // 2. load TimeStamp tree, get run number and part file number + TTree *TSTree = (TTree *)f->Get("TimeStamp"); + TTree *CTCTree = (TTree *)f->Get("Trig"); + TTree *GCTCTree = (TTree *)f->Get("GTrig"); + int runNumber; + int subRunNumber; + int partFileNumber; + int LAPPD_ID; + ULong64_t ppsCount0; + TSTree->SetBranchAddress("RunNumber", &runNumber); + TSTree->SetBranchAddress("SubRunNumber", &subRunNumber); + TSTree->SetBranchAddress("PartFileNumber", &partFileNumber); + TSTree->SetBranchAddress("LAPPD_ID", &LAPPD_ID); + TSTree->SetBranchAddress("ppsCount0", &ppsCount0); + std::vector> loopInfo; + int nEntries = TSTree->GetEntries(); + for (int i = 0; i < nEntries; i++) + { + TSTree->GetEntry(i); + // if this entry is PPS event, continue. + if (ppsCount0 != 0) + continue; + vector info = {runNumber, subRunNumber, partFileNumber, LAPPD_ID}; + // find if this info is already in loopInfo + bool found = std::find_if(loopInfo.begin(), loopInfo.end(), [&info](const std::vector &vec) + { + return vec == info; // compare vec and info + }) != loopInfo.end(); // if find_if doesn't return end,found + + if (!found) + loopInfo.push_back(info); + } + + // 3. for each unique run number and part file number + // 4. in this file, for each LAPPD ID + // do fit: + std::map>> ResultMap; + std::vector>::iterator it; + int pfNumber = 0; + for (it = loopInfo.begin(); it != loopInfo.end(); it++) + { + int runNumber = (*it)[0]; + int subRunNumber = (*it)[1]; + int partFileNumber = (*it)[2]; + int LAPPD_ID = (*it)[3]; + if (processPFNumber != 0) + { + if (pfNumber >= processPFNumber) + break; + } + + vector> Result; + if (!triggerGrouped) + { // cout<<"trigger not grouped"<> Result = {FitInfo, TimeStampRaw, BeamGateRaw, TimeStamp_ns, BeamGate_ns, TimeStamp_ps, BeamGate_ps, EventIndex, EventDeviation_ns, CTCTriggerIndex, CTCTriggerTimeStamp_ns,BeamGate_correction_tick,TimeStamp_correction_tick}; + vector FitInfo = {final_offset_ns, final_offset_ps_negative, gotOrphanCount, gotMin_mean_dev_noOrphan, increament_times, min_mean_dev, final_i, final_j, totalEventNumber}; + vector TimeStampRaw; + vector BeamGateRaw; + vector TimeStamp_ns; + vector BeamGate_ns; + vector TimeStamp_ps; + vector BeamGate_ps; + vector EventIndex; + vector EventDeviation_ns; + vector CTCTriggerIndex; + vector CTCTriggerTimeStamp_ns; + vector BeamGate_correction_tick; + vector TimeStamp_correction_tick; + */ + // Loop the ResultMap, save the result to a root tree in a root file + cout << "Start saving the result to root file and txt file..." << endl; + TFile *fOut = new TFile("offsetFitResult.root", "RECREATE"); + TTree *tOut = new TTree("Events", "Events"); + int runNumber_out; + int subRunNumber_out; + int partFileNumber_out; + int LAPPD_ID_out; + ULong64_t EventIndex; + ULong64_t EventNumberInThisPartFile; + ULong64_t final_offset_ns_0; + ULong64_t final_offset_ns_1; + ULong64_t final_offset_ps_negative_0; + ULong64_t final_offset_ps_negative_1; + double drift0; + double drift1; + ULong64_t gotOrphanCount_0; + ULong64_t gotOrphanCount_1; + ULong64_t gotMin_mean_dev_noOrphan_0; + ULong64_t gotMin_mean_dev_noOrphan_1; + ULong64_t increament_times_0; + ULong64_t increament_times_1; + ULong64_t min_mean_dev_0; + ULong64_t min_mean_dev_1; + ULong64_t TimeStampRaw; + ULong64_t BeamGateRaw; + ULong64_t TimeStamp_ns; + ULong64_t BeamGate_ns; + ULong64_t TimeStamp_ps; + ULong64_t BeamGate_ps; + ULong64_t EventDeviation_ns_0; + ULong64_t EventDeviation_ns_1; + ULong64_t CTCTriggerIndex; + ULong64_t CTCTriggerTimeStamp_ns; + long long BGMinusTrigger_ns; + long long BGCorrection_tick; + long long TSCorrection_tick; + ULong64_t LAPPD_PPS_interval_ticks; + ULong64_t BG_PPSBefore_tick; + ULong64_t BG_PPSAfter_tick; + ULong64_t BG_PPSDiff_tick; + ULong64_t BG_PPSMissing_tick; + ULong64_t TS_PPSBefore_tick; + ULong64_t TS_PPSAfter_tick; + ULong64_t TS_PPSDiff_tick; + ULong64_t TS_PPSMissing_tick; + + ULong64_t TS_driftCorrection_ns; + ULong64_t BG_driftCorrection_ns; + + tOut->Branch("runNumber", &runNumber_out, "runNumber/I"); + tOut->Branch("subRunNumber", &subRunNumber_out, "subRunNumber/I"); + tOut->Branch("partFileNumber", &partFileNumber_out, "partFileNumber/I"); + tOut->Branch("LAPPD_ID", &LAPPD_ID_out, "LAPPD_ID/I"); + tOut->Branch("EventIndex", &EventIndex, "EventIndex/l"); + tOut->Branch("EventNumInThisPF", &EventNumberInThisPartFile, "EventNumInThisPF/l"); + tOut->Branch("final_offset_ns_0", &final_offset_ns_0, "final_offset_ns_0/l"); + tOut->Branch("final_offset_ns_1", &final_offset_ns_1, "final_offset_ns_1/l"); + tOut->Branch("final_offset_ps_negative_0", &final_offset_ps_negative_0, "final_offset_ps_negative_0/l"); + tOut->Branch("final_offset_ps_negative_1", &final_offset_ps_negative_1, "final_offset_ps_negative_1/l"); + tOut->Branch("drift0", &drift0, "drift0/D"); + tOut->Branch("drift1", &drift1, "drift1/D"); + tOut->Branch("gotOrphanCount_0", &gotOrphanCount_0, "gotOrphanCount_0/l"); + tOut->Branch("gotOrphanCount_1", &gotOrphanCount_1, "gotOrphanCount_1/l"); + tOut->Branch("gotMin_mean_dev_noOrphan_0", &gotMin_mean_dev_noOrphan_0, "gotMin_mean_dev_noOrphan_0/l"); + tOut->Branch("gotMin_mean_dev_noOrphan_1", &gotMin_mean_dev_noOrphan_1, "gotMin_mean_dev_noOrphan_1/l"); + tOut->Branch("increament_times_0", &increament_times_0, "increament_times_0/l"); + tOut->Branch("increament_times_1", &increament_times_1, "increament_times_1/l"); + tOut->Branch("min_mean_dev_0", &min_mean_dev_0, "min_mean_dev_0/l"); + tOut->Branch("min_mean_dev_1", &min_mean_dev_1, "min_mean_dev_1/l"); + tOut->Branch("TimeStampRaw", &TimeStampRaw, "TimeStampRaw/l"); + tOut->Branch("BeamGateRaw", &BeamGateRaw, "BeamGateRaw/l"); + tOut->Branch("TimeStamp_ns", &TimeStamp_ns, "TimeStamp_ns/l"); + tOut->Branch("BeamGate_ns", &BeamGate_ns, "BeamGate_ns/l"); + tOut->Branch("TimeStamp_ps", &TimeStamp_ps, "TimeStamp_ps/l"); + tOut->Branch("BeamGate_ps", &BeamGate_ps, "BeamGate_ps/l"); + tOut->Branch("EventDeviation_ns_0", &EventDeviation_ns_0, "EventDeviation_ns_0/l"); + tOut->Branch("EventDeviation_ns_1", &EventDeviation_ns_1, "EventDeviation_ns_1/l"); + tOut->Branch("CTCTriggerIndex", &CTCTriggerIndex, "CTCTriggerIndex/l"); + tOut->Branch("CTCTriggerTimeStamp_ns", &CTCTriggerTimeStamp_ns, "CTCTriggerTimeStamp_ns/l"); + tOut->Branch("BGMinusTrigger_ns", &BGMinusTrigger_ns, "BGMinusTrigger_ns/L"); + tOut->Branch("BGCorrection_tick", &BGCorrection_tick, "BGCorrection_tick/l"); + tOut->Branch("TSCorrection_tick", &TSCorrection_tick, "TSCorrection_tick/l"); + tOut->Branch("LAPPD_PPS_interval_ticks", &LAPPD_PPS_interval_ticks, "LAPPD_PPS_interval_ticks/l"); + tOut->Branch("BG_PPSBefore_tick", &BG_PPSBefore_tick, "BG_PPSBefore_tick/l"); + tOut->Branch("BG_PPSAfter_tick", &BG_PPSAfter_tick, "BG_PPSAfter_tick/l"); + tOut->Branch("BG_PPSDiff_tick", &BG_PPSDiff_tick, "BG_PPSDiff_tick/l"); + tOut->Branch("BG_PPSMissing_tick", &BG_PPSMissing_tick, "BG_PPSMissing_tick/l"); + tOut->Branch("TS_PPSBefore_tick", &TS_PPSBefore_tick, "TS_PPSBefore_tick/l"); + tOut->Branch("TS_PPSAfter_tick", &TS_PPSAfter_tick, "TS_PPSAfter_tick/l"); + tOut->Branch("TS_PPSDiff_tick", &TS_PPSDiff_tick, "TS_PPSDiff_tick/l"); + tOut->Branch("TS_PPSMissing_tick", &TS_PPSMissing_tick, "TS_PPSMissing_tick/l"); + tOut->Branch("TS_driftCorrection_ns", &TS_driftCorrection_ns, "TS_driftCorrection_ns/l"); + tOut->Branch("BG_driftCorrection_ns", &BG_driftCorrection_ns, "BG_driftCorrection_ns/l"); + + std::ofstream outputEvents("outputEvents.txt"); + for (auto it = ResultMap.begin(); it != ResultMap.end(); it++) + { + string key = it->first; + vector> Result = it->second; + + if (Result.size() == 0) + continue; + + runNumber_out = std::stoi(key.substr(0, key.find("_"))); + subRunNumber_out = std::stoi(key.substr(key.find("_") + 1, key.find("_", key.find("_") + 1) - key.find("_") - 1)); + partFileNumber_out = std::stoi(key.substr(key.find("_", key.find("_") + 1) + 1, key.find("_", key.find("_", key.find("_") + 1) + 1) - key.find("_", key.find("_") + 1) - 1)); + LAPPD_ID_out = std::stoi(key.substr(key.find("_", key.find("_", key.find("_") + 1) + 1) + 1, key.size() - key.find("_", key.find("_", key.find("_") + 1) + 1) - 1)); + final_offset_ns_0 = Result[0][0]; + final_offset_ns_1 = Result[24][0]; + final_offset_ps_negative_0 = Result[0][1]; + final_offset_ps_negative_1 = Result[24][1]; + gotOrphanCount_0 = Result[0][2]; + gotOrphanCount_1 = Result[24][2]; + gotMin_mean_dev_noOrphan_0 = Result[0][3]; + gotMin_mean_dev_noOrphan_1 = Result[24][3]; + increament_times_0 = Result[0][4]; + increament_times_1 = Result[24][4]; + min_mean_dev_0 = Result[0][5]; + min_mean_dev_1 = Result[24][5]; + EventNumberInThisPartFile = Result[0][8]; + drift0 = Result[0][9]; + drift1 = Result[24][9]; + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + // vector> Result = {FitInfo, TimeStampRaw, BeamGateRaw, TimeStamp_ns, BeamGate_ns, TimeStamp_ps, BeamGate_ps, EventIndex, EventDeviation_ns, CTCTriggerIndex, CTCTriggerTimeStamp_ns, BeamGate_correction_tick, TimeStamp_correction_tick, LAPPD_PPS_interval_ticks, BG_PPSBefore, BG_PPSAfter, BG_PPSDiff, BG_PPSMiss, TS_PPSBefore, TS_PPSAfter, TS_PPSDiff, TS_PPSMiss}; + // any Result[x] , if x>13, x = x + 8 + for (int j = 0; j < Result[1].size(); j++) + { + long long BGTdiff = Result[4][j] - Result[10][j] - 325250; + // cout<<"BGTDiff: "<Fill(); + } + outputOffset << runNumber_out << "\t" << subRunNumber_out << "\t" << partFileNumber_out << "\t" << 0 << "\t" << LAPPD_ID_out << "\t" << final_offset_ns_0 << "\t" << final_offset_ns_1 << "\t" << final_offset_ps_negative_0 << "\t" << final_offset_ps_negative_1 << "\t" << gotOrphanCount_0 << "\t" << gotOrphanCount_1 << "\t" << EventNumberInThisPartFile << "\t" << gotMin_mean_dev_noOrphan_0 << "\t" << gotMin_mean_dev_noOrphan_1 << "\t" << increament_times_0 << "\t" << increament_times_1 << "\t" << min_mean_dev_0 << "\t" << min_mean_dev_1 << std::endl; + } + outputOffset.close(); + fOut->cd(); + tOut->Write(); + fOut->Close(); + cout << "Result saved." << endl; +}