From 31d8595ebcc32204dfd224e93cc87b3a8da4110e Mon Sep 17 00:00:00 2001 From: Peter Alan Steinberg <peter.steinberg@bnl.gov> Date: Sat, 29 Oct 2016 14:52:40 +0200 Subject: [PATCH] 'CalibEnergy and CalibTime are in EDM even when calibrations off, to maintain format, but set to -1000 each to avoid anyone using them' (ZdcAnalysis-00-00-16) --- .../ZDC/ZdcAnalysis/CMakeLists.txt | 28 + .../ZDC/ZdcAnalysis/Root/ZDCDataAnalyzer.cxx | 315 ++++++ .../ZDC/ZdcAnalysis/Root/ZDCFitWrapper.cxx | 150 +++ .../ZDC/ZdcAnalysis/Root/ZDCPulseAnalyzer.cxx | 506 ++++++++++ .../ZdcAnalysis/Root/ZDCTriggerEfficiency.cxx | 63 ++ .../ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx | 947 ++++++++++++++++++ .../ZdcAnalysis/Root/ZdcAnalysis_entries.cxx | 16 + .../ZDC/ZdcAnalysis/Root/ZdcSincInterp.cxx | 27 + .../ZdcAnalysis/IZdcAnalysisTool.h | 29 + .../ZdcAnalysis/ZdcAnalysis/ZDCDataAnalyzer.h | 153 +++ .../ZdcAnalysis/ZdcAnalysis/ZDCFitWrapper.h | 255 +++++ .../ZdcAnalysis/ZDCPulseAnalyzer.h | 290 ++++++ .../ZdcAnalysis/ZDCTriggerEfficiency.h | 101 ++ .../ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h | 139 +++ .../ZdcAnalysis/ZdcAnalysis/ZdcSincInterp.h | 12 + .../ZDC/ZdcAnalysis/cmt/Makefile.RootCore | 60 ++ .../ZDC/ZdcAnalysis/cmt/requirements | 24 + .../ZdcAnalysis/data/ZdcAnalysisConfig.conf | 3 + .../ZdcAnalysis/tools/RunZDCTreeAnalysis.C | 216 ++++ .../ZdcAnalysis/tools/ZDCNLCalibration.cxx | 603 +++++++++++ .../ZDC/ZdcAnalysis/tools/ZDCNLCalibration.h | 286 ++++++ .../ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.C | 412 ++++++++ .../ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.h | 512 ++++++++++ 23 files changed, 5147 insertions(+) create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/CMakeLists.txt create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCDataAnalyzer.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCFitWrapper.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCPulseAnalyzer.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCTriggerEfficiency.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysis_entries.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcSincInterp.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/IZdcAnalysisTool.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCDataAnalyzer.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCFitWrapper.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCPulseAnalyzer.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCTriggerEfficiency.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcSincInterp.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/cmt/Makefile.RootCore create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/cmt/requirements create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/data/ZdcAnalysisConfig.conf create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/tools/RunZDCTreeAnalysis.C create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.cxx create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.h create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.C create mode 100644 ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.h diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/CMakeLists.txt b/ForwardDetectors/ZDC/ZdcAnalysis/CMakeLists.txt new file mode 100644 index 000000000000..f9fdbeb3d980 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/CMakeLists.txt @@ -0,0 +1,28 @@ +atlas_subdir( ZDCAnalysis ) + + +atlas_depends_on_subdirs( PUBLIC + Control/AthToolSupport/AsgTools + External/GaudiInterface + Event/xAOD/xAODForward + Event/xAOD/xAODTrigL1Calo + PRIVATE + Event/xAOD/xAODEventInfo + Tools/PathResolver) + +find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread MathMore Minuit Minuit2 Matrix Physics HistPainter Rint Graf Graf3d Gpad Html Postscript Gui GX11TTF GX11 ) + +atlas_add_component( ZDCAnalysis + Root/*.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} AsgTools xAODForward xAODTrigL1Calo xAODEventInfo + ) + +atlas_add_library (ZDCAnalysisLib + Root/*.cxx + PUBLIC_HEADERS ZDCAnalysis + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AsgTools xAODForward xAODTrigL1Calo xAODEventInfo + ) + +atlas_install_joboptions( share/*.py) diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCDataAnalyzer.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCDataAnalyzer.cxx new file mode 100644 index 000000000000..8f989dcfb888 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCDataAnalyzer.cxx @@ -0,0 +1,315 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <ZdcAnalysis/ZDCDataAnalyzer.h> +#include <ZdcAnalysis/ZDCPulseAnalyzer.h> + +#include <sstream> + +ZDCDataAnalyzer::ZDCDataAnalyzer(int nSample, float deltaTSample, size_t preSampleIdx, std::string fitFunction, + const ZDCModuleFloatArray& peak2ndDerivMinSamples, + const ZDCModuleFloatArray& peak2ndDerivMinThresholdsHG, + const ZDCModuleFloatArray& peak2ndDerivMinThresholdsLG, + bool forceLG) : + _nSample(nSample), _deltaTSample(deltaTSample), _preSampleIdx(preSampleIdx), + _fitFunction(fitFunction), + _forceLG(forceLG), + _debugLevel(-1), + _eventCount(0), + _moduleMask(0), + _moduleSum({0, 0}), + _moduleSumErrSq({0, 0}), + _moduleSumPreSample({0,0}), + _calibModuleSum({0, 0}), + _calibModuleSumErrSq({0,0}), + _averageTime({0, 0}), + _fail({false, false}), + _haveT0Calib(false), + _haveECalib(false), + _currentLB(-1) +{ + _moduleAnalyzers[0] = {0, 0, 0, 0}; + _moduleAnalyzers[1] = {0, 0, 0, 0}; + + _calibAmplitude[0] = {0, 0, 0, 0}; + _calibAmplitude[1] = {0, 0, 0, 0}; + + _calibTime[0] = {0, 0, 0, 0}; + _calibTime[1] = {0, 0, 0, 0}; + + // For now we are using hard-coded gain factors and pedestals + // + _HGGains[0] = {9.51122, 9.51980, 9.51122, 9.51122}; + _HGGains[1] = {9.50842, 9.49662, 9.50853, 9.50842}; + + _pedestals[0] = {100, 100, 100, 100}; + _pedestals[1] = {100, 100, 100, 100}; + + // Default "calibrations" + // + _currentECalibCoeff = {1, 1, 1, 1, 1, 1, 1, 1}; + + _currentT0OffsetsHG = {0, 0, 0, 0, 0, 0, 0, 0}; + _currentT0OffsetsLG = {0, 0, 0, 0, 0, 0, 0, 0}; + + // Construct the per-module pulse analyzers + // + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + std::ostringstream moduleTag; + moduleTag << "_s" << side << "_m" << module; + + _moduleAnalyzers[side][module] = new ZDCPulseAnalyzer(moduleTag.str().c_str(), _nSample, _deltaTSample, _preSampleIdx, + _pedestals[side][module], _HGGains[side][module], _fitFunction, + peak2ndDerivMinSamples[side][module], + peak2ndDerivMinThresholdsHG[side][module], + peak2ndDerivMinThresholdsLG[side][module]); + if (_forceLG) _moduleAnalyzers[side][module]->SetForceLG(true); + } + } + + // By default we perform quiet pulse fits + // + ZDCPulseAnalyzer::SetQuietFits(true); +} + +ZDCDataAnalyzer::~ZDCDataAnalyzer() +{ + // Delete the per-module pulse analyzers + // + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + if (!_moduleAnalyzers[side][module]) delete _moduleAnalyzers[side][module]; + } + } +} + +void ZDCDataAnalyzer::SetTauT0Values(const ZDCModuleBoolArray& fixTau1, const ZDCModuleBoolArray& fixTau2, + const ZDCModuleFloatArray& tau1, const ZDCModuleFloatArray& tau2, + const ZDCModuleFloatArray& t0HG, const ZDCModuleFloatArray& t0LG) +{ + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _moduleAnalyzers[side][module]->SetTauT0Values(fixTau1[side][module], fixTau2[side][module], + tau1[side][module], tau2[side][module], t0HG[side][module], t0LG[side][module]); + } + } +} + +void ZDCDataAnalyzer::SetADCOverUnderflowValues(const ZDCModuleFloatArray& HGOverflowADC, const ZDCModuleFloatArray& HGUnderflowADC, + const ZDCModuleFloatArray& LGOverflowADC) +{ + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _moduleAnalyzers[side][module]->SetADCOverUnderflowValues(HGOverflowADC[side][module], HGUnderflowADC[side][module], LGOverflowADC[side][module]); + } + } +} + +void ZDCDataAnalyzer::SetCutValues(const ZDCModuleFloatArray& chisqDivAmpCutHG, const ZDCModuleFloatArray& chisqDivAmpCutLG, + const ZDCModuleFloatArray& deltaT0MinHG, const ZDCModuleFloatArray& deltaT0MaxHG, + const ZDCModuleFloatArray& deltaT0MinLG, const ZDCModuleFloatArray& deltaT0MaxLG) +{ + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _moduleAnalyzers[side][module]->SetCutValues(chisqDivAmpCutHG[side][module], chisqDivAmpCutLG[side][module], + deltaT0MinHG[side][module], deltaT0MaxHG[side][module], + deltaT0MinLG[side][module], deltaT0MaxLG[side][module]); + } + } +} + +void ZDCDataAnalyzer::SetTimingCorrParams(const std::array<std::array<std::vector<float>, 4>, 2>& HGParamArr, + const std::array<std::array<std::vector<float>, 4>, 2>& LGParamArr) +{ + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _moduleAnalyzers[side][module]->SetTimingCorrParams(HGParamArr.at(side).at(module), LGParamArr.at(side).at(module)); + } + } + +} + +void ZDCDataAnalyzer::SetNonlinCorrParams(const std::array<std::array<std::vector<float>, 4>, 2>& HGNonlinCorrParams) +{ + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _moduleAnalyzers[side][module]->SetNonlinCorrParams(HGNonlinCorrParams.at(side).at(module)); + } + } +} + +void ZDCDataAnalyzer::StartEvent(int lumiBlock) +{ + if (_debugLevel > 0) { + std::cout << "Starting new event, event index = " << _eventCount << std::endl; + } + + // See if we have to load up new calibrations + // + if (lumiBlock != _currentLB) { + if (_debugLevel > 0) { + std::cout << "Starting new luminosity block " << lumiBlock << std::endl; + } + + if (_haveECalib) { + if (_debugLevel > 1) { + std::cout << "Loading energy calibrations for event " << _eventCount << ", lumi block " << lumiBlock << std::endl; + } + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + float splineLBMin = _LBDepEcalibSplines[side][module]->GetXmin(); + float splineLBMax = _LBDepEcalibSplines[side][module]->GetXmax(); + + if (lumiBlock >= splineLBMin && lumiBlock <= splineLBMax) { + _currentECalibCoeff[side][module] = _LBDepEcalibSplines[side][module]->Eval(lumiBlock); + } + else if (lumiBlock < splineLBMin) { + _currentECalibCoeff[side][module] = _LBDepEcalibSplines[side][module]->Eval(splineLBMin); + } + else { + _currentECalibCoeff[side][module] = _LBDepEcalibSplines[side][module]->Eval(splineLBMax); + } + } + } + } // end of if (_haveEcalib) { + + if (_haveT0Calib) { + if (_debugLevel > 1) { + std::cout << "Loading timing calibrations for event " << _eventCount << ", lumi block " << lumiBlock << std::endl; + } + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + float splineLBMin = _T0HGOffsetSplines[side][module]->GetXmin(); + float splineLBMax = _T0HGOffsetSplines[side][module]->GetXmax(); + + if (lumiBlock >= splineLBMin && lumiBlock <= splineLBMax) { + _currentT0OffsetsHG[side][module] = _T0HGOffsetSplines[side][module]->Eval(lumiBlock); + _currentT0OffsetsLG[side][module] = _T0LGOffsetSplines[side][module]->Eval(lumiBlock); + } + else if (lumiBlock < splineLBMin) { + _currentT0OffsetsHG[side][module] = _T0HGOffsetSplines[side][module]->Eval(splineLBMin); + _currentT0OffsetsLG[side][module] = _T0LGOffsetSplines[side][module]->Eval(splineLBMin); + } + else { + _currentT0OffsetsHG[side][module] = _T0HGOffsetSplines[side][module]->Eval(splineLBMax); + _currentT0OffsetsLG[side][module] = _T0LGOffsetSplines[side][module]->Eval(splineLBMax); + } + } + } + } // end of if (_haveT0Calib) + } + + // Initialize transient results + // + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + _dataLoaded[side][module] = false; + _moduleStatus[side][module] = 0; + _calibAmplitude[side][module] = 0; + _calibTime[side][module] = 0; + // _moduleFail[side][module] = false; + } + + _moduleSum[side] = 0; + _moduleSumErrSq[side] = 0; + _moduleSumPreSample[side] = 0; + + _calibModuleSum[side] = 0; + _calibModuleSumErrSq[side] = 0; + + _averageTime[side] = 0; + _fail[side] = false; + } + + _moduleMask = 0; + _currentLB = lumiBlock; +} + +void ZDCDataAnalyzer::LoadAndAnalyzeData(size_t side, size_t module, const std::vector<float> HGSamples, const std::vector<float> LGSamples) +{ + if (_debugLevel > 1) { + std::cout << "Loading data for event index " << _eventCount << ", side, module = " << side << ", " << module << std::endl; + + if (_debugLevel > 2) { + std::cout << " Number of HG and LG samples = " << HGSamples.size() << ", " << LGSamples.size() << std::endl; + if (_debugLevel > 3) { + for (size_t sample = 0; sample < HGSamples.size(); sample++) { + std::cout << "HGSample[" << sample << "] = " << HGSamples[sample] << std::endl; + } + } + } + } + + ZDCPulseAnalyzer* pulseAna_p = _moduleAnalyzers[side][module]; + + bool result = pulseAna_p->LoadAndAnalyzeData(HGSamples, LGSamples); + _dataLoaded[side][module] = true; + + if (result) { + if (!pulseAna_p->BadT0() && !pulseAna_p->BadChisq()) { + int moduleMaskBit = 4*side + module; + _moduleMask |= 1<< moduleMaskBit; + + float amplitude = pulseAna_p->GetAmplitude(); + float ampError = pulseAna_p->GetAmpError(); + + _calibAmplitude[side][module] = amplitude*_currentECalibCoeff[side][module]; + + float calibAmpError = ampError * _currentECalibCoeff[side][module]; + + float timeCalib = pulseAna_p->GetT0Corr(); + if (pulseAna_p->UseLowGain()) timeCalib -= _currentT0OffsetsLG[side][module]; + else timeCalib -= _currentT0OffsetsHG[side][module]; + + _calibTime[side][module] = timeCalib; + + _moduleSum[side] += amplitude; + _moduleSumErrSq[side] += ampError*ampError; + + _moduleSumPreSample[side] += pulseAna_p->GetPreSampleAmp(); + + _calibModuleSum[side] += _calibAmplitude[side][module]; + _calibModuleSumErrSq[side] += calibAmpError*calibAmpError; + + _averageTime[side] += _calibTime[side][module]*_calibAmplitude[side][module]; + } + } + else { + if (pulseAna_p->Failed()) { + if (_debugLevel >= 0) { + std::cout << "ZDCPulseAnalyzer::LoadData() returned fail for event " << _eventCount << ", side, module = " << side << ", " << module << std::endl; + } + + _fail[side] = true; + } + } + + _moduleStatus[side][module] = pulseAna_p->GetStatusMask(); +} + +bool ZDCDataAnalyzer::FinishEvent() +{ + // First make sure that all data is loaded + // + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + if (!_dataLoaded[side][module]) return false; + } + + // Divide the average times by the calibrated module sums + // + if (_calibModuleSum[side] > 0) { + _averageTime[side] /= _calibModuleSum[side]; + } + else { + _averageTime[side] = 0; + } + } + + _eventCount++; + return true; +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCFitWrapper.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCFitWrapper.cxx new file mode 100644 index 000000000000..0d146a734436 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCFitWrapper.cxx @@ -0,0 +1,150 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ZdcAnalysis/ZDCFitWrapper.h" + +ZDCFitExpFermiVariableTaus::ZDCFitExpFermiVariableTaus(std::string tag, float tmin, float tmax, bool fixTau1, bool fixTau2, float tau1, float tau2) : + ZDCFitWrapper(new TF1(("ExpFermiVariableTaus" + tag).c_str(), ZDCFermiExpFit, tmin, tmax, 5)), + _fixTau1(fixTau1), _fixTau2(fixTau2), _tau1(tau1), _tau2(tau2) +{ + TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + + theTF1->SetParName(0, "Amp"); + theTF1->SetParName(1, "T0"); + theTF1->SetParName(2, "#tau_{1}"); + theTF1->SetParName(3, "#tau_{2}"); + theTF1->SetParName(4, "s_{b}"); + + theTF1->SetParLimits(0, 0, 1024); + theTF1->SetParLimits(1, tmin, tmax); + theTF1->SetParLimits(2, 2.5, 6); + theTF1->SetParLimits(3, 10, 60); + theTF1->SetParLimits(4, -0.005, 10); + + if (_fixTau1) theTF1->FixParameter(2, _tau1); + if (_fixTau2) theTF1->FixParameter(3, _tau2); +} + +void ZDCFitExpFermiVariableTaus::Initialize(float initialAmp, float initialT0) +{ + TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + + theTF1->SetParameter(0, initialAmp); + theTF1->SetParameter(1, initialT0); + + if (!_fixTau1) theTF1->SetParameter(2, _tau1); + if (!_fixTau2) theTF1->SetParameter(3, _tau2); + + theTF1->SetParameter(4, 0); +} + +ZDCFitExpFermiFixedTaus::ZDCFitExpFermiFixedTaus(std::string tag, float tmin, float tmax, float tau1, float tau2) : + ZDCFitWrapper(new TF1(("ExpFermiFixedTaus" + tag).c_str(), this, tmin, tmax, 3)), + _tau1(tau1), _tau2(tau2) +{ + TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + + theTF1->SetParLimits(0, 0, 1024); + theTF1->SetParLimits(1, tmin, tmax); + theTF1->SetParLimits(2, -0.005, 10); + + theTF1->SetParName(0, "Amp"); + theTF1->SetParName(1, "T0"); + theTF1->SetParName(2, "s_{b}"); + + // Now create the reference function that we use to evaluate ExpFermiFit more efficiently + // + std::string funcNameRefFunc = "ExpFermiFixedTausRefFunc" + tag; + + _expFermiFunc = new TF1(funcNameRefFunc.c_str(), ZDCFermiExpFit, -50, 100, 5); + + _expFermiFunc->SetParameter(0, 1); + _expFermiFunc->SetParameter(1, 0); + _expFermiFunc->SetParameter(2, _tau1); + _expFermiFunc->SetParameter(3, _tau2); + _expFermiFunc->SetParameter(4, 0); + + _norm = 1./_expFermiFunc->GetMaximum(); + _timeCorr = 0.5*_tau1*std::log(_tau2/_tau1 - 1.0); +} + +void ZDCFitExpFermiFixedTaus::Initialize(float initialAmp, float initialT0) +{ + GetWrapperTF1()->SetParameter(0, initialAmp); + GetWrapperTF1()->SetParameter(1, initialT0); + GetWrapperTF1()->SetParameter(2, 0); +} + +ZDCFitExpFermiPrePulse::ZDCFitExpFermiPrePulse(std::string tag, float tmin, float tmax, float tau1, float tau2) : + ZDCPrePulseFitWrapper(new TF1(("ExpFermiPrePulse" + tag).c_str(), this, tmin, tmax, 5)), + _tau1(tau1), _tau2(tau2) +{ + // Create the reference function that we use to evaluate ExpFermiFit more efficiently + // + std::string funcNameRefFunc = "ExpFermiPerPulseRefFunc" + tag; + + _expFermiFunc = new TF1(funcNameRefFunc.c_str(), ZDCFermiExpFit, -50, 100, 5); + + _expFermiFunc->SetParameter(0, 1); + _expFermiFunc->SetParameter(1, 0); + _expFermiFunc->SetParameter(2, _tau1); + _expFermiFunc->SetParameter(3, _tau2); + _expFermiFunc->SetParameter(4, 0); + + _norm = 1./_expFermiFunc->GetMaximum(); + _timeCorr = 0.5*_tau1*std::log(_tau2/_tau1 - 1.0); + + // Now set up the actual TF1 + // + TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + + theTF1->SetParLimits(0, 0, 1024); + theTF1->SetParLimits(1, tmin, tmax); + theTF1->SetParLimits(2, 0, 1024); + theTF1->SetParLimits(3, -20, 10); + theTF1->SetParLimits(4, -0.005, 10); + + theTF1->SetParName(0, "Amp"); + theTF1->SetParName(1, "T0"); + theTF1->SetParName(2, "Amp_{pre}"); + theTF1->SetParName(3, "T0_{pre}"); + theTF1->SetParName(4, "s_{b}"); + +} + +void ZDCFitExpFermiPrePulse::Initialize(float initialAmp, float initialT0) +{ + GetWrapperTF1()->SetParameter(0, initialAmp); + GetWrapperTF1()->SetParameter(1, initialT0); + GetWrapperTF1()->SetParameter(2, 5); + GetWrapperTF1()->SetParameter(3, 0); + GetWrapperTF1()->SetParameter(4, 0); +} + +double ZDCFermiExpFit(double* xvec, double* pvec) +{ + static const float offsetScale = 0; + + double t = xvec[0]; + + double amp = pvec[0]; + double t0 = pvec[1]; + double tau1 = pvec[2]; + double tau2 = pvec[3]; + double linSlope = pvec[4]; + + double tauRatio = tau2/tau1; + double tauRatioMinunsOne = tauRatio - 1; + + double norm = ( std::exp(-offsetScale/tauRatio)*pow(1./tauRatioMinunsOne, 1./(1 + tauRatio))/ + ( 1 + pow(1./tauRatioMinunsOne, 1./(1 + 1/tauRatio))) ); + + double deltaT = t - (t0 - offsetScale*tau1); + if (deltaT < 0) deltaT = 0; + + double expTerm = std::exp(-deltaT/tau2); + double fermiTerm = 1./(1. + std::exp(-(t - t0)/tau1)); + + return amp*expTerm*fermiTerm/norm + linSlope*t; +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCPulseAnalyzer.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCPulseAnalyzer.cxx new file mode 100644 index 000000000000..141c2859f98a --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCPulseAnalyzer.cxx @@ -0,0 +1,506 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ZdcAnalysis/ZDCPulseAnalyzer.h" + +#include <numeric> +#include <algorithm> + +#include "TFitResult.h" +#include "TFitResultPtr.h" + +bool ZDCPulseAnalyzer::_quietFits = true; +std::string ZDCPulseAnalyzer::_fitOptions = ""; + +ZDCPulseAnalyzer::ZDCPulseAnalyzer(std::string tag, int Nsample, float deltaTSample, size_t preSampleIdx, int pedestal, + float gainHG, std::string fitFunction, int peak2ndDerivMinSample, + float peak2ndDerivMinThreshHG, float peak2ndDerivMinThreshLG) : + _tag(tag), _Nsample(Nsample), _deltaTSample(deltaTSample), _preSampleIdx(preSampleIdx), + _pedestal(pedestal), _gainHG(gainHG), _forceLG(false), _fitFunction(fitFunction), + _peak2ndDerivMinSample(peak2ndDerivMinSample), + _peak2ndDerivMinThreshHG(peak2ndDerivMinThreshHG), + _peak2ndDerivMinThreshLG(peak2ndDerivMinThreshLG), + _haveTimingCorrections(false), _haveNonlinCorr(false), _initializedFits(false), + _ADCSamplesHGSub(Nsample, 0), _ADCSamplesLGSub(Nsample, 0), + _ADCSSampSigHG(Nsample, 1), _ADCSSampSigLG(Nsample, 1), // By default the ADC uncertainties are set to one + _samplesSub(Nsample, 0), + _defaultFitWrapper(0), _prePulseFitWrapper(0) +{ + // Create the histogram used for fitting + // + _tmin = -deltaTSample/2; + _tmax = _tmin + ((float) Nsample)*deltaTSample; + + std::string histName = "ZDCFitHist" + tag; + + _fitHist = new TH1F(histName.c_str(), "", _Nsample, _tmin, _tmax); + _fitHist->SetDirectory(0); + + SetDefaults(); + Reset(); +} + +ZDCPulseAnalyzer::~ZDCPulseAnalyzer() +{ + if (!_defaultFitWrapper) delete _defaultFitWrapper; + if (!_prePulseFitWrapper) delete _prePulseFitWrapper; +} + +void ZDCPulseAnalyzer::SetDefaults() +{ + _nominalTau1 = 4; + _nominalTau2 = 21; + + _fixTau1 = false; + _fixTau2 = false; + + _HGOverflowADC = 900; + _HGUnderflowADC = 20; + _LGOverflowADC = 1000; + + _chisqDivAmpCutLG = 100; + _chisqDivAmpCutHG = 100; + + _T0CutLowLG = _tmin; + _T0CutLowHG = _tmin; + + _T0CutHighLG = _tmax; + _T0CutHighHG = _tmax; + + _LGT0CorrParams.assign(4, 0); + _HGT0CorrParams.assign(4, 0); + + _fitOptions = "s"; +} + +void ZDCPulseAnalyzer::Reset() +{ + _haveData = false; + _havePulse = false; + _fail = false; + + _HGOverflow = false; + _HGUnderflow = false; + + _LGOverflow = false; + _LGUnderflow = false; + + _PSHGOverUnderflow = false; + + _prePulse = false; + _fitFailed = false; + + _useLowGain = false; + + _badT0 = false; + _badChisq = false; + + _fitAmplitude = 0; + _fitT0 = -100; + _fitChisq = 0; + + _fitT0Corr = -100; + _amplitude = 0; + _ampError = 0; + _preSampleAmp = 0; + _bkgdMaxFraction = 0; + + _samplesSub.clear(); + _samplesDeriv.clear(); + _samplesDeriv2nd.clear(); +} + +void ZDCPulseAnalyzer::SetTauT0Values(bool fixTau1, bool fixTau2, float tau1, float tau2, float t0HG, float t0LG) +{ + _fixTau1 = fixTau1; + _fixTau2 = fixTau2; + _nominalTau1 = tau1; + _nominalTau2 = tau2; + + _nominalT0HG = t0HG; + _nominalT0LG = t0LG; + + _initializedFits = false; +} + +void ZDCPulseAnalyzer::SetADCOverUnderflowValues(int HGOverflowADC, int HGUnderflowADC, int LGOverflowADC) +{ + _HGOverflowADC = HGOverflowADC; + _LGOverflowADC = LGOverflowADC; + _HGUnderflowADC = HGUnderflowADC; +} + +void ZDCPulseAnalyzer::SetCutValues(float chisqDivAmpCutHG, float chisqDivAmpCutLG, + float deltaT0MinHG, float deltaT0MaxHG, + float deltaT0MinLG, float deltaT0MaxLG) +{ + _chisqDivAmpCutHG = chisqDivAmpCutHG; + _chisqDivAmpCutLG = chisqDivAmpCutLG; + + _T0CutLowHG = deltaT0MinHG; + _T0CutLowLG = deltaT0MinLG; + + _T0CutHighHG = deltaT0MaxHG; + _T0CutHighLG = deltaT0MaxLG; +} + +void ZDCPulseAnalyzer::SetupFitFunctions() +{ + if (!_defaultFitWrapper) delete _defaultFitWrapper; + if (!_prePulseFitWrapper) delete _prePulseFitWrapper; + + if (_fitFunction == "FermiExp") { + if (!_fixTau1 || !_fixTau2) { + // + // Use the variable tau version of the expFermiFit + // + _defaultFitWrapper = new ZDCFitExpFermiVariableTaus(_tag, _tmin, _tmax, _fixTau1, _fixTau2, _nominalTau1, _nominalTau2); + } + else { + _defaultFitWrapper = new ZDCFitExpFermiFixedTaus(_tag, _tmin, _tmax, _nominalTau1, _nominalTau2); + } + + _prePulseFitWrapper = new ZDCFitExpFermiPrePulse(_tag, _tmin, _tmax, _nominalTau1, _nominalTau2); + } + else { + throw; + } + + _initializedFits = true; +} + +bool ZDCPulseAnalyzer::LoadAndAnalyzeData(std::vector<float> ADCSamplesHG, std::vector<float> ADCSamplesLG) +{ + if (!_initializedFits) SetupFitFunctions(); + + // Clear any transient data + // + Reset(); + + // Make sure we have the right number of samples. Should never fail. necessry? + // + if (ADCSamplesHG.size() != _Nsample || ADCSamplesLG.size() != _Nsample) { + _fail = true; + return false; + } + + // Now do pedestal subtraction and check for overflows + // + for (size_t isample = 0; isample < _Nsample; isample++) { + float ADCHG = ADCSamplesHG[isample]; + float ADCLG = ADCSamplesLG[isample]; + + if (ADCHG > _HGOverflowADC) { + _HGOverflow = true; + + if (isample == _preSampleIdx) _PSHGOverUnderflow = true; + } + else if (ADCHG < _HGUnderflowADC) { + _HGUnderflow = true; + + if (isample == _preSampleIdx) _PSHGOverUnderflow = true; + } + + if (ADCLG > _LGOverflowADC) { + _LGOverflow = true; + _fail = true; + _amplitude = 1024 * _gainHG; // Give a vale here even though we know it's wrong because + // the user may not check the return value and we know that + // amplitude is bigger than this + } + + if (ADCLG == 0) { + _LGUnderflow = true; + _fail = true; + } + + _ADCSamplesHGSub[isample] = ADCHG - _pedestal; + _ADCSamplesLGSub[isample] = ADCLG - _pedestal; + } + + // if (_fail) return false; + + // Now we actually do the analysis using the high or low gain samples as determined + // on the basis of the above analysis + // + _useLowGain = _HGUnderflow || _HGOverflow || _forceLG; + + if (_useLowGain) { + bool result = AnalyzeData(_ADCSamplesLGSub, _ADCSSampSigLG, _LGT0CorrParams, _chisqDivAmpCutLG, + _T0CutLowLG, _T0CutHighLG, _peak2ndDerivMinThreshLG); + if (result) { + // + // Multiply amplitude by gain factor + // + _amplitude = _fitAmplitude * _gainHG; + _ampError = _fitAmpError * _gainHG; + _preSampleAmp = _preSample * _gainHG; + } + + return result; + } + else { + bool result = AnalyzeData(_ADCSamplesHGSub, _ADCSSampSigHG, _HGT0CorrParams, _chisqDivAmpCutHG, + _T0CutLowHG, _T0CutHighHG, _peak2ndDerivMinThreshHG); + if (result) { + _preSampleAmp = _preSample; + _amplitude = _fitAmplitude; + _ampError = _fitAmpError; + + // If we have a non-linear correction, apply it here + // + if (_haveNonlinCorr) { + float ampCorrFact = _amplitude/1000. - 0.5; + float corrFactor = 1./(1. + _nonLinCorrParams[0]*ampCorrFact + _nonLinCorrParams[1]*ampCorrFact*ampCorrFact); + + _amplitude *= corrFactor; + _ampError *= corrFactor; + } + } + + return result; + } +} + +bool ZDCPulseAnalyzer::AnalyzeData(const std::vector<float>& samples, // The samples used for this event + const std::vector<float>& samplesSig, // The "resolution" on the ADC value + const std::vector<float>& t0CorrParams, // The parameters used to correct the t0 + float maxChisqDivAmp, // The maximum chisq / amplitude ratio + float minT0Corr, float maxT0Corr, // The minimum and maximum corrected T0 values + float peak2ndDerivMinThresh + ) +{ + // Do the presample subtraction using a lambda function + // + float preSample = samples[_preSampleIdx]; + _preSample = preSample; + _samplesSub = samples; + + std::for_each(_samplesSub.begin(), _samplesSub.end(), [=] (float& adcUnsub) {return adcUnsub -= preSample;} ); + + // Find maximum and minimum values + // + std::pair<SampleCIter, SampleCIter> minMaxIters = std::minmax_element(_samplesSub.begin(), _samplesSub.end()); + SampleCIter minIter = minMaxIters.first; + SampleCIter maxIter = minMaxIters.second; + + _maxADCValue = *maxIter; + _minADCValue = *minIter; + + float maxMinADCDiff = _maxADCValue - _minADCValue; + + _maxSampl = std::distance(_samplesSub.cbegin(), maxIter); + _minSampl = std::distance(_samplesSub.cbegin(), minIter); + + // Calculate first and 2nd "derivatives" + // + std::vector<float> deriv(_Nsample, 0); + std::adjacent_difference(samples.begin(), samples.end(), deriv.begin()); + + // Save the derivatives, dropping the useless first element + // + _samplesDeriv.insert(_samplesDeriv.begin(), deriv.begin() + 1, deriv.end()); + + std::vector<float> deriv2nd(_Nsample, 0); + std::adjacent_difference(_samplesDeriv.begin(), _samplesDeriv.end(), deriv2nd.begin()); + + // Save the second derivatives, dropping the useless first element + // + _samplesDeriv2nd.insert(_samplesDeriv2nd.begin(), deriv2nd.begin() + 1, deriv2nd.end()); + + // Find the sampl which has the lowest 2nd derivative + // + SampleCIter minDeriv2ndIter = std::min_element(_samplesDeriv2nd.begin(), _samplesDeriv2nd.end()); + + _minDeriv2nd = *minDeriv2ndIter; + _minDeriv2ndIndex = std::distance(_samplesDeriv2nd.cbegin(), minDeriv2ndIter); + + // The ket test for presence of a pulse: is the minimum 2nd derivative in the right place and is it + // large enough (sufficiently negative) + // + if (std::abs(_minDeriv2ndIndex - _peak2ndDerivMinSample) <= 1 && _minDeriv2nd <= peak2ndDerivMinThresh) { + _havePulse = true; + } + else { + _havePulse = false; + } + + // Now decide whether we have a preceeding pulse or not + // + + // Have to be careful with the derivative indices, but test up to minDeriv2ndIndex - 1 + // + bool haveNegDeriv = false; + + for (int isampl = 0; isampl < _minDeriv2ndIndex; isampl++) { + + // If any of the derivatives prior to the peak (as determined by the 2nd derivative) is negative + // Then we are on the tailing edge of a previous pulse. + // + if (_samplesDeriv[isampl] < 0) { + + // + // Put a threshold on the derivative as a fraction of the difference between max and min so that + // we don't waste lots of time for insignificant prepulses. + // + if (std::abs(_samplesDeriv[isampl]) / (_maxADCValue - _minADCValue + 1) > 0.05) _prePulse = true; + + // Also, if we have two negative derivatives in a row, we have a prepulse + // + if (haveNegDeriv) _prePulse = true; + else haveNegDeriv = true; + } + + // If any of the 2nd derivatives before the minium are negative, we have the possibility of positive + // preceeding pulse + // + if (_samplesDeriv2nd[isampl] < 0 && _samplesDeriv2nd[isampl + 1] > 0) _prePulse = true; + } + + // Additional specific tests for pre pulses etc. + // + if (_deltaTSample < 20) { + // + // Don't do this check for the 40 MHz data as the pulse often drops below baseline + // due to overshoot, not pre-pulses + // + if (_samplesSub[_Nsample - 1] <= 0 || + _samplesSub[_Nsample - 1] <= _samplesSub[_preSampleIdx+1] ) _prePulse = true; + + } + + + FillHistogram(_samplesSub, samplesSig); + + // Stop now if we have no pulse + // + if (_fail || !_havePulse) return false; + + DoFit(); + + if (!FitFailed()) { + _fitT0Corr = _fitT0; + + if (_haveTimingCorrections) { + + // + // We correct relative to the middle of the amplitude range, divided by 100 to make corrections smaller + // + float t0CorrFact = (_fitAmplitude - 500)/100.; + + float correction = (t0CorrParams[0] + t0CorrParams[1]*t0CorrFact + t0CorrParams[2]*t0CorrFact*t0CorrFact + + t0CorrParams[3]*t0CorrFact*t0CorrFact*t0CorrFact); + + _fitT0Corr -= correction; + } + + + // Now check for valid chisq and valid time + // + if (_fitChisq / _fitAmplitude > maxChisqDivAmp) _badChisq = true; + if (_fitT0Corr < minT0Corr || _fitT0Corr > maxT0Corr) _badT0 = true; + + // std::cout << "Testing t0 cut: t0corr = " << _fitT0Corr << ", min max cuts = " << minT0Corr << ", " << maxT0Corr << std::endl; + } + + return !_fitFailed; +} + +void ZDCPulseAnalyzer::DoFit() +{ + // Set the initial values + // + float ampInitial = _maxADCValue - _minADCValue; + float t0Initial = (_useLowGain ? _nominalT0LG : _nominalT0HG); + + ZDCFitWrapper* fitWrapper = _defaultFitWrapper; + if (PrePulse()) fitWrapper = _prePulseFitWrapper; + + fitWrapper->Initialize(ampInitial, t0Initial); + if (PrePulse() && _samplesDeriv[0] < 0) { + (static_cast<ZDCPrePulseFitWrapper*>(_prePulseFitWrapper))->SetInitialPrePulseT0(-10); + } + + // Now perform the fit + // + std::string options = _fitOptions; + if (QuietFits()) options += "Q0"; + options += "s"; + + TFitResultPtr result_ptr = _fitHist->Fit(fitWrapper->GetWrapperTF1(), options.c_str()); + + int fitStatus = result_ptr; + if (fitStatus != 0) { + TFitResultPtr try2Result_ptr = _fitHist->Fit(fitWrapper->GetWrapperTF1(), options.c_str()); + if ((int) try2Result_ptr != 0) _fitFailed = true; + } + else _fitFailed = false; + + // if (!_fitFailed) { + _bkgdMaxFraction = fitWrapper->GetBkgdMaxFraction(); + if (std::abs(_bkgdMaxFraction) > 0.25) { + options += "e"; + _fitHist->Fit(fitWrapper->GetWrapperTF1(), options.c_str()); + _bkgdMaxFraction = fitWrapper->GetBkgdMaxFraction(); + } + + _fitAmplitude = fitWrapper->GetAmplitude(); + _fitT0 = fitWrapper->GetTime() - t0Initial; + _fitChisq = result_ptr->Chi2(); + + _fitTau1 = fitWrapper->GetTau1(); + _fitTau2 = fitWrapper->GetTau2(); + + _fitAmpError = fitWrapper->GetAmpError(); + // } +} + +void ZDCPulseAnalyzer::Dump() const +{ + std::cout << "ZDCPulseAnalyzer dump for tag = " << _tag << std::endl; + + std::cout << "Presample index, value = " << _preSampleIdx << ", " << _preSample << std::endl; + + std::cout << "samplesSub "; + for (size_t sample = 0; sample < _samplesSub.size(); sample++) { + std::cout << ", [" << sample << "] = " << _samplesSub[sample]; + } + std::cout << std::endl; + + std::cout << "samplesDeriv "; + for (size_t sample = 0; sample < _samplesDeriv.size(); sample++) { + std::cout << ", [" << sample << "] = " << _samplesDeriv[sample]; + } + std::cout << std::endl; + + std::cout << "samplesDeriv2nd "; + for (size_t sample = 0; sample < _samplesDeriv2nd.size(); sample++) { + std::cout << ", [" << sample << "] = " << _samplesDeriv2nd[sample]; + } + std::cout << std::endl; + + std::cout << "minimum 2nd deriv sample, value = " << _minDeriv2ndIndex << ", " << _minDeriv2nd << std::endl; +} + +unsigned int ZDCPulseAnalyzer::GetStatusMask() const +{ + unsigned int statusMask = 0; + + if (HavePulse()) statusMask |= 1 << PulseBit; + if (UseLowGain()) statusMask |= 1 << LowGainBit; + if (Failed()) statusMask |= 1 << FailBit; + if (HGOverflow()) statusMask |= 1 << HGOverflowBit; + + if (HGUnderflow()) statusMask |= 1 << HGUnderflowBit; + if (PSHGOverUnderflow()) statusMask |= 1 << PSHGOverUnderflowBit; + if (LGOverflow()) statusMask |= 1 << LGOverflowBit; + if (LGUnderflow()) statusMask |= 1 << LGUnderflowBit; + + if (FitFailed()) statusMask |= 1 << FitFailedBit; + if (PrePulse()) statusMask |= 1 << PrePulseBit; + if (BadChisq()) statusMask |= 1 << BadChisqBit; + if (BadT0()) statusMask |= 1 << BadT0Bit; + + return statusMask; +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCTriggerEfficiency.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCTriggerEfficiency.cxx new file mode 100644 index 000000000000..d1f702893b66 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZDCTriggerEfficiency.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ZdcAnalysis/ZDCTriggerEfficiency.h" +#include <vector> + +using namespace std; +float ZDCTriggerEfficiency::GetEfficiency(int side, float ADCSum){ + double alpha = _currentParams[side][0]; + double beta = _currentParams[side][1]; + double theta = _currentParams[side][2]; + if(alpha<10e-5||beta<10e-5||theta<10e-5) + { + return -1; + } + float m = exp(-ADCSum/theta); + float p = exp(-(ADCSum - alpha) / beta); + float efficiency = (1 - m) / (1 + p); + return efficiency; +} + +std::pair<float, float> ZDCTriggerEfficiency::GetEfficiencyAndError(int side, float ADCSum){ + double alpha = _currentParams[side][0]; + double beta = _currentParams[side][1]; + double theta = _currentParams[side][2]; + if(alpha<10e-5||beta<10e-5||theta<10e-5) + { + return std::make_pair(-1,-1); + } + + double alphaErr = _currentParamErrors[side][0]; + double betaErr = _currentParamErrors[side][1]; + double thetaErr = _currentParamErrors[side][2]; + + double cov_alpha_beta = _currentCorrCoefff[side][0]; + double cov_alpha_theta = _currentCorrCoefff[side][1]; + double cov_beta_theta = _currentCorrCoefff[side][2]; + + float m = exp(-ADCSum/theta); + float n = exp(alpha/beta); + float p = exp(-(ADCSum - alpha) / beta); + float efficiency = (1 - m) / (1 + p); + float dda = (1 - m) * -n / beta / (1 + p) / (1 + p); + float ddb = (1 - m) * -p / pow(1 + p, 2.0) * ADCSum / beta / beta; + float ddt = -ADCSum * m / theta / theta / (1 + p); + + float efficiencyErr = sqrt( + alphaErr * alphaErr * dda * dda + + betaErr * betaErr * ddb * ddb + + thetaErr * thetaErr * ddt * ddt + + 2 * cov_alpha_beta * dda * ddb + + 2 * cov_alpha_theta * dda * ddt + + 2 * cov_beta_theta * ddb * ddt); + if(alphaErr * alphaErr * dda * dda + + betaErr * betaErr * ddb * ddb + + thetaErr * thetaErr * ddt * ddt + + 2 * cov_alpha_beta * dda * ddb + + 2 * cov_alpha_theta * dda * ddt + + 2 * cov_beta_theta * ddb * ddt<0) efficiencyErr = 0; + + return std::make_pair(efficiency, efficiencyErr); +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx new file mode 100644 index 000000000000..535aa78f78b8 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysisTool.cxx @@ -0,0 +1,947 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ZdcAnalysis/ZdcAnalysisTool.h" +#include "TGraph.h" +#include "TEnv.h" +#include "TSystem.h" +#include "ZdcAnalysis/ZdcSincInterp.h" +#include "xAODEventInfo/EventInfo.h" +#include "TFile.h" +#include <sstream> +#include <memory> +#include <xAODForward/ZdcModuleAuxContainer.h> +#include "PathResolver/PathResolver.h" + +namespace ZDC +{ + + ZdcAnalysisTool::ZdcAnalysisTool(const std::string& name) : asg::AsgTool(name), m_name(name), m_init(false), + m_writeAux(false), m_eventReady(false), + m_runNumber(0), m_lumiBlock(0), + m_splines{0,0,0,0,0,0,0,0}, m_zdcTriggerEfficiency(0) +{ + +#ifndef XAOD_STANDALONE + declareInterface<IZdcAnalysisTool>(this); +#endif + + declareProperty("ZdcModuleContainerName",m_zdcModuleContainerName="ZdcModules","Location of ZDC processed data"); + declareProperty("Configuration", m_configuration = "PbPb2015"); + declareProperty("FlipEMDelay",m_flipEMDelay=false); + declareProperty("LowGainOnly",m_lowGainOnly=false); + declareProperty("WriteAux",m_writeAux=true); + declareProperty("AuxSuffix",m_auxSuffix=""); + + // The following job properties enable/disable and affect the calibration of the ZDC energies + // + declareProperty("DoCalib",m_doCalib=true); + declareProperty("ZdcAnalysisConfigPath",m_zdcAnalysisConfigPath="$ROOTCOREBIN/data/ZdcAnalysis","ZDC Analysis config file path"); + //declareProperty("ForceCalibRun",m_forceCalibRun=287931); // last run of Pb+Pb 2015 + declareProperty("ForceCalibRun",m_forceCalibRun=-1); // last run of Pb+Pb 2015 + declareProperty("ForceCalibLB",m_forceCalibLB=814); // last LB of Pb+Pb 2015 + + // The following parameters are primarily used for the "default" configuration, but also may be + // use to modify/tailor other configurations + // + declareProperty("NumSampl", m_numSample = 7); + declareProperty("DeltaTSample", m_deltaTSample = 25); + declareProperty("Presample", m_presample = 0); + declareProperty("PeakSample", m_peakSample = 2); + declareProperty("Peak2ndDerivThresh", m_Peak2ndDerivThresh = 10); + + declareProperty("T0", m_t0 = 50); + declareProperty("Tau1", m_tau1 = 5); + declareProperty("Tau2", m_tau2 = 25); + declareProperty("FixTau1", m_fixTau1 = false); + declareProperty("FixTau2", m_fixTau2 = false); + + declareProperty("DeltaTCut", m_deltaTCut = 25); + declareProperty("ChisqRatioCut", m_ChisqRatioCut = 10); + + //ATH_MSG_INFO("Creating ZdcAnalysisoTool named " << m_name); + //ATH_MSG_INFO("ZDC config file path " << m_zdcAnalysisConfigPath); + +} + +ZdcAnalysisTool::~ZdcAnalysisTool() +{ + ATH_MSG_DEBUG("Deleting ZdcAnalysisTool named " << m_name); + //SafeDelete( m_zdcDataAnalyzer ); +} + +void ZdcAnalysisTool::initializeTriggerEffs(unsigned int runNumber) +{ + if (!m_zdcTriggerEfficiency) + { + m_zdcTriggerEfficiency = new ZDCTriggerEfficiency(); + } + + std::string filename = PathResolverFindCalibFile( ("ZdcAnalysis/"+m_zdcTriggerEffParamsFileName) ); + //std::cout << "Found trigger config file " << filename << std::endl; + + TFile* file = TFile::Open(filename.c_str()); + if (!file->IsOpen()) + { + ATH_MSG_ERROR("No trigger efficiencies at " << filename); + return; + } + + //file->Print(); + + stringstream Aalpha_name; + Aalpha_name<<"A_alpha_"<<runNumber; + TSpline3* par_A_alpha = (TSpline3*)file->GetObjectChecked(Aalpha_name.str().c_str(),"TSpline3"); + + if (!par_A_alpha) + { + ATH_MSG_ERROR("No trigger efficiencies for run number " << runNumber); + m_doCalib = false; + } + + stringstream Abeta_name; + Abeta_name<<"A_beta_"<<runNumber; + TSpline3* par_A_beta = (TSpline3*)file->GetObjectChecked(Abeta_name.str().c_str(),"TSpline3"); + stringstream Atheta_name; + Atheta_name<<"A_theta_"<<runNumber; + TSpline3* par_A_theta = (TSpline3*)file->GetObjectChecked(Atheta_name.str().c_str(),"TSpline3"); + + stringstream Calpha_name; + Calpha_name<<"C_alpha_"<<runNumber; + TSpline3* par_C_alpha = (TSpline3*)file->GetObjectChecked(Calpha_name.str().c_str(),"TSpline3"); + stringstream Cbeta_name; + Cbeta_name<<"C_beta_"<<runNumber; + TSpline3* par_C_beta = (TSpline3*)file->GetObjectChecked(Cbeta_name.str().c_str(),"TSpline3"); + stringstream Ctheta_name; + Ctheta_name<<"C_theta_"<<runNumber; + TSpline3* par_C_theta = (TSpline3*)file->GetObjectChecked(Ctheta_name.str().c_str(),"TSpline3"); + + stringstream Err_Aalpha_name; + Err_Aalpha_name<<"A_alpha_error_"<<runNumber; + TSpline3* parErr_A_alpha = (TSpline3*)file->GetObjectChecked(Err_Aalpha_name.str().c_str(),"TSpline3"); + stringstream Err_Abeta_name; + Err_Abeta_name<<"A_beta_error_"<<runNumber; + TSpline3* parErr_A_beta = (TSpline3*)file->GetObjectChecked(Err_Abeta_name.str().c_str(),"TSpline3"); + stringstream Err_Atheta_name; + Err_Atheta_name<<"A_theta_error_"<<runNumber; + TSpline3* parErr_A_theta = (TSpline3*)file->GetObjectChecked(Err_Atheta_name.str().c_str(),"TSpline3"); + + stringstream Err_Calpha_name; + Err_Calpha_name<<"C_alpha_error_"<<runNumber; + TSpline3* parErr_C_alpha = (TSpline3*)file->GetObjectChecked(Err_Calpha_name.str().c_str(),"TSpline3"); + stringstream Err_Cbeta_name; + Err_Cbeta_name<<"C_beta_error_"<<runNumber; + TSpline3* parErr_C_beta = (TSpline3*)file->GetObjectChecked(Err_Cbeta_name.str().c_str(),"TSpline3"); + stringstream Err_Ctheta_name; + Err_Ctheta_name<<"C_theta_error_"<<runNumber; + TSpline3* parErr_C_theta = (TSpline3*)file->GetObjectChecked(Err_Ctheta_name.str().c_str(),"TSpline3"); + + + stringstream Cov_A_alpha_beta_name; + Cov_A_alpha_beta_name<<"cov_A_alpha_beta_"<<runNumber; + TSpline3* cov_A_alpha_beta = (TSpline3*)file->GetObjectChecked(Cov_A_alpha_beta_name.str().c_str(),"TSpline3"); + stringstream Cov_A_alpha_theta_name; + Cov_A_alpha_theta_name<<"cov_A_alpha_theta_"<<runNumber; + TSpline3* cov_A_alpha_theta = (TSpline3*)file->GetObjectChecked(Cov_A_alpha_theta_name.str().c_str(),"TSpline3"); + stringstream Cov_A_beta_theta_name; + Cov_A_beta_theta_name<<"cov_A_beta_theta_"<<runNumber; + TSpline3* cov_A_beta_theta = (TSpline3*)file->GetObjectChecked(Cov_A_beta_theta_name.str().c_str(),"TSpline3"); + + stringstream Cov_C_alpha_beta_name; + Cov_C_alpha_beta_name<<"cov_C_alpha_beta_"<<runNumber; + TSpline3* cov_C_alpha_beta = (TSpline3*)file->GetObjectChecked(Cov_C_alpha_beta_name.str().c_str(),"TSpline3"); + stringstream Cov_C_alpha_theta_name; + Cov_C_alpha_theta_name<<"cov_C_alpha_theta_"<<runNumber; + TSpline3* cov_C_alpha_theta = (TSpline3*)file->GetObjectChecked(Cov_C_alpha_theta_name.str().c_str(),"TSpline3"); + stringstream Cov_C_beta_theta_name; + Cov_C_beta_theta_name<<"cov_C_beta_theta_"<<runNumber; + TSpline3* cov_C_beta_theta = (TSpline3*)file->GetObjectChecked(Cov_C_beta_theta_name.str().c_str(),"TSpline3"); + + std::array<std::vector<TSpline3*>, 2> effparams; + std::array<std::vector<TSpline3*>, 2> effparamErrors; + std::array<std::vector<TSpline3*>, 2> effparamsCorrCoeffs; + //side0: C; side1: A + effparams[0] = {par_C_alpha, par_C_beta, par_C_theta}; + effparams[1] = {par_A_alpha, par_A_beta, par_A_theta}; + effparamErrors[0] = {parErr_C_alpha, parErr_C_beta, parErr_C_theta}; + effparamErrors[1] = {parErr_A_alpha, parErr_A_beta, parErr_A_theta}; + effparamsCorrCoeffs[0] = {cov_C_alpha_beta, cov_C_alpha_theta, cov_C_beta_theta}; + effparamsCorrCoeffs[1] = {cov_A_alpha_beta, cov_A_alpha_theta, cov_A_beta_theta}; + + m_zdcTriggerEfficiency->SetEffParamsAndErrors(effparams, effparamErrors); + m_zdcTriggerEfficiency->SetEffParamCorrCoeffs(effparamsCorrCoeffs); + + return; + +} + +ZDCDataAnalyzer* ZdcAnalysisTool::initializeDefault() +{ + // We rely completely on the default parameters specified in the job properties to control: + // # samples + // frequency (more precisely, time/sample) + // which sample to use as the pre-sample + // where to expact the maxim of the peak (min 2nd derivative) + // thresholds on the 2nd derivative for valid pulses + // whether to fix the tau values in the pulse fitting + // the default tau values + // the nominal T0 + // delta T and chisq/amp cuts + // + // For now, we continue to use hard-coded values for the maximum and minimum ADC values + // For now we also use the FermiExp pulse model. + + ZDCDataAnalyzer::ZDCModuleFloatArray tau1, tau2, peak2ndDerivMinSamples, t0; + ZDCDataAnalyzer::ZDCModuleFloatArray peak2ndDerivMinThresholdsHG, peak2ndDerivMinThresholdsLG; + ZDCDataAnalyzer::ZDCModuleFloatArray deltaT0CutLow, deltaT0CutHigh, chisqDivAmpCut; + ZDCDataAnalyzer::ZDCModuleBoolArray fixTau1Arr, fixTau2Arr; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + fixTau1Arr[side][module] = m_fixTau1; + fixTau2Arr[side][module] = m_fixTau2; + tau1[side][module] = m_tau1; + tau2[side][module] = m_tau2; + + peak2ndDerivMinSamples[side][module] = m_peakSample; + peak2ndDerivMinThresholdsHG[side][module] = -m_Peak2ndDerivThresh; + peak2ndDerivMinThresholdsLG[side][module] = -m_Peak2ndDerivThresh/2; + + t0[side][module] = m_t0; + deltaT0CutLow[side][module] = -m_deltaTCut; + deltaT0CutHigh[side][module] = m_deltaTCut; + chisqDivAmpCut[side][module] = m_ChisqRatioCut; + } + } + + ATH_MSG_INFO( "Default: delta t cut, value low = " << deltaT0CutLow[0][0] << ", high = " << deltaT0CutHigh[0][0] ); + + ZDCDataAnalyzer::ZDCModuleFloatArray HGOverFlowADC = {800, 800, 800, 800, 800, 800, 800, 800}; + ZDCDataAnalyzer::ZDCModuleFloatArray HGUnderFlowADC = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray LGOverFlowADC = {1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020}; + + // Construct the data analyzer + // + ZDCDataAnalyzer* zdcDataAnalyzer = new ZDCDataAnalyzer(m_numSample, m_deltaTSample, m_presample, "FermiExp", peak2ndDerivMinSamples, + peak2ndDerivMinThresholdsHG, peak2ndDerivMinThresholdsLG, m_lowGainOnly); + + zdcDataAnalyzer->SetADCOverUnderflowValues(HGOverFlowADC, HGUnderFlowADC, LGOverFlowADC); + zdcDataAnalyzer->SetTauT0Values(fixTau1Arr, fixTau2Arr, tau1, tau2, t0, t0); + zdcDataAnalyzer->SetCutValues(chisqDivAmpCut, chisqDivAmpCut, deltaT0CutLow, deltaT0CutHigh, deltaT0CutLow, deltaT0CutHigh); + + return zdcDataAnalyzer; +} + + +void ZdcAnalysisTool::initialize40MHz() +{ + // We have a complete configuration and so we override all of the default parameters + // + + ZDCDataAnalyzer::ZDCModuleFloatArray tau1 = {4.2, 3.8, 5.2, 5.0, + 5.0, 3.7, 3.5, 3.5}; + + // identical to 80 MHz -- is this right + ZDCDataAnalyzer::ZDCModuleFloatArray tau2 = {20.0, 20.4, 18.9, 20.8, + 19.1, 21.9, 22.6, 23.4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray peak2ndDerivMinSamples = {1, 1, 2, 1, + 1, 1, 1, 1}; + + ZDCDataAnalyzer::ZDCModuleFloatArray peak2ndDerivMinThresholdsHG = {-8, -8, -8, -8, + -8, -8, -8, -8}; + + ZDCDataAnalyzer::ZDCModuleFloatArray peak2ndDerivMinThresholdsLG = {-4, -4, -4, -4, + -4, -4, -4, -4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray HGOverFlowADC = {800, 800, 800, 800, 800, 800, 800, 800}; + ZDCDataAnalyzer::ZDCModuleFloatArray HGUnderFlowADC = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray LGOverFlowADC = {1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020}; + + // Set Tau and nominal timing offsets + ZDCDataAnalyzer::ZDCModuleBoolArray fixTau1Arr, fixTau2Arr; + + bool fixTau1 = true; + bool fixTau2 = true; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + fixTau1Arr[side][module] = fixTau1; + fixTau2Arr[side][module] = fixTau2; + } + } + + ZDCDataAnalyzer::ZDCModuleFloatArray t0HG = {53.942, 49.887, 59.633, 46.497, + 46.314, 42.267, 50.327, 41.605}; + ZDCDataAnalyzer::ZDCModuleFloatArray t0LG = {51.771, 47.936, 57.438, 44.191, + 44.295, 41.755, 48.081, 40.175}; + + + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutHG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutLG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowHG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighHG = {8, 8, 8, 11, 8, 10, 8, 12}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowLG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighLG = {8, 8, 8, 11, 8, 10, 8, 12}; + + std::array<std::array<std::vector<float>, 4>, 2> slewingParamsHG, slewingParamsLG; + + slewingParamsHG[0][0] = {0, -7.904e-02, 4.686e-02, 1.530e-03 }; + slewingParamsHG[0][1] = {0, 2.250e-02, 4.732e-02, 6.050e-03 }; + slewingParamsHG[0][2] = {0, 4.388e-02, 6.707e-02, -5.526e-05 }; + slewingParamsHG[0][3] = {0, 1.205e-01, 2.726e-02, 2.610e-03 }; + + slewingParamsHG[1][0] = {0, 6.861e-02, 5.175e-03, -9.018e-04 }; + slewingParamsHG[1][1] = {0, 3.855e-01, -4.442e-02, -2.022e-02 }; + slewingParamsHG[1][2] = {0, -4.337e-03, 3.841e-02, 4.661e-03 }; + slewingParamsHG[1][3] = {0, 3.623e-01, -3.882e-02, -1.805e-02 }; + + slewingParamsLG[0][0] = {0, 1.708e-02, 7.929e-02, 5.079e-03 }; + slewingParamsLG[0][1] = {0, 1.406e-01, 1.209e-01, -1.922e-04 }; + slewingParamsLG[0][2] = {0, 1.762e-01, 1.118e-01, 1.679e-04 }; + slewingParamsLG[0][3] = {0, 1.361e-02, -2.685e-02, -4.168e-02 }; + + slewingParamsLG[1][0] = {0, 1.962e-01, -5.025e-03, -2.001e-02 }; + slewingParamsLG[1][1] = {0, 3.258e-01, 1.229e-02, -2.925e-02 }; + slewingParamsLG[1][2] = {0, 1.393e-01, 8.113e-02, -2.594e-03 }; + slewingParamsLG[1][3] = {0, 1.939e-01, 2.188e-02, -5.579e-02 }; + + std::array<std::array<std::vector<float>, 4>, 2> moduleHGNonLinCorr; + moduleHGNonLinCorr[0][0] = {-3.76800e-02, 4.63597e-02}; + moduleHGNonLinCorr[0][1] = {-1.02185e-01, -1.17548e-01}; + moduleHGNonLinCorr[0][2] = {-8.78451e-02, -1.52174e-01}; + moduleHGNonLinCorr[0][3] = {-1.04835e-01, -1.96514e-01}; + moduleHGNonLinCorr[1][0] = {-6.83115e-02, 3.57802e-02}; + moduleHGNonLinCorr[1][1] = {-1.08162e-01, -1.91413e-01}; + moduleHGNonLinCorr[1][2] = {-7.82514e-02, -1.21218e-01}; + moduleHGNonLinCorr[1][3] = {-2.34354e-02, -2.52033e-01}; + + m_zdcDataAnalyzer_40MHz = new ZDCDataAnalyzer(7,25,0,"FermiExp",peak2ndDerivMinSamples, + peak2ndDerivMinThresholdsHG, peak2ndDerivMinThresholdsLG,m_lowGainOnly); + + m_zdcDataAnalyzer_40MHz->SetADCOverUnderflowValues(HGOverFlowADC, HGUnderFlowADC, LGOverFlowADC); + m_zdcDataAnalyzer_40MHz->SetTauT0Values(fixTau1Arr, fixTau2Arr, tau1, tau2, t0HG, t0LG); + m_zdcDataAnalyzer_40MHz->SetCutValues(chisqDivAmpCutHG, chisqDivAmpCutLG, DeltaT0CutLowHG, DeltaT0CutHighHG, DeltaT0CutLowLG, DeltaT0CutHighLG); + m_zdcDataAnalyzer_40MHz->SetTimingCorrParams(slewingParamsHG, slewingParamsLG); + m_zdcDataAnalyzer_40MHz->SetNonlinCorrParams(moduleHGNonLinCorr); + +} + +void ZdcAnalysisTool::initialize80MHz() +{ + // We have a complete configuration and so we override all of the default parameters + // + + _peak2ndDerivMinSamples = {3, 2, 3, 2, + 2, 2, 2, 2}; + + _peak2ndDerivMinThresholdsHG = {-8, -8, -8, -8, + -8, -8, -8, -8}; + + _peak2ndDerivMinThresholdsLG = {-4, -4, -4, -4, + -4, -4, -4, -4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray HGOverFlowADC = {800, 800, 800, 800, 800, 800, 800, 800}; + ZDCDataAnalyzer::ZDCModuleFloatArray HGUnderFlowADC = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray LGOverFlowADC = {950, 950, 950, 950, 950, 950, 950, 950}; + + // Set Tau and nominal timing offsets + ZDCDataAnalyzer::ZDCModuleBoolArray fixTau1Arr, fixTau2Arr; + + bool fixTau1 = true; + bool fixTau2 = true; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + fixTau1Arr[side][module] = fixTau1; + fixTau2Arr[side][module] = fixTau2; + } + } + + ZDCDataAnalyzer::ZDCModuleFloatArray tau1 = {3.9, 3.4, 4.1, 4.2, + 4.2, 3.6, 3.3, 3.4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray tau2 = {20.0, 20.4, 18.9, 20.8, + 19.1, 21.9, 22.6, 23.4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray t0HG = {44.24, 40.35, 49.3, 36.0, + 36.0, 31.1, 40.75, 30.5}; + + ZDCDataAnalyzer::ZDCModuleFloatArray t0LG = {42.65, 38.5, 47.4, 34, + 33.7, 29.9, 39.0, 29.3}; + + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutHG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutLG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowHG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighHG = {8, 8, 8, 11, 8, 10, 8, 12}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowLG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighLG = {8, 8, 8, 11, 8, 10, 8, 12}; + + std::array<std::array<std::vector<float>, 4>, 2> slewingParamsHG, slewingParamsLG; + + slewingParamsHG[0][0] = {0, -6.5e-2, 2.85e-2, -2.83e-3}; + slewingParamsHG[0][1] = {0, -5.5e-2, 5.13e-2, 5.6e-3}; + slewingParamsHG[0][2] = {0, -1.45e-3, 9.3e-2, 3.9e-3}; + slewingParamsHG[0][3] = {0, -2.36e-2, 8.3e-2, 1.1e-3}; + + slewingParamsHG[1][0] = {0, -6.5e-2, 4.84e-2, -3.7e-3}; + slewingParamsHG[1][1] = {0, 1.34e-2, 6.57e-2, 5.37e-3}; + slewingParamsHG[1][2] = {0, -5.37e-2, 3.49e-2, 3.8e-3}; + slewingParamsHG[1][3] = {0, -3.3e-2, 3.9e-2, 2.2e-3}; + + slewingParamsLG[0][0] = {0, -9.6e-2, 4.39e-2, 2.93e-3 }; + slewingParamsLG[0][1] = {0, -5.0e-2, 14.9e-2, 20.6e-3 }; + slewingParamsLG[0][2] = {0, -4.4e-2, 5.3e-2, 0, }; + slewingParamsLG[0][3] = {0, -9.90e-2, 4.08e-2, 0, }; + + slewingParamsLG[1][0] = {0, -8.7e-2, 4.2e-2, -3.2e-3 }; + slewingParamsLG[1][1] = {0, -3.26e-2, 3.84e-2, -2.32e-3}; + slewingParamsLG[1][2] = {0, -26.8e-2, -2.64e-2, -5.3e-3 }; + slewingParamsLG[1][3] = {0, -13.2e-2, 0.45e-2, -2.4e-3 }; + + std::array<std::array<std::vector<float>, 4>, 2> moduleHGNonLinCorr; + moduleHGNonLinCorr[0][0] = {-3.76800e-02, 4.63597e-02}; + moduleHGNonLinCorr[0][1] = {-1.02185e-01, -1.17548e-01}; + moduleHGNonLinCorr[0][2] = {-8.78451e-02, -1.52174e-01}; + moduleHGNonLinCorr[0][3] = {-1.04835e-01, -1.96514e-01}; + moduleHGNonLinCorr[1][0] = {-6.83115e-02, 3.57802e-02}; + moduleHGNonLinCorr[1][1] = {-1.08162e-01, -1.91413e-01}; + moduleHGNonLinCorr[1][2] = {-7.82514e-02, -1.21218e-01}; + moduleHGNonLinCorr[1][3] = {-2.34354e-02, -2.52033e-01}; + + m_zdcDataAnalyzer_80MHz = new ZDCDataAnalyzer(7 , 12.5, 0, "FermiExp",_peak2ndDerivMinSamples, + _peak2ndDerivMinThresholdsHG, _peak2ndDerivMinThresholdsLG,m_lowGainOnly); + + m_zdcDataAnalyzer_80MHz->SetADCOverUnderflowValues(HGOverFlowADC, HGUnderFlowADC, LGOverFlowADC); + m_zdcDataAnalyzer_80MHz->SetTauT0Values(fixTau1Arr, fixTau2Arr, tau1, tau2, t0HG, t0LG); + m_zdcDataAnalyzer_80MHz->SetCutValues(chisqDivAmpCutHG, chisqDivAmpCutLG, DeltaT0CutLowHG, DeltaT0CutHighHG, DeltaT0CutLowLG, DeltaT0CutHighLG); + m_zdcDataAnalyzer_80MHz->SetTimingCorrParams(slewingParamsHG, slewingParamsLG); + m_zdcDataAnalyzer_80MHz->SetNonlinCorrParams(moduleHGNonLinCorr); +} + +StatusCode ZdcAnalysisTool::initializeTool() +{ + tf1SincInterp = new TF1("SincInterp",ZDC::SincInterp,-5.,160.,8); + tf1SincInterp->SetNpx(300); + + // Set up calibrations + // + std::string filename = PathResolverFindCalibFile( "ZdcAnalysis/ZdcAnalysisConfig.conf" ); + TEnv env(filename.c_str()); + + m_zdcEnergyCalibFileName = std::string(env.GetValue("ZdcEnergyCalibFileName","ZdcCalibrations_v1.root")); + ATH_MSG_INFO("ZDC energy calibration filename " << m_zdcEnergyCalibFileName); + m_zdcTimeCalibFileName = std::string(env.GetValue("ZdcTimeCalibFileName","ZdcTimeCalibrations_v1.root")); + ATH_MSG_INFO("ZDC time calibration filename " << m_zdcTimeCalibFileName); + m_zdcTriggerEffParamsFileName = std::string(env.GetValue("ZdcTriggerEffFileName", "ZdcTriggerEffParameters_v4.root")); + ATH_MSG_INFO("ZDC trigger efficiencies filename " << m_zdcTriggerEffParamsFileName); + + ATH_MSG_INFO("Configuration: "<<m_configuration); + ATH_MSG_INFO("FlipEMDelay: "<<m_flipEMDelay); + ATH_MSG_INFO("LowGainOnly: "<<m_lowGainOnly); + ATH_MSG_INFO("WriteAux: "<<m_writeAux); + ATH_MSG_INFO("AuxSuffix: "<<m_auxSuffix); + ATH_MSG_INFO("DoCalib: "<<m_doCalib); + ATH_MSG_INFO("ForceCalibRun: "<<m_forceCalibRun); + ATH_MSG_INFO("ForceCalibLB: "<<m_forceCalibLB); + ATH_MSG_INFO("NumSampl: "<<m_numSample); + ATH_MSG_INFO("DeltaTSample: "<<m_deltaTSample); + ATH_MSG_INFO("Presample: "<<m_presample); + ATH_MSG_INFO("PeakSample: "<<m_peakSample); + ATH_MSG_INFO("Peak2ndDerivThresh: "<<m_Peak2ndDerivThresh); + ATH_MSG_INFO("T0: "<<m_t0); + ATH_MSG_INFO("Tau1: "<<m_tau1); + ATH_MSG_INFO("Tau2: "<<m_tau2); + ATH_MSG_INFO("FixTau1: "<<m_fixTau1); + ATH_MSG_INFO("FixTau2: "<<m_fixTau2); + ATH_MSG_INFO("DeltaTCut: "<<m_deltaTCut); + ATH_MSG_INFO("ChisqRatioCut: "<<m_ChisqRatioCut); + + if (m_forceCalibRun>-1) { + ATH_MSG_INFO("CAREFUL: forcing calibration run/LB =" << m_forceCalibRun << "/" << m_forceCalibLB); + + if (m_forceCalibLB < 0) { + ATH_MSG_ERROR("Invalid settings: Forced run > 0 but lumi block < 0"); + return StatusCode::FAILURE; + } + } + + // Use configuration to direct initialization + // + if (m_configuration == "default") { + m_zdcDataAnalyzer = initializeDefault(); + } + else if (m_configuration == "PbPb2015") { + initialize80MHz(); + initialize40MHz(); + + m_zdcDataAnalyzer = m_zdcDataAnalyzer_80MHz; // default + } + else { + ATH_MSG_ERROR("Unknown configuration: " << m_configuration); + return StatusCode::FAILURE; + } + + // If an aux suffix is provided, prepend it with "_" so we don't have to do so at each use + // + if (m_writeAux && m_auxSuffix != "") { + m_auxSuffix = "_" + m_auxSuffix; + } + + + m_init = true; + return StatusCode::SUCCESS; +} + +StatusCode ZdcAnalysisTool::configureNewRun(unsigned int runNumber) +{ + ATH_MSG_INFO("Setting up new run " << runNumber); + + // We do nothing for the default configuration + // + if (m_configuration != "default") { + if (m_configuration == "PbPb2015") { + // + // Two periods, 40 MHz and 80 MHz readout + // + if (runNumber < 287222) m_zdcDataAnalyzer = m_zdcDataAnalyzer_40MHz; + else m_zdcDataAnalyzer = m_zdcDataAnalyzer_80MHz; + } + } + + return StatusCode::SUCCESS; +} + +StatusCode ZdcAnalysisTool::recoZdcModule(const xAOD::ZdcModule& module) +{ + ATH_MSG_DEBUG("Processing ZDC module S/T/M/C = " + << module.side() << " " + << module.type() << " " + << module.zdcModule() << " " + << module.channel() + ); + const std::vector<unsigned short>* adc0; + const std::vector<unsigned short>* adc1; + + + if (module.type()==0 && module.zdcModule()==0 && m_flipEMDelay) // flip delay/non-delay for EM big tube + { + adc0 = &(*(module.TTg0d1Link()))->adc(); + adc1 = &(*(module.TTg1d1Link()))->adc(); + } + else + { + adc0 = &(*(module.TTg0d0Link()))->adc(); + adc1 = &(*(module.TTg1d0Link()))->adc(); + } + + float amp; + float time; + float qual; + + float deltaT = m_deltaTSample; + + sigprocMaxFinder(*adc0,deltaT,amp,time,qual); + if (m_writeAux) { + module.auxdecor<float>("amplitudeG0_mf" + m_auxSuffix)=amp; + module.auxdecor<float>("timeG0_mf" + m_auxSuffix)=time; + } + + sigprocMaxFinder(*adc1,deltaT,amp,time,qual); + module.auxdecor<float>("amplitudeG1_mf" + m_auxSuffix)=amp; + module.auxdecor<float>("timeG1_mf" + m_auxSuffix)=time; + + if (module.type()==0) + { + sigprocSincInterp(*adc0,deltaT,amp,time,qual); + module.auxdecor<float>("amplitudeG0_si" + m_auxSuffix)=amp; + module.auxdecor<float>("timeG0_si" + m_auxSuffix)=time; + } + + return StatusCode::SUCCESS; +} + +StatusCode ZdcAnalysisTool::recoZdcModules(const xAOD::ZdcModuleContainer& moduleContainer) +{ + if (!m_eventReady) + { + ATH_MSG_INFO("Event not ready for ZDC reco!"); + return StatusCode::FAILURE; + } + + const xAOD::EventInfo* eventInfo = 0; + ATH_CHECK(evtStore()->retrieve(eventInfo,"EventInfo")); + + // check for new run number, if new, possibly update configuration and/or calibrations + // + unsigned int thisRunNumber = eventInfo->runNumber(); + if (thisRunNumber != m_runNumber) { + ATH_MSG_DEBUG("ZDC analysis tool will be configured for run " << thisRunNumber); + + ATH_CHECK(configureNewRun(thisRunNumber)); // ALWAYS check methods that return StatusCode + + ATH_MSG_DEBUG("Setting up calibrations"); + + if (m_doCalib) { + // + // Check for calibration override + // + unsigned int calibRunNumber = thisRunNumber; + if (m_forceCalibRun > -1) calibRunNumber = m_forceCalibRun; + + setEnergyCalibrations(calibRunNumber); + initializeTriggerEffs(calibRunNumber); // if energy calibrations fail to load, then so will trigger efficiencies + //setTimeCalibrations(); + } + + m_runNumber = thisRunNumber; + } + + m_lumiBlock = eventInfo->lumiBlock(); + + unsigned int calibLumiBlock = m_lumiBlock; + if (m_doCalib) { + if (m_forceCalibRun > 0) calibLumiBlock = m_forceCalibLB; + } + + ATH_MSG_DEBUG("Starting event processing"); + m_zdcDataAnalyzer->StartEvent(calibLumiBlock); + + const std::vector<unsigned short>* adc0; + const std::vector<unsigned short>* adc1; + + ATH_MSG_DEBUG("Processing modules"); + for (const auto zdcModule : moduleContainer) + { + + if (zdcModule->type()!=0) continue; + + if (zdcModule->zdcModule()==0 && m_flipEMDelay) // flip delay/non-delay for EM big tube + { + adc0 = &(*(zdcModule->TTg0d1Link()))->adc(); + adc1 = &(*(zdcModule->TTg1d1Link()))->adc(); + } + else + { + adc0 = &(*(zdcModule->TTg0d0Link()))->adc(); + adc1 = &(*(zdcModule->TTg1d0Link()))->adc(); + } + + static std::vector<float> HGADCSamples(m_numSample); + static std::vector<float> LGADCSamples(m_numSample); + + std::copy(adc0->begin(),adc0->end(),LGADCSamples.begin()); + std::copy(adc1->begin(),adc1->end(),HGADCSamples.begin()); + + int side = (zdcModule->side()==-1) ? 0 : 1 ; + + //std::cout << "LG: ";for (int i = 0;i<7;i++){std::cout<<LGADCSamples.at(i)<< " ";};std::cout<<std::endl; + //std::cout << "HG: ";for (int i = 0;i<7;i++){std::cout<<HGADCSamples.at(i)<< " ";};std::cout<<std::endl; + + m_zdcDataAnalyzer->LoadAndAnalyzeData(side,zdcModule->zdcModule(),HGADCSamples, LGADCSamples); + } + + ATH_MSG_DEBUG("Finishing event processing"); + + m_zdcDataAnalyzer->FinishEvent(); + + ATH_MSG_DEBUG("Adding variables"); + + for (const auto zdcModule : moduleContainer) + { + + if (zdcModule->type()!=0) continue; + + int side = (zdcModule->side()==-1) ? 0 : 1 ; + int mod = zdcModule->zdcModule(); + + if (m_writeAux) { + if (m_doCalib) { + float calibEnergy = m_zdcDataAnalyzer->GetModuleCalibAmplitude(side, mod); + zdcModule->auxdecor<float>("CalibEnergy" + m_auxSuffix) = calibEnergy; + zdcModule->auxdecor<float>("CalibTime" + m_auxSuffix) = m_zdcDataAnalyzer->GetModuleCalibTime(side, mod); + } + else + { + zdcModule->auxdecor<float>("CalibEnergy" + m_auxSuffix) = -1000; + zdcModule->auxdecor<float>("CalibTime" + m_auxSuffix) = -1000; + } + + zdcModule->auxdecor<unsigned int>("Status" + m_auxSuffix) = m_zdcDataAnalyzer->GetModuleStatus(side, mod); + zdcModule->auxdecor<float>("Amplitude" + m_auxSuffix) = m_zdcDataAnalyzer->GetModuleAmplitude(side, mod); + zdcModule->auxdecor<float>("Time" + m_auxSuffix) = m_zdcDataAnalyzer->GetModuleTime(side, mod); + + const ZDCPulseAnalyzer* pulseAna_p = m_zdcDataAnalyzer->GetPulseAnalyzer(side, mod); + zdcModule->auxdecor<float>("Chisq" + m_auxSuffix) = pulseAna_p->GetChisq(); + zdcModule->auxdecor<float>("FitAmp" + m_auxSuffix) = pulseAna_p->GetFitAmplitude(); + zdcModule->auxdecor<float>("FitAmpError" + m_auxSuffix) = pulseAna_p->GetAmpError(); + zdcModule->auxdecor<float>("FitT0" + m_auxSuffix) = pulseAna_p->GetFitT0(); + zdcModule->auxdecor<float>("BkgdMaxFraction" + m_auxSuffix) = pulseAna_p->GetBkgdMaxFraction(); + } + /* + std::cout << "side = " << side << " module=" << zdcModule->zdcModule() << " CalibEnergy=" << zdcModule->auxdecor<float>("CalibEnergy") + << " should be " << m_zdcDataAnalyzer->GetModuleCalibAmplitude(side,mod) << std::endl; + */ + } + + // Record sum objects + + //xAOD::ZdcModuleContainer* newModuleContainer = new xAOD::ZdcModuleContainer(); + //xAOD::ZdcModuleAuxContainer* newModuleAuxContainer = new xAOD::ZdcModuleAuxContainer() ; + + std::unique_ptr<xAOD::ZdcModuleContainer> newModuleContainer( new xAOD::ZdcModuleContainer() ); + std::unique_ptr<xAOD::ZdcModuleAuxContainer> newModuleAuxContainer( new xAOD::ZdcModuleAuxContainer() ); + + newModuleContainer->setStore( newModuleAuxContainer.get() ); + + for (int iside=0;iside<2;iside++) + { + xAOD::ZdcModule* zdc_sum = new xAOD::ZdcModule; + newModuleContainer.get()->push_back(zdc_sum); + zdc_sum->setSide(iside); + + float calibEnergy = getCalibModuleSum(iside); + zdc_sum->auxdecor<float>("CalibEnergy") = calibEnergy; + + float finalEnergy = calibEnergy; + if (iside==0) finalEnergy = finalEnergy*(1 + 7e-7 * finalEnergy); // nonlinear correction for side C + + zdc_sum->auxdecor<float>("FinalEnergy") = finalEnergy; + zdc_sum->auxdecor<float>("AverageTime") = getAverageTime(iside); + zdc_sum->auxdecor<unsigned int>("Status") = !sideFailed(iside); + zdc_sum->auxdecor<unsigned int>("ModuleMask") = (getModuleMask()>>(4*iside)) & 0xF; + } + + ATH_CHECK( evtStore()->record( newModuleContainer.release() , "ZdcSums" + m_auxSuffix) ) ; + ATH_CHECK( evtStore()->record( newModuleAuxContainer.release() , "ZdcSums" + m_auxSuffix +"Aux.") ); + + return StatusCode::SUCCESS; +} + +void ZdcAnalysisTool::setEnergyCalibrations(unsigned int runNumber) +{ + + char name[128]; + /* + sprintf(name,"%s/%s",m_zdcAnalysisConfigPath.c_str(),m_zdcEnergyCalibFileName.c_str()); + ATH_MSG_INFO("Opening energy calibration file " << name); + TFile* fCalib = TFile::Open(name); + */ + + std::string filename = PathResolverFindCalibFile( ("ZdcAnalysis/"+m_zdcEnergyCalibFileName).c_str() ); + ATH_MSG_INFO("Opening energy calibration file " << filename); + TFile* fCalib = TFile::Open(filename.c_str()); + + //std::array<std::array<TSpline*, 4>, 2> splines; + + for (int iside=0;iside<2;iside++) + { + for(int imod=0;imod<4;imod++) + { + // need to delete old splines + //std::cout << "m_splines[iside][imod] = " << m_splines[iside][imod] << std::endl; + SafeDelete( m_splines[iside][imod] ); + + sprintf(name,"ZDC_Gcalib_run%d_s%d_m%d",runNumber,iside,imod); + ATH_MSG_INFO("Searching for graph " << name); + TGraph* g = (TGraph*) fCalib->GetObjectChecked(name,"TGraph"); + if (!g && m_doCalib) + { + ATH_MSG_ERROR("No calibrations for run " << runNumber); + m_doCalib = false; + } + + if (g) + { + m_splines[iside][imod] = new TSpline3(name,g); + } + else + { + ATH_MSG_ERROR("No graph " << name); + } + } + } + fCalib->Close(); + if (m_doCalib) m_zdcDataAnalyzer->LoadEnergyCalibrations(m_splines); + + return; +} + +void ZdcAnalysisTool::setTimeCalibrations(unsigned int runNumber) +{ + char name[128]; + sprintf(name,"%s/%s",m_zdcAnalysisConfigPath.c_str(),m_zdcTimeCalibFileName.c_str()); + ATH_MSG_INFO("Opening time calibration file " << name); + TFile* fCalib = TFile::Open(name); + std::array<std::array<TSpline*, 4>, 2> T0HGOffsetSplines; + std::array<std::array<TSpline*, 4>, 2> T0LGOffsetSplines; + TSpline3* spline; + for (int iside=0;iside<2;iside++) + { + for(int imod=0;imod<4;imod++) + { + sprintf(name,"ZDC_T0calib_run%d_s%d_m%d_HG",runNumber,iside,imod); + spline = (TSpline3*) fCalib->GetObjectChecked(name,"TSpline3"); + T0HGOffsetSplines[iside][imod] = spline; + sprintf(name,"ZDC_T0calib_run%d_s%d_m%d_LG",runNumber,iside,imod); + spline = (TSpline3*) fCalib->GetObjectChecked(name,"TSpline3"); + T0LGOffsetSplines[iside][imod] = spline; + } + } + m_zdcDataAnalyzer->LoadT0Calibrations(T0HGOffsetSplines,T0LGOffsetSplines); + fCalib->Close(); +} + +StatusCode ZdcAnalysisTool::reprocessZdc() +{ + if (!m_init) + { + ATH_MSG_INFO("Tool not initialized!"); + return StatusCode::FAILURE; + } + m_eventReady = false; + //std::cout << "Trying to retrieve " << m_zdcModuleContainerName << std::endl; + m_zdcModules = 0; + ATH_CHECK(evtStore()->retrieve(m_zdcModules,m_zdcModuleContainerName)); + m_eventReady = true; + + ATH_CHECK(recoZdcModules(*m_zdcModules)); + + return StatusCode::SUCCESS; +} + + bool ZdcAnalysisTool::sigprocMaxFinder(const std::vector<unsigned short>& adc, float deltaT, float& amp, float& time, float& qual) + { + size_t nsamp = adc.size(); + float presamp = adc.at(0); + unsigned short max_adc = 0; + int max_index = -1; + for (size_t i = 0;i<nsamp;i++) + { + if (adc[i]>max_adc) + { + max_adc = adc[i]; + max_index = i; + } + } + amp = max_adc - presamp; + time = max_index*deltaT; + qual = 1.; + + if(max_index==-1) + { + qual=0.; + return false; + } + + return true; + } + + bool ZdcAnalysisTool::sigprocSincInterp(const std::vector<unsigned short>& adc, float deltaT, float& amp, float& time, float& qual) + { + size_t nsamp = adc.size(); + float presamp = adc.at(0); + tf1SincInterp->SetParameter(0,deltaT); + for (size_t i = 0;i<nsamp;i++) + { + tf1SincInterp->SetParameter(i+1,adc.at(i)-presamp); + } + amp = tf1SincInterp->GetMaximum(); + time = tf1SincInterp->GetMaximumX(); + qual = 1.; + return true; + } + + float ZdcAnalysisTool::getModuleSum(int side) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleSum(side); + } + +/* + float ZdcAnalysisTool::getModuleAmplitude(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetPulseAnalyzer(side,mod)->GetAmplitude(); + } + + float ZdcAnalysisTool::getModuleFitAmplitude(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetPulseAnalyzer(side,mod)->GetFitAmplitude(); + } + + float ZdcAnalysisTool::getModuleFitT0(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetPulseAnalyzer(side,mod)->GetFitT0(); + } + + float ZdcAnalysisTool::getModuleTime(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleTime(side,mod); + } + + float ZdcAnalysisTool::getModuleCalibAmplitude(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleCalibAmplitude(side,mod); + } + + float ZdcAnalysisTool::getModuleCalibTime(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleCalibTime(side,mod); + } + + float ZdcAnalysisTool::getModuleStatus(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleStatus(side,mod); + } + + float ZdcAnalysisTool::getModuleChisq(int side, int mod) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleChisq(side,mod); + } +*/ + + float ZdcAnalysisTool::getCalibModuleSum(int side) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetCalibModuleSum(side); + } + + float ZdcAnalysisTool::getAverageTime(int side) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetAverageTime(side); + } + + bool ZdcAnalysisTool::sideFailed(int side) + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->SideFailed(side); + } + + unsigned int ZdcAnalysisTool::getModuleMask() + { + if (!m_zdcDataAnalyzer) return 0; + return m_zdcDataAnalyzer->GetModuleMask(); + } + + float ZdcAnalysisTool::getTriggerEfficiency(int side) + { + if (!m_doCalib) return -1; + + m_zdcTriggerEfficiency->UpdatelumiBlock(m_lumiBlock); + float adcSum = getModuleSum(side); + float eff = m_zdcTriggerEfficiency->GetEfficiency(side, adcSum); + //if(eff<0) std::cout << "eff= " << eff << " --> Invalid lumiBlock input: m_lumiBlock = " << m_lumiBlock << std::endl; // looking for -1's + return eff; + } + +} // namespace ZDC diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysis_entries.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysis_entries.cxx new file mode 100644 index 000000000000..ff4c36e6867d --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcAnalysis_entries.cxx @@ -0,0 +1,16 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef XAOD_STANDALONE + +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "ZdcAnalysis/ZdcAnalysisTool.h" + +DECLARE_TOOL_FACTORY (ZDC::ZdcAnalysisTool) + +DECLARE_FACTORY_ENTRIES (ZdcAnalysis) { + DECLARE_TOOL (ZDC::ZdcAnalysisTool) +} + +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcSincInterp.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcSincInterp.cxx new file mode 100644 index 000000000000..7593c7e6a67d --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/Root/ZdcSincInterp.cxx @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "ZdcAnalysis/ZdcSincInterp.h" +#include "TMath.h" +#include <cmath> + +namespace ZDC +{ + double SincInterp(double* xvec, double* pvec) + { + // pvec are the sample values + double ret = 0; + double T = pvec[0]; // deltaT + double t = xvec[0]; + for (int isamp = 0;isamp<7;isamp++) + { + double arg = (t - isamp*T)/T; + if (arg!=0.0) + { + ret += pvec[isamp+1] * std::sin(TMath::Pi()*arg)/(TMath::Pi()*arg); + } + } + return ret; + } +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/IZdcAnalysisTool.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/IZdcAnalysisTool.h new file mode 100644 index 000000000000..c4a9e9bdeb9f --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/IZdcAnalysisTool.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __IZDCRECTOOL_H__ +#define __IZDCRECTOOL_H__ + +#include "AsgTools/IAsgTool.h" +#include "xAODForward/ZdcModuleContainer.h" + +namespace ZDC +{ + +class IZdcAnalysisTool : virtual public asg::IAsgTool +{ + ASG_TOOL_INTERFACE( ZDC::IZdcAnalysisTool ) + + public: + + /// Initialize the tool. + virtual StatusCode initializeTool() = 0; + virtual StatusCode recoZdcModule(const xAOD::ZdcModule& module) = 0; + virtual StatusCode recoZdcModules(const xAOD::ZdcModuleContainer& moduleContainer) = 0; + virtual StatusCode reprocessZdc() = 0; +}; + +} + +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCDataAnalyzer.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCDataAnalyzer.h new file mode 100644 index 000000000000..9bcafdd3cd29 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCDataAnalyzer.h @@ -0,0 +1,153 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef _ZDCDataAnalyzer_h +#define _ZDCDataAnalyzer_h + +#include <ZdcAnalysis/ZDCPulseAnalyzer.h> +#include <TSpline.h> + +#include <array> +#include <string> + +class ZDCDataAnalyzer +{ +public: + typedef std::array<std::array<float, 4>, 2> ZDCModuleFloatArray; + typedef std::array<std::array<bool, 4>, 2> ZDCModuleBoolArray; + +private: + size_t _nSample; + float _deltaTSample; + size_t _preSampleIdx; + std::string _fitFunction; + bool _forceLG; + + std::array<std::array<ZDCPulseAnalyzer*, 4>, 2> _moduleAnalyzers; + + int _debugLevel; + int _eventCount; + + ZDCModuleFloatArray _HGGains; + ZDCModuleFloatArray _pedestals; + + bool _haveECalib; + std::array<std::array<TSpline*, 4>, 2> _LBDepEcalibSplines; + + bool _haveT0Calib; + std::array<std::array<TSpline*, 4>, 2> _T0HGOffsetSplines; + std::array<std::array<TSpline*, 4>, 2> _T0LGOffsetSplines; + + // Transient data that is updated each LB or each event + // + int _currentLB; + ZDCModuleFloatArray _currentECalibCoeff; + ZDCModuleFloatArray _currentT0OffsetsHG; + ZDCModuleFloatArray _currentT0OffsetsLG; + + std::array<std::array<bool, 4>, 2> _dataLoaded; + // std::array<std::array<bool, 4>, 2> _moduleFail; + + unsigned int _moduleMask; + + std::array<std::array<unsigned int, 4>, 2> _moduleStatus; + std::array<std::array<float, 4>, 2> _calibAmplitude; + std::array<std::array<float, 4>, 2> _calibTime; + + std::array<float, 2> _moduleSum; + std::array<float, 2> _moduleSumErrSq; + std::array<float, 2> _moduleSumPreSample; + + std::array<float, 2> _calibModuleSum; + std::array<float, 2> _calibModuleSumErrSq; + + std::array<float, 2> _averageTime; + std::array<bool, 2> _fail; + +public: + + ZDCDataAnalyzer(int nSample, float deltaTSample, size_t preSampleIdx, std::string fitFunction, + const ZDCModuleFloatArray& peak2ndDerivMinSamples, + const ZDCModuleFloatArray& peak2ndDerivMinThresholdsHG, + const ZDCModuleFloatArray& peak2ndDerivMinThresholdsLG, + bool forceLG = false); + + ~ZDCDataAnalyzer(); + + void SetDebugLevel(int level = 0) { + _debugLevel = level; + if (level < 2) ZDCPulseAnalyzer::SetQuietFits(true); + else ZDCPulseAnalyzer::SetQuietFits(false); + } + + unsigned int GetModuleMask() const {return _moduleMask;} + + float GetModuleSum(size_t side) const {return _moduleSum.at(side);} + float GetModuleSumErr(size_t side) const {return std::sqrt(_moduleSumErrSq.at(side));} + + float GetCalibModuleSum(size_t side) const {return _calibModuleSum.at(side);} + float GetCalibModuleSumErr(size_t side) const {return std::sqrt(_calibModuleSumErrSq.at(side));} + + float GetModuleSumPreSample(size_t side) const {return _moduleSumPreSample.at(side);} + + float GetAverageTime(size_t side) const {return _averageTime.at(side);} + bool SideFailed(size_t side) const {return _fail.at(side);} + + float GetModuleAmplitude(size_t side, size_t module) const {return _moduleAnalyzers.at(side).at(module)->GetAmplitude();} + float GetModuleTime(size_t side, size_t module) const {return _moduleAnalyzers.at(side).at(module)->GetT0Corr();} + float GetModuleChisq(size_t side, size_t module) const {return _moduleAnalyzers.at(side).at(module)->GetChisq();} + + float GetModuleCalibAmplitude(size_t side, size_t module) const {return _calibAmplitude.at(side).at(module);} + float GetModuleCalibTime(size_t side, size_t module) const {return _calibTime.at(side).at(module);} + float GetModuleStatus(size_t side, size_t module) const {return _moduleStatus.at(side).at(module);} + + const ZDCPulseAnalyzer* GetPulseAnalyzer(size_t side, size_t module) const {return _moduleAnalyzers.at(side).at(module);} + + void SetADCOverUnderflowValues(const ZDCModuleFloatArray& HGOverflowADC, const ZDCModuleFloatArray& HGUnderflowADC, + const ZDCModuleFloatArray& LGOverflowADC); + + void SetTauT0Values(const ZDCModuleBoolArray& fxiTau1, const ZDCModuleBoolArray& fxiTau2, + const ZDCModuleFloatArray& tau1, const ZDCModuleFloatArray& tau2, + const ZDCModuleFloatArray& t0HG, const ZDCModuleFloatArray& t0LG); + + void SetCutValues(const ZDCModuleFloatArray& chisqDivAmpCutHG, const ZDCModuleFloatArray& chisqDivAmpCutLG, + const ZDCModuleFloatArray& deltaT0MinHG, const ZDCModuleFloatArray& deltaT0MaxHG, + const ZDCModuleFloatArray& deltaT0MinLG, const ZDCModuleFloatArray& deltaT0MaxLG); + + + void SetTimingCorrParams(const std::array<std::array<std::vector<float>, 4>, 2>& HGParamArr, + const std::array<std::array<std::vector<float>, 4>, 2>& LGParamArr); + + void SetNonlinCorrParams(const std::array<std::array<std::vector<float>, 4>, 2>& HGNonlinCorrParams); + + void LoadEnergyCalibrations(const std::array<std::array<TSpline*, 4>, 2>& calibSplines) + { + if (_debugLevel > 0) { + std::cout << "Loading energy calibrations" << std::endl; + } + + _LBDepEcalibSplines = calibSplines; + _haveECalib = true; + } + + void LoadT0Calibrations(const std::array<std::array<TSpline*, 4>, 2>& T0HGOffsetSplines, + const std::array<std::array<TSpline*, 4>, 2>& T0LGOffsetSplines) + { + if (_debugLevel > 0) { + std::cout << "Loading timing calibrations" << std::endl; + } + _T0HGOffsetSplines = T0HGOffsetSplines; + _T0LGOffsetSplines = T0LGOffsetSplines; + + _haveT0Calib = true; + } + + void StartEvent(int lumiBlock); + + void LoadAndAnalyzeData(size_t side, size_t module, const std::vector<float> HGSamples, const std::vector<float> LGSamples); + + bool FinishEvent(); + +}; +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCFitWrapper.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCFitWrapper.h new file mode 100644 index 000000000000..e24e80bb0ee3 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCFitWrapper.h @@ -0,0 +1,255 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef _ZDCFitWrapper_h +#define _ZDCFitWrapper_h + +// Base class that defines the interface +// +#include <TF1.h> + +double ZDCFermiExpFit(double* xvec, double* pvec); + +class ZDCFitWrapper +{ + TF1* _wrapperTF1; + +public: + ZDCFitWrapper(TF1* wrapperTF1) : _wrapperTF1(wrapperTF1) {} + + virtual ~ZDCFitWrapper() {delete _wrapperTF1;} + + virtual void Initialize(float initialAmp, float initialT0) = 0; + + virtual float GetAmplitude() const = 0; + virtual float GetAmpError() const = 0; + virtual float GetTime() const = 0; + virtual float GetTau1() const = 0; + virtual float GetTau2() const = 0; + + virtual float GetBkgdMaxFraction() const = 0; + + virtual float GetShapeParameter(size_t index) const = 0; + + virtual double operator()(double *x, double *p) = 0; + + virtual TF1* GetWrapperTF1() {return _wrapperTF1;} + virtual const TF1* GetWrapperTF1() const {return _wrapperTF1;} +}; + +class ZDCPrePulseFitWrapper : public ZDCFitWrapper +{ +public: + ZDCPrePulseFitWrapper(TF1* wrapperTF1) : ZDCFitWrapper(wrapperTF1) {} + + virtual void SetInitialPrePulseT0(float t0) = 0; +}; + +class ZDCFitExpFermiVariableTaus : public ZDCFitWrapper +{ + bool _fixTau1; + bool _fixTau2; + + float _tau1; + float _tau2; + +public: + + ZDCFitExpFermiVariableTaus(std::string tag, float tmin, float tmax, bool fixTau1, bool fixTau2, float tau1, float tau2); + + virtual void Initialize(float initialAmp, float initialT0); + + virtual float GetAmplitude() const {return GetWrapperTF1()->GetParameter(0); } + virtual float GetAmpError() const {return GetWrapperTF1()->GetParError(0); } + + virtual float GetTau1() const {return GetWrapperTF1()->GetParameter(2);} + virtual float GetTau2() const {return GetWrapperTF1()->GetParameter(3);} + + virtual float GetTime() const { + const TF1* theTF1 = GetWrapperTF1(); + + float fitT0 = theTF1->GetParameter(1); + + float tau1 = theTF1->GetParameter(2); + float tau2 = theTF1->GetParameter(3); + + // Correct the time to the maximum (the factor of 1/2 is still not fully understood) + // + if (tau2 > tau1) fitT0 += 0.5*tau1*std::log(tau2/tau1 - 1.0); + return fitT0; + } + + virtual float GetShapeParameter(size_t index) const + { + if (index == 0) return GetWrapperTF1()->GetParameter(2); + else if (index == 1) return GetWrapperTF1()->GetParameter(3); + else throw; + } + + virtual float GetBkgdMaxFraction() const + { + const TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + double amp = theTF1->GetParameter(0); + double slope = theTF1->GetParameter(4); + + double background = slope*GetTime(); + return background/amp; + } + + // virtual float GetNDOF() const {return _fitFunc->GetNDF(); } + + virtual double operator()(double *x, double *p) { + return ZDCFermiExpFit(x, p); + } + +}; + +class ZDCFitExpFermiFixedTaus : public ZDCFitWrapper +{ + float _tau1; + float _tau2; + + float _norm; + float _timeCorr; + + TF1* _expFermiFunc; + +public: + + ZDCFitExpFermiFixedTaus(std::string tag, float tmin, float tmax, float tau1, float tau2); + + ~ZDCFitExpFermiFixedTaus() { + delete _expFermiFunc; + } + + virtual void Initialize(float initialAmp, float initialT0); + + virtual float GetAmplitude() const {return GetWrapperTF1()->GetParameter(0); } + virtual float GetAmpError() const {return GetWrapperTF1()->GetParError(0); } + + virtual float GetTau1() const {return _tau1;} + virtual float GetTau2() const {return _tau2;} + + virtual float GetTime() const { + float fitT0 = GetWrapperTF1()->GetParameter(1); + + // Correct the time to the maximum (the factor of 1/2 is still not fully understood) + // + fitT0 += _timeCorr; + return fitT0; + } + + virtual float GetShapeParameter(size_t index) const + { + if (index == 0) return _tau1; + else if (index == 1) return _tau2; + else throw; + } + + virtual float GetBkgdMaxFraction() const + { + const TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + double amp = theTF1->GetParameter(0); + double slope = theTF1->GetParameter(2); + + double background = slope*GetTime(); + return background/amp; + } + + virtual double operator() (double *x, double *p) + { + double amp = p[0]; + double t0 = p[1]; + double deltaT = x[0] - t0; + + double bckgd = p[2]*x[0]; + + double expFermi = amp*_norm*_expFermiFunc->operator()(deltaT); + + return expFermi + bckgd; + } +}; + +class ZDCFitExpFermiPrePulse : public ZDCPrePulseFitWrapper +{ + float _tau1; + float _tau2; + float _norm; + float _timeCorr; + TF1* _expFermiFunc; + +public: + ZDCFitExpFermiPrePulse(std::string tag, float tmin, float tmax, float tau1, float tau2); + + virtual void Initialize(float initialAmp, float initialT0); + // void InitializePrePulseT0(float initPreT0) { GetWrapperTF1()->SetParameter(3, initPreT0);} + + virtual void SetInitialPrePulseT0(float t0) {GetWrapperTF1()->SetParameter(3, t0);} + + virtual float GetAmplitude() const {return GetWrapperTF1()->GetParameter(0); } + virtual float GetAmpError() const {return GetWrapperTF1()->GetParError(0); } + + virtual float GetTau1() const {return GetWrapperTF1()->GetParameter(2);} + virtual float GetTau2() const {return GetWrapperTF1()->GetParameter(3);} + + virtual float GetTime() const { + float fitT0 = GetWrapperTF1()->GetParameter(1); + + // Correct the time to the maximum (the factor of 1/2 is still not fully understood) + // + fitT0 += _timeCorr; + return fitT0; + } + + virtual float GetShapeParameter(size_t index) const + { + if (index == 0) return _tau1; + else if (index == 1) return _tau2; + else if (index < 5) return GetWrapperTF1()->GetParameter(index); + else throw; + } + + virtual float GetBkgdMaxFraction() const + { + const TF1* theTF1 = ZDCFitWrapper::GetWrapperTF1(); + + double maxTime = GetTime(); + + double amp = theTF1->GetParameter(0); + double preAmp = theTF1->GetParameter(2); + double preT0 = theTF1->GetParameter(3); + double slope = theTF1->GetParameter(4); + + double deltaTPre = maxTime - preT0; + + double background = slope*maxTime + preAmp*_norm*(_expFermiFunc->operator()(deltaTPre) - + _expFermiFunc->operator()(-preT0)); + + return background/amp; + } + + virtual double operator() (double *x, double *p) + { + double t = x[0]; + + double amp = p[0]; + double t0 = p[1]; + double preAmp = p[2]; + double preT0 = p[3]; + double linSlope = p[4]; + + double deltaT = t - t0; + double deltaTPre = t - preT0; + + double bckgd = linSlope*t; + + double pulse1 = amp*_norm*_expFermiFunc->operator()(deltaT); + double pulse2 = preAmp*_norm*(_expFermiFunc->operator()(deltaTPre) - + _expFermiFunc->operator()(-preT0)); + + return pulse1 + pulse2 + bckgd; + } +}; + +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCPulseAnalyzer.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCPulseAnalyzer.h new file mode 100644 index 000000000000..8939f8170715 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCPulseAnalyzer.h @@ -0,0 +1,290 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef _ZDCPulseAnalyzer_h +#define _ZDCPulseAnalyzer_h + +//#include <valarray> +#include <vector> +#include <string> + +#include <TF1.h> +#include <TH1.h> + +#include "ZdcAnalysis/ZDCFitWrapper.h" + +class ZDCPulseAnalyzer +{ +public: + enum {PulseBit = 0, LowGainBit, FailBit, HGOverflowBit, + HGUnderflowBit, PSHGOverUnderflowBit, LGOverflowBit, LGUnderflowBit, + PrePulseBit, PostPulseBit, FitFailedBit, BadChisqBit, BadT0Bit}; + +private: + typedef std::vector<float>::const_iterator SampleCIter; + + // Static data + // + static std::string _fitOptions; + static bool _quietFits; + + // Quantities provided/set in the constructor + // + std::string _tag; + size_t _Nsample; + size_t _preSampleIdx; + float _deltaTSample; + int _pedestal; + float _gainHG; + bool _forceLG; + float _tmin; + float _tmax; + std::string _fitFunction; + float _peak2ndDerivMinSample; + float _peak2ndDerivMinThreshLG; + float _peak2ndDerivMinThreshHG; + + // Default fit values and cuts that can be set via modifier methods + // + int _HGOverflowADC; + int _HGUnderflowADC; + int _LGOverflowADC; + + float _nominalT0HG; + float _nominalT0LG; + + float _nominalTau1; + float _nominalTau2; + + bool _fixTau1; + bool _fixTau2; + + float _chisqDivAmpCutLG; // maximum good LG chisq / amplitude + float _chisqDivAmpCutHG; // maximum good HG chisq / amplitude + + float _T0CutLowLG; // minimum good corrected time for LG fits + float _T0CutHighLG; // maximum good corrected time for LG fits + + float _T0CutLowHG; // minimum good corrected time for HG fits + float _T0CutHighHG; // maximum good corrected time for HG fits + + bool _haveTimingCorrections; + std::vector<float> _LGT0CorrParams; // Parameters used to correct the fit LG times + std::vector<float> _HGT0CorrParams; // Parameters used to correct the fit HG times + + bool _haveNonlinCorr; + std::vector<float> _nonLinCorrParams; + + // Histogram used to perform the fits and function wrappers + // + mutable TH1* _fitHist; + + bool _initializedFits; + ZDCFitWrapper* _defaultFitWrapper; + ZDCFitWrapper* _prePulseFitWrapper; + + // TH1* _LGFitHist; + // TH1* _fitHist; + // TF1* _FitFuncNoPrePulse; + // TF1* _FitFuncPrePulse; + + // Dynamic data loaded for each pulse (event) + // ========================================== + + // Statuses + // + bool _haveData; + bool _havePulse; + bool _fail; + bool _useLowGain; + bool _HGOverflow; + bool _HGUnderflow; + bool _LGOverflow; + bool _LGUnderflow; + bool _PSHGOverUnderflow; + bool _prePulse; + bool _postPulse; + bool _fitFailed; + bool _badT0; + bool _badChisq; + + // Pulse analysis + // + float _preSample; + + float _maxADCValue; + float _minADCValue; + float _maxDelta; + float _minDelta; + + int _maxSampl; + int _minSampl; + int _maxDeltaSampl; + int _minDeltaSampl; + + float _minDeriv2nd; + int _minDeriv2ndIndex; + + float _fitAmplitude; + float _fitAmpError; + float _fitT0; + float _fitT0Corr; + float _fitTau1; + float _fitTau2; + float _fitChisq; + float _amplitude; + float _ampError; + float _preSampleAmp; + float _bkgdMaxFraction; + + std::vector<float> _ADCSamplesHGSub; + std::vector<float> _ADCSamplesLGSub; + + std::vector<float> _ADCSSampSigHG; + std::vector<float> _ADCSSampSigLG; + + std::vector<float> _samplesSub; + std::vector<float> _samplesDeriv; + std::vector<float> _samplesDeriv2nd; + + // Private methods + // + void Reset(); + void SetDefaults(); + void SetupFitFunctions(); + + bool AnalyzeData(const std::vector<float>& samples, // The samples used for this event + const std::vector<float>& samplesSig, // The "resolution" on the ADC value + const std::vector<float>& toCorrParams, // The parameters used to correct the t0 + float maxChisqDivAmp, // The maximum chisq / amplitude ratio + float minT0Corr, float maxT0Corr, // The minimum and maximum corrected T0 values + float peak2ndDerivMinThresh + ); + + + void FillHistogram(const std::vector<float>& samples, const std::vector<float>& samplesSig) const + { + // Set the data and errors in the histogram object + // + for (size_t isample = 0; isample < _Nsample; isample++) { + _fitHist->SetBinContent(isample + 1, samples[isample]); + _fitHist->SetBinError(isample + 1, samplesSig[isample]); + } + } + +public: + + ZDCPulseAnalyzer(std::string tag, int Nsample, float deltaTSample, size_t preSampleIdx, int pedestal, float gainHG, + std::string fitFunction, int peak2ndDerivMinSample, float peak2DerivMinThreshHG, float peak2DerivMinThreshLG); + + ~ZDCPulseAnalyzer(); + + static void SetFitOPtions(std::string fitOptions) { _fitOptions = fitOptions;} + static void SetQuietFits(bool quiet) {_quietFits = quiet;} + static bool QuietFits() {return _quietFits;} + + void SetForceLG(bool forceLG) {_forceLG = forceLG;} + bool ForceLG() const {return _forceLG;} + + void SetCutValues(float chisqDivAmpCutHG, float chisqDivAmpCutLG, + float deltaT0MinHG, float deltaT0MaxHG, + float deltaT0MinLG, float deltaT0MaxLG) ; + + void SetTauT0Values(bool fixTau1, bool fixTau2, float tau1, float tau2, float t0HG, float t0LG); + + void SetADCOverUnderflowValues(int HGOverflowADC, int HGUnderflowADC, int LGOverflowADC); + + void SetTimingCorrParams(std::vector<float> HGT0CorrParams, std::vector<float> LGT0CorrParams) + { + if (HGT0CorrParams.size() == 4 && LGT0CorrParams.size() == 4) { + _HGT0CorrParams = HGT0CorrParams; + _LGT0CorrParams = LGT0CorrParams; + _haveTimingCorrections = true; + } + else throw; + } + + void SetNonlinCorrParams(const std::vector<float>& params) + { + // Check for valid length + // + if (params.size() != 2) throw; + + std::cout << "Setting non-linear parameters for module: " << _tag << ", vlues = " + << params[0] << ", " << params[1] << std::endl; + + _nonLinCorrParams = params; + } + + bool LoadAndAnalyzeData(std::vector<float> ADCSamplesHG, std::vector<float> ADCSamplesLG); + + bool HaveData() const {return _haveData;} + bool HavePulse() const {return _havePulse;} + bool Failed() const {return _fail;} + bool BadChisq() const {return _badChisq;} + bool BadT0() const {return _badT0;} + bool FitFailed() const {return _fitFailed;} + bool PrePulse() const {return _prePulse;} + bool UseLowGain() const {return _useLowGain;} + + bool HGOverflow() const {return _HGOverflow;} + bool HGUnderflow() const {return _HGOverflow;} + bool LGOverflow() const {return _LGOverflow;} + bool LGUnderflow() const {return _LGUnderflow;} + + bool PSHGOverUnderflow() const {return _PSHGOverUnderflow;} + + float GetFitAmplitude() const {return _fitAmplitude;} + float GetFitT0() const {return _fitT0;} + float GetT0Corr() const {return _fitT0Corr;} + float GetChisq() const {return _fitChisq;} + + float GetFitTau1() const {return _fitTau1;} + float GetFitTau2() const {return _fitTau2;} + + float GetAmplitude() const {return _amplitude;} + float GetAmpError() const {return _ampError;} + + float GetPresample() const {return _preSample;} + + float GetMaxADC() const {return _maxADCValue;} + float GetMinADC() const {return _minADCValue;} + + int GetMaxADCSample() const {return _maxSampl;} + int GetMinADCSample() const {return _minSampl;} + + float GetMaxDelta() const {return _maxDelta;} + float GetMinDelta() const {return _minDelta;} + + float GetMinDeriv2nd() const {return _minDeriv2nd;} + float GetMinDeriv2ndIndex() const {return _minDeriv2ndIndex;} + + unsigned int GetStatusMask() const; + + float GetPreSampleAmp() const {return _preSampleAmp;} + float GetBkgdMaxFraction() const {return _bkgdMaxFraction;} + + const TH1* GetHistogramPtr() const { + // + // We defer filling the histogram if we don't have a pulse until the histogram is requested + // + if (!_havePulse) { + if (UseLowGain()) FillHistogram(_samplesSub, _ADCSSampSigLG); + else FillHistogram(_samplesSub, _ADCSSampSigHG); + } + + return _fitHist; + } + + void DoFit(); + + void Dump() const; + + const std::vector<float>& GetSamplesSub() const {return _samplesSub;} + const std::vector<float>& GetSamplesDeriv() const {return _samplesDeriv;} + const std::vector<float>& GetSamplesDeriv2nd() const {return _samplesDeriv2nd;} +}; + + +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCTriggerEfficiency.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCTriggerEfficiency.h new file mode 100644 index 000000000000..0bc68d012e02 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZDCTriggerEfficiency.h @@ -0,0 +1,101 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef _ZDCTriggerEfficiency_ +#define _ZDCTriggerEfficiency_ + +#include <TSpline.h> +#include <iostream> +#include <vector> +#include <array> +#include <algorithm> +using namespace std; +class ZDCTriggerEfficiency{ + public: + bool _haveParams; + bool _haveCorrCoeffs; + + unsigned int _minLB; + unsigned int _maxLB; + + unsigned int _currentLB; + + std::array<std::vector<TSpline3*>, 2> _effParams; + std::array<std::vector<TSpline3*>, 2> _effParamErrors; + std::array<std::vector<TSpline3*>, 2> _effParamCorrCoeffs; + + std::array<std::vector<double>, 2> _currentParams; + std::array<std::vector<double>, 2> _currentParamErrors; + std::array<std::vector<double>, 2> _currentCorrCoefff; + + void UpdatelumiBlock(unsigned int lumiBlock) + { + if (!_haveParams) throw; + + if (lumiBlock != _currentLB) { + int newLB = std::max(std::min(lumiBlock, _maxLB), _minLB); + for (int side : {0, 1}) { + _currentParams[side].clear(); + _currentParamErrors[side].clear(); + _currentCorrCoefff[side].clear(); + + for (size_t ipar = 0; ipar < _effParams[side].size(); ipar++) { + _currentParams[side].push_back(_effParams[side][ipar]->Eval(newLB)); + _currentParamErrors[side].push_back(_effParamErrors[side][ipar]->Eval(newLB)); + + if (_haveCorrCoeffs) { + _currentCorrCoefff[side].push_back(_effParamCorrCoeffs[side][ipar]->Eval(newLB)); + } + } + _currentLB = lumiBlock; + } + } + } + +public: + ZDCTriggerEfficiency() : // in order, alpha-beta, alpha-theta, beta-theta + _haveParams(false), _haveCorrCoeffs(false), + _minLB(0), _maxLB(0), _currentLB(0) + { + + } + + void SetEffParamsAndErrors(std::array<std::vector<TSpline3*>, 2> effParams, + std::array<std::vector<TSpline3*>, 2> effParamErrors) + { + for (int side : {0, 1}) { + _effParams[side] = effParams[side]; + _effParamErrors[side] = effParamErrors[side]; + for (int iarr=0;iarr<3;iarr++) + { + _effParams[side].at(iarr)->Print(); + _effParamErrors[side].at(iarr)->Print(); + } + } + + _minLB = _effParams[0][0]->GetXmin(); + _maxLB = _effParams[0][0]->GetXmax(); + _haveParams = true; + } + + void SetEffParamCorrCoeffs(std::array<std::vector<TSpline3*>, 2> effParamsCorrCoeffs) + { + for (int side : {0, 1}) { + _effParamCorrCoeffs[side] = effParamsCorrCoeffs[side]; + for (int iarr=0;iarr<3;iarr++) + { + _effParamCorrCoeffs[side].at(iarr)->Print(); + } + } + + _haveCorrCoeffs = true; + } + + float GetEfficiency(int side, float ADCSum); + + std::pair<float, float> GetEfficiencyAndError(int side, float ADCSum); + +}; + +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h new file mode 100644 index 000000000000..278e115d3683 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcAnalysisTool.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef __ZDCANALYSISTOOL_H__ +#define __ZDCANALYSISTOOL_H__ + +#include "AsgTools/AsgTool.h" +#include "xAODForward/ZdcModuleContainer.h" +#include "xAODTrigL1Calo/TriggerTowerContainer.h" + +#include "ZdcAnalysis/ZDCDataAnalyzer.h" +#include "ZdcAnalysis/ZDCTriggerEfficiency.h" +#include "ZdcAnalysis/IZdcAnalysisTool.h" + +#include "TF1.h" +#include "TMath.h" + +namespace ZDC +{ + +class ZdcAnalysisTool : public virtual IZdcAnalysisTool, public asg::AsgTool +{ + + ASG_TOOL_CLASS(ZdcAnalysisTool, ZDC::IZdcAnalysisTool) + + public: + ZdcAnalysisTool(const std::string& name); + virtual ~ZdcAnalysisTool(); + + //interface from AsgTool + StatusCode initializeTool(); + StatusCode initialize() {return initializeTool();} + void initialize80MHz(); + void initialize40MHz(); + void initializeTriggerEffs(unsigned int runNumber); + + StatusCode recoZdcModule(const xAOD::ZdcModule& module); + StatusCode recoZdcModules(const xAOD::ZdcModuleContainer& moduleContainer); + StatusCode reprocessZdc(); + + // methods for processing, used for decoration + bool sigprocMaxFinder(const std::vector<unsigned short>& adc, float deltaT, float& amp, float& time, float& qual); + bool sigprocSincInterp(const std::vector<unsigned short>& adc, float deltaT, float& amp, float& time, float& qual); + + void setEnergyCalibrations(unsigned int runNumber); + void setTimeCalibrations(unsigned int runNumber); + + float getModuleSum(int side); + + //float getModuleFitAmplitude(int side, int imod); + //float getModuleFitT0(int side, int imod); + //float getModuleAmplitude(int side, int imod); + //float getModuleTime(int side, int imod); + //float getModuleChisq(int side, int imod); + //float getModuleStatus(int side, int imod); + + //float getModuleCalibAmplitude(int side, int imod); + //float getModuleCalibTime(int side, int imod); + + float getCalibModuleSum(int side); + float getAverageTime(int side); + bool sideFailed(int side); + unsigned int getModuleMask(); + + float getTriggerEfficiency(int side); + + const ZDCDataAnalyzer* getDataAnalyzer() {return m_zdcDataAnalyzer;} + + private: + // Private methods + // + ZDCDataAnalyzer* initializeDefault(); + + StatusCode configureNewRun(unsigned int runNumber); + + // Data members + // + std::string m_name; + bool m_init; + std::string m_configuration; + std::string m_zdcAnalysisConfigPath; + std::string m_zdcEnergyCalibFileName; + std::string m_zdcTimeCalibFileName; + std::string m_zdcTriggerEffParamsFileName; + + bool m_writeAux; + std::string m_auxSuffix; + + bool m_eventReady; + unsigned int m_runNumber; + unsigned int m_lumiBlock; + + // internal functions + TF1* tf1SincInterp; + + std::string m_zdcModuleContainerName; + const xAOD::ZdcModuleContainer* m_zdcModules; + bool m_flipEMDelay; + bool m_lowGainOnly; + bool m_doCalib; + int m_forceCalibRun; + int m_forceCalibLB; + + // Parameters that control the pulse fitting analysis + // + unsigned int m_numSample; + float m_deltaTSample; + unsigned int m_presample; + unsigned int m_peakSample; + float m_Peak2ndDerivThresh; + float m_t0; + float m_tau1; + float m_tau2; + bool m_fixTau1; + bool m_fixTau2; + float m_deltaTCut; + float m_ChisqRatioCut; + + std::array<std::array<TSpline*, 4>, 2> m_splines; + + ZDCDataAnalyzer* m_zdcDataAnalyzer; + ZDCDataAnalyzer* m_zdcDataAnalyzer_40MHz; + ZDCDataAnalyzer* m_zdcDataAnalyzer_80MHz; + ZDCDataAnalyzer::ZDCModuleFloatArray _peak2ndDerivMinSamples; + ZDCDataAnalyzer::ZDCModuleFloatArray _peak2ndDerivMinThresholdsHG; + ZDCDataAnalyzer::ZDCModuleFloatArray _peak2ndDerivMinThresholdsLG; + + + ZDCTriggerEfficiency* m_zdcTriggerEfficiency; + +}; + +} // namespace ZDC + +#endif + + + diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcSincInterp.h b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcSincInterp.h new file mode 100644 index 000000000000..ec4f60a5d69a --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/ZdcAnalysis/ZdcSincInterp.h @@ -0,0 +1,12 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef _ZDC_SINC_INTERP_ +#define _ZDC_SINC_INTERP_ + +namespace ZDC +{ +double SincInterp(double* xvec, double* pvec); +} +#endif diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/cmt/Makefile.RootCore b/ForwardDetectors/ZDC/ZdcAnalysis/cmt/Makefile.RootCore new file mode 100644 index 000000000000..4b26464a70b3 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/cmt/Makefile.RootCore @@ -0,0 +1,60 @@ +# this makefile also gets parsed by shell scripts +# therefore it does not support full make syntax and features +# edit with care + +# for full documentation check: +# https://twiki.cern.ch/twiki/bin/viewauth/Atlas/RootCore#Package_Makefile + + +# the name of the package: +PACKAGE = ZdcAnalysis + +# the libraries to link with this one: +PACKAGE_PRELOAD = + +# additional compilation flags to pass (not propagated to dependent packages): +PACKAGE_CXXFLAGS = + +# additional compilation flags to pass (propagated to dependent packages): +PACKAGE_OBJFLAGS = + +# additional linker flags to pass (for compiling the library): +PACKAGE_LDFLAGS = + +# additional linker flags to pass (for compiling binaries): +PACKAGE_BINFLAGS = + +# additional linker flags to pass (propagated to client libraries): +PACKAGE_LIBFLAGS = + +# the list of packages we depend on: +PACKAGE_DEP = xAODRootAccess xAODBase xAODForward xAODEventInfo AsgTools xAODTrigL1Calo PathResolver + +# the list of packages we use if present, but that we can work without : +PACKAGE_TRYDEP = + +# list pattern of scripts to link directly into binary path: +PACKAGE_SCRIPTS = + +# whether to use pedantic compilation: +PACKAGE_PEDANTIC = 1 + +# whether to turn *off* optimization (set to dict to do it only for +# dictionaries): +PACKAGE_NOOPT = 0 + +# whether to build no library (needs to be set if no source files are +# present): +PACKAGE_NOCC = 0 + +# whether we build a reflex dictionary: +PACKAGE_REFLEX = 0 + +# the list of all unit tests that should be called in recursive testing, +# i.e. in unit tests that call other unit tests +# for that unit tests need to pass on all machines, and run very fast +PACKAGE_RECURSIVE_UT = + + + +include $(ROOTCOREDIR)/Makefile-common diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/cmt/requirements b/ForwardDetectors/ZDC/ZdcAnalysis/cmt/requirements new file mode 100644 index 000000000000..937d3d8020ad --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/cmt/requirements @@ -0,0 +1,24 @@ +package ZdcAnalysis + +author Peter Steinberg <peter.steinberg@bnl.gov> + +use AtlasPolicy AtlasPolicy-* + +use AsgTools AsgTools-* Control/AthToolSupport +use AtlasROOT AtlasROOT-* External +use GaudiInterface GaudiInterface-* External +use xAODForward xAODForward-* Event/xAOD +use xAODTrigL1Calo xAODTrigL1Calo-* Event/xAOD + +private +use xAODEventInfo xAODEventInfo-* Event/xAOD +use PathResolver PathResolver-* Tools +end_private + +library ZdcAnalysis ../Root/*.cxx +apply_pattern component_library + +apply_pattern declare_python_modules files="*.py" +apply_pattern declare_joboptions files="*.py" + + diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/data/ZdcAnalysisConfig.conf b/ForwardDetectors/ZDC/ZdcAnalysis/data/ZdcAnalysisConfig.conf new file mode 100644 index 000000000000..2378e74959fc --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/data/ZdcAnalysisConfig.conf @@ -0,0 +1,3 @@ +ZdcEnergyCalibFileName ZdcCalibration_comb_v4.root +ZdcTriggerEffFileName ZdcTriggerEffParameters_v3.root + diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/tools/RunZDCTreeAnalysis.C b/ForwardDetectors/ZDC/ZdcAnalysis/tools/RunZDCTreeAnalysis.C new file mode 100644 index 000000000000..fc9c53e45090 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/tools/RunZDCTreeAnalysis.C @@ -0,0 +1,216 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include <string> +#include <iostream> +#include <sstream> + +void SetT0Values(double LGt0Array[2][4], double HGt0Array[2][4]) +{ + + HGt0Array[0][0] = 44.0 + 0.24; + HGt0Array[0][1] = 40.7 - 0.34; + HGt0Array[0][2] = 48.2 + 0.13; + HGt0Array[0][3] = 35.5 + 0.53; + + HGt0Array[1][0] = 35.2 + 0.04; + HGt0Array[1][1] = 31.3 - 0.22; + HGt0Array[1][2] = 40.9 - 0.15; + HGt0Array[1][3] = 30.7 - 0.17; + + LGt0Array[0][0] = 42.5 + 0.15; + LGt0Array[0][1] = 39.0 - 0.52 + 0.027; + LGt0Array[0][2] = 46.3 - 0.06 - 0.06; + LGt0Array[0][3] = 33.7 - 0.37 - 0.10; + + LGt0Array[1][0] = 33.4 + 0.33 - 0.66; + LGt0Array[1][1] = 30.1 - 0.21 - 0.04; + LGt0Array[1][2] = 39.5 - 0.37 - 0.05; + LGt0Array[1][3] = 29.6 - 0.28 - 0.058; + +} + +void LoadCalibrations(ZDCTreeAnalysis* ana, std::string filename, int runNumber, bool eCalib = true, bool t0Calib = true) +{ + TFile* file = TFile::Open(filename.c_str()); + if (!file->IsOpen()) { + std::cout << "Error opening calibration file, quitting" << std::endl; + } + + std::ostringstream runString; + runString << "run" << runNumber; + + if (eCalib) { + + std::string calibNamePrefix = "ZDC_Ecalib_" + runString.str(); + + std::array<std::array<TSpline*, 4>, 2> ECalibSplinePtrs; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + std::ostringstream sideModStr; + sideModStr << "_s" << side << "_m" << module; + + TSpline3* spline_p = (TSpline3*) file->GetObjectChecked((calibNamePrefix + sideModStr.str()).c_str(), "TSpline3"); + + ECalibSplinePtrs[side][module] = spline_p; + } + } + + ana->LoadEnergyCalibrations(ECalibSplinePtrs); + } + + if (t0Calib) { + std::string calibNamePrefix = "ZDC_T0calib_" + runString.str(); + + std::array<std::array<TSpline*, 4>, 2> t0CalibSplinePtrsHG, t0CalibSplinePtrsLG; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + std::ostringstream sideModStr; + sideModStr << "_s" << side << "_m" << module; + + std::string HGName = calibNamePrefix + "_HG" + sideModStr.str(); + std::string LGName = calibNamePrefix + "_LG" + sideModStr.str(); + + TSpline3* HGSpline_p = (TSpline3*) file->GetObjectChecked(HGName.c_str(), "TSpline3"); + TSpline3* LGSpline_p = (TSpline3*) file->GetObjectChecked(LGName.c_str(), "TSpline3"); + + if (!HGSpline_p || !LGSpline_p) { + std::cout << "Error reading t0 calibrations for side, mod = " << side << ", " << module << " -- quitting" << std::endl; + return; + } + + t0CalibSplinePtrsHG[side][module] = HGSpline_p; + t0CalibSplinePtrsLG[side][module] = LGSpline_p; + } + } + + ana->LoadT0Calibrations(t0CalibSplinePtrsHG, t0CalibSplinePtrsLG); + } + + file->Close(); +} + +ZDCTreeAnalysis* InitZDCAnalysis(std::string inputFile, std::string calibFile, bool fixTau1, bool fixTau2, + bool eCalib = true, bool t0Calib = true, bool doSlew = false) +{ + + ZDCTreeAnalysis* ana = new ZDCTreeAnalysis(inputFile, 7, 12.5, 0); + + ana->SetDebugLevel(0); + + // ADC over/underflow thresholds + // + ZDCDataAnalyzer::ZDCModuleFloatArray HGOverFlowADC = {800, 800, 800, 800, 800, 800, 800, 800}; + ZDCDataAnalyzer::ZDCModuleFloatArray HGUnderFlowADC = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray LGOverFlowADC = {950, 950, 950, 950, 950, 950, 950, 950}; + + ana->SetADCOverUnderflowValues(HGOverFlowADC, HGUnderFlowADC, LGOverFlowADC); + + // Set Tau and nominal timing offsets + // + ZDCDataAnalyzer::ZDCModuleBoolArray fixTau1Arr, fixTau2Arr; + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + fixTau1Arr[side][module] = fixTau1; + fixTau2Arr[side][module] = fixTau2; + } + } + + ZDCDataAnalyzer::ZDCModuleFloatArray tau1 = {3.9, 3.4, 4.1, 4.2, + 4.2, 3.6, 3.3, 3.4}; + + ZDCDataAnalyzer::ZDCModuleFloatArray tau2 = {20.0, 20.4, 18.9, 20.8, + 19.1, 21.9, 22.6, 23.4}; + + + ZDCDataAnalyzer::ZDCModuleFloatArray t0HG = {44.0 + 0.24, 40.7 - 0.34, 48.2 + 0.13, 35.5 + 0.53, + 35.2 + 0.04, 31.3 - 0.22, 40.9 - 0.15, 30.7 - 0.17}; + + ZDCDataAnalyzer::ZDCModuleFloatArray t0LG = {42.5 + 0.15, 39.0 - 0.52 + 0.027, 46.3 - 0.06 - 0.06, 33.7 - 0.37 - 0.10, + 33.4 + 0.33 - 0.66, 30.1 - 0.21 - 0.04, 39.5 - 0.37 - 0.05, 29.6 - 0.28 - 0.058}; + + + ana->SetTauT0Values(fixTau1Arr, fixTau2Arr, tau1, tau2, t0HG, t0LG); + + int runNumber = ana->GetRunNumber(); + + if (doSlew) { + // float HGSlewCoeff[2][4][3] = {-6.5e-2, 2.85e-2, -2.83e-3, + // -5.5e-2, 5.13e-2, 5.6e-3, + // -1.45e-3, 9.3e-2, 3.9e-3, + // -2.36e-2, 8.3e-2, 1.1e-3, + // -6.5e-2, 4.84e-2, -3.7e-3, + // 1.34e-2, 6.57e-2, 5.37e-3, + // -5.37e-2, 3.49e-2, 3.8e-3, + // -3.3e-2,3.9e-2,2.2e-3}; + + // float LGSlewCoeff[2][4][3] = {-9.6e-2, 4.39e-2, 2.93e-3, //[0][0] + // -5.0e-2, 14.9e-2, 20.6e-3, //[0][1] + // -4.4e-2, 5.3e-2, 0, //[0][2] + // -9.90e-2, 4.08e-2, 0, //[0][3] + // -8.7e-2, 4.2e-2, -3.2e-3, //[1][0] + // -3.26e-2, 3.84e-2, -2.32e-3, //[1][1] + // -26.8e-2, -2.64e-2, -5.3e-3,//[1][2] + // -13.2e-2, 0.45e-2, -2.4e-3}; //[1][3] + // + // + std::array<std::array<std::vector<float>, 4>, 2> slewingParamsHG, slewingParamsLG; + + slewingParamsHG[0][0] = {0, -6.5e-2, 2.85e-2, -2.83e-3}; + slewingParamsHG[0][1] = {0, -5.5e-2, 5.13e-2, 5.6e-3}; + slewingParamsHG[0][2] = {0, -1.45e-3, 9.3e-2, 3.9e-3}; + slewingParamsHG[0][3] = {0, -2.36e-2, 8.3e-2, 1.1e-3}; + + slewingParamsHG[1][0] = {0, -6.5e-2, 4.84e-2, -3.7e-3}; + slewingParamsHG[1][1] = {0, 1.34e-2, 6.57e-2, 5.37e-3}; + slewingParamsHG[1][2] = {0, -5.37e-2, 3.49e-2, 3.8e-3}; + slewingParamsHG[1][3] = {0, -3.3e-2, 3.9e-2, 2.2e-3}; + + slewingParamsLG[0][0] = {0, -9.6e-2, 4.39e-2, 2.93e-3 }; + slewingParamsLG[0][1] = {0, -5.0e-2, 14.9e-2, 20.6e-3 }; + slewingParamsLG[0][2] = {0, -4.4e-2, 5.3e-2, 0, }; + slewingParamsLG[0][3] = {0, -9.90e-2, 4.08e-2, 0, }; + + slewingParamsLG[1][0] = {0, -8.7e-2, 4.2e-2, -3.2e-3 }; + slewingParamsLG[1][1] = {0, -3.26e-2, 3.84e-2, -2.32e-3}; + slewingParamsLG[1][2] = {0, -26.8e-2, -2.64e-2, -5.3e-3 }; + slewingParamsLG[1][3] = {0, -13.2e-2, 0.45e-2, -2.4e-3 }; + + ana->SetSlewingCoeff(slewingParamsHG, slewingParamsLG); + } + + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutHG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray chisqDivAmpCutLG = {10, 10, 10, 10, 10, 10, 10, 10}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowHG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighHG = {8, 8, 8, 11, 8, 10, 8, 12}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutLowLG = {-6, -5, -5, -5, -5, -5, -5, -5}; + ZDCDataAnalyzer::ZDCModuleFloatArray DeltaT0CutHighLG = {8, 8, 8, 11, 8, 10, 8, 12}; + + ana->SetCutValues(chisqDivAmpCutHG, chisqDivAmpCutLG, DeltaT0CutLowHG, DeltaT0CutHighHG, DeltaT0CutLowLG, DeltaT0CutHighLG); + + + // float moduleECalib[2][4] = {1., 1, 1, 1, 1., 1, 1, 1}; + + // if (eCalib) ana->EnableECalib(moduleECalib); + + if (eCalib || t0Calib) LoadCalibrations(ana, calibFile, runNumber, eCalib, t0Calib); + + return ana; +} + +void RunZDCAnalysis(std::string inputFile, std::string outputFile, std::string calibFile, int nevent = -1, + bool fixTau1 = true, bool fixTau2 = true, bool eCalib = false, bool t0Calib = false, bool doSlew = false) +{ + + ZDCTreeAnalysis* ana = InitZDCAnalysis(inputFile, calibFile, fixTau1, fixTau2, eCalib, t0Calib, doSlew); + + ana->OpenOutputTree(outputFile); + ana->Loop(nevent); + ana->CloseOutputTree(); +} + + diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.cxx b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.cxx new file mode 100644 index 000000000000..b251b010fca1 --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.cxx @@ -0,0 +1,603 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#define ZDCNLCalibration_cxx +#include "ZDCNLCalibration.h" + +#include <TF1.h> +#include <TH2.h> +#include <TStyle.h> +#include <TCanvas.h> + +#include <iomanip> +#include <numeric> + +void ZDCNLCalibration::FillLumiBlockEvtMap() +{ + Long64_t numEntries = m_tree->GetEntriesFast(); + + unsigned int countPassed = 0; + + int lastLumiBlock = -1; + int LBStartEntry = -1; + + for (Long64_t entry = 0; entry < numEntries; entry++) { + Long64_t numBytes = m_tree->GetEntry(entry); + + if (m_useGRL && passBits !=0) { + //std::cout << "lumiBlock = " << lumiBlock << " passBits = " << passBits << std::endl; + continue; // reject based on GRL or errors + } + + if (lumiBlock != lastLumiBlock) { + if (lastLumiBlock > -1) { + m_LumiBlockEvtMap.insert(LBEvtMap::value_type(lumiBlock, std::pair<unsigned int, unsigned int>(LBStartEntry, entry - 1))); + } + + LBStartEntry = entry; + lastLumiBlock = lumiBlock; + } + + countPassed++; + } + + if (m_debugLevel >= 0) { + std::cout << "From a total of " << numEntries << " entries, " << countPassed << " were selected for analysis" << std::endl; + } +} + +void ZDCNLCalibration::AddCalibration(size_t side, std::string tag, const CalibData& calib) +{ + std::map<std::string, CalibData>::iterator iter = m_calibrations.at(side).find(tag); + if (iter != m_calibrations[side].end()) (*iter).second = calib;//*iter = std::pair<std::string, CalibData>(tag, calib); + else { + m_calibrations[side].insert(std::pair<std::string, CalibData>(tag, calib)); + } +} + +CalibData ZDCNLCalibration::GetCalibration(size_t side, std::string tag) +{ + CalibData null; + + auto iter = m_calibrations.at(side).find(tag); + if (iter != m_calibrations.at(side).end()) { + return iter->second; + } + else return null; +} + +std::pair<float, float> ZDCNLCalibration::FindSNRange(size_t LBLow, size_t LBHigh, size_t side) +{ + static TH1D* snHist = new TH1D("ZDCNLCalibSNHist", "", 200, 0, 2000); + snHist->Reset(); + + LBEvtMap::const_iterator LBStart = m_LumiBlockEvtMap.lower_bound(LBLow); + LBEvtMap::const_iterator LBEnd = m_LumiBlockEvtMap.upper_bound(LBHigh); + + // Select which trigger we're going to look at based on the side + // + const bool& trigger = (side == 1 ? L1_ZDC_C : L1_ZDC_A); + + for ( LBEvtMap::const_iterator iter = LBStart; iter != LBEnd; iter++) { + unsigned int entryStart = iter->second.first; + unsigned int entryEnd = iter->second.second; + + for (unsigned int entry = entryStart; entry < entryEnd; entry++) { + Long64_t nb = m_tree->GetEntry(entry); + if (nb < 0) { + std::cout << "Error reading entry " << entry << ", quitting" << std::endl; + throw; + } + + if (!trigger) continue; + + int testMask = zdc_ZdcModuleMask >> side*4; + if ((testMask & 0xf) != 0xf) continue; + + float sumAmp = zdc_ZdcAmp[side]; + snHist->Fill(sumAmp); + } + } + + int ibin = snHist->GetMaximumBin(); + double center = snHist->GetBinCenter(ibin); + double maxCounts = snHist->GetBinContent(ibin); + + static TF1* gaussFunc = new TF1("gaussFunc", "gaus", 100, 2000); + + gaussFunc->SetParameters(maxCounts, center, 100); + snHist->Fit("gaussFunc", "", "", center*0.7, center*1.3); + + double gaussMean = gaussFunc->GetParameter(1); + double gaussWidth = gaussFunc->GetParameter(2); + + double cutLow = gaussMean -2.*gaussWidth; + double cutHigh = gaussMean + 2*gaussWidth; + + if (m_debugLevel >= 0) { + std::cout << "SN cut range = " << cutLow << " to " << cutHigh << std::endl; + } + + return std::pair<float, float>(cutLow, cutHigh); +} + +std::pair<std::pair<float, float>,std::pair<float, float> > +ZDCNLCalibration::FindSNTwoNRanges(size_t LBLow, size_t LBHigh, size_t side) +{ + static TH1D* sntnHist = new TH1D("ZDCNLCalibSNTNHist", "", 200, 0, 2000); + sntnHist->Reset(); + + LBEvtMap::const_iterator LBStart = m_LumiBlockEvtMap.lower_bound(LBLow); + LBEvtMap::const_iterator LBEnd = m_LumiBlockEvtMap.upper_bound(LBHigh); + + // Select which trigger we're going to look at based on the side + // + const bool& trigger = (side == 1 ? L1_ZDC_C : L1_ZDC_A); + + for ( LBEvtMap::const_iterator iter = LBStart; iter != LBEnd; iter++) { + unsigned int entryStart = iter->second.first; + unsigned int entryEnd = iter->second.second; + + for (unsigned int entry = entryStart; entry < entryEnd; entry++) { + Long64_t nb = m_tree->GetEntry(entry); + if (nb < 0) { + std::cout << "Error reading entry " << entry << ", quitting" << std::endl; + throw; + } + + if (!trigger) continue; + + int testMask = zdc_ZdcModuleMask >> side*4; + if ((testMask & 0xf) != 0xf) continue; + + float sumAmp = zdc_ZdcAmp[side]; + sntnHist->Fill(sumAmp); + } + } + + int ibin = sntnHist->GetMaximumBin(); + double center = sntnHist->GetBinCenter(ibin); + double maxCounts = sntnHist->GetBinContent(ibin); + + static TF1* twogaussFunc = new TF1("twogaussFunc", "[0]*exp(-pow((x-[1])/[2],2)/2.) + [3]*exp(-pow((x-[4])/[5],2)/2.)", 100, 2000); + + twogaussFunc->SetParameters(maxCounts, center, 100, maxCounts/2, 2*center, 200); + sntnHist->Fit("twogaussFunc", "", "", center*0.7, 2*center*1.3); + + double gaussMean1 = twogaussFunc->GetParameter(1); + double gaussMean2 = twogaussFunc->GetParameter(4); + + double gaussWidth1 = std::abs(twogaussFunc->GetParameter(2)); + double gaussWidth2 = std::abs(twogaussFunc->GetParameter(5)); + + double cutLow1 = gaussMean1 -2.*gaussWidth1; + double cutHigh1 = gaussMean1 + 2*gaussWidth1 +; + double cutLow2 = gaussMean2 -2.*gaussWidth2; + double cutHigh2 = gaussMean2 + 2*gaussWidth2; + + if (cutHigh1 > cutLow2) { + double middle = 0.5*(cutHigh1 + cutLow2); + cutHigh1 = middle; + cutLow2 = middle; + } + + if (m_debugLevel >= 0) { + std::cout << "SN cut range = " << cutLow1 << " to " << cutHigh1 << std::endl; + std::cout << "TN cut range = " << cutLow2 << " to " << cutHigh2 << std::endl; + } + + return std::pair<std::pair<float, float>, std::pair<float, float> >(std::pair<float, float>(cutLow1, cutHigh1), + std::pair<float, float>(cutLow2, cutHigh2)); +} + +void ZDCNLCalibration::Calibrate(size_t side, std::string calibInput, std::string calibOutput, + size_t LBLow, size_t LBHigh, std::array<int, 4> maxPowerModule, + std::vector<std::pair<double, double> > nNeutERange, + bool excludeHE, float heSumThresh, float HEDeweight) +{ + std::for_each(maxPowerModule.begin(), maxPowerModule.end(), + [](int power) { + if (power == 0) { + std::cout << "Found max power = 0, quitting" << std::endl; + return; + } + } ); + + // Set up container for sums that we will use to calcualting the weights + // + size_t numWeights = std::accumulate(maxPowerModule.begin(), maxPowerModule.end(), 0); + size_t arrayDim = 4*m_maxNLPower; + + size_t arrayDim2D = arrayDim*arrayDim; + + size_t numNeutMax = nNeutERange.size(); + + std::vector<double> sumsHE(arrayDim, 0); + std::vector<double> sums2DHE(arrayDim2D, 0); + + std::vector<std::vector<double> > sumsNeutVec(numNeutMax, std::vector<double>(arrayDim, 0)); + std::vector<std::vector<double> > sums2DNeutVec(numNeutMax, std::vector<double>(arrayDim2D, 0)); + + LBEvtMap::const_iterator LBStart = m_LumiBlockEvtMap.lower_bound(LBLow); + LBEvtMap::const_iterator LBEnd = m_LumiBlockEvtMap.upper_bound(LBHigh); + + // Select which trigger we're going to look at based on the side + // + const bool& triggerOpp = (side == 1 ? L1_ZDC_C : L1_ZDC_A); + const bool& triggerSame = (side == 1 ? L1_ZDC_A : L1_ZDC_C); + + std::vector<int> numNeutEvent(numNeutMax, 0); + int numHEEvent = 0; + + // + // + std::string calibName = (calibInput != "" ? calibInput : "default"); + CalibData calib = GetCalibration(side, calibName); + + for ( LBEvtMap::const_iterator iter = LBStart; iter != LBEnd; iter++) { + unsigned int entryStart = iter->second.first; + unsigned int entryEnd = iter->second.second; + + for (unsigned int entry = entryStart; entry < entryEnd; entry++) { + Long64_t nb = m_tree->GetEntry(entry); + if (nb < 0) { + std::cout << "Error reading entry " << entry << ", quitting" << std::endl; + throw; + } + + int testMask = zdc_ZdcModuleMask >> side*4; + if ((testMask & 0xf) != 0xf) continue; + + double sumAmp = CalculateEnergy(zdc_ZdcModuleAmp[side], calib); + + if (triggerSame && sumAmp > heSumThresh && !excludeHE) { + AddToSums(sumsHE, sums2DHE, zdc_ZdcModuleAmp[side]); + numHEEvent++; + } + + // For 1N we require the opposite side trigger + // + if (triggerOpp && sumAmp > nNeutERange[0].first && sumAmp < nNeutERange[0].second) { + AddToSums(sumsNeutVec[0], sums2DNeutVec[0], zdc_ZdcModuleAmp[side]); + numNeutEvent[0]++; + } + + for (size_t iNNeut = 1; iNNeut < numNeutMax; iNNeut++) { + if (sumAmp > nNeutERange[iNNeut].first && sumAmp < nNeutERange[iNNeut].second) { + AddToSums(sumsNeutVec[iNNeut], sums2DNeutVec[iNNeut], zdc_ZdcModuleAmp[side]); + numNeutEvent[iNNeut]++; + } + } + } + } + + if (m_debugLevel >= 0) { + std::cout << "Statistics for side " << side << ", lb range = " << LBLow << ", " << LBHigh + << " : # high energy events = " << numHEEvent; + + for (size_t iNNeut = 0; iNNeut < numNeutMax; iNNeut++) { + std::cout << ", # of " + std::to_string(iNNeut) + " N events = " << numNeutEvent[iNNeut]; + } + + std::cout << std::endl; + } + + + // Normalize the averages + // + for (size_t iNNeut = 0; iNNeut < numNeutMax; iNNeut++) { + if (numNeutEvent[iNNeut] == 0) { + std::cout << "Found no " + std::to_string(iNNeut) + "N events, quitting" << std::endl; + return; + } + + std::for_each(sumsNeutVec[iNNeut].begin(), sumsNeutVec[iNNeut].end(), [&](double& sum) {sum /= numNeutEvent[iNNeut];}); + std::for_each(sums2DNeutVec[iNNeut].begin(), sums2DNeutVec[iNNeut].end(), [&](double& sum) {sum /= numNeutEvent[iNNeut];}); + } + + if (!excludeHE) { + if (numHEEvent == 0) { + std::cout << "Found no high-energy events, quitting" << std::endl; + return; + } + + std::for_each(sumsHE.begin(), sumsHE.end(), [&](double& sum) {sum /= numHEEvent;}); + std::for_each(sums2DHE.begin(), sums2DHE.end(), [&](double& sum) {sum /= numHEEvent;}); + } + + + // Now we have the averages, set up to do the minimization + // + size_t numFitParams = numWeights; + TMatrixD minimMatrix(numFitParams, numFitParams); + TVectorD minimVector(numFitParams); + + FillMinimizationData(minimMatrix, minimVector, maxPowerModule, HEDeweight, + sumsNeutVec, sumsHE, sums2DNeutVec, sums2DHE); + + if (m_debugLevel >= 2) { + std::cout << "Dumping matrix equation: " << std::endl; + + for (size_t index1 = 0; index1 < numFitParams; index1++) { + std::cout << "| "; + + for (size_t index2 = 0; index2 < numFitParams; index2++) { + std::cout << std::scientific << std::setw(9) << std::setprecision(2) << minimMatrix(index1, index2) << " "; + } + + std::cout << "| | w_" << index1 << " = | " << minimVector(index1) << std::endl; + } + std::cout << std::endl; + } + + + TDecompLU lu(minimMatrix); + lu.Decompose(); + + bool status = lu.Solve(minimVector); + + if (!status) { + std::cout << "Minimization failed for side " << side << ", lb range " + << LBLow << ", " << LBHigh << endl; + } + else { + CalibData calibData; + calibData.LBStart = LBLow; + calibData.LBEnd = LBHigh; + + int weightIndex = 0; + for (size_t module : {0, 1, 2, 3}) { + calibData.weights[module].assign(maxPowerModule[module], 0); + + for (size_t power = 0; power < maxPowerModule[module]; power++) { + calibData.weights.at(module).at(power) = minimVector(weightIndex++); + + if (m_debugLevel >= 0) { + std::cout << "Weight for module,power " << module << ", " << power << " = " << calibData.weights.at(module).at(power) + << std::endl; + } + } + } + + // Now store this calibration + // + AddCalibration(side, calibOutput, calibData); + } +} + +void ZDCNLCalibration::TestCalibration(int side, std::string name) +{ + std::string calibName = (name != "" ? name : "default"); + CalibData calib = GetCalibration(side, calibName); + + if (m_debugLevel >= 0) { + std::cout << "Testing calibration for side " << side << "name: " << calibName << std::endl; + } + + m_testCalibSNHist = new TH1D("testCalibSNHist" , "", 4000, 0, 200000); + for (int module : {0, 1, 2, 3}) { + std::string fracHistName = "testCalibHEFracHist_" + std::to_string(module); + std::string energyHistName = "testCalibEnergyHist_" + std::to_string(module); + + m_testCalibHEFracHist[module] = new TH1D(fracHistName.c_str(), "", 200, 0., 1.); + m_testCalibEnergyHist[module] = new TH1D(energyHistName.c_str(), "", 1000, 0., 100000); + } + + static std::array<float, 4> treeRawAmp; + static std::array<float, 4> treeCalibAmp; + static float treeRawSum, treeCalibSum, treeRawSumOpp; + static unsigned int treeEventNumber; + static bool passedSN, passedTN, passedHE; + + if (m_testTree != 0) delete m_testTree; + + m_testTree = new TTree("ZDCNLCalibTest", "ZDCNLCalibTest"); + m_testTree->SetDirectory(0); + + m_testTree->Branch("EventNumber", &treeEventNumber, "eventNumber/I"); + m_testTree->Branch("lumiBlock", &lumiBlock, "lumiBlock/I"); + m_testTree->Branch("L1_ZDC_A", &L1_ZDC_A, "L1_ZDC_A/b"); + m_testTree->Branch("L1_ZDC_C", &L1_ZDC_C, "L1_ZDC_C/b"); + m_testTree->Branch("L1_ZDC_A_C", &L1_ZDC_A_C, "L1_ZDC_A_C/b"); + + m_testTree->Branch("RawSum", &treeRawSum, "RawSum/f"); + m_testTree->Branch("CalibSum", &treeCalibSum, "CalibSum/f"); + m_testTree->Branch("RawAmp", &treeRawAmp[0], "RawAmp[4]/f"); + m_testTree->Branch("CalibAmp", &treeCalibAmp[0], "CalibAmp[4]/f"); + m_testTree->Branch("RawSumOpp", &treeRawSumOpp, "RawSumOpp/f"); + + LBEvtMap::const_iterator LBStart = m_LumiBlockEvtMap.lower_bound(calib.LBStart); + LBEvtMap::const_iterator LBEnd = m_LumiBlockEvtMap.upper_bound(calib.LBEnd); + + int count = 0; + for ( LBEvtMap::const_iterator iter = LBStart; iter != LBEnd; iter++) { + unsigned int entryStart = iter->second.first; + unsigned int entryEnd = iter->second.second; + + for (unsigned int entry = entryStart; entry < entryEnd; entry++) { + Long64_t nb = m_tree->GetEntry(entry); + if (nb < 0) { + std::cout << "Error reading entry " << entry << ", quitting" << std::endl; + throw; + } + + int testMask = zdc_ZdcModuleMask >> side*4; + if ((testMask & 0xf) != 0xf) continue; + + double sumAmp = zdc_ZdcAmp[side]; + + // Calculate the calibrated energy + // + float sumCalibAmp = 0; + float weightIndex = 0; + + std::array<double, 4> calibAmpModule = {0, 0, 0, 0}; + + if (m_debugLevel > 2 && count < 20) { + std::cout << "TestCalibration:: dumping calibration results for event " << count << std::endl; + } + + for (size_t module : {0, 1, 2, 3}) { + float amp = zdc_ZdcModuleAmp[side][module]; + float ampPow = amp; + + for (size_t power = 0; power < calib.weights[module].size(); power++) { + calibAmpModule[module] += calib.weights[module][power]*ampPow; + ampPow *= amp;; + } + + double energy = calibAmpModule[module]; + sumCalibAmp += energy; + m_testCalibEnergyHist[module]->Fill(energy); + + treeRawAmp[module] = amp; + treeCalibAmp[module] = energy; + + if (m_debugLevel > 2 && count < 20) { + std::cout << "Module " << module << " : raw, calibrated energy = " << std::fixed << amp << ", " << energy << std::endl; + } + } + + if (m_debugLevel > 2 && count < 20) { + std::cout << "Total: raw, calibrated energy = " << std::fixed << sumAmp << ", " << sumCalibAmp << std::endl; + } + + treeRawSum = sumAmp; + treeRawSumOpp = (side == 0 ? zdc_ZdcAmp[1] : zdc_ZdcAmp[0]); + treeCalibSum = sumCalibAmp; + + m_testTree->Fill(); + + m_testCalibSNHist->Fill(sumCalibAmp); + + count++; + } + } + + m_haveTest = true; +} + +void ZDCNLCalibration::FillMinimizationData(TMatrixD& minimMatrix, TVectorD& minimVector, + std::array<int, 4> maxPowerModule, float HEDeweight, + const std::vector<std::vector<double> >& sums1DVec, const std::vector<double>& sumsHE, + const std::vector<std::vector<double> >& sums2DVec, const std::vector<double>& sumsHE2D) +{ + size_t numWeights = minimVector.GetNrows(); + size_t numColumns = minimMatrix.GetNcols(); + size_t numRows = minimMatrix.GetNrows(); + size_t numNeutMax = sums1DVec.size(); + + if (numRows != numWeights || numColumns != numWeights) throw; + + // if (m_debugLevel > 0) std::cout << "Filling single neutorn entries in matrix" << std::endl; + + double sumFracSqr = 0; + for (size_t module : {0, 1, 2, 3}) { + sumFracSqr += m_HEFraction.at(module)*m_HEFraction.at(module); + } + + // Start with the single neutron contributions + // + { + size_t index1 = 0; + + for (size_t module1 : {0, 1, 2, 3}) { + for (size_t power1 = 0; power1 < maxPowerModule[module1]; power1++) { + + size_t index2 = 0; + size_t sumIndexOffset = (module1*m_maxNLPower + power1)*4*m_maxNLPower; + + for (size_t module2 : {0, 1, 2, 3}) { + for (size_t power2 = 0; power2 < maxPowerModule[module2]; power2++) { + + // The N neutron contributions + // + unsigned int sum2DIndex = sumIndexOffset + power2; + double element = 0; + std::for_each(sums2DVec.begin(), sums2DVec.end(), [&] (const std::vector<double>& sums) {element += 2*sums.at(sum2DIndex);}); + + // The TN contribution + // + // element += 2*sumsTN2D.at(sumIndexOffset + power2); + + // The HE fraction contribution + // + double sum = sumsHE2D.at(sumIndexOffset + power2); + sum *= HEDeweight; + + if (module2 == module1) element += 2*sum; + element -= 2*m_HEFraction.at(module2)*sum; + element -= 2*m_HEFraction.at(module1)*sum; + element += 2*sumFracSqr*sum; + + minimMatrix(index1, index2) += element; + + if (m_debugLevel > 2) { + std::cout << "Filling module 1, power 1 = " << module1 << ", " << power1 << ", module 2, power 2 = " + << module2 << ", " << power2 << " with sum at index " << sumIndexOffset + power2 + << ", value = " << minimMatrix(index1, index2) << std::endl; + } + + index2++; + } + + sumIndexOffset += m_maxNLPower; + } + + size_t sum1DIndex = module1*m_maxNLPower + power1; + + minimVector[index1] = 0; + for (unsigned int iNNeut = 0; iNNeut < numNeutMax; iNNeut++) { + minimVector[index1] += 2*((double) iNNeut + 1)*m_SNEnergy*sums1DVec[iNNeut].at(sum1DIndex); + } + + if (m_debugLevel > 2) { + std::cout << "Filling vector module , power = " << module1 << ", " << power1 << " with sum at index " << sum1DIndex + << ", value = " << minimVector[index1] << std::endl; + } + + // minimVector[index1] = 2*m_SNEnergy*sumsSN.at(sum1DIndex) + 2*2*m_SNEnergy*sumsTN.at(sum1DIndex); + index1++; + } + } + } + + // if (m_debugLevel > 0) std::cout << "Filling high energy entries in matrix" << std::endl; + + // { + + // size_t sumIndexOffset = 0; + // size_t index1 = 0; + + // for (size_t module1 : {0, 1, 2, 3}) { + // for (size_t power1 = 0; power1 < maxPowerModule[module1]; power1++) { + // size_t index2 = 0; + + // for (size_t module2 : {0, 1, 2, 3}) { + // for (size_t power2 = 0; power2 < maxPowerModule[module2]; power2++) { + + // double element = 0; + // double sum = sumsHE2D.at(sumIndexOffset + power2); + + // // Now assemble to terms contributing to this matrix element + // // + // if (module2 == module1) element += 2*sum; + // element -= 2*m_HEFraction.at(module2)*sum; + // element -= 2*m_HEFraction.at(module1)*sum; + // element += 2*sumFracSqr*sum; + + // minimMatrix(index1, index2) += m_HEDeweight*element; + // index2++; + // } + + // sumIndexOffset += m_maxNLPower; + // } + + // index1++; + // } + // } + // } + +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.h b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.h new file mode 100644 index 000000000000..6628fc7792db --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCNLCalibration.h @@ -0,0 +1,286 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +////////////////////////////////////////////////////////// +// This class has been automatically generated on +// Fri Aug 26 05:51:09 2016 by ROOT version 6.06/02 +// from TTree zdcTree/ZDC Tree +// found on file: ../user.steinber.data15_hi.00287931.calibration_zdcCalib.merge.AOD.c932_m1533.42testNL3_output.root +////////////////////////////////////////////////////////// + +#ifndef ZDCNLCalibration_h +#define ZDCNLCalibration_h + +#include <TROOT.h> +#include <TTree.h> +#include <TFile.h> +#include <TH1.h> + +#include <array> +#include <map> +#include <algorithm> +#include <iostream> + +#include <TVectorD.h> +#include <TMatrixD.h> +#include <TDecompLU.h> + + +struct CalibData +{ + std::array<std::vector<float>, 4> weights; + unsigned int LBStart; + unsigned int LBEnd; + + CalibData() + { + std::vector<float> unity(1, 1); + weights = {unity, unity, unity, unity}; + LBStart = 0; + LBEnd = 10000; + }; + +CalibData(int inLBStart, int inLBEnd, const std::array<std::vector<float>, 4>& inWeights) : + LBStart(inLBStart), LBEnd(inLBEnd), weights(inWeights) + {}; +}; + +// Header file for the classes stored in the TTree if any. + +class ZDCNLCalibration +{ + TFile* m_TFile; + TTree* m_tree; + + size_t m_maxNLPower; + // float m_HEDeweight; + bool m_useGRL; + int m_debugLevel; + + // size_t m_numWeights; + // size_t m_numFitParams; + + const float m_SNEnergy; + const std::vector<float> m_HEFraction; + + // Declaration of leaf types + UInt_t runNumber; + UInt_t eventNumber; + UInt_t lumiBlock; + UInt_t bcid; + UInt_t passBits; + + Float_t zdc_ZdcAmp[2]; + // Float_t zdc_ZdcEnergy[2]; + // Float_t zdc_ZdcTime[2]; + // Short_t zdc_ZdcStatus[2]; + // Float_t zdc_ZdcTrigEff[2]; + UInt_t zdc_ZdcModuleMask; + Float_t zdc_ZdcModuleAmp[2][4]; + // Float_t zdc_ZdcModuleTime[2][4]; + // Float_t zdc_ZdcModuleFitAmp[2][4]; + // Float_t zdc_ZdcModuleFitT0[2][4]; + // UInt_t zdc_ZdcModuleStatus[2][4]; + // Float_t zdc_ZdcModuleChisq[2][4]; + // Float_t zdc_ZdcModuleCalibAmp[2][4]; + // Float_t zdc_ZdcModuleCalibTime[2][4]; + // Float_t zdc_ZdcModuleBkgdMaxFraction[2][4]; + // Float_t zdc_ZdcModuleAmpError[2][4]; + Bool_t L1_ZDC_A; + Bool_t L1_ZDC_C; + Bool_t L1_ZDC_AND; + Bool_t L1_ZDC_A_C; + + // List of branches + TBranch *b_runNumber; //! + TBranch *b_eventNumber; //! + TBranch *b_lumiBlock; //! + TBranch *b_bcid; //! + + TBranch *b_passBits; //! + + TBranch *b_zdc_ZdcAmp; //! + // TBranch *b_zdc_ZdcEnergy; //! + // TBranch *b_zdc_ZdcTime; //! + // TBranch *b_zdc_ZdcStatus; //! + // TBranch *b_zdc_ZdcTrigEff; //! + TBranch *b_zdc_ZdcModuleMask; //! + TBranch *b_zdc_ZdcModuleAmp; //! + // TBranch *b_zdc_ZdcModuleTime; //! + // TBranch *b_zdc_ZdcModuleFitAmp; //! + // TBranch *b_zdc_ZdcModuleFitT0; //! + // TBranch *b_zdc_ZdcModuleStatus; //! + // TBranch *b_zdc_ZdcModuleChisq; //! + // TBranch *b_zdc_ZdcModuleCalibAmp; //! + // TBranch *b_zdc_ZdcModuleCalibTime; //! + // TBranch *b_zdc_ZdcModuleBkgdMaxFraction; //! + // TBranch *b_zdc_ZdcModuleAmpError; //! + TBranch *b_L1_ZDC_A; //! + TBranch *b_L1_ZDC_C; //! + TBranch *b_L1_ZDC_AND; //! + TBranch *b_L1_ZDC_A_C; //! + + // Map that keeps lumi block and event associations to optimize + // processing of lumi block ranges + // + typedef multimap<unsigned int, std::pair<unsigned int, unsigned int> > LBEvtMap; + LBEvtMap m_LumiBlockEvtMap; + +public: + + std::array<std::map<std::string, CalibData>, 2> m_calibrations; + + bool m_haveTest; + TH1D* m_testCalibSNHist; + std::array<TH1D*, 4> m_testCalibHEFracHist; + std::array<TH1D*, 4> m_testCalibEnergyHist; + TTree* m_testTree; + + + ZDCNLCalibration(std::string file, int maxNLPower = 3, bool useGRL = true, int debugLevel = 0); + virtual ~ZDCNLCalibration() {} + + std::array<float, 4> FindSNPeaks(size_t LBLow, size_t LBHigh, size_t side); + + std::pair<float, float> FindSNRange(size_t LBLow, size_t LBHigh, size_t side); + + std::pair<std::pair<float, float>,std::pair<float, float> > FindSNTwoNRanges(size_t LBLow, size_t LBHigh, size_t side); + + void SetDefaultCalibration(size_t side, const CalibData& calib) { + AddCalibration(side, "default", calib); + } + + void Calibrate(size_t side, std::string calibInput, std::string calibOutput, + size_t LBLow, size_t LBHigh, std::array<int, 4> maxPowerModule, + std::vector<std::pair<double, double> > nNeutERange, + bool excludeHE, float heSumThresh, float HEDeweight); + + void TestCalibration(int side, std::string calibName); + + TH1* GetTestSNHist() {return (m_haveTest ? m_testCalibSNHist : 0);} + TH1* GetTestFracHist(size_t module) {return (m_haveTest ? m_testCalibHEFracHist.at(module) : 0);} + + TTree* GetTestTree() {return m_testTree;} + +private: + + void FillLumiBlockEvtMap(); + + void FillMinimizationData(TMatrixD& minimMatrix, TVectorD& minimVector, + std::array<int, 4> maxPowerModule, float HEDeweight, + const std::vector<std::vector<double> >& sums1DVec, const std::vector<double>& sumsHE, + const std::vector<std::vector<double> >& sums2DVec, const std::vector<double>& sumsHE2D); + + void AddCalibration(size_t side, std::string tag, const CalibData& calib); + CalibData GetCalibration(size_t side, std::string tag); + + // Add the four amplitudes from a given event to the set of sums used in the NL weight fitting + // we need to make all combinations of amplitude products and for all combinations of powers + // + void AddToSums(std::vector<double>& sums1D, std::vector<double>& sums2D, float* amps) + { + size_t index1D = 0; + size_t index2D = 0; + + for (size_t module1 : {0, 1, 2, 3}) { + double amp1 = amps[module1]; + double amp1Pow = amp1; + + for (size_t power1 = 0; power1 < m_maxNLPower; power1++) { + for (size_t module2 : {0, 1, 2, 3}) { + double amp2 = amps[module2]; + double amp2Pow = amp2; + + for (size_t power2 = 0; power2 < m_maxNLPower; power2++) { + sums2D.at(index2D++) += amp1Pow*amp2Pow; + amp2Pow *= amp2; + } + } + + sums1D.at(index1D++) += amp1Pow; + amp1Pow *= amp1; + } + } + } + + static double CalculateEnergy(const float* moduleAmps, const CalibData& calib) + { + double energy = 0; + + for (size_t module : {0, 1, 2, 3}) { + float amp = moduleAmps[module]; + float ampPow = amp; + + for (size_t power = 0; power < calib.weights[module].size(); power++) { + energy += calib.weights[module][power]*ampPow; + ampPow *= amp;; + } + } + + return energy; + } + +}; + +#endif + +#ifdef ZDCNLCalibration_cxx +ZDCNLCalibration::ZDCNLCalibration(std::string file, int maxNLPower, bool useGRL, int debugLevel) : + m_TFile(0), m_tree(0), m_maxNLPower(maxNLPower), //m_HEDeweight(heDeweight), + m_useGRL(useGRL), m_debugLevel(debugLevel), + // m_numWeights(m_maxNLPower*4), m_numFitParams(m_maxNLPower *4), + m_SNEnergy(2510), m_HEFraction({0.31, 0.27, 0.21, 0.21}), + m_haveTest(false) +{ + std::cout << "Initializing ZDCNLCalibration with debug level " << m_debugLevel << std::endl; + + TFile* temp_p = new TFile(file.c_str()); + if (!temp_p->IsOpen()) { + std::cout << "Error opening input file " << file << std::endl; + return; + } + + m_TFile = temp_p; + m_tree = static_cast<TTree*>(m_TFile->GetObjectChecked("zdcTree","TTree")); + if (!m_tree) { + std::cout << "Error reading tree from input file " << file << std::endl; + return; + } + + m_tree->SetBranchAddress("runNumber", &runNumber, &b_runNumber); + m_tree->SetBranchAddress("eventNumber", &eventNumber, &b_eventNumber); + m_tree->SetBranchAddress("lumiBlock", &lumiBlock, &b_lumiBlock); + m_tree->SetBranchAddress("bcid", &bcid, &b_bcid); + m_tree->SetBranchAddress("passBits", &passBits, &b_passBits); + + if (m_tree->FindBranch("zdc_ZdcModuleMask")) { + m_tree->SetBranchAddress("zdc_ZdcAmp", zdc_ZdcAmp, &b_zdc_ZdcAmp); + m_tree->SetBranchAddress("zdc_ZdcModuleMask", &zdc_ZdcModuleMask, &b_zdc_ZdcModuleMask); + m_tree->SetBranchAddress("zdc_ZdcModuleAmp", zdc_ZdcModuleAmp, &b_zdc_ZdcModuleAmp); + } + else if (m_tree->FindBranch("zdc_ModuleMask")) { + m_tree->SetBranchAddress("zdc_OptSumAmp", zdc_ZdcAmp, &b_zdc_ZdcAmp); + m_tree->SetBranchAddress("zdc_ModuleMask", (int*) &zdc_ZdcModuleMask, &b_zdc_ZdcModuleMask); + m_tree->SetBranchAddress("zdc_OptAmp", zdc_ZdcModuleAmp, &b_zdc_ZdcModuleAmp); + } + else throw; + + m_tree->SetBranchAddress("L1_ZDC_A", &L1_ZDC_A, &b_L1_ZDC_A); + m_tree->SetBranchAddress("L1_ZDC_C", &L1_ZDC_C, &b_L1_ZDC_C); + m_tree->SetBranchAddress("L1_ZDC_AND", &L1_ZDC_AND, &b_L1_ZDC_AND); + m_tree->SetBranchAddress("L1_ZDC_A_C", &L1_ZDC_A_C, &b_L1_ZDC_A_C); + + if (m_debugLevel > 0) { + std::cout << "Filling LumiBlock-event map" << std::endl; + } + + FillLumiBlockEvtMap(); + + // Provide "null" default calibration + // + AddCalibration(0, "default", CalibData()); + AddCalibration(1, "default", CalibData()); +} + +#endif // #ifdef ZDCNLCalibration_cxx diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.C b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.C new file mode 100644 index 000000000000..223f0137777e --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.C @@ -0,0 +1,412 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#define ZDCTreeAnalysis_cxx +#include "ZDCTreeAnalysis.h" + +#include <algorithm> +#include <cmath> + +#include <TH2.h> +#include <TStyle.h> +#include <TCanvas.h> + +#include <TH2.h> +#include <TStyle.h> +#include <TCanvas.h> +#include <TMath.h> +#include <TH1.h> +#include <TF1.h> +#include <TLatex.h> +#include <TPaveStats.h> + +#include <cmath> + +template <typename T> T Sqr(const T& inT) {return inT*inT;} + +void ZDCTreeAnalysis::InitInternal() +{ + for (int iside = 0; iside < 2; iside++) { + for (int imod = 0; imod < 4; imod++) { + _fixTau1[iside][imod] = false; + _fixTau2[iside][imod] = false; + _moduleTau1[iside][imod] = 4; + _moduleTau2[iside][imod] = 20; + + _chisqDivAmpCutHG[iside][imod] = 1e6; + _chisqDivAmpCutLG[iside][imod] = 1e6; + _DeltaT0CutLow[iside][imod] = -100; + _DeltaT0CutHigh[iside][imod] = 100; + _HGOverFlowADC[iside][imod] = 800; + _HGUnderFlowADC[iside][imod] = 25; + + for (size_t ipar = 0; ipar < 3; ipar++) { + _T0SlewCoeffHG[iside][imod][ipar] = 0; + _T0SlewCoeffLG[iside][imod][ipar] = 0; + } + + _modECalib[iside][imod] = 1; + _haveLBDepECalib[iside][imod] = false; + _haveLBDepT0[iside][imod] = false; + } + } + + zdc_samplesSub = new std::vector<float>(7, 0); + zdc_samplesDeriv = new std::vector<float>(7, 0); + zdc_samplesDeriv2nd = new std::vector<float>(7, 0); +} + + +void ZDCTreeAnalysis::SetupBunchTrains() +{ + GetEntry(0); + + _BCIDGap.assign(3300, 0); + _BCIDPosInTrain.assign(3300, 0); + + std::cout << "Run = " << runNumber << std::endl; + + if (runNumber >= 287706) { + + int trainStartBCIDS[21] = {5, 155, 305, 446, 596, 746, 896, 1046, 1196, 1487, 1637, 1787, 1937, 2087, 2228, 2378, 2528, 2678, 2828, 2978, 3119}; + int trainNumBCIDS[21] = {24, 24, 20, 24, 24, 24, 24, 24, 20, 24, 24, 24, 24, 22, 24, 24, 24, 24, 24, 22, 24}; + + int lastBCID = -1; + int numBCID = 0; + + for (int train = 0; train < 21; train++) { + int bcid = trainStartBCIDS[train]; + + std::cout << "Train " << train << ", bcids = "; + + for (int PIT = 0; PIT < trainNumBCIDS[train]; PIT++) { + int gapNext = PIT % 2 == 0 ? 4 : 6; + + _BCIDGap[bcid] = bcid - lastBCID; + _BCIDPosInTrain[bcid] = PIT; + + std::cout << bcid << ", "; + + numBCID++; + lastBCID = bcid; + bcid += gapNext; + } + + std::cout << std::endl; + } + + std::cout << "Found " << numBCID << "bcids" << std::endl; + } +} + +void ZDCTreeAnalysis::OpenOutputTree(std::string file) +{ + TFile* outputFile = new TFile(file.c_str(), "recreate"); + if (!outputFile->IsOpen()) { + std::cout << "Error opening output file " << file << ", quitting" << std::endl; + return; + } + + _outTFile = outputFile; + + _outTree = fChain->CloneTree(0); + _outTree->Branch("bcidGap", &bcidGap, "bcidGap/I"); + _outTree->Branch("bcidPosInTrain", &bcidPosInTrain, "bcidPosInTrain/I"); + + _outTree->Branch("zdc_SumAmp", zdc_SumAmp, "zdc_SumAmp[2]/F"); + _outTree->Branch("zdc_SumCalibAmp", zdc_SumCalibAmp, "zdc_SumCalibAmp[2]/F"); + _outTree->Branch("zdc_AvgTime", zdc_AvgTime, "zdc_AvgTime[2]/F"); + _outTree->Branch("zdc_ModuleMask", &zdc_ModuleMask, "zdc_ModuleMask/I"); + + _outTree->Branch("zdc_Status", zdc_Status, "zdc_Status[2][4]/I"); + _outTree->Branch("zdc_Amp", zdc_Amp, "zdc_Amp[2][4]/F"); + _outTree->Branch("zdc_FitT0", zdc_FitT0, "zdc_FitT0[2][4]/F"); + _outTree->Branch("zdc_T0Corr", zdc_T0Corr, "zdc_T0Corr[2][4]/F"); + _outTree->Branch("zdc_FitChisq", zdc_FitChisq, "zdc_FitChisq[2][4]/F"); + + _outTree->Branch("zdc_CalibAmp", zdc_CalibAmp, "zdc_CalibAmp[2][4]/F"); + _outTree->Branch("zdc_CalibTime", zdc_CalibTime, "zdc_CalibTime[2][4]/F"); + + _outTree->Branch("zdc_MaxADC", zdc_MaxADC, "zdc_MaxADC[2][4]/f"); + _outTree->Branch("zdc_MinADC", zdc_MinADC, "zdc_MinADC[2][4]/f"); + _outTree->Branch("zdc_MaxADCSample", zdc_MaxADCSample, "zdc_MaxADCSample[2][4]/I"); + _outTree->Branch("zdc_MinADCSample", zdc_MaxADCSample, "zdc_MinADCSample[2][4]/I"); + _outTree->Branch("zdc_Min2ndDeriv", zdc_Min2ndDeriv, "zdc_Min2ndDeriv[2][4]/F"); + _outTree->Branch("zdc_Min2ndDerivSample", zdc_Min2ndDerivSample, "zdc_Min2ndDerivSample[2][4]/I"); + + _outTree->Branch("zdc_samplesSub", &zdc_samplesSub); + _outTree->Branch("zdc_samplesDeriv", &zdc_samplesDeriv); + _outTree->Branch("zdc_samplesDeriv2nd", &zdc_samplesDeriv2nd); + + _doOutput = true; +} + +void ZDCTreeAnalysis::CloseOutputTree() +{ + if (!_doOutput) return; + + _outTree->AutoSave(); + delete _outTFile; + _outTFile = 0; + _outTree = 0; + _doOutput = false; +} + +void ZDCTreeAnalysis::Loop(int numEntries, int startEntry) +{ + if (fChain == 0) return; + + int loopStart = (startEntry == -1 ? _currentEntry : startEntry); + + Long64_t nentries = fChain->GetEntriesFast() - loopStart; + + Long64_t numLoopEntry = (numEntries != -1 ? numEntries : nentries); + + Long64_t nbytes = 0, nb = 0; + + _inLoop = true; + + for (Long64_t jentry = loopStart; jentry < loopStart + numLoopEntry; jentry++) { + Long64_t ientry = LoadTree(jentry); + if (ientry < 0) break; + nb = fChain->GetEntry(jentry); + _currentEntry = jentry; + nbytes += nb; + + DoAnalysis(); + + if (jentry > 1) { + float log10Entry = std::floor(std::log ((float) jentry)/std::log(10)); + int modEntry = jentry % (int) pow(10, log10Entry); + + if (modEntry == 0) { + std::cout << "Processed event " << jentry << std::endl; + } + } + } + + _inLoop = false; +} + +void ZDCTreeAnalysis::DoAnalysis() +{ + // Starting a new event + // + _dataAnalyzer_p->StartEvent(lumiBlock); + + bcidGap = _BCIDGap[bcid]; + bcidPosInTrain = _BCIDPosInTrain[bcid]; + + if (_doOutput) { + // // + // // Initialize outout arrays + // // + } + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + + static std::vector<float> HGADCSamples(7); + static std::vector<float> LGADCSamples(7); + + // Copy data into a proper vector of floats + // + if (module == 0) { + std::copy(&zdc_raw[side][module][0][1][0], &zdc_raw[side][module][0][1][7], LGADCSamples.begin()); + std::copy(&zdc_raw[side][module][1][1][0], &zdc_raw[side][module][1][1][7], HGADCSamples.begin()); + } + else { + std::copy(&zdc_raw[side][module][0][0][0], &zdc_raw[side][module][0][0][7], LGADCSamples.begin()); + std::copy(&zdc_raw[side][module][1][0][0], &zdc_raw[side][module][1][0][7], HGADCSamples.begin()); + } + + // Load the data + // + _dataAnalyzer_p->LoadAndAnalyzeData(side, module, HGADCSamples, LGADCSamples); + } + } + + + // We're done + // + _dataAnalyzer_p->FinishEvent(); + + zdc_ModuleMask = _dataAnalyzer_p->GetModuleMask(); + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + + const ZDCPulseAnalyzer* pulseAna_p = _dataAnalyzer_p->GetPulseAnalyzer(side, module); + + *zdc_samplesSub = pulseAna_p->GetSamplesSub(); + *zdc_samplesDeriv = pulseAna_p->GetSamplesDeriv(); + *zdc_samplesDeriv2nd = pulseAna_p->GetSamplesDeriv2nd(); + + zdc_Min2ndDeriv[side][module] = pulseAna_p->GetMinDeriv2nd(); + zdc_Min2ndDerivSample[side][module] = pulseAna_p->GetMinDeriv2ndIndex(); + + zdc_MaxADC[side][module] = pulseAna_p->GetMaxADC(); + zdc_MinADC[side][module] = pulseAna_p->GetMinADC(); + + zdc_MaxADCSample[side][module] = pulseAna_p->GetMaxADCSample(); + zdc_MinADCSample[side][module] = pulseAna_p->GetMinADCSample(); + + zdc_Status[side][module] = pulseAna_p->GetStatusMask(); + zdc_Amp[side][module] = pulseAna_p->GetAmplitude(); + zdc_FitT0[side][module] = pulseAna_p->GetFitT0(); + zdc_T0Corr[side][module] = pulseAna_p->GetT0Corr(); + zdc_FitChisq[side][module] = pulseAna_p->GetChisq(); + + zdc_CalibAmp[side][module] = _dataAnalyzer_p->GetModuleCalibAmplitude(side, module); + zdc_CalibTime[side][module] = _dataAnalyzer_p->GetModuleCalibTime(side, module); + } + + zdc_SumAmp[side] = _dataAnalyzer_p->GetModuleSum(side); + zdc_SumCalibAmp[side] = _dataAnalyzer_p->GetCalibModuleSum(side); + zdc_AvgTime[side] = _dataAnalyzer_p->GetAverageTime(side); + zdc_sideFailed[side] = _dataAnalyzer_p->SideFailed(side); + + + } + + + if (_doOutput) { + _outTree->Fill(); + } +} + + +void ZDCTreeAnalysis::PlotFits(std::string canvasSavePath) +{ + static bool first = true; + static std::array<TCanvas*, 2> plotCanvases; + static TLatex* statusLabel; + static TLatex* sideModuleLabel; + static TLatex* highLowGainLabel; + static TLatex* eventLabel; + static TLatex* warningLabel; + + if (first) { + plotCanvases[0] = new TCanvas("ZDCFitsSide0","ZDCFitsSide0", 1000, 800); + plotCanvases[1] = new TCanvas("ZDCFitsSide1","ZDCFitsSide1", 1000, 800); + + plotCanvases[0]->Divide(2, 2, 0.001, 0.0001); + plotCanvases[1]->Divide(2, 2, 0.001, 0.0001); + + first = false; + + gStyle->SetOptStat(0); + gStyle->SetOptFit(111); + + sideModuleLabel = new TLatex; + sideModuleLabel->SetTextFont(42); + sideModuleLabel->SetTextSize(0.05); + sideModuleLabel->SetTextAlign(12); + sideModuleLabel->SetTextColor(2); + sideModuleLabel->SetNDC(1); + + statusLabel = new TLatex; + statusLabel->SetTextFont(42); + statusLabel->SetTextSize(0.045); + statusLabel->SetTextAlign(12); + statusLabel->SetNDC(1); + + highLowGainLabel = new TLatex; + highLowGainLabel->SetTextFont(42); + highLowGainLabel->SetTextSize(0.045); + highLowGainLabel->SetTextAlign(12); + highLowGainLabel->SetNDC(1); + + warningLabel = new TLatex; + warningLabel->SetTextFont(62); + warningLabel->SetTextColor(2); + warningLabel->SetTextSize(0.045); + warningLabel->SetTextAlign(12); + warningLabel->SetNDC(1); + } + + for (size_t side : {0, 1}) { + for (size_t module : {0, 1, 2, 3}) { + TVirtualPad* pad_p = plotCanvases[side]->cd(module + 1); + + pad_p->SetTopMargin(0.03); + pad_p->SetRightMargin(0.03); + + const ZDCPulseAnalyzer* pulseAna_p = _dataAnalyzer_p->GetPulseAnalyzer(side, module); + + const TH1* hist_p = pulseAna_p->GetHistogramPtr(); + TH1* cloneHist_p = (TH1*) hist_p->Clone((std::string(hist_p->GetName()) + "_clone").c_str()); + + // Set the maximum to make sure we include the peak of the function + // + TF1* func_p = (TF1*) cloneHist_p->GetListOfFunctions()->First(); + double funcMax = func_p->GetMaximum(); + + if (pulseAna_p->HavePulse()) { + if (cloneHist_p->GetMaximum() < funcMax*1.1) cloneHist_p->SetMaximum(funcMax*1.1); + if (cloneHist_p->GetMaximum() < 20) cloneHist_p->SetMaximum(20); + } + else { + float maxADC = pulseAna_p->GetMaxADC(); + float minADC = pulseAna_p->GetMinADC(); + + cloneHist_p->SetMaximum(maxADC*1.1); + cloneHist_p->SetMinimum(std::min(0.0,minADC*1.1)); + } + + if (pulseAna_p->HavePulse()) cloneHist_p->Draw(); + else cloneHist_p->Draw("hist"); + + gPad->Modified(); + gPad->Update(); + + TPaveStats* stats_p = (TPaveStats *)cloneHist_p->GetListOfFunctions()->FindObject("stats"); + if (stats_p) { + stats_p->SetX1NDC(0.135); + stats_p->SetX2NDC(0.4); + stats_p->SetFitFormat("5.3f"); + } + + unsigned int status = pulseAna_p->GetStatusMask(); + + std::ostringstream sideModule, statusHex; + sideModule << "Side " << side << ", module " << module; + statusHex << "0x" << std::hex << status; + + sideModuleLabel->DrawLatex(0.135, 0.6, sideModule.str().c_str()); + + std::string statusString = "status = " + statusHex.str(); + statusLabel->DrawLatex(0.135, 0.54, statusString.c_str()); + + if (pulseAna_p->UseLowGain()) { + highLowGainLabel->DrawLatex(0.135, 0.48, "low gain"); + } + else { + highLowGainLabel->DrawLatex(0.135, 0.48, "high gain"); + } + + std::string warning = ""; + + if (pulseAna_p->Failed()) warning += "Failed"; + + if (pulseAna_p->BadT0()) { + if (warning != "") warning += ","; + warning += "BadT0"; + } + + if (pulseAna_p->BadChisq()) { + if (warning != "") warning += ","; + warning += "BadChisq"; + } + + if (warning != "") warningLabel->DrawLatex(0.135, 0.42, warning.c_str()); + + gPad->Modified(); + gPad->Update(); + } + + plotCanvases[side]->Modified(); + plotCanvases[side]->Update(); + } +} diff --git a/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.h b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.h new file mode 100644 index 000000000000..19be5440a2cb --- /dev/null +++ b/ForwardDetectors/ZDC/ZdcAnalysis/tools/ZDCTreeAnalysis.h @@ -0,0 +1,512 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +////////////////////////////////////////////////////////// +// This class has been automatically generated on +// Wed Dec 16 10:23:25 2015 by ROOT version 6.04/12 +// from TTree zdcTree/ZDC Tree +// found on file: data15_hi.00287259.calibration_zdcCalib.recon.AOD.c931.root +////////////////////////////////////////////////////////// + +#ifndef ZDCTreeAnalysis_h +#define ZDCTreeAnalysis_h + +#include <TROOT.h> +#include <TChain.h> +#include <TFile.h> +#include <TH1.h> +#include <TF1.h> +#include <TSpline.h> + +// Header file for the classes stored in the TTree if any. +#include <vector> +#include <iostream> +#include <sstream> + +#include "ZDCDataAnalyzer.h" + +class ZDCTreeAnalysis { +public : + TTree *fChain; //!pointer to the analyzed TTree or TChain + Int_t fCurrent; //!current Tree number in a TChain + + TFile* _outTFile; + TTree* _outTree; + bool _doOutput; + +// Fixed size dimensions of array or collections stored in the TTree if any. + + // Declaration of leaf types + UInt_t runNumber; + UInt_t eventNumber; + UInt_t lumiBlock; + UInt_t bcid; + ULong64_t trigger; + UInt_t trigger_TBP; + UInt_t tbp[16]; + UInt_t tav[16]; + + UInt_t passBits; + UShort_t zdc_raw[2][4][2][2][7]; + + Float_t fcalEt; + Int_t ntrk; + Int_t nvx; + Float_t vx[3]; + Int_t vxntrk; + Float_t vxcov[6]; + UShort_t mbts_countA; + UShort_t mbts_countC; + Float_t mbts_timeA; + Float_t mbts_timeC; + Float_t mbts_timeDiff; + + Bool_t L1_ZDC_A; + Float_t ps_L1_ZDC_A; + Bool_t L1_ZDC_C; + Float_t ps_L1_ZDC_C; + Bool_t L1_ZDC_AND; + Float_t ps_L1_ZDC_AND; + Bool_t L1_ZDC_A_C; + Float_t ps_L1_ZDC_A_C; + + // Data for branches that are to be added to the tree + // + int bcidGap; + int bcidPosInTrain; + + // Data obtained from the analysis + // + // Summary data + // + int zdc_ModuleMask; + float zdc_SumAmp[2]; + float zdc_SumCalibAmp[2]; + float zdc_AvgTime[2]; + bool zdc_sideFailed[2]; + + // Per-module data + // + std::vector<float>* zdc_samplesSub; + std::vector<float>* zdc_samplesDeriv; + std::vector<float>* zdc_samplesDeriv2nd; + + float zdc_Presample[2][4]; + + float zdc_MaxADC[2][4]; + int zdc_MaxADCSample[2][4]; + + float zdc_MinADC[2][4]; + int zdc_MinADCSample[2][4]; + + float zdc_Min2ndDeriv[2][4]; + int zdc_Min2ndDerivSample[2][4]; + + int zdc_Status[2][4]; + float zdc_Amp[2][4]; + float zdc_FitT0[2][4]; + float zdc_FitChisq[2][4]; + float zdc_T0Corr[2][4]; + + float zdc_CalibAmp[2][4]; + float zdc_CalibTime[2][4]; + + // The object responsible for the actual analysis + // + ZDCDataAnalyzer* _dataAnalyzer_p; + +private: + // Critical construction parameters + // + int _nSample; + float _deltaTSample; + int _preSampleIdx; + std::string _fitFunction; + + ZDCDataAnalyzer::ZDCModuleFloatArray _peak2ndDerivMinSamples; + ZDCDataAnalyzer::ZDCModuleFloatArray _peak2ndDerivMinThresholds; + + // Cut quantities + // + float _HGOverFlowADC[2][4]; + float _HGUnderFlowADC[2][4]; + float _DeltaT0CutLow[2][4]; + float _DeltaT0CutHigh[2][4]; + float _chisqDivAmpCutHG[2][4]; + float _chisqDivAmpCutLG[2][4]; + + // Per-module calibration factors + // + // Time-dependent + // + bool _haveLBDepT0[2][4]; + TSpline* _moduleT0HGLB[2][4]; + TSpline* _moduleT0LGLB[2][4]; + + bool _haveCalibrations; + float _modECalib[2][4]; + + bool _haveLBDepECalib[2][4]; + TSpline* _modECalibLB[2][4]; + + // Allow per-module Tau1, tau2 settings + // + bool _haveModuleSettings[2][4]; + bool _fixTau1[2][4]; + bool _fixTau2[2][4]; + float _moduleTau1[2][4]; + float _moduleTau2[2][4]; + float _moduleT0LG[2][4]; + float _moduleT0HG[2][4]; + + std::array<std::array<float, 4>, 2> _moduleHGGains; + + // Time slewing corrections + // + float _T0SlewCoeffHG[2][4][3]; + float _T0SlewCoeffLG[2][4][3]; + + // Bunch information + // + std::vector<std::set<int> > _trains; + std::vector<int> _BCIDGap; + std::vector<int> _BCIDPosInTrain; + + // Which entry we're reading + // + bool _inLoop; + int _currentEntry; + unsigned int _runNumber; + +private: + // List of branches + TBranch *b_runNumber; //! + TBranch *b_eventNumber; //! + TBranch *b_lumiBlock; //! + TBranch *b_bcid; //! + TBranch *b_trigger; //! + TBranch *b_trigger_TBP; //! + TBranch *b_tbp; //! + TBranch *b_tav; //! + TBranch *b_decisions; //! + TBranch *b_prescales; //! + TBranch *b_passBits; //! + + TBranch *b_zdc_raw; //! + // TBranch *b_fcalEt; //! + // TBranch *b_ntrk; //! + // TBranch *b_nvx; //! + // TBranch *b_vx; //! + // TBranch *b_vxntrk; //! + // TBranch *b_vxcov; //! + // TBranch *b_mbts_countA; //! + // TBranch *b_mbts_countC; //! + // TBranch *b_mbts_timeA; //! + // TBranch *b_mbts_timeC; //! + // TBranch *b_mbts_timeDiff; //! + + TBranch *b_L1_ZDC_A; //! + TBranch *b_ps_L1_ZDC_A; //! + TBranch *b_L1_ZDC_C; //! + TBranch *b_ps_L1_ZDC_C; //! + TBranch *b_L1_ZDC_AND; //! + TBranch *b_ps_L1_ZDC_AND; //! + TBranch *b_L1_ZDC_A_C; //! + TBranch *b_ps_L1_ZDC_A_C; //! + + void InitInternal(); + void SetupBunchTrains(); + +public: + + ZDCTreeAnalysis(std::string filename, int nSample = 7, double deltaT = 12.5, int preSamplIdx = 1, std::string fitFunction = "FermiExp"); + + void SetADCOverUnderflowValues(const ZDCDataAnalyzer::ZDCModuleFloatArray& HGOverFlowADC, + const ZDCDataAnalyzer::ZDCModuleFloatArray& HGUnderFlowADC, + const ZDCDataAnalyzer::ZDCModuleFloatArray& LGOverFlowADC) + { + _dataAnalyzer_p->SetADCOverUnderflowValues(HGOverFlowADC, HGUnderFlowADC, LGOverFlowADC); + } + + void SetCutValues(const ZDCDataAnalyzer::ZDCModuleFloatArray& chisqDivAmpCutHG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& chisqDivAmpCutLG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& DeltaT0CutLowHG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& DeltaT0CutHighHG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& DeltaT0CutLowLG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& DeltaT0CutHighLG) + + { + _dataAnalyzer_p->SetCutValues(chisqDivAmpCutHG, chisqDivAmpCutLG, + DeltaT0CutLowHG, DeltaT0CutHighHG, + DeltaT0CutLowLG, DeltaT0CutHighLG); + } + + void SetTauT0Values(const ZDCDataAnalyzer::ZDCModuleBoolArray& fixTau1, + const ZDCDataAnalyzer::ZDCModuleBoolArray& fixTau2, + const ZDCDataAnalyzer::ZDCModuleFloatArray& tau1, + const ZDCDataAnalyzer::ZDCModuleFloatArray& tau2, + const ZDCDataAnalyzer::ZDCModuleFloatArray& t0HG, + const ZDCDataAnalyzer::ZDCModuleFloatArray& t0LG) + { + _dataAnalyzer_p->SetTauT0Values(fixTau1, fixTau2, tau1, tau2, t0HG, t0LG); + } + + + void SetDebugLevel(int debugLevel = 0) + { + _dataAnalyzer_p->SetDebugLevel(debugLevel); + } + + void LoadEnergyCalibrations(const std::array<std::array<TSpline*, 4>, 2>& calibSplines) + { + _dataAnalyzer_p->LoadEnergyCalibrations(calibSplines); + } + + void LoadT0Calibrations(const std::array<std::array<TSpline*, 4>, 2>& calibSplinesHG, + const std::array<std::array<TSpline*, 4>, 2>& calibSplinesLG) + { + _dataAnalyzer_p->LoadtT0Calibrations(calibSplinesHG, calibSplinesLG); + } + + void SetLBDepT0(int iside, int imod, TSpline* t0SplineLG, TSpline* t0SplineHG); + + void SetSlewingCoeff(const std::array<std::array<std::vector<float>, 4>, 2>& HGParamArr, + const std::array<std::array<std::vector<float>, 4>, 2>& LGParamArr) + { + _dataAnalyzer_p->SetTimingCorrParams(HGParamArr, LGParamArr); + } + + void OpenOutputTree(std::string file); + void CloseOutputTree(); + + void PlotFits(std::string canvasSavePath = ""); + + virtual ~ZDCTreeAnalysis(); + virtual Int_t Cut(Long64_t entry); + virtual Int_t GetEntry(Long64_t entry); + virtual Long64_t LoadTree(Long64_t entry); + virtual void Init(TTree *tree); + virtual void Loop(int numEntries = -1, int startEntry = 0); + virtual Bool_t Notify(); + virtual void Show(Long64_t entry = -1); + + void LoadEntry(int entry) + { + GetEntry(entry); + DoAnalysis(); + } + + void LoadNextEntry() + { + GetEntry(_currentEntry + 1); + DoAnalysis(); + } + + unsigned int GetRunNumber() const {return _runNumber;} + + void DoAnalysis(); +}; + + +#endif + +#ifdef ZDCTreeAnalysis_cxx + +ZDCTreeAnalysis::ZDCTreeAnalysis(std::string filename, int nSample, double deltaT, int preSamplIdx, std::string fitFunction) : + fChain(0), _outTFile(0), _outTree(0), + _nSample(nSample), _deltaTSample(deltaT), _preSampleIdx(preSamplIdx), + _doOutput(false), _currentEntry(-1), _inLoop(false), + _haveCalibrations(false) +{ + + // Open the fiel, extract and initialize the tree + // + TTree* tree; + TFile* f = new TFile(filename.c_str()); + f->GetObject("zdcTree",tree); + Init(tree); + + // Capture the run number + // + GetEntry(1); + _runNumber = runNumber; + + InitInternal(); + + // Figure out the bunch spacing + // + SetupBunchTrains(); + + // Set the HV gains + // + _moduleHGGains = {9.51122, 9.51980, 9.51122, 9.51122, + 9.51415, 9.5049, 9.51659, 9.51415}; + + _peak2ndDerivMinSamples = {3, 3, 3, 2, + 2, 2, 2, 2}; + + _peak2ndDerivMinThresholds = {-7, -7, -7, -7, + -7, -7, -7, -7}; + + _dataAnalyzer_p = new ZDCDataAnalyzer(_nSample, _deltaTSample, _preSampleIdx, fitFunction, + _peak2ndDerivMinSamples, _peak2ndDerivMinThresholds); + +/* 81Undelayed */ +/* 81H1: 9.5049 */ +/* 81H2: 9.51659 */ +/* 81H3: 9.50119 */ +/* 81EM: 9.51415 */ +/* 81Delayed */ +/* 81H1: 9.52632 */ +/* 81H2: 9.49662 */ +/* 81H3: 9.50853 */ +/* 81EM: 9.50842 */ +/* 12Undelayed */ +/* 12H1: 9.5198 */ +/* 12H2: 9.51122 */ +/* 12H3: 9.51122 */ +/* 12EM: 9.51122 */ +/* 12Delayed */ +/* 12H1: 9.51237 */ +/* 12H2: 9.50178 */ +/* 12H3: 9.50178 */ +/* 12EM: 9.50178 */ +} + +ZDCTreeAnalysis::~ZDCTreeAnalysis() +{ + if (!fChain) return; + delete fChain->GetCurrentFile(); +} + +Int_t ZDCTreeAnalysis::GetEntry(Long64_t entry) +{ +// Read contents of entry. + if (!fChain) return 0; + int result = fChain->GetEntry(entry); + if (result > 0) _currentEntry = entry; + return result; +} +Long64_t ZDCTreeAnalysis::LoadTree(Long64_t entry) +{ +// Set the environment to read one entry + if (!fChain) return -5; + Long64_t centry = fChain->LoadTree(entry); + if (centry < 0) return centry; + if (fChain->GetTreeNumber() != fCurrent) { + fCurrent = fChain->GetTreeNumber(); + Notify(); + } + return centry; +} + +void ZDCTreeAnalysis::Init(TTree *tree) +{ + // The Init() function is called when the selector needs to initialize + // a new tree or chain. Typically here the branch addresses and branch + // pointers of the tree will be set. + // It is normally not necessary to make changes to the generated + // code, but the routine can be extended by the user if needed. + // Init() will be called many times when running on PROOF + // (once per file to be processed). + + // Set object pointer + // decisions = 0; + // prescales = 0; + // Set branch addresses and branch pointers + if (!tree) return; + fChain = tree; + fCurrent = -1; + // fChain->SetMakeClass(1); + + fChain->SetBranchAddress("runNumber", &runNumber, &b_runNumber); + fChain->SetBranchAddress("eventNumber", &eventNumber, &b_eventNumber); + fChain->SetBranchAddress("lumiBlock", &lumiBlock, &b_lumiBlock); + fChain->SetBranchAddress("bcid", &bcid, &b_bcid); + // fChain->SetBranchAddress("trigger", &trigger, &b_trigger); + // fChain->SetBranchAddress("trigger_TBP", &trigger_TBP, &b_trigger_TBP); + fChain->SetBranchAddress("tbp", tbp, &b_tbp); + + // fChain->SetBranchAddress("tav", tav, &b_tav); + // // fChain->SetBranchAddress("decisions", &decisions, &b_decisions); + // // fChain->SetBranchAddress("prescales", &prescales, &b_prescales); + fChain->SetBranchAddress("passBits", &passBits, &b_passBits); + + // fChain->SetBranchAddress("zdc_amp", zdc_amp, &b_zdc_amp); + // fChain->SetBranchAddress("zdc_amp_rp", zdc_amp_rp, &b_zdc_amp_rp); + // fChain->SetBranchAddress("zdc_time", zdc_time, &b_zdc_time); + fChain->SetBranchAddress("zdc_raw", zdc_raw, &b_zdc_raw); + // fChain->SetBranchAddress("zdc_ampHG", zdc_ampHG, &b_zdc_ampHG); + // fChain->SetBranchAddress("zdc_ampLG", zdc_ampLG, &b_zdc_ampLG); + // fChain->SetBranchAddress("zdc_sumHG", zdc_sumHG, &b_zdc_sumHG); + // fChain->SetBranchAddress("zdc_sumLG", zdc_sumLG, &b_zdc_sumLG); + // fChain->SetBranchAddress("zdc_ampHG_rp", zdc_ampHG_rp, &b_zdc_ampHG_rp); + // fChain->SetBranchAddress("zdc_ampLG_rp", zdc_ampLG_rp, &b_zdc_ampLG_rp); + // fChain->SetBranchAddress("zdc_sumHG_rp", zdc_sumHG_rp, &b_zdc_sumHG_rp); + // fChain->SetBranchAddress("zdc_sumLG_rp", zdc_sumLG_rp, &b_zdc_sumLG_rp); + // fChain->SetBranchAddress("fcalEt", &fcalEt, &b_fcalEt); + // fChain->SetBranchAddress("ntrk", &ntrk, &b_ntrk); + // fChain->SetBranchAddress("nvx", &nvx, &b_nvx); + // fChain->SetBranchAddress("vx", vx, &b_vx); + // fChain->SetBranchAddress("vxntrk", &vxntrk, &b_vxntrk); + // fChain->SetBranchAddress("vxcov", vxcov, &b_vxcov); + // fChain->SetBranchAddress("mbts_countA", &mbts_countA, &b_mbts_countA); + // fChain->SetBranchAddress("mbts_countC", &mbts_countC, &b_mbts_countC); + // fChain->SetBranchAddress("mbts_timeA", &mbts_timeA, &b_mbts_timeA); + // fChain->SetBranchAddress("mbts_timeC", &mbts_timeC, &b_mbts_timeC); + // fChain->SetBranchAddress("mbts_timeDiff", &mbts_timeDiff, &b_mbts_timeDiff); + + fChain->SetBranchAddress("L1_ZDC_A", &L1_ZDC_A, &b_L1_ZDC_A); + // fChain->SetBranchAddress("ps_L1_ZDC_A", &ps_L1_ZDC_A, &b_ps_L1_ZDC_A); + fChain->SetBranchAddress("L1_ZDC_C", &L1_ZDC_C, &b_L1_ZDC_C); + // fChain->SetBranchAddress("ps_L1_ZDC_C", &ps_L1_ZDC_C, &b_ps_L1_ZDC_C); + fChain->SetBranchAddress("L1_ZDC_AND", &L1_ZDC_AND, &b_L1_ZDC_AND); + // fChain->SetBranchAddress("ps_L1_ZDC_AND", &ps_L1_ZDC_AND, &b_ps_L1_ZDC_AND); + fChain->SetBranchAddress("L1_ZDC_A_C", &L1_ZDC_A_C, &b_L1_ZDC_A_C); + // fChain->SetBranchAddress("ps_L1_ZDC_A_C", &ps_L1_ZDC_A_C, &b_ps_L1_ZDC_A_C); + + fChain->SetBranchStatus("*", 0); + fChain->SetBranchStatus("runNumber", 1); + fChain->SetBranchStatus("eventNumber", 1); + fChain->SetBranchStatus("lumiBlock", 1); + fChain->SetBranchStatus("bcid", 1); + fChain->SetBranchStatus("zdc_raw", 1); + fChain->SetBranchStatus("tbp", 1); + + fChain->SetBranchStatus("passBits", 1); + + fChain->SetBranchStatus("L1_ZDC_A", 1); + fChain->SetBranchStatus("L1_ZDC_C", 1); + fChain->SetBranchStatus("L1_ZDC_AND", 1); + fChain->SetBranchStatus("L1_ZDC_A_C", 1); + + Notify(); +} + +Bool_t ZDCTreeAnalysis::Notify() +{ + // The Notify() function is called when a new file is opened. This + // can be either for a new TTree in a TChain or when when a new TTree + // is started when using PROOF. It is normally not necessary to make changes + // to the generated code, but the routine can be extended by the + // user if needed. The return value is currently not used. + + return kTRUE; +} + +void ZDCTreeAnalysis::Show(Long64_t entry) +{ +// Print contents of entry. +// If entry is not specified, print current entry + if (!fChain) return; + fChain->Show(entry); +} +Int_t ZDCTreeAnalysis::Cut(Long64_t entry) +{ +// This function may be called from Loop. +// returns 1 if entry is accepted. +// returns -1 otherwise. + return 1; +} +#endif // #ifdef ZDCTreeAnalysis_cxx -- GitLab