diff --git a/DataFormats/Detectors/ZDC/CMakeLists.txt b/DataFormats/Detectors/ZDC/CMakeLists.txt index deda5de9cd739..2e69c27e74c0a 100644 --- a/DataFormats/Detectors/ZDC/CMakeLists.txt +++ b/DataFormats/Detectors/ZDC/CMakeLists.txt @@ -11,8 +11,8 @@ o2_add_library(DataFormatsZDC SOURCES src/ChannelData.cxx src/BCData.cxx src/BCRecData.cxx src/RecEvent.cxx src/RecEventAux.cxx src/RawEventData.cxx - src/OrbitRawData.cxx src/OrbitRecData.cxx src/OrbitData.cxx src/ZDCTDCData.cxx src/ZDCEnergy.cxx - src/CTF.cxx src/RecEventFlat.cxx src/InterCalibData.cxx + src/OrbitRawData.cxx src/OrbitRecData.cxx src/OrbitData.cxx src/ZDCTDCData.cxx src/ZDCEnergy.cxx src/ZDCWaveform.cxx + src/CTF.cxx src/RecEventFlat.cxx PUBLIC_LINK_LIBRARIES O2::CommonConstants O2::CommonDataFormat O2::DetectorsCalibration O2::ZDCBase ROOT::MathCore FairRoot::Base O2::SimulationDataFormat @@ -24,6 +24,5 @@ o2_target_root_dictionary(DataFormatsZDC include/DataFormatsZDC/OrbitData.h include/DataFormatsZDC/CTF.h include/DataFormatsZDC/RecEvent.h include/DataFormatsZDC/RecEventAux.h include/DataFormatsZDC/RecEventFlat.h include/DataFormatsZDC/OrbitRawData.h include/DataFormatsZDC/ZDCTDCData.h - include/DataFormatsZDC/BCRecData.h include/DataFormatsZDC/ZDCEnergy.h - include/DataFormatsZDC/OrbitRecData.h include/DataFormatsZDC/RawEventData.h - include/DataFormatsZDC/InterCalibData.h) + include/DataFormatsZDC/BCRecData.h include/DataFormatsZDC/ZDCEnergy.h include/DataFormatsZDC/ZDCWaveform.h + include/DataFormatsZDC/OrbitRecData.h include/DataFormatsZDC/RawEventData.h) diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h index c7c8f2f23dd4e..c4417c73a9707 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCRecData.h @@ -35,6 +35,7 @@ struct BCRecData { o2::dataformats::RangeRefComp<5> refe; // Reference to reconstructed energy o2::dataformats::RangeRefComp<5> reft; // Reference to reconstructed TDC o2::dataformats::RangeRefComp<5> refi; // Reference to reconstruction error/information flags + o2::dataformats::RangeRefComp<5> refw; // Reference to waveform interpolated data BCRecData() = default; @@ -47,6 +48,21 @@ struct BCRecData { reft.setEntries(0); refi.setFirstEntry(firsti); refi.setEntries(0); + refw.setFirstEntry(0); + refw.setEntries(0); + ir = iRec; + } + + BCRecData(int firste, int firstt, int firsti, int firstd, o2::InteractionRecord iRec) + { + refe.setFirstEntry(firste); + refe.setEntries(0); + reft.setFirstEntry(firstt); + reft.setEntries(0); + refi.setFirstEntry(firsti); + refi.setEntries(0); + refw.setFirstEntry(firstd); + refw.setEntries(0); ir = iRec; } @@ -68,6 +84,12 @@ struct BCRecData { refi.setEntries(refi.getEntries() + 1); } + // Update counter of Waveform entries + inline void addWaveform() + { + refw.setEntries(refw.getEntries() + 1); + } + // Get information about event inline void getRef(int& firste, int& ne, int& firstt, int& nt, int& firsti, int& ni) { @@ -79,9 +101,41 @@ struct BCRecData { ni = refi.getEntries(); } + inline void getRef(int& firste, int& ne, int& firstt, int& nt, int& firsti, int& ni, int& firstw, int& nw) + { + firste = refe.getFirstEntry(); + firstt = reft.getFirstEntry(); + firsti = refi.getFirstEntry(); + firstw = refw.getFirstEntry(); + ne = refe.getEntries(); + nt = reft.getEntries(); + ni = refi.getEntries(); + nw = refw.getEntries(); + } + inline void getRefE(int& firste, int& ne) + { + firste = refe.getFirstEntry(); + ne = refe.getEntries(); + } + inline void getRefT(int& firstt, int& nt) + { + firstt = reft.getFirstEntry(); + nt = reft.getEntries(); + } + inline void getRefI(int& firsti, int& ni) + { + firsti = refi.getFirstEntry(); + ni = refi.getEntries(); + } + inline void getRefW(int& firstw, int& nw) + { + firstw = refw.getFirstEntry(); + nw = refw.getEntries(); + } + void print() const; - ClassDefNV(BCRecData, 1); + ClassDefNV(BCRecData, 2); }; } // namespace zdc } // namespace o2 diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h index 9c35d400608fa..9d1efc5ed12c7 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/OrbitData.h @@ -9,15 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef _ZDC_PEDESTAL_DATA_H_ -#define _ZDC_PEDESTAL_DATA_H_ +#ifndef _ZDC_ORBIT_DATA_H_ +#define _ZDC_ORBIT_DATA_H_ #include "CommonDataFormat/InteractionRecord.h" #include "ZDCBase/Constants.h" #include #include -/// \file Pedestal.h +/// \file OrbitData.h /// \brief Class to describe pedestal data accumulated over the orbit /// \author ruben.shahoyan@cern.ch diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h index ed6151f3be40a..9ac9494a45d1d 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEvent.h @@ -17,6 +17,7 @@ #include "DataFormatsZDC/BCRecData.h" #include "DataFormatsZDC/ZDCEnergy.h" #include "DataFormatsZDC/ZDCTDCData.h" +#include "DataFormatsZDC/ZDCWaveform.h" #include "DataFormatsZDC/RecEventAux.h" #include "ZDCBase/Constants.h" #include "MathUtils/Cartesian.h" @@ -34,20 +35,23 @@ namespace o2 namespace zdc { struct RecEvent { - std::vector mRecBC; /// Interaction record and references to data - std::vector mEnergy; /// ZDC energy - std::vector mTDCData; /// ZDC TDC - std::vector mInfo; /// Event quality information + std::vector mRecBC; /// Interaction record and references to data + std::vector mEnergy; /// ZDC energy + std::vector mTDCData; /// ZDC TDC + std::vector mInfo; /// Event quality information + std::vector mWaveform; /// ZDC waveform + // Add new bunch crossing inline void addBC(const RecEventAux& reca) { #ifdef O2_ZDC_DEBUG printf("addBC %u.%-4u En_start:%-2lu TDC_start:%-2lu Info_start:%-2lu ch=0x%08x tr=0x%08x\n", reca.ir.orbit, reca.ir.bc, mEnergy.size(), mTDCData.size(), mInfo.size(), reca.channels, reca.triggers); #endif - mRecBC.emplace_back(mEnergy.size(), mTDCData.size(), mInfo.size(), reca.ir); + mRecBC.emplace_back(mEnergy.size(), mTDCData.size(), mInfo.size(), mWaveform.size(), reca.ir); mRecBC.back().channels = reca.channels; mRecBC.back().triggers = reca.triggers; } + // Add energy inline void addEnergy(uint8_t ch, float energy) { @@ -57,6 +61,7 @@ struct RecEvent { mEnergy.emplace_back(ch, energy); mRecBC.back().addEnergy(); } + // Add TDC - int16_t inline void addTDC(uint8_t ch, int16_t val, int16_t amp, bool isbeg = false, bool isend = false) { @@ -66,6 +71,7 @@ struct RecEvent { mTDCData.emplace_back(ch, val, amp, isbeg, isend); mRecBC.back().addTDC(); } + // Add TDC - float inline void addTDC(uint8_t ch, float val, float amp, bool isbeg = false, bool isend = false) { @@ -75,6 +81,7 @@ struct RecEvent { mTDCData.emplace_back(ch, val, amp, isbeg, isend); mRecBC.back().addTDC(); } + // Add event information inline void addInfo(uint16_t info) { @@ -102,9 +109,23 @@ struct RecEvent { uint32_t addInfo(const RecEventAux& reca, const std::array& vec, const uint16_t code); uint32_t addInfos(const RecEventAux& reca); + // Add waveform + inline void addWaveform(uint8_t ch, std::vector& wave) + { +#ifdef O2_ZDC_DEBUG + printf("ch:%-2u [%s] Waveform\n", ch, ChannelNames[ch].data()); +#endif + if (wave.size() == NIS) { + mWaveform.emplace_back(ch, wave.data()); + mRecBC.back().addWaveform(); + } else { + LOG(error) << __func__ << ": ch " << int(ch) << " inconsistent waveform size " << wave.size(); + } + } + void print() const; // TODO: remove persitency of this object (here for debugging) - ClassDefNV(RecEvent, 1); + ClassDefNV(RecEvent, 2); }; } // namespace zdc diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h index 9fc0c0fb73ea7..e384d19083c02 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventAux.h @@ -31,7 +31,7 @@ namespace zdc { struct RecEventAux : public RecEventFlat { - uint32_t flags; /// reconstruction flags + uint32_t flags; #ifdef O2_ZDC_TDC_C_ARRAY int16_t tdcVal[NTDCChannels][MaxTDCValues]; /// TdcValues (encoded) int16_t tdcAmp[NTDCChannels][MaxTDCValues]; /// TdcAmplitudes (encoded) @@ -43,9 +43,7 @@ struct RecEventAux : public RecEventFlat { uint32_t ref[NChannels]; /// Cache of references std::array err; /// Generic error condition std::array data[NChannels] = {0}; /// Samples (raw or filtered) -#ifdef O2_ZDC_INTERP_DEBUG - float inter[NTDCChannels][NTimeBinsPerBC * TSN] = {0}; /// Interpolated samples -#endif + // Functions RecEventAux() { diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h index 11dd493ad722a..5617ccc42a181 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/RecEventFlat.h @@ -63,7 +63,8 @@ struct RecEventFlat { // NOLINT: false positive in clang-tidy !! NElem mNI = 0; //! N info std::array isBeg{}; //! Beginning of sequence std::array isEnd{}; //! End of sequence - o2::zdc::BCRecData mCurB; //! Current BC + BCRecData mCurB; //! Current BC + std::vector inter[NChannels]; //! Interpolated samples // Reconstruction messages std::array genericE{}; /// 0 Generic error @@ -99,6 +100,32 @@ struct RecEventFlat { // NOLINT: false positive in clang-tidy !! void init(const gsl::span RecBC, const gsl::span Energy, const gsl::span TDCData, const gsl::span Info); int next(); + int at(int ientry); + + void allocate(int isig) + { + if (inter[isig].size() != NIS) { + inter[isig].resize(NIS); + for (int iis = 0; iis < NIS; iis++) { + inter[isig][iis] = 0; + } + } + } + + BCRecData& getCurB() + { + return mCurB; + } + + inline int getEntries() const + { + return mNEntries; + } + + inline int getNextEntry() const + { + return mEntry; + } inline NElem getNEnergy() const { diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCWaveform.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCWaveform.h new file mode 100644 index 0000000000000..97c9af0b43b3b --- /dev/null +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/ZDCWaveform.h @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_WAVEFORM_H +#define ZDC_WAVEFORM_H + +#include "ZDCBase/Constants.h" +#include +#include +#include + +/// \file ZDCWaveform.h +/// \brief Container class to store the interpolated waveform of the ZDC +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct ZDCWaveform { + + uint8_t sig = 0; /// Signal id + float inter[NTimeBinsPerBC * TSN] = {0}; + + ZDCWaveform() = default; + + ZDCWaveform(uint8_t mych, float* waveform) + { + set(mych, waveform); + } + + inline void set(uint8_t ch, float* waveform) + { + sig = ch; + for (int i = 0; i < (NTimeBinsPerBC * TSN); i++) { + inter[i] = waveform[i]; + } + } + + const float* waveform() const + { + return inter; + } + + int ch() const + { + return sig; + } + + void print() const; + + ClassDefNV(ZDCWaveform, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/DataFormats/Detectors/ZDC/src/BCRecData.cxx b/DataFormats/Detectors/ZDC/src/BCRecData.cxx index 7810644f022df..929269dc3070e 100644 --- a/DataFormats/Detectors/ZDC/src/BCRecData.cxx +++ b/DataFormats/Detectors/ZDC/src/BCRecData.cxx @@ -17,8 +17,9 @@ using namespace o2::zdc; void BCRecData::print() const { - printf("Orbit %9u bc %4u nch %2d pos %d ntdc %2d pos %d nmsg %2d pos %d\n", ir.orbit, ir.bc, + printf("Orbit %9u bc %4u nch=%2d pos %d ntdc=%2d pos %d nmsg=%2d pos %d nwav=%d pos %d\n", ir.orbit, ir.bc, refe.getEntries(), refe.getFirstEntry(), reft.getEntries(), reft.getFirstEntry(), - refi.getEntries(), refi.getFirstEntry()); + refi.getEntries(), refi.getFirstEntry(), + refw.getEntries(), refw.getFirstEntry()); } diff --git a/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h b/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h index abe1d66311913..6e272dbc8a118 100644 --- a/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h +++ b/DataFormats/Detectors/ZDC/src/DataFormatsZDCLinkDef.h @@ -32,13 +32,14 @@ #pragma link C++ class o2::zdc::RecEventFlat + ; #pragma link C++ class o2::zdc::ZDCEnergy + ; #pragma link C++ class o2::zdc::ZDCTDCData + ; -#pragma link C++ class o2::zdc::InterCalibData + ; +#pragma link C++ class o2::zdc::ZDCWaveform + ; #pragma link C++ class std::vector < o2::zdc::ChannelData> + ; #pragma link C++ class std::vector < o2::zdc::BCData> + ; #pragma link C++ class std::vector < o2::zdc::OrbitData> + ; #pragma link C++ class std::vector < o2::zdc::BCRecData> + ; #pragma link C++ class std::vector < o2::zdc::ZDCEnergy> + ; #pragma link C++ class std::vector < o2::zdc::ZDCTDCData> + ; +#pragma link C++ class std::vector < o2::zdc::ZDCWaveform> + ; #pragma link C++ class std::vector < o2::zdc::RecEvent> + ; #pragma link C++ class std::vector < o2::zdc::RecEventAux> + ; #pragma link C++ class std::vector < o2::zdc::OrbitRawData> + ; diff --git a/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx b/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx index 440edff22f27a..7c9d50c3d61eb 100644 --- a/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx +++ b/DataFormats/Detectors/ZDC/src/RecEventFlat.cxx @@ -65,6 +65,12 @@ void RecEventFlat::clearBitmaps() int RecEventFlat::next() { + return at(mEntry); +} + +int RecEventFlat::at(int ientry) +{ + mEntry = ientry; ezdcDecoded = 0; if (mEntry >= mNEntries) { return 0; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibWorkflow.h b/DataFormats/Detectors/ZDC/src/ZDCWaveform.cxx similarity index 65% rename from Detectors/ZDC/calib/include/ZDCCalib/InterCalibWorkflow.h rename to DataFormats/Detectors/ZDC/src/ZDCWaveform.cxx index 6870ba306501d..66b398e3fb5f2 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibWorkflow.h +++ b/DataFormats/Detectors/ZDC/src/ZDCWaveform.cxx @@ -9,18 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef O2_ZDC_INTERCALIBWORKFLOW_H -#define O2_ZDC_INTERCALIBWORKFLOW_H +#include "DataFormatsZDC/ZDCWaveform.h" -/// @file InterCalibWorkflow.h +using namespace o2::zdc; -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace zdc +void ZDCWaveform::print() const { -framework::WorkflowSpec getInterCalibWorkflow(const int verbosity); -} // namespace zdc -} // namespace o2 -#endif + auto id = this->ch(); + printf("%2d (%s)\n", id, channelName(id)); +} diff --git a/Detectors/ZDC/base/include/ZDCBase/Constants.h b/Detectors/ZDC/base/include/ZDCBase/Constants.h index 015187f87d927..f6fb3741831ca 100644 --- a/Detectors/ZDC/base/include/ZDCBase/Constants.h +++ b/Detectors/ZDC/base/include/ZDCBase/Constants.h @@ -25,10 +25,6 @@ //#define O2_ZDC_DEBUG // TDC arrays in debug output //#define O2_ZDC_TDC_C_ARRAY -// Debug output of full interpolated function -//#define O2_ZDC_INTERP_DEBUG -// Low pass filtering of acquired samples -#define O2_ZDC_RECO_FILTERING namespace o2 { @@ -93,6 +89,7 @@ constexpr int TSN = 200; // Number of interpolated points betwe constexpr int TSNH = TSN / 2; // Half of TSN constexpr int NTS = 2 * TSL * TSN + 1; // Tapered sinc function array size constexpr static float FTDCAmp = 1. / 8.; // Multiplication factor in conversion from integer +constexpr int NIS = NTimeBinsPerBC * TSN; // Number of interpolated samples // With a reference clock of 40 MHz exact this FTDCVal would have been // constexpr static float FTDCVal = 1. / TSNS; // with constexpr int TSNS = 96; @@ -209,6 +206,7 @@ constexpr std::string_view ChannelNames[] = { "ZPC4", "ZPCS"}; +// From TDC ID to signal ID const int TDCSignal[NTDCChannels] = { IdZNAC, // TDCZNAC IdZNASum, // TDCZNAS @@ -222,6 +220,19 @@ const int TDCSignal[NTDCChannels] = { IdZPCSum // TDCZPCS }; +// From Signal ID to TDC ID +const int SignalTDC[NChannels] = { + TDCZNAC, + TDCZNAS, TDCZNAS, TDCZNAS, TDCZNAS, TDCZNAS, + TDCZPAC, + TDCZPAS, TDCZPAS, TDCZPAS, TDCZPAS, TDCZPAS, + TDCZEM1, + TDCZEM2, + TDCZNCC, + TDCZNCS, TDCZNCS, TDCZNCS, TDCZNCS, TDCZNCS, + TDCZPCC, + TDCZPCS, TDCZPCS, TDCZPCS, TDCZPCS, TDCZPCS}; + constexpr int DbgZero = 0; constexpr int DbgMinimal = 1; constexpr int DbgMedium = 2; @@ -240,6 +251,8 @@ const std::string CCDBPathTDCCorr = "ZDC/Calib/TDCCorr"; const std::string CCDBPathEnergyCalib = "ZDC/Calib/EnergyCalib"; const std::string CCDBPathTowerCalib = "ZDC/Calib/TowerCalib"; const std::string CCDBPathInterCalibConfig = "ZDC/Calib/InterCalibConfig"; +const std::string CCDBPathWaveformCalib = "ZDC/Calib/WaveformCalib"; +const std::string CCDBPathWaveformCalibConfig = "ZDC/Calib/WaveformCalibConfig"; enum Ped { PedND = 0, PedEv = 1, @@ -353,6 +366,12 @@ constexpr int toDet(int channel, int& tower) } } +// Calibration workflows +static constexpr int WaveformCalib_NBB = 3; +static constexpr int WaveformCalib_NBA = 6; +static constexpr int WaveformCalib_NBT = WaveformCalib_NBB + WaveformCalib_NBA + 1; +static constexpr int WaveformCalib_NW = WaveformCalib_NBT * NIS; + } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h b/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h index b9f7f650aace3..7560307b45137 100644 --- a/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h +++ b/Detectors/ZDC/base/include/ZDCBase/ModuleConfig.h @@ -15,6 +15,7 @@ #include "ZDCBase/Constants.h" #include #include +#include namespace o2 { @@ -54,6 +55,8 @@ struct ModuleConfig { void print() const; void check() const; + uint32_t getTriggerMask() const; + std::string getPrintTriggerMask() const; ClassDefNV(ModuleConfig, 1); }; diff --git a/Detectors/ZDC/base/src/ModuleConfig.cxx b/Detectors/ZDC/base/src/ModuleConfig.cxx index 5b9abdf1fd25f..291d76a14c51c 100644 --- a/Detectors/ZDC/base/src/ModuleConfig.cxx +++ b/Detectors/ZDC/base/src/ModuleConfig.cxx @@ -108,3 +108,39 @@ void Module::setChannel(int slot, int8_t chID, int16_t fID, bool read, bool trig trigChannelConf[slot].threshold = tT; } } + +//______________________________________________________________________________ +uint32_t ModuleConfig::getTriggerMask() const +{ + uint32_t triggermask = 0; + for (int im = 0; im < NModules; im++) { + for (int ic = 0; ic < NChPerModule; ic++) { + if (modules[im].trigChannel[ic]) { + uint32_t tmask = 0x1 << (im * NChPerModule + ic); + triggermask = triggermask | tmask; + } + } + } + return triggermask; +} + +std::string ModuleConfig::getPrintTriggerMask() const +{ + std::string printTriggerMask{}; + for (int im = 0; im < NModules; im++) { + if (im > 0) { + printTriggerMask += " "; + } + printTriggerMask += std::to_string(im); + printTriggerMask += "["; + for (int ic = 0; ic < NChPerModule; ic++) { + if (modules[im].trigChannel[ic]) { + printTriggerMask += "T"; + } else { + printTriggerMask += " "; + } + } + printTriggerMask += "]"; + } + return printTriggerMask; +} diff --git a/Detectors/ZDC/calib/CMakeLists.txt b/Detectors/ZDC/calib/CMakeLists.txt index d163e440c7af8..ceb66931164fc 100644 --- a/Detectors/ZDC/calib/CMakeLists.txt +++ b/Detectors/ZDC/calib/CMakeLists.txt @@ -11,11 +11,21 @@ o2_add_library(ZDCCalib SOURCES + src/InterCalibData.cxx src/InterCalib.cxx src/InterCalibConfig.cxx src/InterCalibSpec.cxx src/InterCalibEPN.cxx src/InterCalibEPNSpec.cxx + src/WaveformCalibConfig.cxx + src/WaveformCalib.cxx + src/WaveformCalibSpec.cxx + src/WaveformCalibEPN.cxx + src/WaveformCalibEPNSpec.cxx + src/WaveformCalibQueue.cxx + src/WaveformCalibData.cxx + src/WaveformCalibParam.cxx + src/CalibParamZDC.cxx PUBLIC_LINK_LIBRARIES O2::CCDB O2::DPLUtils @@ -34,11 +44,21 @@ o2_add_library(ZDCCalib o2_target_root_dictionary(ZDCCalib HEADERS + include/ZDCCalib/InterCalibData.h include/ZDCCalib/InterCalib.h include/ZDCCalib/InterCalibConfig.h include/ZDCCalib/InterCalibSpec.h include/ZDCCalib/InterCalibEPN.h - include/ZDCCalib/InterCalibEPNSpec.h) + include/ZDCCalib/InterCalibEPNSpec.h + include/ZDCCalib/WaveformCalibConfig.h + include/ZDCCalib/WaveformCalib.h + include/ZDCCalib/WaveformCalibSpec.h + include/ZDCCalib/WaveformCalibEPN.h + include/ZDCCalib/WaveformCalibEPNSpec.h + include/ZDCCalib/WaveformCalibQueue.h + include/ZDCCalib/WaveformCalibData.h + include/ZDCCalib/WaveformCalibParam.h + include/ZDCCalib/CalibParamZDC.h) o2_add_executable(intercalib-workflow COMPONENT_NAME zdc @@ -49,3 +69,13 @@ o2_add_executable(intercalib-epn-workflow COMPONENT_NAME zdc SOURCES src/zdc-intercalib-epn-workflow.cxx PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCCalib O2::DetectorsCalibration) + +o2_add_executable(waveformcalib-epn-workflow + COMPONENT_NAME zdc + SOURCES src/zdc-waveformcalib-epn-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCCalib O2::DetectorsCalibration) + +o2_add_executable(waveformcalib-workflow + COMPONENT_NAME zdc + SOURCES src/zdc-waveformcalib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCCalib O2::DetectorsCalibration) diff --git a/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h b/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h new file mode 100644 index 0000000000000..ab02d04d55e6c --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_CALIBPARAMZDC_H +#define O2_ZDC_CALIBPARAMZDC_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "ZDCBase/Constants.h" + +/// \file CalibParamZDC.h +/// \brief ZDC calibration common parameters +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct CalibParamZDC : public o2::conf::ConfigurableParamHelper { + int debug_output = -1; // Debug output + void print(); + O2ParamDef(CalibParamZDC, "CalibParamZDC"); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h index b32711f9edc6d..dc90cb6ff2acb 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h @@ -20,13 +20,13 @@ #include "CommonDataFormat/FlatHisto1D.h" #include "CommonDataFormat/FlatHisto2D.h" #include "DataFormatsZDC/RecEvent.h" -#include "DataFormatsZDC/InterCalibData.h" #include "ZDCReconstruction/ZDCEnergyParam.h" #include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalibConfig.h" #include "CCDB/CcdbObjectInfo.h" -#ifndef ALICEO2_ZDC_INTERCALIB_H_ -#define ALICEO2_ZDC_INTERCALIB_H_ +#ifndef ALICEO2_ZDC_INTERCALIB_H +#define ALICEO2_ZDC_INTERCALIB_H namespace o2 { namespace zdc diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/InterCalibData.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibData.h similarity index 95% rename from DataFormats/Detectors/ZDC/include/DataFormatsZDC/InterCalibData.h rename to Detectors/ZDC/calib/include/ZDCCalib/InterCalibData.h index 82279ad855572..dbe45280def65 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/InterCalibData.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibData.h @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef _ZDC_INTERCALIB_DATA_H_ -#define _ZDC_INTERCALIB_DATA_H_ +#ifndef _ZDC_INTERCALIB_DATA_H +#define _ZDC_INTERCALIB_DATA_H #include "ZDCBase/Constants.h" #include diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPN.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPN.h index 01fbfd49239d3..38e68d86ab504 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPN.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPN.h @@ -20,9 +20,9 @@ #include "CommonDataFormat/FlatHisto1D.h" #include "CommonDataFormat/FlatHisto2D.h" #include "DataFormatsZDC/RecEvent.h" -#include "DataFormatsZDC/InterCalibData.h" #include "ZDCReconstruction/ZDCEnergyParam.h" #include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalibConfig.h" #ifndef ALICEO2_ZDC_INTERCALIBEPN_H_ #define ALICEO2_ZDC_INTERCALIBEPN_H_ @@ -55,8 +55,9 @@ class InterCalibEPN const InterCalibConfig* getInterCalibConfig() const { return mInterCalibConfig; }; void setSaveDebugHistos() { mSaveDebugHistos = true; } void setDontSaveDebugHistos() { mSaveDebugHistos = false; } - InterCalibData& getData() { return mData; } + void setVerbosity(int val) { mVerbosity = val; } InterCalibData mData; + InterCalibData& getData() { return mData; } std::array*, 2 * NH> mH{}; std::array*, NH> mC{}; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPNSpec.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPNSpec.h index d6e545092350a..264d5cdfe3fdb 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPNSpec.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibEPNSpec.h @@ -21,7 +21,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "CommonUtils/NameConf.h" -#include "DataFormatsZDC/InterCalibData.h" +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalibEPN.h" #include "ZDCCalib/InterCalibConfig.h" @@ -42,9 +42,9 @@ class InterCalibEPNSpec : public o2::framework::Task void endOfStream(o2::framework::EndOfStreamContext& ec) final; private: - int mVerbosity = 0; // Verbosity level - bool mInitialized = false; // Connect once to CCDB during initialization - InterCalibEPN mInterCalibEPN; // Intercalibration object + int mVerbosity = 0; // Verbosity level + bool mInitialized = false; // Connect once to CCDB during initialization + InterCalibEPN mWorker; // Intercalibration object TStopwatch mTimer; }; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibSpec.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibSpec.h index e6551ea86b726..14e4186803c61 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibSpec.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibSpec.h @@ -23,8 +23,8 @@ #include "Framework/Task.h" #include "CommonDataFormat/FlatHisto1D.h" #include "CommonDataFormat/FlatHisto2D.h" -#include "DataFormatsZDC/InterCalibData.h" #include "CommonUtils/NameConf.h" +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalib.h" #include "ZDCCalib/InterCalibConfig.h" #include "DetectorsCalibration/Utils.h" @@ -49,7 +49,7 @@ class InterCalibSpec : public o2::framework::Task private: int mVerbosity = DbgMinimal; // Verbosity level - InterCalib mInterCalib; // Intercalibration object + InterCalib mWorker; // Intercalibration object TStopwatch mTimer; }; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalib.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalib.h new file mode 100644 index 0000000000000..b7f749c4b7bf7 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalib.h @@ -0,0 +1,65 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include +#include +#include +#include "ZDCBase/Constants.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include "CCDB/CcdbObjectInfo.h" +#ifndef ALICEO2_ZDC_WAVEFORMCALIB_H +#define ALICEO2_ZDC_WAVEFORMCALIB_H +namespace o2 +{ +namespace zdc +{ +class WaveformCalib +{ + using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; + + public: + WaveformCalib() = default; + int init(); + void clear(); + int process(const WaveformCalibData& data); // Calibration of RUN3 data - aggregator node + int endOfRun(); // Perform minimization + int saveDebugHistos(const std::string fn = "ZDCWaveformCalib.root"); + + CcdbObjectInfo& getCcdbObjectInfo() { return mInfo; } + + void setConfig(const WaveformCalibConfig* param) { mConfig = param; }; + const WaveformCalibConfig* getConfig() const { return mConfig; }; + + void setVerbosity(int v) { mVerbosity = v; } + int getVerbosity() const { return mVerbosity; } + + void setSaveDebugHistos() { mSaveDebugHistos = true; } + void setDontSaveDebugHistos() { mSaveDebugHistos = false; } + + WaveformCalibData& getData() { return mData; } + + private: + WaveformCalibData mData; + bool mInitDone = false; + bool mSaveDebugHistos = false; + int32_t mVerbosity = DbgMinimal; + const WaveformCalibConfig* mConfig = nullptr; /// Configuration of intercalibration + CcdbObjectInfo mInfo; /// CCDB Info +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibConfig.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibConfig.h new file mode 100644 index 0000000000000..b7f51f02f0498 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibConfig.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ZDC_WAVEFORMCALIBCONFIG_H +#define O2_ZDC_WAVEFORMCALIBCONFIG_H + +//#define O2_ZDC_WAVEFORMCALIB_DEBUG + +#include "ZDCBase/Constants.h" +#include +#include + +/// \file WaveformCalibConfig.h +/// \brief Configuration of ZDC Tower intercalibration procedure +/// \author P. Cortese + +namespace o2 +{ +namespace zdc +{ +struct WaveformCalibConfig { + static constexpr int NBB = WaveformCalib_NBB; + static constexpr int NBA = WaveformCalib_NBA; + static constexpr int NBT = WaveformCalib_NBT; + static constexpr int NW = WaveformCalib_NW; + + WaveformCalibConfig(); + + double cutLow[NChannels]; /// Amplitude cut low + double cutHigh[NChannels]; /// Amplitude cut high + double min_e[NChannels] = {0.}; /// Minimum entries to compute waveform + double cutTimeLow[NTDCChannels]; /// TDC cut low + double cutTimeHigh[NTDCChannels]; /// TDC cut high + std::string desc = ""; + int ibeg = -NBB; + int iend = NBA; + int nbun = iend - ibeg + 1; + + void print() const; + void restrictRange(int ib, int ie); + void resetCuts(); + void resetCutLow(); + void resetCutHigh(); + void resetCutLow(int ih); + void resetCutHigh(int ih); + void setMinEntries(double val); + void setMinEntries(int ih, double val); + void setCutLow(double val); + void setCutHigh(double val); + void setCutLow(int ih, double val); + void setCutHigh(int ih, double val); + void setCuts(double low, double high); + void setCuts(int ih, double low, double high); + void setTimeCuts(double low, double high); + void setTimeCuts(int itdc, double low, double high); + void setDescription(std::string d) { desc = d; } + + int getFirst() const + { + return ibeg; + } + + int getLast() const + { + return iend; + } + + ClassDefNV(WaveformCalibConfig, 1); +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h new file mode 100644 index 0000000000000..87bb6886f7cad --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_WAVEFORMCALIB_DATA_H +#define ZDC_WAVEFORMCALIB_DATA_H + +#include "ZDCBase/Constants.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include + +/// \file WaveformCalibData.h +/// \brief Waveform calibration intermediate data +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct WaveformCalibChData { + static constexpr int NBT = WaveformCalib_NBT; + static constexpr int NW = WaveformCalib_NW; + + int mFirstValid = 0; /// First bin with valid data + int mLastValid = 0; /// Last bin with valid data + uint32_t mEntries = 0; /// Number of waveforms added + std::array mData = {0}; /// Waveform + + WaveformCalibChData& operator+=(const WaveformCalibChData& other); + int getEntries() const; + int getFirstValid() const; + int getLastValid() const; + void clear(); + void setN(int n); + ClassDefNV(WaveformCalibChData, 1); +}; + +struct WaveformCalibData { + static constexpr int NBB = WaveformCalib_NBB; + static constexpr int NBA = WaveformCalib_NBA; + static constexpr int NBT = WaveformCalib_NBT; + static constexpr int NW = WaveformCalib_NW; + + uint64_t mCTimeBeg = 0; /// Time of processed time frame + uint64_t mCTimeEnd = 0; /// Time of processed time frame + int mN = 0; /// Number of bunches in waveform + int mPeak = 0; /// Peak position + + std::array mWave; + WaveformCalibData& operator+=(const WaveformCalibData& other); + inline void setFirstValid(int isig, int ipos) + { + if (ipos > mWave[isig].mFirstValid) { + mWave[isig].mFirstValid = ipos; + } + } + inline void setLastValid(int isig, int ipos) + { + if (ipos < mWave[isig].mLastValid) { + mWave[isig].mLastValid = ipos; + } + } + inline void addEntry(int isig) + { + mWave[isig].mEntries++; + } + int getEntries(int is) const; + int getFirstValid(int is) const; + int getLastValid(int is) const; + void print() const; + void clear(); + void setCreationTime(uint64_t ctime); + void setN(int n); + int saveDebugHistos(const std::string fn); + ClassDefNV(WaveformCalibData, 1); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h new file mode 100644 index 0000000000000..b759d94ff781a --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h @@ -0,0 +1,74 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include "ZDCBase/Constants.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/ZDCWaveform.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" +#include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include "ZDCCalib/WaveformCalibQueue.h" +#ifndef ALICEO2_ZDC_WAVEFORMCALIBEPN_H +#define ALICEO2_ZDC_WAVEFORMCALIBEPN_H +namespace o2 +{ +namespace zdc +{ +class WaveformCalibEPN +{ + public: + WaveformCalibEPN() = default; + int init(); + void clear(int ih = -1); + int process(const gsl::span& bcrec, + const gsl::span& energy, + const gsl::span& tdc, + const gsl::span& info, + const gsl::span& wave); + int endOfRun(); + int saveDebugHistos(const std::string fn = "ZDCWaveformCalibEPN.root"); + void setConfig(const WaveformCalibConfig* param) { mConfig = param; }; + const WaveformCalibConfig* getConfig() const { return mConfig; }; + void setSaveDebugHistos() { mSaveDebugHistos = true; } + void setDontSaveDebugHistos() { mSaveDebugHistos = false; } + void setVerbosity(int val) { mVerbosity = val; } + WaveformCalibData mData; + WaveformCalibData& getData() { return mData; } + + private: + bool mInitDone = false; + bool mSaveDebugHistos = false; + int32_t mNBin = 0; + int32_t mVerbosity = DbgMinimal; + const WaveformCalibConfig* mConfig = nullptr; /// Configuration of intercalibration + + int mFirst = 0; + int mLast = 0; + int mN = 1; + + void configure(int ifirst, int ilast) + { + if (ifirst > 0 || ilast < 0 || ilast < ifirst) { + LOGF(fatal, "WaveformCalibEPN configure error with ifirst=%d ilast=%d", ifirst, ilast); + } + mFirst = ifirst; + mLast = ilast; + mN = ilast - ifirst + 1; + } + + WaveformCalibQueue mQueue; +}; +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPNSpec.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPNSpec.h new file mode 100644 index 0000000000000..d3493654d7500 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPNSpec.h @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file InterCalibEPNSpec.h +/// @brief ZDC intercalibration pre-processing on EPN +/// @author pietro.cortese@cern.ch + +#ifndef O2_ZDC_WAVEFORMCALIBEPN_SPEC +#define O2_ZDC_WAVEFORMCALIBEPN_SPEC + +#include +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "CommonUtils/NameConf.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibEPN.h" +#include "ZDCCalib/WaveformCalibConfig.h" + +namespace o2 +{ +namespace zdc +{ + +class WaveformCalibEPNSpec : public o2::framework::Task +{ + public: + WaveformCalibEPNSpec(); + WaveformCalibEPNSpec(const int verbosity); + ~WaveformCalibEPNSpec() override = default; + void init(o2::framework::InitContext& ic) final; + void updateTimeDependentParams(o2::framework::ProcessingContext& pc); + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + int mVerbosity = 0; // Verbosity level + bool mInitialized = false; // Connect once to CCDB during initialization + WaveformCalibEPN mWorker; // Waveform calibration object + TStopwatch mTimer; +}; + +framework::DataProcessorSpec getWaveformCalibEPNSpec(); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibParam.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibParam.h new file mode 100644 index 0000000000000..969e7b406a3d2 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibParam.h @@ -0,0 +1,51 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_WAVEFORMCALIB_PARAM_H +#define ZDC_WAVEFORMCALIB_PARAM_H + +#include "ZDCBase/Constants.h" +#include +#include "ZDCCalib/WaveformCalibData.h" +#include + +/// \file WaveformCalibParam.h +/// \brief Waveform calibration data +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct WaveformCalibChParam { + using Histo = std::vector; + Histo shape; + int ampMinID = 0; + void print() const; + ClassDefNV(WaveformCalibChParam, 1); +}; + +struct WaveformCalibParam { + + WaveformCalibChParam channels[NChannels]; // configuration per channel + + void assign(const WaveformCalibData& data); + int saveDebugHistos(const std::string fn) const; + void print() const; + + ClassDefNV(WaveformCalibParam, 1); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h new file mode 100644 index 0000000000000..a18f23fab7ea8 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibQueue.h @@ -0,0 +1,118 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ZDC_WAVEFORMCALIB_QUEUE_H +#define ZDC_WAVEFORMCALIB_QUEUE_H + +#include "CommonDataFormat/InteractionRecord.h" +#include "ZDCBase/Constants.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/RecEventFlat.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include + +/// \file WaveformCalibQueue.h +/// \brief Waveform calibration intermediate data queue +/// \author pietro.cortese@cern.ch + +namespace o2 +{ +namespace zdc +{ + +struct WaveformCalibQueue { + WaveformCalibQueue() = default; + WaveformCalibQueue(WaveformCalibConfig* cfg) + { + configure(cfg); + } + + int mFirst = 0; // First bunch of waveform w.r.t. bunch of signal peak + int mLast = 0; // Last bunch of waveform w.r.t. bunch of signal peak + int mPk = 0; // Bunch position of peak w.r.t. first bunch + int mN = 1; // Number of bunches in waveform + int mPeak = 0; // Peak position (interpolated samples) w.r.t. first point + int mNP = 0; // Number of interpolated points in waveform + int mTimeLow[NChannels]; /// Cut on position difference low + int mTimeHigh[NChannels]; /// Cut on position difference high + + const WaveformCalibConfig* mCfg = nullptr; + + static int peak(int pk) + { + return NIS * pk + NIS / 2; + } + + void configure(const WaveformCalibConfig* cfg); + + std::deque mEntry; // Position of event + std::deque mIR; // IR of event + std::deque mHasInfos[NChannels]; // Channel has info messages + std::deque mNTDC[NTDCChannels]; // Number of TDCs in event + std::deque mTDCA[NTDCChannels]; // Peak amplitude + std::deque mTDCP[NTDCChannels]; // Peak position + std::deque mFirstW; // Position of first waveform in event + std::deque mNW; // Number of waveforms in event + + void clear() + { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibConfig::" << __func__; +#endif + mIR.clear(); + mEntry.clear(); + for (int isig = 0; isig < NChannels; isig++) { + mHasInfos[isig].clear(); + } + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + mNTDC[itdc].clear(); + mTDCA[itdc].clear(); + mTDCP[itdc].clear(); + } + mFirstW.clear(); + mNW.clear(); + } + + void pop() + { + mIR.pop_front(); + mEntry.pop_front(); + for (int isig = 0; isig < NChannels; isig++) { + mHasInfos[isig].pop_front(); + } + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + mNTDC[itdc].pop_front(); + mTDCA[itdc].pop_front(); + mTDCP[itdc].pop_front(); + } + mFirstW.pop_front(); + mNW.pop_front(); +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibConfig::" << __func__ << " remaining: " << mNW.size(); +#endif + } + + uint32_t append(RecEventFlat& ev); + void appendEv(RecEventFlat& ev); + int hasData(int isig, const gsl::span& wave); + int addData(int isig, const gsl::span& wave, WaveformCalibData& data); + void print(); + void printConf(); +}; + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibSpec.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibSpec.h new file mode 100644 index 0000000000000..eb8525e912565 --- /dev/null +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibSpec.h @@ -0,0 +1,62 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file InterCalibSpec.h +/// @brief ZDC intercalibration +/// @author pietro.cortese@cern.ch + +#ifndef O2_ZDC_WAVEFORMCALIB_SPEC +#define O2_ZDC_WAVEFORMCALIB_SPEC + +#include +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataAllocator.h" +#include "Framework/Task.h" +#include "CommonDataFormat/FlatHisto1D.h" +#include "CommonDataFormat/FlatHisto2D.h" +#include "CommonUtils/NameConf.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalib.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include "DetectorsCalibration/Utils.h" +#include "CCDB/CcdbObjectInfo.h" + +namespace o2 +{ +namespace zdc +{ + +class WaveformCalibSpec : public o2::framework::Task +{ + public: + WaveformCalibSpec(); + WaveformCalibSpec(const int verbosity); + ~WaveformCalibSpec() override = default; + void init(o2::framework::InitContext& ic) final; + void updateTimeDependentParams(o2::framework::ProcessingContext& pc); + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + void sendOutput(o2::framework::DataAllocator& output); + + private: + int mVerbosity = DbgMinimal; // Verbosity level + bool mInitialized = false; // Connect once to CCDB during initialization + WaveformCalib mWorker; // Intercalibration object + TStopwatch mTimer; +}; + +framework::DataProcessorSpec getWaveformCalibSpec(); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/calib/src/CalibParamZDC.cxx b/Detectors/ZDC/calib/src/CalibParamZDC.cxx new file mode 100644 index 0000000000000..bf23926b60286 --- /dev/null +++ b/Detectors/ZDC/calib/src/CalibParamZDC.cxx @@ -0,0 +1,28 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCCalib/CalibParamZDC.h" + +O2ParamImpl(o2::zdc::CalibParamZDC); + +void o2::zdc::CalibParamZDC::print() +{ + bool printed = false; + if (debug_output >= 0) { + LOG(info) << "CalibParamZDC::print()"; + printed = true; + if (debug_output >= 0) { + printf(" debug_output=%d", debug_output); + } + printf("\n"); + } +} diff --git a/Detectors/ZDC/calib/src/InterCalib.cxx b/Detectors/ZDC/calib/src/InterCalib.cxx index f8eafb0250dc3..c93713f2ab4e3 100644 --- a/Detectors/ZDC/calib/src/InterCalib.cxx +++ b/Detectors/ZDC/calib/src/InterCalib.cxx @@ -18,10 +18,10 @@ #include #include #include "CommonUtils/MemFileHelper.h" +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalib.h" #include "ZDCReconstruction/ZDCEnergyParam.h" #include "ZDCReconstruction/ZDCTowerParam.h" -#include "DataFormatsZDC/InterCalibData.h" #include "Framework/Logger.h" #include "CCDB/CcdbApi.h" diff --git a/DataFormats/Detectors/ZDC/src/InterCalibData.cxx b/Detectors/ZDC/calib/src/InterCalibData.cxx similarity index 97% rename from DataFormats/Detectors/ZDC/src/InterCalibData.cxx rename to Detectors/ZDC/calib/src/InterCalibData.cxx index 9504c64b93239..bf56dcad23bd7 100644 --- a/DataFormats/Detectors/ZDC/src/InterCalibData.cxx +++ b/Detectors/ZDC/calib/src/InterCalibData.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. #include "Framework/Logger.h" -#include "DataFormatsZDC/InterCalibData.h" +#include "ZDCCalib/InterCalibData.h" using namespace o2::zdc; diff --git a/Detectors/ZDC/calib/src/InterCalibEPN.cxx b/Detectors/ZDC/calib/src/InterCalibEPN.cxx index b6436c1bf964f..2e5d3fd39631f 100644 --- a/Detectors/ZDC/calib/src/InterCalibEPN.cxx +++ b/Detectors/ZDC/calib/src/InterCalibEPN.cxx @@ -17,11 +17,11 @@ #include #include #include +#include "ZDCCalib/InterCalibData.h" #include "ZDCCalib/InterCalibEPN.h" #include "ZDCCalib/InterCalib.h" #include "ZDCReconstruction/ZDCEnergyParam.h" #include "ZDCReconstruction/ZDCTowerParam.h" -#include "DataFormatsZDC/InterCalibData.h" #include "Framework/Logger.h" using namespace o2::zdc; diff --git a/Detectors/ZDC/calib/src/InterCalibEPNSpec.cxx b/Detectors/ZDC/calib/src/InterCalibEPNSpec.cxx index 99d305d2c7031..868a8c1dc2063 100644 --- a/Detectors/ZDC/calib/src/InterCalibEPNSpec.cxx +++ b/Detectors/ZDC/calib/src/InterCalibEPNSpec.cxx @@ -59,6 +59,9 @@ InterCalibEPNSpec::InterCalibEPNSpec(const int verbosity) : mVerbosity(verbosity void InterCalibEPNSpec::init(o2::framework::InitContext& ic) { mVerbosity = ic.options().get("verbosity-level"); + mWorker.setVerbosity(mVerbosity); + mTimer.CpuTime(); + mTimer.Start(false); } void InterCalibEPNSpec::updateTimeDependentParams(ProcessingContext& pc) @@ -86,7 +89,7 @@ void InterCalibEPNSpec::run(ProcessingContext& pc) } } - mInterCalibEPN.setInterCalibConfig(interConfig.get()); + mWorker.setInterCalibConfig(interConfig.get()); LOG(info) << loadedConfFiles; mTimer.CpuTime(); @@ -95,7 +98,7 @@ void InterCalibEPNSpec::run(ProcessingContext& pc) const auto ref = pc.inputs().getFirstValid(true); auto creationTime = DataRefUtils::getHeader(ref)->creation; // approximate time in ms - mInterCalibEPN.getData().setCreationTime(creationTime); + mWorker.getData().setCreationTime(creationTime); auto bcrec = pc.inputs().get>("bcrec"); auto energy = pc.inputs().get>("energy"); @@ -103,27 +106,27 @@ void InterCalibEPNSpec::run(ProcessingContext& pc) auto info = pc.inputs().get>("info"); // Process reconstructed data - mInterCalibEPN.process(bcrec, energy, tdc, info); + mWorker.process(bcrec, energy, tdc, info); // Send intermediate calibration data and debug histograms o2::framework::Output output("ZDC", "INTERCALIBDATA", 0, Lifetime::Timeframe); - pc.outputs().snapshot(output, mInterCalibEPN.mData); + pc.outputs().snapshot(output, mWorker.mData); char outputd[o2::header::gSizeDataDescriptionString]; for (int ih = 0; ih < (2 * InterCalibData::NH); ih++) { snprintf(outputd, o2::header::gSizeDataDescriptionString, "INTER_1DH%d", ih); o2::framework::Output output("ZDC", outputd, 0, Lifetime::Timeframe); - pc.outputs().snapshot(output, mInterCalibEPN.mH[ih]->getBase()); + pc.outputs().snapshot(output, mWorker.mH[ih]->getBase()); } for (int ih = 0; ih < InterCalibData::NH; ih++) { snprintf(outputd, o2::header::gSizeDataDescriptionString, "INTER_2DH%d", ih); o2::framework::Output output("ZDC", outputd, 0, Lifetime::Timeframe); - pc.outputs().snapshot(output, mInterCalibEPN.mC[ih]->getBase()); + pc.outputs().snapshot(output, mWorker.mC[ih]->getBase()); } } void InterCalibEPNSpec::endOfStream(EndOfStreamContext& ec) { - mInterCalibEPN.endOfRun(); + mWorker.endOfRun(); mTimer.Stop(); LOGF(info, "ZDC EPN Intercalibration total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } diff --git a/Detectors/ZDC/calib/src/InterCalibSpec.cxx b/Detectors/ZDC/calib/src/InterCalibSpec.cxx index 3e0f02303f70f..ae4fed95383a4 100644 --- a/Detectors/ZDC/calib/src/InterCalibSpec.cxx +++ b/Detectors/ZDC/calib/src/InterCalibSpec.cxx @@ -64,7 +64,7 @@ void InterCalibSpec::init(o2::framework::InitContext& ic) // int slotL = ic.options().get("tf-per-slot"); // int delay = ic.options().get("max-delay"); mVerbosity = ic.options().get("verbosity-level"); - mInterCalib.setVerbosity(mVerbosity); + mWorker.setVerbosity(mVerbosity); mTimer.CpuTime(); mTimer.Start(false); } @@ -114,29 +114,29 @@ void InterCalibSpec::updateTimeDependentParams(ProcessingContext& pc) LOG(info) << loadedConfFiles; - mInterCalib.setEnergyParam(energyParam.get()); - mInterCalib.setTowerParam(towerParam.get()); - mInterCalib.setInterCalibConfig(interConfig.get()); + mWorker.setEnergyParam(energyParam.get()); + mWorker.setTowerParam(towerParam.get()); + mWorker.setInterCalibConfig(interConfig.get()); } void InterCalibSpec::run(ProcessingContext& pc) { updateTimeDependentParams(pc); auto data = pc.inputs().get("intercalibdata"); - mInterCalib.process(data); + mWorker.process(data); for (int ih = 0; ih < (2 * InterCalibData::NH); ih++) { o2::dataformats::FlatHisto1D histoView(pc.inputs().get>(fmt::format("inter_1dh{}", ih).data())); - mInterCalib.add(ih, histoView); + mWorker.add(ih, histoView); } for (int ih = 0; ih < InterCalibData::NH; ih++) { o2::dataformats::FlatHisto2D histoView(pc.inputs().get>(fmt::format("inter_2dh{}", ih).data())); - mInterCalib.add(ih, histoView); + mWorker.add(ih, histoView); } } void InterCalibSpec::endOfStream(EndOfStreamContext& ec) { - mInterCalib.endOfRun(); + mWorker.endOfRun(); mTimer.Stop(); sendOutput(ec.outputs()); LOGF(info, "ZDC Intercalibration total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); @@ -148,18 +148,18 @@ void InterCalibSpec::sendOutput(o2::framework::DataAllocator& output) // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output // TODO in principle, this routine is generic, can be moved to Utils.h using clbUtils = o2::calibration::Utils; - const auto& payload = mInterCalib.getTowerParamUpd(); - auto& info = mInterCalib.getCcdbObjectInfo(); + const auto& payload = mWorker.getTowerParamUpd(); + auto& info = mWorker.getCcdbObjectInfo(); auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); if (mVerbosity > DbgMinimal) { payload.print(); } - LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() - << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "ZDC_Intercalib", 0}, *image.get()); // vector output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "ZDC_Intercalib", 0}, info); // root-serialized // TODO: reset the outputs once they are already sent (is it necessary?) - // mInterCalib.init(); + // mWorker.init(); } framework::DataProcessorSpec getInterCalibSpec() @@ -195,11 +195,7 @@ framework::DataProcessorSpec getInterCalibSpec() inputs, outputs, AlgorithmSpec{adaptFromTask()}, - Options{ - {"tf-per-slot", VariantType::Int, 5, {"number of TFs per calibration time slot"}}, - {"max-delay", VariantType::Int, 3, {"number of slots in past to consider"}}, - {"min-entries", VariantType::Int, 500, {"minimum number of entries to fit single time slot"}}, - {"verbosity-level", o2::framework::VariantType::Int, 1, {"Verbosity level"}}}}; + Options{{"verbosity-level", o2::framework::VariantType::Int, 1, {"Verbosity level"}}}}; } } // namespace zdc diff --git a/Detectors/ZDC/calib/src/WaveformCalib.cxx b/Detectors/ZDC/calib/src/WaveformCalib.cxx new file mode 100644 index 0000000000000..23464aae2ee2c --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalib.cxx @@ -0,0 +1,108 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include +#include +#include "ZDCCalib/CalibParamZDC.h" +#include "ZDCCalib/WaveformCalib.h" +#include "ZDCCalib/WaveformCalibQueue.h" +#include "Framework/Logger.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/CcdbApi.h" + +using namespace o2::zdc; + +int WaveformCalib::init() +{ + if (mConfig == nullptr) { + LOG(fatal) << "o2::zdc::WaveformCalib: missing configuration object"; + return -1; + } + + auto* cfg = mConfig; + if (mVerbosity > DbgZero) { + mConfig->print(); + } + + // Inspect reconstruction parameters + o2::zdc::CalibParamZDC& opt = const_cast(CalibParamZDC::Instance()); + opt.print(); + + if (opt.debug_output > 0) { + setSaveDebugHistos(); + } + + clear(); + mData.setN(mConfig->nbun); + mData.mPeak = WaveformCalibQueue::peak(-(mConfig->ibeg)); + mInitDone = true; + return 0; +} + +//______________________________________________________________________________ +void WaveformCalib::clear() +{ + mData.clear(); +} + +//______________________________________________________________________________ +int WaveformCalib::process(const WaveformCalibData& data) +{ + if (!mInitDone) { + init(); + } + // Add checks before addition + if ((mData.mN != data.mN) || (mData.mPeak != data.mPeak)) { + LOG(fatal) << "WaveformCalib::process adding inconsistent data mN cfg=" << mData.mN << " vs data=" << data.mN << " mPeak cfg=" << mData.mPeak << " vs data=" << data.mPeak; + return -1; + } + mData += data; + return 0; +} + +//______________________________________________________________________________ +// Create calibration object +int WaveformCalib::endOfRun() +{ + if (mVerbosity > DbgZero) { + LOGF(info, "Finalizing WaveformCalibData object"); + } + auto clName = o2::utils::MemFileHelper::getClassName(mData); + mInfo.setObjectType(clName); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + mInfo.setFileName(flName); + mInfo.setPath(CCDBPathWaveformCalib); + std::map md; + md["config"] = mConfig->desc; + mInfo.setMetaData(md); + uint64_t starting = mData.mCTimeBeg; + if (starting >= 10000) { + starting = starting - 10000; // start 10 seconds before + } + uint64_t stopping = mData.mCTimeEnd + 10000; // stop 10 seconds after + mInfo.setStartValidityTimestamp(starting); + mInfo.setEndValidityTimestamp(stopping); + + if (mSaveDebugHistos) { + saveDebugHistos(); + } + return 0; +} + +//______________________________________________________________________________ +int WaveformCalib::saveDebugHistos(const std::string fn) +{ + return mData.saveDebugHistos(fn); +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx new file mode 100644 index 0000000000000..d9e732c9aba2c --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx @@ -0,0 +1,150 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCCalib/WaveformCalibConfig.h" + +using namespace o2::zdc; +WaveformCalibConfig::WaveformCalibConfig() +{ + for (int isig = 0; isig < NChannels; isig++) { + cutLow[isig] = -std::numeric_limits::infinity(); + cutHigh[isig] = std::numeric_limits::infinity(); + } + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + cutTimeLow[itdc] = -2.5; + cutTimeHigh[itdc] = 2.5; + } +} + +void WaveformCalibConfig::restrictRange(int ib, int ie) +{ + ibeg = -NBB; + iend = NBA; + if (ib >= ibeg && ib <= 0) { + ibeg = ib; + } else { + LOG(fatal) << __func__ << " wrong setting for ibeg = " << ib; + } + if (ie <= iend && ie >= 0) { + iend = ie; + } else { + LOG(fatal) << __func__ << " wrong setting for iend = " << ie; + } + nbun = iend - ibeg + 1; +} + +void WaveformCalibConfig::print() const +{ + LOG(info) << "WaveformCalibConfig range [" << ibeg << ":" << iend << "]"; + for (int isig = 0; isig < NChannels; isig++) { + LOG(info) << ChannelNames[isig] << " limits A = (" << cutLow[isig] << " : " << cutHigh[isig] << ") min_entries = " << min_e[isig]; + } + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + LOG(info) << ChannelNames[TDCSignal[itdc]] << " T = (" << cutTimeLow[itdc] << " : " << cutTimeHigh[itdc] << ")"; + } +} + +void WaveformCalibConfig::setMinEntries(double val) +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + min_e[isig] = val; + } +} + +void WaveformCalibConfig::setMinEntries(int isig, double val) +{ + min_e[isig] = val; +} + +void WaveformCalibConfig::resetCuts() +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutLow[isig] = -std::numeric_limits::infinity(); + cutHigh[isig] = std::numeric_limits::infinity(); + } +} + +void WaveformCalibConfig::resetCutLow() +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutLow[isig] = -std::numeric_limits::infinity(); + } +} + +void WaveformCalibConfig::resetCutHigh() +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutHigh[isig] = std::numeric_limits::infinity(); + } +} + +void WaveformCalibConfig::resetCutLow(int isig) +{ + cutLow[isig] = -std::numeric_limits::infinity(); +} + +void WaveformCalibConfig::resetCutHigh(int isig) +{ + cutHigh[isig] = std::numeric_limits::infinity(); +} + +void WaveformCalibConfig::setCutLow(double val) +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutLow[isig] = val; + } +} + +void WaveformCalibConfig::setCutHigh(double val) +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutHigh[isig] = val; + } +} + +void WaveformCalibConfig::setCutLow(int isig, double val) +{ + cutLow[isig] = val; +} + +void WaveformCalibConfig::setCutHigh(int isig, double val) +{ + cutHigh[isig] = val; +} + +void WaveformCalibConfig::setCuts(double low, double high) +{ + for (int32_t isig = 0; isig < NChannels; isig++) { + cutLow[isig] = low; + cutHigh[isig] = high; + } +} + +void WaveformCalibConfig::setCuts(int isig, double low, double high) +{ + cutHigh[isig] = low; + cutLow[isig] = high; +} + +void WaveformCalibConfig::setTimeCuts(double low, double high) +{ + for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) { + cutTimeLow[itdc] = low; + cutTimeHigh[itdc] = high; + } +} + +void WaveformCalibConfig::setTimeCuts(int itdc, double low, double high) +{ + cutTimeHigh[itdc] = low; + cutTimeLow[itdc] = high; +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibData.cxx b/Detectors/ZDC/calib/src/WaveformCalibData.cxx new file mode 100644 index 0000000000000..1b68f075cdeae --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibData.cxx @@ -0,0 +1,202 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include "Framework/Logger.h" +#include "ZDCCalib/WaveformCalibData.h" + +using namespace o2::zdc; + +//______________________________________________________________________________ +void WaveformCalibData::print() const +{ + LOGF(info, "WaveformCalibData mN = %d/%d [%llu : %llu]", mN, NBT, mCTimeBeg, mCTimeEnd); + for (int32_t is = 0; is < NChannels; is++) { + if (getEntries(is) > 0) { + LOGF(info, "WaveformCalibData %2d %s: entries=%d [%d:%d:%d]", is, ChannelNames[is].data(), getEntries(is), getFirstValid(is), mPeak, getLastValid(is)); + } + } +} + +//______________________________________________________________________________ +WaveformCalibData& WaveformCalibData::operator+=(const WaveformCalibData& other) +{ + if (mN != other.mN) { + LOG(fatal) << "Mixing waveform with different configurations mN = " << mN << " != " << other.mN; + return *this; + } + if (mPeak != other.mPeak) { + LOG(fatal) << "Mixing waveform with different configurations mPeak = " << mPeak << " != " << other.mPeak; + return *this; + } + if (mCTimeBeg == 0 || other.mCTimeBeg < mCTimeBeg) { + mCTimeBeg = other.mCTimeBeg; + } + if (other.mCTimeEnd > mCTimeEnd) { + mCTimeEnd = other.mCTimeEnd; + } + for (int32_t is = 0; is < NChannels; is++) { + mWave[is] += other.mWave[is]; + } +#ifdef O2_ZDC_DEBUG + LOG(info) << __func__; + print(); +#endif + return *this; +} + +WaveformCalibChData& WaveformCalibChData::operator+=(const WaveformCalibChData& other) +{ + if (other.mEntries > 0) { + if (other.mFirstValid > mFirstValid) { + mFirstValid = other.mFirstValid; + } + if (other.mLastValid < mLastValid) { + mLastValid = other.mLastValid; + } + mEntries = mEntries + other.mEntries; + for (int32_t i = mFirstValid; i <= mLastValid; i++) { + mData[i] = mData[i] + other.mData[i]; + } + } + return *this; +} + +//______________________________________________________________________________ +void WaveformCalibData::setCreationTime(uint64_t ctime) +{ + mCTimeBeg = ctime; + mCTimeEnd = ctime; +#ifdef O2_ZDC_DEBUG + LOGF(info, "WaveformCalibData::setCreationTime %llu", ctime); +#endif +} + +//______________________________________________________________________________ +int WaveformCalibData::getEntries(int is) const +{ + if (is < 0 || is >= NChannels) { + LOGF(error, "WaveformCalibData::getEntries channel index %d is out of range", is); + return 0; + } + return mWave[is].getEntries(); +} + +int WaveformCalibChData::getEntries() const +{ + return mEntries; +} + +//______________________________________________________________________________ +int WaveformCalibData::getFirstValid(int is) const +{ + if (is < 0 || is >= NChannels) { + LOGF(error, "WaveformCalibData::getFirstValid channel index %d is out of range", is); + return 0; + } + return mWave[is].getFirstValid(); +} + +int WaveformCalibChData::getFirstValid() const +{ + return mFirstValid; +} + +//______________________________________________________________________________ +int WaveformCalibData::getLastValid(int is) const +{ + if (is < 0 || is >= NChannels) { + LOGF(error, "WaveformCalibData::getLastValid channel index %d is out of range", is); + return 0; + } + return mWave[is].getLastValid(); +} + +int WaveformCalibChData::getLastValid() const +{ + return mLastValid; +} + +//______________________________________________________________________________ +void WaveformCalibData::setN(int n) +{ + if (n >= 0 && n < NBT) { + mN = n; + for (int is = 0; is < NChannels; is++) { + mWave[is].setN(n); + } + } else { + LOG(fatal) << "WaveformCalibData " << __func__ << " wrong stored b.c. setting " << n << " not in range [0:" << NBT << "]"; + } +} + +void WaveformCalibChData::setN(int n) +{ + if (n >= 0 && n < NBT) { + mFirstValid = 0; + mLastValid = n * NTimeBinsPerBC * TSN - 1; + } else { + LOG(fatal) << "WaveformCalibChData " << __func__ << " wrong stored b.c. setting " << n << " not in range [0:" << NBT << "]"; + } +} + +//______________________________________________________________________________ +int WaveformCalibData::saveDebugHistos(const std::string fn) +{ + TDirectory* cwd = gDirectory; + TFile* f = new TFile(fn.data(), "recreate"); + if (f->IsZombie()) { + LOG(error) << "Cannot create file: " << fn; + return 1; + } + for (int32_t is = 0; is < NChannels; is++) { + if (mWave[is].mEntries > 0) { + TString n = TString::Format("h%d", is); + TString t = TString::Format("Waveform %d %s", is, ChannelNames[is].data()); + int nbx = mWave[is].mLastValid - mWave[is].mFirstValid + 1; + int min = mWave[is].mFirstValid - mPeak - 0.5; + int max = mWave[is].mLastValid - mPeak + 0.5; + TH1F h(n, t, nbx, min, max); + for (int ibx = 0; ibx < nbx; ibx++) { + h.SetBinContent(ibx + 1, mWave[is].mData[mWave[is].mFirstValid + ibx]); + } + h.SetEntries(mWave[is].mEntries); + h.Write("", TObject::kOverwrite); + } + } + f->Close(); + cwd->cd(); + return 0; +} + +//______________________________________________________________________________ +void WaveformCalibData::clear() +{ + mCTimeBeg = 0; + mCTimeEnd = 0; + mN = 0; + mPeak = 0; + for (int32_t is = 0; is < NChannels; is++) { + mWave[is].clear(); + } +} + +void WaveformCalibChData::clear() +{ + mEntries = 0; + mFirstValid = -1; + mLastValid = -1; + for (int iw = 0; iw < NW; iw++) { + mData[iw] = 0; + } +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx new file mode 100644 index 0000000000000..3179670579bfb --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx @@ -0,0 +1,131 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include +#include +#include +#include "ZDCCalib/CalibParamZDC.h" +#include "ZDCCalib/WaveformCalibEPN.h" +#include "Framework/Logger.h" + +using namespace o2::zdc; + +int WaveformCalibEPN::init() +{ + if (mConfig == nullptr) { + LOG(fatal) << "o2::zdc::WaveformCalibEPN: missing configuration object"; + return -1; + } + + auto* cfg = mConfig; + if (mVerbosity > DbgZero) { + mConfig->print(); + } + + // Inspect reconstruction parameters + o2::zdc::CalibParamZDC& opt = const_cast(CalibParamZDC::Instance()); + opt.print(); + + if (opt.debug_output > 0) { + setSaveDebugHistos(); + } + + mQueue.configure(cfg); + if (mVerbosity > DbgZero) { + mQueue.printConf(); + } + + // number of bins + mNBin = cfg->nbun * TSN; + mFirst = cfg->ibeg; + mLast = cfg->iend; + mData.setN(cfg->nbun); + mData.mPeak = mQueue.mPeak; + mInitDone = true; + return 0; +} + +//______________________________________________________________________________ +int WaveformCalibEPN::process(const gsl::span& RecBC, + const gsl::span& Energy, + const gsl::span& TDCData, + const gsl::span& Info, + const gsl::span& wave) +{ + if (!mInitDone) { + init(); + } + o2::zdc::RecEventFlat ev; + ev.init(RecBC, Energy, TDCData, Info); + auto nen = ev.getEntries(); + std::vector ir; + while (int ientry = ev.next()) { + uint32_t mask = mQueue.append(ev); +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOGF(info, "WaveformCalibEPN::%s mask=0x%04x %s %s %s %s %s %s %s %s %s %s", __func__, mask, + (mask & 0x001) ? ChannelNames[TDCSignal[0]] : " ", + (mask & 0x002) ? ChannelNames[TDCSignal[1]] : " ", + (mask & 0x004) ? ChannelNames[TDCSignal[2]] : " ", + (mask & 0x008) ? ChannelNames[TDCSignal[3]] : " ", + (mask & 0x010) ? ChannelNames[TDCSignal[4]] : " ", + (mask & 0x020) ? ChannelNames[TDCSignal[5]] : " ", + (mask & 0x040) ? ChannelNames[TDCSignal[6]] : " ", + (mask & 0x080) ? ChannelNames[TDCSignal[7]] : " ", + (mask & 0x100) ? ChannelNames[TDCSignal[8]] : " ", + (mask & 0x200) ? ChannelNames[TDCSignal[9]] : " "); +#endif + if (mask != 0) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + ev.print(); + ev.printDecodedMessages(); + mQueue.print(); +#endif + // Analyze signals that refer to the TDC channels that satisfy condition + for (int isig = 0; isig < NChannels; isig++) { + int itdc = SignalTDC[isig]; + if ((mask & (0x1 << itdc)) != 0) { + // Check which channels have consecutive data + mQueue.addData(isig, wave, mData); + } + } + } + } + return 0; +} + +//______________________________________________________________________________ +int WaveformCalibEPN::endOfRun() +{ + if (mVerbosity > DbgZero) { + LOGF(info, "WaveformCalibEPN::endOfRun ts (%llu:%llu)", mData.mCTimeBeg, mData.mCTimeEnd); + for (int is = 0; is < NChannels; is++) { + if (mData.getEntries(is) > 0) { + LOGF(info, "Waveform %2d %s with %10d events and cuts AMP:(%g:%g) TDC:(%g:%g) Valid:[%d:%d:%d]", is, ChannelNames[is].data(), + mData.getEntries(is), mConfig->cutLow[is], mConfig->cutHigh[is], + mConfig->cutTimeLow[is], mConfig->cutTimeHigh[is], + mData.getFirstValid(is), mData.mPeak, mData.getLastValid(is)); + } + } + } + if (mSaveDebugHistos) { + saveDebugHistos(); + } + return 0; +} + +//______________________________________________________________________________ +int WaveformCalibEPN::saveDebugHistos(const std::string fn) +{ + return mData.saveDebugHistos(fn); +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx b/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx new file mode 100644 index 0000000000000..38a931e36bcc3 --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibEPNSpec.cxx @@ -0,0 +1,144 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file WaveformCalibEPNSpec.cxx +/// @brief ZDC reconstruction +/// @author pietro.cortese@cern.ch + +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "Framework/Logger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/DataRefUtils.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "ZDCBase/ModuleConfig.h" +#include "CommonUtils/NameConf.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibEPNSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +WaveformCalibEPNSpec::WaveformCalibEPNSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +WaveformCalibEPNSpec::WaveformCalibEPNSpec(const int verbosity) : mVerbosity(verbosity) +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void WaveformCalibEPNSpec::init(o2::framework::InitContext& ic) +{ + mVerbosity = ic.options().get("verbosity-level"); + mWorker.setVerbosity(mVerbosity); + mTimer.CpuTime(); + mTimer.Start(false); +} + +void WaveformCalibEPNSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + // we call these methods just to trigger finaliseCCDB callback + pc.inputs().get("wavecalibconfig"); +} + +void WaveformCalibEPNSpec::run(ProcessingContext& pc) +{ + updateTimeDependentParams(pc); + if (!mInitialized) { + mInitialized = true; + std::string loadedConfFiles = "Loaded ZDC configuration files:"; + std::string ct = "WaveformCalibConfig"; + std::string cn = "wavecalibconfig"; + // WaveformCalib configuration + auto config = pc.inputs().get(cn); + if (!config) { + LOG(fatal) << "Missing calibration object: " << ct; + return; + } else { + loadedConfFiles += " "; + loadedConfFiles += ct; + mWorker.setConfig(config.get()); + } + LOG(info) << loadedConfFiles; + mTimer.CpuTime(); + mTimer.Start(false); + } + + const auto ref = pc.inputs().getFirstValid(true); + auto creationTime = DataRefUtils::getHeader(ref)->creation; // approximate time in ms + WaveformCalibData& data = mWorker.getData(); + data.setCreationTime(creationTime); + + auto bcrec = pc.inputs().get>("bcrec"); + auto energy = pc.inputs().get>("energy"); + auto tdc = pc.inputs().get>("tdc"); + auto info = pc.inputs().get>("info"); + auto wave = pc.inputs().get>("wave"); + + // Process reconstructed data + mWorker.process(bcrec, energy, tdc, info, wave); + + // Send intermediate calibration data + o2::framework::Output output("ZDC", "WAVECALIBDATA", 0, Lifetime::Timeframe); + pc.outputs().snapshot(output, mWorker.mData); +} + +void WaveformCalibEPNSpec::endOfStream(EndOfStreamContext& ec) +{ + mWorker.endOfRun(); + mTimer.Stop(); + LOGF(info, "ZDC EPN Waveform calibration total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +framework::DataProcessorSpec getWaveformCalibEPNSpec() +{ + using device = o2::zdc::WaveformCalibEPNSpec; + std::vector inputs; + inputs.emplace_back("bcrec", "ZDC", "BCREC", 0, Lifetime::Timeframe); + inputs.emplace_back("energy", "ZDC", "ENERGY", 0, Lifetime::Timeframe); + inputs.emplace_back("tdc", "ZDC", "TDCDATA", 0, Lifetime::Timeframe); + inputs.emplace_back("info", "ZDC", "INFO", 0, Lifetime::Timeframe); + inputs.emplace_back("wave", "ZDC", "WAVE", 0, Lifetime::Timeframe); + inputs.emplace_back("wavecalibconfig", "ZDC", "WAVECALIBCONFIG", 0, Lifetime::Condition, o2::framework::ccdbParamSpec(fmt::format("{}", o2::zdc::CCDBPathWaveformCalibConfig.data()))); + + std::vector outputs; + outputs.emplace_back("ZDC", "WAVECALIBDATA", 0, Lifetime::Timeframe); + return DataProcessorSpec{ + "zdc-waveformcalib-epn", + inputs, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{{"verbosity-level", o2::framework::VariantType::Int, 0, {"Verbosity level"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/calib/src/WaveformCalibParam.cxx b/Detectors/ZDC/calib/src/WaveformCalibParam.cxx new file mode 100644 index 0000000000000..78af3372d6d20 --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibParam.cxx @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include +#include "Framework/Logger.h" +#include "ZDCCalib/WaveformCalibParam.h" + +using namespace o2::zdc; + +void WaveformCalibChParam::print() const +{ + if (shape.size() > 0) { + printf("Shape min at bin %d/%lu\n", ampMinID, shape.size()); + } else { + printf("No data\n"); + } +} + +void WaveformCalibParam::print() const +{ + for (int i = 0; i < NChannels; i++) { + printf("%s ", channelName(i)); + channels[i].print(); + } +} + +void WaveformCalibParam::assign(const WaveformCalibData& data) +{ + for (int isig = 0; isig < NChannels; isig++) { + float entries = data.getEntries(isig); + int peak = data.mPeak; + if (entries > 0) { + int ifirst = data.getFirstValid(isig); + int ilast = data.getLastValid(isig); + channels[isig].ampMinID = peak - ifirst; + for (int ip = ifirst; ip <= ilast; ip++) { + channels[isig].shape.push_back(data.mWave[isig].mData[ip] / entries); + } + } + } +} + +//______________________________________________________________________________ +int WaveformCalibParam::saveDebugHistos(const std::string fn) const +{ + TDirectory* cwd = gDirectory; + TFile* f = new TFile(fn.data(), "recreate"); + if (f->IsZombie()) { + LOG(error) << "Cannot create file: " << fn; + return 1; + } + for (int32_t is = 0; is < NChannels; is++) { + auto& channel = channels[is]; + auto& shape = channel.shape; + int nbx = shape.size(); + int iamin = channel.ampMinID; + if (nbx > 0) { + TString n = TString::Format("h%d", is); + TString t = TString::Format("Waveform %d %s", is, ChannelNames[is].data()); + TH1F h(n, t, nbx, -0.5 - iamin, nbx - iamin - 0.5); + for (int ibx = 0; ibx < nbx; ibx++) { + h.SetBinContent(ibx + 1, shape[ibx]); + } + h.SetEntries(1); + h.Write("", TObject::kOverwrite); + } + } + f->Close(); + cwd->cd(); + return 0; +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx new file mode 100644 index 0000000000000..e019b5f386018 --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx @@ -0,0 +1,330 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "ZDCCalib/WaveformCalibQueue.h" + +namespace o2 +{ +namespace zdc +{ + +void WaveformCalibQueue::configure(const WaveformCalibConfig* cfg) +{ + mCfg = cfg; + int ifirst = mCfg->getFirst(); + int ilast = mCfg->getLast(); + if (ifirst > 0 || ilast < 0 || ilast < ifirst) { + LOGF(fatal, "WaveformCalibQueue configure error with ifirst=%d ilast=%d", ifirst, ilast); + } + mFirst = ifirst; + mLast = ilast; + mN = ilast - ifirst + 1; + mPk = -mFirst; + mPeak = peak(mPk); + mNP = mN * NIS; + for (int32_t isig = 0; isig < NChannels; isig++) { + mTimeLow[isig] = std::nearbyint(cfg->cutTimeLow[SignalTDC[isig]] / FTDCVal); + mTimeHigh[isig] = std::nearbyint(cfg->cutTimeHigh[SignalTDC[isig]] / FTDCVal); + } +} + +// appends an event to the queue with the request that there are at most +// mN consecutive bunches +// The TDC conditions are checked and returned in output +uint32_t WaveformCalibQueue::append(RecEventFlat& ev) +{ + auto& toadd = ev.ir; + // If queue is empty insert event + if (mIR.size() == 0) { + appendEv(ev); + return 0; + } + // Check last element + auto& last = mIR.back(); + // If BC are not consecutive, clear queue + if (toadd.differenceInBC(last) > 1) { + clear(); + } + // If queue is not empty and is too long remove first element + while (mIR.size() >= mN) { + pop(); + } + // If BC are consecutive or cleared queue append element + appendEv(ev); + if (mIR.size() == mN) { + uint32_t mask = 0; + for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) { + // Check which channels satisfy the condition on TDC + bool tdccond = true; + for (int i = 0; i < mN; i++) { + int n = mNTDC[itdc].at(i); + if (i == mPk) { + if (n != 1) { + tdccond = false; + break; + } else { + auto tdca = mTDCA[itdc].at(i); + auto tdcv = mTDCP[itdc].at(i); + if (tdca < mCfg->cutLow[itdc] || tdca > mCfg->cutHigh[itdc] || tdcv < mCfg->cutTimeLow[itdc] || tdcv > mCfg->cutTimeHigh[itdc]) { + tdccond = false; + break; + } + } + } else { + if (n != 0) { + tdccond = false; + break; + } + } + } + if (tdccond) { + mask = mask | (0x1 << itdc); + } + } + return mask; + } else { + return 0; + } +} + +void WaveformCalibQueue::appendEv(RecEventFlat& ev) +{ +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOGF(info, "WaveformCalibQueue::%s %u.%04u", __func__, ev.ir.orbit, ev.ir.bc); +#endif + mIR.push_back(ev.ir); + mEntry.push_back(ev.getNextEntry() - 1); + + auto& curb = ev.getCurB(); + int firstw, nw; + curb.getRefW(firstw, nw); + mFirstW.push_back(firstw); + mNW.push_back(nw); + + // Note: pile-up messages are computed only for the 10 TDCs + for (int isig = 0; isig < NChannels; isig++) { + mHasInfos[isig].push_back(false); + } + if (ev.getNInfo() > 0) { + // Need clean data (no messages) + auto& decodedInfo = ev.getDecodedInfo(); + for (uint16_t info : decodedInfo) { + uint8_t ch = (info >> 10) & 0x1f; + uint16_t code = info & 0x03ff; + auto& last = mHasInfos[ch].back(); + last = true; + } + // if (mVerbosity > DbgMinimal) { + // ev.print(); + // } + } + // TDC channels are used to select reconstructed waveforms + for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) { + int ich = o2::zdc::TDCSignal[itdc]; + int nhit = ev.NtdcV(itdc); + if (ev.NtdcA(itdc) != nhit) { + LOGF(error, "Mismatch in TDC %d data Val=%d Amp=%d\n", itdc, ev.NtdcV(itdc), ev.NtdcA(ich)); + mNTDC[itdc].push_back(0); + mTDCA[itdc].push_back(0); + mTDCP[itdc].push_back(0); + } else if (nhit == 0) { + mNTDC[itdc].push_back(0); + mTDCA[itdc].push_back(0); + mTDCP[itdc].push_back(0); + } else { + // Store single TDC entry + mNTDC[itdc].push_back(nhit); + mTDCA[itdc].push_back(ev.tdcA(itdc, 0)); + mTDCP[itdc].push_back(ev.tdcV(itdc, 0)); + } + } +} + +int WaveformCalibQueue::hasData(int isig, const gsl::span& wave) +{ + int ipk = -1; + int ipkb = -1; + float min = std::numeric_limits::infinity(); + for (int ib = 0; ib < mN; ib++) { + int ifound = false; +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibQueue::" << __func__ << " mNW[" << ib << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib]; +#endif + for (int iw = 0; iw < mNW[ib]; iw++) { + auto& mywave = wave[iw + mFirstW[ib]]; + if (mywave.ch() == isig) { + ifound = true; + for (int ip = 0; ip < NIS; ip++) { + if (mywave.inter[ip] < min) { + ipkb = ib; + ipk = ip; + min = mywave.inter[ip]; + } + } + } + } + // Need to have consecutive data for all bunches + if (!ifound) { + return -1; + } + } + if (ipkb != mPk) { + return -1; + } else { + int ipos = NTimeBinsPerBC * TSN * ipkb + ipk; +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibConfig::" << __func__ << " isig = " << isig << " ipkb " << ipkb << " ipk " << ipk << " min " << min; +#endif + return ipos; + } +} + +// Checks if waveform has available data and adds it to summary data +// a compensation of the time jitter +int WaveformCalibQueue::addData(int isig, const gsl::span& wave, WaveformCalibData& data) +{ + int ipkb = -1; // Bunch where peak is found + int ipk = -1; // peak position within bunch + float min = std::numeric_limits::infinity(); + float max = -std::numeric_limits::infinity(); + bool hasInfos = false; + for (int ib = 0; ib < mN; ib++) { + bool ifound = false; +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "mNW[" << ib << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib]; +#endif + if (mHasInfos[isig][ib] || mHasInfos[TDCSignal[SignalTDC[isig]]][ib]) { + LOG(info) << "isig=" << isig << " ib=" << ib << " tdcid=" << SignalTDC[isig] << " tdc_sig=" << TDCSignal[SignalTDC[isig]] << " " << mHasInfos[isig][ib] << " " << mHasInfos[TDCSignal[SignalTDC[isig]]][ib]; + hasInfos = true; + } + for (int iw = 0; iw < mNW[ib]; iw++) { + // Signal shouldn't have info messages. We check also corresponding TDC signal for pile-up information + // TODO: relax this condition to avoid to check pedestal messages since pedestal is subtracted + // when converting waveform calibration object into SimConfig object + auto& mywave = wave[iw + mFirstW[ib]]; + if (mywave.ch() == isig) { + ifound = true; + for (int ip = 0; ip < NIS; ip++) { + if (mywave.inter[ip] < min) { + ipkb = ib; + ipk = ip; + min = mywave.inter[ip]; + } + if (mywave.inter[ip] > max) { + max = mywave.inter[ip]; + } + } + } + } +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibQueue::" << __func__ << " isig=" << isig << " mNW[" << ib << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib] + << " ifound=" << ifound << " hasInfos=" << hasInfos; +#endif + // Need to have consecutive data for all bunches + if (!ifound || hasInfos) { + return -1; + } + } + if (ipkb != mPk) { + return -1; + } else { + int ppos = NIS * ipkb + ipk; + int itdc = SignalTDC[isig]; + if (isig != TDCSignal[itdc]) { + // Additional checks for towers + float amp = max - min; + if (amp < mCfg->cutLow[isig] || amp > mCfg->cutHigh[isig]) { + // No warning messages for amplitude cuts on towers + return -1; + } + if ((ppos - mPeak) < mTimeLow[itdc] || (ppos - mPeak) > mTimeHigh[itdc]) { + // Put a warning message for a signal out of time + LOGF(warning, "%d.%04d Signal %2d peak position %d-%d=%d is outside allowed range [%d:%d]", mIR[mPk].orbit, mIR[mPk].bc, isig, ppos, mPeak, ppos - mPeak, mTimeLow[isig], mTimeHigh[isig]); + return -1; + } + } + int ipos = mPeak - ppos; + data.addEntry(isig); + // Restrict validity range because of signal jitter + data.setFirstValid(isig, ipos); + // We know that points are consecutive + for (int ib = 0; ib < mN; ib++) { + for (int iw = 0; iw < mNW[ib]; iw++) { + auto& mywave = wave[iw + mFirstW[ib]]; + if (mywave.ch() == isig) { + for (int ip = 0; ip < NIS; ip++) { + if (ipos >= 0 && ipos < mNP) { + // We don't use incapsulation because this section is called too many times + data.mWave[isig].mData[ipos] += mywave.inter[ip]; + } + ipos++; + } + } + } + } + ipos--; + // Restrict validity range because of signal jitter + data.setLastValid(isig, ipos); +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibConfig::" << __func__ << " isig = " << isig << " ipkb " << ipkb << " ipk " << ipk << " min " << min << " range=[" << data.getFirstValid(isig) << ":" << ppos << ":" << data.getLastValid(isig) << "]"; +#endif + return ipos; + } +} + +void WaveformCalibQueue::print() +{ + int n = mIR.size(); + for (int i = 0; i < n; i++) { + printf("%d.%04d mEntry=%d mFirstW=%d mNW=%d\n", mIR[i].orbit, mIR[i].bc, mEntry[i], mFirstW[i], mNW[i]); + printf("mHasInfos:"); + for (int j = 0; j < NChannels; j++) { + if (mHasInfos[j][i] != 0) { + printf(" %2d=%d", j, mHasInfos[j][i] != 0); + } + } + printf("\n"); + printf("mNTDC:"); + for (int j = 0; j < NTDCChannels; j++) { + if (mNTDC[j][i] > 0) { + printf(" %2d=%6u", j, mNTDC[j][i]); + } + } + printf("\n"); + printf("mTDCA:"); + for (int j = 0; j < NTDCChannels; j++) { + if (mNTDC[j][i] > 0) { + printf(" %2d=%6.1f", j, mTDCA[j][i]); + } + } + printf("\n"); + printf("mTDCP:"); + for (int j = 0; j < NTDCChannels; j++) { + if (mNTDC[j][i] > 0) { + printf(" %2d=%6.1f", j, mTDCP[j][i]); + } + } + printf("\n"); + } +} + +void WaveformCalibQueue::printConf() +{ + LOG(info) << "WaveformCalibQueue::" << __func__; + LOGF(info, "mFirst=%d mLast=%d mPk=%d mN=%d mPeak=%d/mNP=%d", mFirst, mLast, mPk, mN, mPeak, mNP); + for (int isig = 0; isig < NChannels; isig++) { + LOGF(info, "ch%02d pos [%d:%d]", isig, mTimeLow[isig], mTimeHigh[isig]); + } +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/calib/src/WaveformCalibSpec.cxx b/Detectors/ZDC/calib/src/WaveformCalibSpec.cxx new file mode 100644 index 0000000000000..92e5e09063092 --- /dev/null +++ b/Detectors/ZDC/calib/src/WaveformCalibSpec.cxx @@ -0,0 +1,156 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file WaveformCalibSpec.cxx +/// @brief ZDC reconstruction +/// @author pietro.cortese@cern.ch + +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "Framework/Logger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/DataRefUtils.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "ZDCBase/ModuleConfig.h" +#include "CommonUtils/NameConf.h" +#include "CommonUtils/MemFileHelper.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "ZDCCalib/WaveformCalibParam.h" +#include "ZDCCalib/WaveformCalibData.h" +#include "ZDCCalib/WaveformCalibSpec.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +WaveformCalibSpec::WaveformCalibSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +WaveformCalibSpec::WaveformCalibSpec(const int verbosity) : mVerbosity(verbosity) +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void WaveformCalibSpec::init(o2::framework::InitContext& ic) +{ + mVerbosity = ic.options().get("verbosity-level"); + mWorker.setVerbosity(mVerbosity); + mTimer.CpuTime(); + mTimer.Start(false); +} + +void WaveformCalibSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + // we call these methods just to trigger finaliseCCDB callback + pc.inputs().get("wavecalibconfig"); +} + +void WaveformCalibSpec::run(ProcessingContext& pc) +{ + updateTimeDependentParams(pc); + if (!mInitialized) { + mInitialized = true; + std::string loadedConfFiles = "Loaded ZDC configuration files:"; + std::string ct = "WaveformCalibConfig"; + std::string cn = "wavecalibconfig"; + // WaveformCalib configuration + auto config = pc.inputs().get(cn); + if (!config) { + LOG(fatal) << "Missing calibration object: " << ct; + return; + } else { + loadedConfFiles += " "; + loadedConfFiles += ct; + mWorker.setConfig(config.get()); + } + LOG(info) << loadedConfFiles; + mTimer.CpuTime(); + mTimer.Start(false); + } + + auto data = pc.inputs().get("waveformcalibdata"); + if (mVerbosity >= DbgFull) { + data.print(); + } + mWorker.process(data); +} + +void WaveformCalibSpec::endOfStream(EndOfStreamContext& ec) +{ + mWorker.endOfRun(); + mTimer.Stop(); + sendOutput(ec.outputs()); + LOGF(info, "ZDC Waveform calibration total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +//________________________________________________________________ +void WaveformCalibSpec::sendOutput(o2::framework::DataAllocator& output) +{ + // extract CCDB infos and calibration objects, convert it to TMemFile and send them to the output + // TODO in principle, this routine is generic, can be moved to Utils.h + using clbUtils = o2::calibration::Utils; + const auto& data = mWorker.getData(); + WaveformCalibParam payload; + payload.assign(data); + auto& info = mWorker.getCcdbObjectInfo(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + if (mVerbosity > DbgZero) { + payload.print(); + } + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "ZDCWaveformCalib", 0}, *image.get()); // vector + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "ZDCWaveformCalib", 0}, info); // root-serialized + // TODO: reset the outputs once they are already sent (is it necessary?) + // mWorker.init(); +} + +framework::DataProcessorSpec getWaveformCalibSpec() +{ + using device = o2::zdc::WaveformCalibSpec; + using clbUtils = o2::calibration::Utils; + + std::vector inputs; + inputs.emplace_back("waveformcalibdata", "ZDC", "WAVECALIBDATA", 0, Lifetime::Timeframe); + inputs.emplace_back("wavecalibconfig", "ZDC", "WAVECALIBCONFIG", 0, Lifetime::Condition, o2::framework::ccdbParamSpec(fmt::format("{}", o2::zdc::CCDBPathWaveformCalibConfig.data()))); + + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "ZDCWaveformCalib"}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "ZDCWaveformCalib"}, Lifetime::Sporadic); + + return DataProcessorSpec{ + "zdc-waveformcalib", + inputs, + outputs, + AlgorithmSpec{adaptFromTask()}, + Options{{"verbosity-level", o2::framework::VariantType::Int, 1, {"Verbosity level"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/calib/src/ZDCCalibLinkDef.h b/Detectors/ZDC/calib/src/ZDCCalibLinkDef.h index 800fef2f11d83..aaa5c0cba21c5 100644 --- a/Detectors/ZDC/calib/src/ZDCCalibLinkDef.h +++ b/Detectors/ZDC/calib/src/ZDCCalibLinkDef.h @@ -15,6 +15,14 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::zdc::CalibParamZDC + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::zdc::CalibParamZDC> + ; +#pragma link C++ class o2::zdc::InterCalibData + ; #pragma link C++ class o2::zdc::InterCalibConfig + ; +#pragma link C++ class o2::zdc::WaveformCalibConfig + ; +#pragma link C++ class o2::zdc::WaveformCalibChData + ; +#pragma link C++ class o2::zdc::WaveformCalibData + ; +#pragma link C++ class o2::zdc::WaveformCalibChParam + ; +#pragma link C++ class o2::zdc::WaveformCalibParam + ; #endif diff --git a/Detectors/ZDC/calib/src/zdc-intercalib-epn-workflow.cxx b/Detectors/ZDC/calib/src/zdc-intercalib-epn-workflow.cxx index 059d50f345a27..9fab9a7b0ca18 100644 --- a/Detectors/ZDC/calib/src/zdc-intercalib-epn-workflow.cxx +++ b/Detectors/ZDC/calib/src/zdc-intercalib-epn-workflow.cxx @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. #include "Framework/DataProcessorSpec.h" +#include "CommonUtils/ConfigurableParam.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "ZDCCalib/InterCalibEPNSpec.h" @@ -25,6 +26,8 @@ void customize(std::vector& policies) void customize(std::vector& workflowOptions) { // option allowing to set parameters + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); } @@ -34,6 +37,8 @@ void customize(std::vector& workflowOptions) WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); WorkflowSpec specs; specs.emplace_back(o2::zdc::getInterCalibEPNSpec()); // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit diff --git a/Detectors/ZDC/calib/src/zdc-waveformcalib-epn-workflow.cxx b/Detectors/ZDC/calib/src/zdc-waveformcalib-epn-workflow.cxx new file mode 100644 index 0000000000000..bb3e66f6991e1 --- /dev/null +++ b/Detectors/ZDC/calib/src/zdc-waveformcalib-epn-workflow.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "ZDCCalib/WaveformCalibEPNSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + WorkflowSpec specs; + specs.emplace_back(o2::zdc::getWaveformCalibEPNSpec()); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return specs; +} diff --git a/Detectors/ZDC/calib/src/zdc-waveformcalib-workflow.cxx b/Detectors/ZDC/calib/src/zdc-waveformcalib-workflow.cxx new file mode 100644 index 0000000000000..ea7876023c62d --- /dev/null +++ b/Detectors/ZDC/calib/src/zdc-waveformcalib-workflow.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/DataProcessorSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "ZDCCalib/WaveformCalibSpec.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::string keyvaluehelp("Semicolon separated key=value strings ..."); + workflowOptions.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {keyvaluehelp}}); + o2::raw::HBFUtilsInitializer::addConfigOption(workflowOptions); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + WorkflowSpec specs; + specs.emplace_back(o2::zdc::getWaveformCalibSpec()); + // configure dpl timer to inject correct firstTFOrbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return specs; +} diff --git a/Detectors/ZDC/macro/CMakeLists.txt b/Detectors/ZDC/macro/CMakeLists.txt index 4793e8eb3cff0..928d115b233fd 100644 --- a/Detectors/ZDC/macro/CMakeLists.txt +++ b/Detectors/ZDC/macro/CMakeLists.txt @@ -58,3 +58,21 @@ o2_add_test_root_macro(CreateInterCalibConfig.C O2::SimulationDataFormat O2::CCDB O2::ZDCCalib LABELS zdc) + +o2_add_test_root_macro(CreateWaveformCalibConfig.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + O2::ZDCCalib + LABELS zdc) + +o2_add_test_root_macro(CreateWaveformCalibParam.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + O2::ZDCCalib + LABELS zdc) + +o2_add_test_root_macro(InspectCCDBFile.C + PUBLIC_LINK_LIBRARIES O2::ZDCBase O2::ZDCReconstruction + O2::SimulationDataFormat O2::CCDB + O2::ZDCCalib + LABELS zdc) diff --git a/Detectors/ZDC/macro/CreateWaveformCalibConfig.C b/Detectors/ZDC/macro/CreateWaveformCalibConfig.C new file mode 100644 index 0000000000000..82905ace393e2 --- /dev/null +++ b/Detectors/ZDC/macro/CreateWaveformCalibConfig.C @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include +#include +#include "Framework/Logger.h" +#include "CCDB/CcdbApi.h" +#include "ZDCBase/Constants.h" +#include "ZDCCalib/WaveformCalibConfig.h" + +#endif + +using namespace o2::zdc; +using namespace std; + +void CreateWaveformCalibConfig(long tmin = 0, long tmax = -1, std::string ccdbHost = "") +{ + + // This object configures the measurement of the average waveforms for the ZDC channels + WaveformCalibConfig conf; + + // Threshold to include the interpolated waveform into the average + // One should avoid to sum signals that are too small and have + // low signal/background + // By taking into account the baseline (~1800) and the waveform + // range -2048 : 2047 one should not use signals too close to + // maximum allowed amplitude (1800+2048) + conf.setCuts(100, 3000); + + conf.setDescription("Simulated data"); + conf.setMinEntries(200); + + // Restrict waveform range (default is -3, 6 as defined in WaveformCalib_NBB + // WaveformCalib_NBA in file Detectors/ZDC/base/include/ZDCBase/Constants.h) + conf.restrictRange(-1, 0); + + conf.print(); + + o2::ccdb::CcdbApi api; + map metadata; // can be empty + if (ccdbHost.size() == 0 || ccdbHost == "external") { + ccdbHost = "http://alice-ccdb.cern.ch:8080"; + } else if (ccdbHost == "internal") { + ccdbHost = "http://o2-ccdb.internal/"; + } else if (ccdbHost == "test") { + ccdbHost = "http://ccdb-test.cern.ch:8080"; + } else if (ccdbHost == "local") { + ccdbHost = "http://localhost:8080"; + } + api.init(ccdbHost.c_str()); + LOG(info) << "CCDB server: " << api.getURL(); + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, CCDBPathWaveformCalibConfig, metadata, tmin, tmax); +} diff --git a/Detectors/ZDC/macro/CreateWaveformCalibParam.C b/Detectors/ZDC/macro/CreateWaveformCalibParam.C new file mode 100644 index 0000000000000..35670e198c043 --- /dev/null +++ b/Detectors/ZDC/macro/CreateWaveformCalibParam.C @@ -0,0 +1,92 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) + +#include +#include +#include +#include +#include "CCDB/CcdbApi.h" + +#endif + +#include "Framework/Logger.h" +#include "ZDCBase/Constants.h" +#include "ZDCCalib/WaveformCalibParam.h" + +using namespace o2::zdc; +using namespace std; + +void CreateWaveformCalibParam(long tmin = 0, long tmax = -1, std::string ccdbHost = "", std::string sourceDataPath = "signal_shapes.root") +{ + + TFile sourceData(sourceDataPath.c_str()); + if (!sourceData.IsOpen() || sourceData.IsZombie()) { + LOG(fatal) << "Failed to open input file " << sourceDataPath; + } + + // Source of line shapes, pedestal and noise for each channel + // Missing histos for: towers 1-4 of all calorimeters, zem1, all towers of zpc + std::string ShapeName[o2::zdc::NChannels] = { + "znatc", "znatc", "znatc", "znatc", "znatc", "znatc", // ZNAC, ZNA1, ZNA2, ZNA3, ZNA4, ZNAS (shape not used) + "zpatc", "zpatc", "zpatc", "zpatc", "zpatc", "zpatc", // ZPAC, ZPA1, ZPA2, ZPA3, ZPA4, ZPAS (shape not used) + "zem2", "zem2", // ZEM1, ZEM2 + "znctc", "znctc", "znctc", "znctc", "znctc", "znctc", // ZNCC, ZNC1, ZNC2, ZNC3, ZNC4, ZNCS (shape not used) + "zpatc", "zpatc", "zpatc", "zpatc", "zpatc", "zpatc" // ZPCC, ZPC1, ZPC2, ZPC3, ZPC4, ZPCS (shape not used) + }; + + o2::zdc::WaveformCalibParam conf; + + for (int ic = 0; ic < o2::zdc::NChannels; ic++) { + auto& channel = conf.channels[ic]; + std::string histoShapeName = "hw_" + ShapeName[ic]; + TH1* histoShape = (TH1*)sourceData.GetObjectUnchecked(histoShapeName.c_str()); + if (!histoShape) { + LOG(fatal) << "Failed to extract the shape histogram " << histoShapeName; + } + int nb = histoShape->GetNbinsX(); + channel.shape.resize(nb); + // we need min amplitude and its bin + double ampMin = histoShape->GetBinContent(1); + channel.ampMinID = 0; + for (int i = 0; i < nb; i++) { + channel.shape[i] = histoShape->GetBinContent(i + 1); + if (channel.shape[i] < ampMin) { + ampMin = channel.shape[i]; + channel.ampMinID = i; + } + } + if (ampMin == 0.) { + LOG(fatal) << "Amplitude minimum =0 for histo " << histoShapeName; + } + } + + conf.print(); + + o2::ccdb::CcdbApi api; + map metadata; // can be empty + if (ccdbHost.size() == 0 || ccdbHost == "external") { + ccdbHost = "http://alice-ccdb.cern.ch:8080"; + } else if (ccdbHost == "internal") { + ccdbHost = "http://o2-ccdb.internal/"; + } else if (ccdbHost == "test") { + ccdbHost = "http://ccdb-test.cern.ch:8080"; + } else if (ccdbHost == "local") { + ccdbHost = "http://localhost:8080"; + } + api.init(ccdbHost.c_str()); + LOG(info) << "CCDB server: " << api.getURL(); + // store abitrary user object in strongly typed manner + api.storeAsTFileAny(&conf, CCDBPathWaveformCalib, metadata, tmin, tmax); + + // return conf; +} diff --git a/Detectors/ZDC/macro/InspectCCDBFile.C b/Detectors/ZDC/macro/InspectCCDBFile.C new file mode 100644 index 0000000000000..d8abd88bb7362 --- /dev/null +++ b/Detectors/ZDC/macro/InspectCCDBFile.C @@ -0,0 +1,91 @@ +#include "TObject.h" +#include "TString.h" +#include "TSystem.h" +#include "TKey.h" +#include "TFile.h" +#include "TDirectory.h" +#include "ZDCBase/ModuleConfig.h" +#include "ZDCBase/Constants.h" +#include "ZDCSimulation/SimCondition.h" +#include "ZDCReconstruction/RecoConfigZDC.h" +#include "ZDCReconstruction/ZDCTDCCorr.h" +#include "ZDCReconstruction/ZDCTDCParam.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" +#include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCCalib/InterCalibConfig.h" +#include "ZDCCalib/WaveformCalibConfig.h" +#include "ZDCCalib/WaveformCalibParam.h" + +void InspectCCDBFile() +{ + TString dn = gDirectory->GetName(); + auto p_und = dn.First('_'); + auto p_dot = dn.Last('.'); + if (p_und >= 0 && p_dot > 0 && p_dot > p_und) { + TSubString dat = dn(p_und + 1, p_dot - p_und - 1); + TString data = dat; + if (data.IsDec()) { + auto val = data.Atoll(); + val = val / 1000; + gSystem->Exec(TString::Format("date -d \"@%lld\"", val)); + } + } + TIter nextkey(gDirectory->GetListOfKeys()); + TKey* key; + while ((key = (TKey*)nextkey())) { + TString cn = key->GetClassName(); + if (cn.EqualTo("o2::zdc::ModuleConfig")) { + o2::zdc::ModuleConfig* ob = (o2::zdc::ModuleConfig*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathConfigModule.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::SimCondition")) { + // o2::zdc::SimCondition *ob=(o2::zdc::SimCondition *)key->ReadObj(); + o2::zdc::SimCondition* ob = (o2::zdc::SimCondition*)gFile->GetObjectUnchecked("ccdb_object"); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathConfigSim.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::RecoConfigZDC")) { + o2::zdc::RecoConfigZDC* ob = (o2::zdc::RecoConfigZDC*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathRecoConfigZDC.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::ZDCTDCCorr")) { + o2::zdc::ZDCTDCCorr* ob = (o2::zdc::ZDCTDCCorr*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathTDCCorr.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::ZDCTDCParam")) { + o2::zdc::ZDCTDCParam* ob = (o2::zdc::ZDCTDCParam*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathTDCCalib.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::ZDCEnergyParam")) { + o2::zdc::ZDCEnergyParam* ob = (o2::zdc::ZDCEnergyParam*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathEnergyCalib.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::ZDCTowerParam")) { + o2::zdc::ZDCTowerParam* ob = (o2::zdc::ZDCTowerParam*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathTowerCalib.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::InterCalibConfig")) { + o2::zdc::InterCalibConfig* ob = (o2::zdc::InterCalibConfig*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathInterCalibConfig.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::WaveformCalibConfig")) { + o2::zdc::WaveformCalibConfig* ob = (o2::zdc::WaveformCalibConfig*)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathWaveformCalibConfig.data()); + ob->print(); + } else if (cn.EqualTo("o2::zdc::WaveformCalibParam")) { + o2::zdc::WaveformCalibParam* ob = (o2::zdc::WaveformCalibParam*)gFile->GetObjectUnchecked("ccdb_object"); + // o2::zdc::WaveformCalibParam *ob=(o2::zdc::WaveformCalibParam *)key->ReadObj(); + printf("%s %s %d %s @ %s\n", "OBJ", key->GetName(), key->GetCycle(), key->GetTitle(), o2::zdc::CCDBPathWaveformCalib.data()); + ob->print(); + ob->saveDebugHistos("InspectCCDBFile_WaveformCalibParam.root"); + } else { + printf("%s %s %d %s\n", key->GetClassName(), key->GetName(), key->GetCycle(), key->GetTitle()); + } + } + + // TObject *ob = (TObject*)gDirectory->Get("ccdb_object"); + // if(ob == nullptr){ + // printf("Object not found\n"); + // return; + // } + // printf("%s %d\n", ob->Class_Name(), ob->Class_Version()); +} diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h index 447cf8ca76740..2a23965789b55 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiReco.h @@ -33,6 +33,14 @@ #ifndef ALICEO2_ZDC_DIGI_RECO_H #define ALICEO2_ZDC_DIGI_RECO_H + +//#define ALICEO2_ZDC_DIGI_RECO_DEBUG +#ifdef O2_ZDC_DEBUG +#ifndef ALICEO2_ZDC_DIGI_RECO_DEBUG +#define ALICEO2_ZDC_DIGI_RECO_DEBUG +#endif +#endif + namespace o2 { namespace zdc @@ -111,6 +119,13 @@ class DigiReco LOG(warn) << __func__ << " Configuration of low pass filtering: " << (mLowPassFilter ? "enabled" : "disabled"); }; bool getLowPassFilter() { return mLowPassFilter; }; + void setFullInterpolation(bool val = true) + { + mFullInterpolation = val; + mFullInterpolationSet = true; + LOG(warn) << __func__ << " Full waveform interpolation: " << (mFullInterpolation ? "enabled" : "disabled"); + }; + bool getFullInterpolation() { return mFullInterpolation; }; // Enable or disable TDC corrections void setCorrSignal(bool val = true) { @@ -140,9 +155,12 @@ class DigiReco void processTrigger(int itdc, int ibeg, int iend); /// Replay of trigger algorithm on acquired data void processTriggerExtended(int itdc, int ibeg, int iend); /// Replay of trigger algorithm on acquired data void interpolate(int itdc, int ibeg, int iend); /// Interpolation of samples to evaluate signal amplitude and arrival time + void fullInterpolation(int itdc, int ibeg, int iend); /// Interpolation of samples void correctTDCPile(); /// Correction of pile-up in TDC bool mLowPassFilter = true; /// Enable low pass filtering bool mLowPassFilterSet = false; /// Low pass filtering set via function call + bool mFullInterpolation = false; /// Full waveform interpolation + bool mFullInterpolationSet = false; /// Full waveform interpolation set via function call bool mCorrSignal = true; /// Enable TDC signal correction bool mCorrSignalSet = false; /// TDC signal correction set via function call bool mCorrBackground = true; /// Enable TDC pile-up correction @@ -152,9 +170,7 @@ class DigiReco int correctTDCBackground(int ibc, int itdc, std::deque& tdc); /// TDC amplitude and time corrections due to pile-up from previous bunches O2_ZDC_DIGIRECO_FLT getPoint(int itdc, int ibeg, int iend, int i); /// Interpolation for current TDC -#ifdef O2_ZDC_INTERP_DEBUG - void setPoint(int itdc, int ibeg, int iend, int i); /// Interpolation for current TDC -#endif + void setPoint(int itdc, int ibeg, int iend, int i); /// Interpolation for current TDC void assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float amp); /// Set reconstructed TDC values void findSignals(int ibeg, int iend); /// Find signals around main-main that satisfy condition on TDC @@ -166,8 +182,9 @@ class DigiReco const ZDCTDCCorr* mTDCCorr = nullptr; /// TDC correction coefficients const ZDCEnergyParam* mEnergyParam = nullptr; /// Energy calibration object const ZDCTowerParam* mTowerParam = nullptr; /// Tower calibration object - uint32_t mTDCMask[NTDCChannels] = {0}; /// Identify TDC channels in trigger mask - uint32_t mChMask[NChannels] = {0}; /// Identify channels + uint32_t mTriggerMask = 0; /// Mask of triggering channels + uint32_t mTDCMask[NTDCChannels] = {0}; /// Identify TDC channels in trigger pattern + uint32_t mChMask[NChannels] = {0}; /// Identify all channels in readout pattern const RecoConfigZDC* mRecoConfigZDC = nullptr; /// CCDB configuration parameters int32_t mVerbosity = DbgMinimal; O2_ZDC_DIGIRECO_FLT mTS[NTS]; /// Tapered sinc function diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h index 8e485161ad784..0c95e1f1550c1 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoConfigZDC.h @@ -32,9 +32,10 @@ struct RecoConfigZDC { void setBit(uint32_t ibit, bool val = true); // Signal processing - bool low_pass_filter = true; // Low pass filtering - bool corr_signal = true; // TDC signal correction - bool corr_background = true; // TDC pile-up correction + bool low_pass_filter = true; // Low pass filtering + bool full_interpolation = false; // Full interpolation of waveform + bool corr_signal = true; // TDC signal correction + bool corr_background = true; // TDC pile-up correction // TDC int tdc_search[NTDCChannels] = {250, 250, 250, 250, 250, 250, 250, 250, 250, 250}; // Search zone for a TDC signal ideally 2.5 ns (units of ~10 ps) @@ -59,7 +60,7 @@ struct RecoConfigZDC { void print(); - ClassDefNV(RecoConfigZDC, 1); + ClassDefNV(RecoConfigZDC, 2); }; } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h index 01752a9ac8ea9..ef4369147818e 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/RecoParamZDC.h @@ -32,9 +32,12 @@ struct RecoParamZDC : public o2::conf::ConfigurableParamHelper { void setBit(uint32_t ibit, bool val = true); // Signal processing - int low_pass_filter = -1; // Low pass filtering - int corr_signal = -1; // TDC signal correction - int corr_background = -1; // TDC pile-up correction + int low_pass_filter = -1; // Low pass filtering + int full_interpolation = -1; // Full interpolation of waveform + int corr_signal = -1; // TDC signal correction + int corr_background = -1; // TDC pile-up correction + + int debug_output = -1; // Debug output // TDC Int_t tmod[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of TDC channel in raw data @@ -59,6 +62,9 @@ struct RecoParamZDC : public o2::conf::ConfigurableParamHelper { // Energy calibration float energy_calib[NChannels] = {0}; // Energy calibration coefficients float tower_calib[NChannels] = {0}; // Tower calibration coefficients + + void print(); + O2ParamDef(RecoParamZDC, "RecoParamZDC"); }; } // namespace zdc diff --git a/Detectors/ZDC/reconstruction/src/DigiReco.cxx b/Detectors/ZDC/reconstruction/src/DigiReco.cxx index b98b18e508e89..c09c29b9489f4 100644 --- a/Detectors/ZDC/reconstruction/src/DigiReco.cxx +++ b/Detectors/ZDC/reconstruction/src/DigiReco.cxx @@ -32,6 +32,8 @@ void DigiReco::init() return; } + mTriggerMask = mModuleConfig->getTriggerMask(); + prepareInterpolation(); if (mTreeDbg) { @@ -45,6 +47,7 @@ void DigiReco::init() // Update reconstruction parameters // auto& ropt=RecoParamZDC::Instance(); o2::zdc::RecoParamZDC& ropt = const_cast(RecoParamZDC::Instance()); + ropt.print(); mRopt = (o2::zdc::RecoParamZDC*)&ropt; // Fill maps to decode the pattern of channels with hit @@ -89,6 +92,21 @@ void DigiReco::init() LOG(info) << "Low pass filtering is " << (mLowPassFilter ? "enabled" : "disabled"); } + // Full interpolation of waveform (N.B. function call overrides other settings) + if (mFullInterpolationSet == false) { + if (ropt.full_interpolation < 0) { + if (!mRecoConfigZDC) { + LOG(fatal) << "Configuration of interpolation: missing configuration object and no manual override"; + } else { + ropt.full_interpolation = mRecoConfigZDC->full_interpolation; + } + } + mFullInterpolation = ropt.full_interpolation > 0 ? true : false; + } + if (mVerbosity > DbgZero) { + LOG(info) << "Full waveform interpolation is " << (mFullInterpolation ? "enabled" : "disabled"); + } + if (mCorrSignalSet == false) { if (ropt.corr_signal < 0) { if (!mRecoConfigZDC) { @@ -143,6 +161,7 @@ void DigiReco::init() LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " shift= " << tdc_shift[itdc] << " i.s. = " << val * o2::zdc::FTDCVal << " ns"; } } + // Amplitude calibration for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) { float fval = ropt.tdc_calib[itdc]; @@ -215,14 +234,14 @@ void DigiReco::init() } } else { ropt.tower_calib[ChTowerCalib[il]] = 1; - LOG(warning) << "Default Tower Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]]; + LOG(warning) << "Default Tower Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]]; } } // Tower energy calibration for (int il = 0; il < ChTowerCalib.size(); il++) { if (ropt.energy_calib[ChTowerCalib[il]] > 0) { - LOG(info) << "Tower Energy Calibration from command line " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]]; + LOG(info) << "Tower Energy Calibration set to " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]]; } else { ropt.energy_calib[ChTowerCalib[il]] = ropt.tower_calib[ChTowerCalib[il]] * ropt.energy_calib[CaloCommonPM[ChTowerCalib[il]]]; if (mVerbosity > DbgZero) { @@ -240,7 +259,7 @@ void DigiReco::init() if (mModuleConfig->modules[im].channelID[ic] == ich && mModuleConfig->modules[im].readChannel[ic]) { ropt.amod[ich] = im; ropt.ach[ich] = ic; - // Fill mask to identify TDC channels + // Fill mask to identify all channels mChMask[ich] = (0x1 << (4 * im + ic)); goto next_ich; } @@ -340,7 +359,7 @@ void DigiReco::prepareInterpolation() int DigiReco::process(const gsl::span& orbitdata, const gsl::span& bcdata, const gsl::span& chdata) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << "________________________________________________________________________________"; LOG(info) << __func__; #endif @@ -388,13 +407,13 @@ int DigiReco::process(const gsl::span& orbitdata, cons } // Probably this is not necessary - // for(int itdc=0; itdc& orbitdata, cons // Low pass filtering if (mLowPassFilter) { + // N.B. At the moment low pass filtering is performed only on TDC + // signals and not on the rest of the signals lowPassFilter(); + } else { + // Copy samples + for (int itdc = 0; itdc < NTDCChannels; itdc++) { + auto isig = TDCSignal[itdc]; + for (int ibc = 0; ibc < mNBC; ibc++) { + auto ref_c = mReco[ibc].ref[isig]; + if (ref_c != ZDCRefInitVal) { + for (int is = 0; is < NTimeBinsPerBC; is++) { + mReco[ibc].data[isig][is] = mChData[ref_c].data[is]; + } + } + } + } + } + + if (mFullInterpolation) { + // Copy remaining channels + for (int isig = 0; isig < NChannels; isig++) { + int isig_tdc = TDCSignal[SignalTDC[isig]]; + if (isig == isig_tdc) { + // Already copied + continue; + } + for (int ibc = 0; ibc < mNBC; ibc++) { + auto ref_c = mReco[ibc].ref[isig]; + if (ref_c != ZDCRefInitVal) { + for (int is = 0; is < NTimeBinsPerBC; is++) { + mReco[ibc].data[isig][is] = mChData[ref_c].data[is]; + } + } + } + } } // Find consecutive bunch crossings by taking into account just the presence // of bunch crossing data and then perform signal interpolation in the identified ranges. // With this definition of "consecutive" bunch crossings gaps in the sample data - // may be present , therefore in the reconstruction method we take into account for signals + // may be present, therefore in the reconstruction method we take into account for signals // that do not span the entire range int seq_beg = 0; int seq_end = 0; @@ -456,6 +509,10 @@ int DigiReco::process(const gsl::span& orbitdata, cons // Look for another bunch seq_end = ibc; } +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG + // Here in order to avoid mixing information + mBCData[ibc].print(mTriggerMask); +#endif } // Apply pile-up correction for TDCs to get corrected TDC amplitudes and values @@ -497,7 +554,7 @@ void DigiReco::lowPassFilter() // First attempt to low pass filtering uses the average of three consecutive samples // ringing noise has T~6 ns w.r.t. a sampling period of ~ 2 ns // one should get smoothing of the noise -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << "________________________________________________________________________________"; LOG(info) << __func__; #endif @@ -505,32 +562,37 @@ void DigiReco::lowPassFilter() for (int itdc = 0; itdc < NTDCChannels; itdc++) { auto isig = TDCSignal[itdc]; for (int ibc = 0; ibc < mNBC; ibc++) { + // Indexes of current, previous and next recorded bunch crossings auto ref_c = mReco[ibc].ref[isig]; - uint32_t ref_p = ibc == 0 ? ZDCRefInitVal : mReco[ibc - 1].ref[isig]; - uint32_t ref_n = ibc == (mNBC - 1) ? ZDCRefInitVal : mReco[ibc + 1].ref[isig]; - if (ref_c != ZDCRefInitVal) { + uint32_t ref_p = ZDCRefInitVal; + uint32_t ref_n = ZDCRefInitVal; + int64_t bcd_p = ZDCRefInitVal; + int64_t bcd_n = ZDCRefInitVal; + if (ibc > 0) { // Is not first bunch in list + ref_p = mReco[ibc - 1].ref[isig]; + bcd_p = mReco[ibc].ir.differenceInBC(mReco[ibc - 1].ir); // b.c. number of (ibc) - b.c. number (ibc-1) + } + if (ibc < (mNBC - 1)) { // Is not last bunch in list + ref_n = mReco[ibc + 1].ref[isig]; + bcd_n = mReco[ibc + 1].ir.differenceInBC(mReco[ibc].ir); // b.c. number of (ibc+1) - b.c. number (ibc) + } + if (ref_c != ZDCRefInitVal) { // Should always be true for (int is = 0; is < NTimeBinsPerBC; is++) { int32_t sum = mChData[ref_c].data[is]; if (is == 0) { sum += mChData[ref_c].data[1]; - if (ref_p != ZDCRefInitVal) { - // b.c. number of (ibc) - b.c. number (ibc-1) - auto bcd = mReco[ibc].ir.differenceInBC(mReco[ibc - 1].ir); - if (bcd == 1) { // Previous bunch crossing - sum += mChData[ref_p].data[MaxTimeBin]; - } + if (ref_p != ZDCRefInitVal && bcd_p == 1) { + // Add last sample of previous bunch crossing + sum += mChData[ref_p].data[MaxTimeBin]; } else { // As a backup we count twice the first sample sum += mChData[ref_c].data[0]; } } else if (is == MaxTimeBin) { sum += mChData[ref_c].data[MaxTimeBin - 1]; - if (ref_n != ZDCRefInitVal) { - // b.c. number of (ibc+1) - b.c. number (ibc) - auto bcd = mReco[ibc + 1].ir.differenceInBC(mReco[ibc].ir); - if (bcd == 1) { - sum += mChData[ref_n].data[0]; - } + if (ref_n != ZDCRefInitVal && bcd_n == 1) { + // Add first sample of next bunch crossing + sum += mChData[ref_n].data[0]; } else { // As a backup we count twice the last sample sum += mChData[ref_c].data[MaxTimeBin]; @@ -563,7 +625,7 @@ void DigiReco::lowPassFilter() void DigiReco::reconstructTDC(int ibeg, int iend) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << "________________________________________________________________________________"; LOG(info) << __func__ << "(" << ibeg << ", " << iend << ")"; #endif @@ -607,11 +669,47 @@ void DigiReco::reconstructTDC(int ibeg, int iend) // The following TDC processing stage findSignals(..) assumes that time shift // due to pile-up has been corrected because main-main is assumed to be // in position 0 + // In case we do full interpolation, we process also the channels that are not + // considered in TDC list + if (mFullInterpolation) { + for (int isig = 0; isig < NChannels; isig++) { + int isig_tdc = TDCSignal[SignalTDC[isig]]; + if (isig == isig_tdc) { + // Already computed + continue; + } + // Check if channel has valid data for consecutive bunches in current bunch range + // N.B. there are events recorded from ibeg-iend but we are not sure if it is the + // case for every channel + int istart = -1, istop = -1; + // Loop allows for gaps in the data sequence for each TDC channel + for (int ibun = ibeg; ibun <= iend; ibun++) { + if (mBCData[ibun].channels & mChMask[isig]) { // Channel has data for this event + if (istart < 0) { + istart = ibun; + } + istop = ibun; + } else { // No data from channel + // A gap is detected + if (istart >= 0 && (istop - istart) > 0) { + // Need data for at least two consecutive bunch crossings + fullInterpolation(isig, istart, istop); + } + istart = -1; + istop = -1; + } + } + // Check if there are consecutive bunch crossings at the end of group + if (istart >= 0 && (istop - istart) > 0) { + fullInterpolation(isig, istart, istop); + } + } + } } // reconstructTDC int DigiReco::reconstruct(int ibeg, int iend) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << "________________________________________________________________________________"; LOG(info) << __func__ << "(" << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif @@ -625,7 +723,7 @@ int DigiReco::reconstruct(int ibeg, int iend) } return 0; } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG for (int ibun = ibeg; ibun <= iend; ibun++) { printf("%d CH Mask: 0x%08x TDC data for:", ibun, mBCData[ibun].channels); for (int itdc = 0; itdc < NTDCChannels; itdc++) { @@ -688,7 +786,7 @@ int DigiReco::reconstruct(int ibeg, int iend) mt.w = mBCData[ibun].moduleTriggers[mRopt->amod[ich]]; hasAuto0[bcd] = mt.f.Auto_0; hasAutoM[bcd] = mt.f.Auto_m; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG printf("%2d %s bcd = %d ibun = %d ibeg = %d ref = %3u %s %s %s\n", ich, ChannelNames[ich].data(), bcd, ibun, ibeg, ref[bcd], hasHit[bcd] ? "H" : "-", hasAuto0[bcd] ? "A0" : "--", hasAutoM[bcd] ? "AM" : "--"); @@ -845,7 +943,7 @@ void DigiReco::updateOffsets(int ibun) if (mSource[ich] == PedND) { LOGF(error, "Missing pedestal for ch %2d %s orbit %u ", ich, ChannelNames[ich], mOffsetOrbit); } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOGF(info, "Pedestal for ch %2d %s orbit %u %s: %f", ich, ChannelNames[ich], mOffsetOrbit, mSource[ich] == PedOr ? "OR" : (mSource[ich] == PedQC ? "QC" : "??"), mOffset[ich]); #endif } @@ -853,7 +951,7 @@ void DigiReco::updateOffsets(int ibun) void DigiReco::processTrigger(int itdc, int ibeg, int iend) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[TDCSignal[itdc]] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif // Extracting TDC information for TDC number itdc, in consecutive bunches from ibeg to iend @@ -864,7 +962,7 @@ void DigiReco::processTrigger(int itdc, int ibeg, int iend) int is1 = 0, is2 = 1; uint8_t isfired = 0; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG int16_t m[3] = {0}; int16_t s[3] = {0}; #endif @@ -872,7 +970,7 @@ void DigiReco::processTrigger(int itdc, int ibeg, int iend) for (;;) { // Shift data isfired = isfired << 1; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG for (int i = 2; i > 0; i--) { m[i] = m[i - 1]; s[i] = s[i - 1]; @@ -898,7 +996,7 @@ void DigiReco::processTrigger(int itdc, int ibeg, int iend) } int diff = mChData[ref_m].data[s1] - mChData[ref_s].data[s2]; // Triple trigger condition -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG m[0] = mChData[ref_m].data[s1]; s[0] = mChData[ref_s].data[s2]; #endif @@ -908,7 +1006,7 @@ void DigiReco::processTrigger(int itdc, int ibeg, int iend) // Fired bit is assigned to the second sample, i.e. to the one that can identify the // signal peak position mReco[b2].fired[itdc] |= mMask[s2]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG if (mTriggerCondition == 0x7) { printf("0x7 TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (%5d-%5d)=%5d>%2d && (s%02d:%-5d-s%02d:%-5d)=%5d>%2d\n", itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2, @@ -944,7 +1042,7 @@ void DigiReco::processTrigger(int itdc, int ibeg, int iend) void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) { auto isig = TDCSignal[itdc]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif // Extends search zone at the beginning of sequence. Need pedestal information. @@ -966,7 +1064,7 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) int is1 = -shift, is2 = 0; uint8_t isfired = 0; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG int16_t m[3] = {0}; int16_t s[3] = {0}; #endif @@ -975,7 +1073,7 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) for (;;) { // Shift data isfired = isfired << 1; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG for (int i = 2; i > 0; i--) { m[i] = m[i - 1]; s[i] = s[i - 1]; @@ -993,7 +1091,7 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) return; } diff = mOffset[isig] - mChData[ref_s].data[s2]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG m[0] = mOffset[isig]; s[0] = mChData[ref_s].data[s2]; #endif @@ -1012,7 +1110,7 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) return; } diff = mChData[ref_m].data[s1] - mChData[ref_s].data[s2]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG m[0] = mChData[ref_m].data[s1]; s[0] = mChData[ref_s].data[s2]; #endif @@ -1024,7 +1122,7 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) // Fired bit is assigned to the second sample, i.e. to the one that can identify the // signal peak position mReco[b2].fired[itdc] |= mMask[s2]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG if (mTriggerCondition == 0x7) { printf("0x7E TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (%5d-%5d)=%5d>%5d && (s%02d:%-5d-s%02d:%-5d)=%-5d>%2d\n", itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2, @@ -1055,11 +1153,12 @@ void DigiReco::processTriggerExtended(int itdc, int ibeg, int iend) interpolate(itdc, ibeg, iend); } // processTrigger -O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) +// Interpolation for single point +O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int isig, int ibeg, int iend, int i) { constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing if (i >= mNtot || i < 0) { - LOG(fatal) << "Error addressing TDC itdc=" << itdc << " i=" << i << " mNtot=" << mNtot; + LOG(fatal) << "Error addressing isig=" << isig << " i=" << i << " mNtot=" << mNtot; return std::numeric_limits::infinity(); } // Constant extrapolation at the beginning and at the end of the array @@ -1071,7 +1170,6 @@ O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) return mLastSample; } else { // Identification of the point to be assigned - int isig = TDCSignal[itdc]; int ibun = ibeg + i / nsbun; // Interpolation between acquired points (N.B. from 0 to mNint) i = i - TSNH; @@ -1084,11 +1182,8 @@ O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) LOG(fatal) << "ib=" << ib << " ibun=" << ibun; return std::numeric_limits::infinity(); } -#ifdef O2_ZDC_RECO_FILTERING return mReco[ibun].data[isig][ip]; // Filtered point -#else - return mChData[mReco[ibun].ref[isig]].data[ip]; // Original point -#endif + // return mChData[mReco[ibun].ref[isig]].data[ip]; // Original point } else { // Do the actual interpolation O2_ZDC_DIGIRECO_FLT y = 0; @@ -1101,11 +1196,8 @@ O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) if (ii < mNsam) { int ip = ii % NTimeBinsPerBC; int ib = ibeg + ii / NTimeBinsPerBC; -#ifdef O2_ZDC_RECO_FILTERING yy = mReco[ib].data[isig][ip]; -#else - yy = mChData[mReco[ib].ref[isig]].data[ip]; -#endif + // yy = mChData[mReco[ib].ref[isig]].data[ip]; } else { // Last acquired point yy = mLastSample; @@ -1120,36 +1212,84 @@ O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int itdc, int ibeg, int iend, int i) } } -#ifdef O2_ZDC_INTERP_DEBUG -void DigiReco::setPoint(int itdc, int ibeg, int iend, int i) +void DigiReco::setPoint(int isig, int ibeg, int iend, int i) { + // This function needs to be used only if mFullInterpolation is true otherwise the + // vectors are not allocated + if (!mFullInterpolation) { + LOG(fatal) << __func__ << " call with mFullInterpolation = " << mFullInterpolation; + return; + } constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing if (i >= mNtot || i < 0) { - LOG(fatal) << "Error addressing TDC itdc=" << itdc << " i=" << i << " mNtot=" << mNtot; + LOG(fatal) << "Error addressing signal isig=" << isig << " i=" << i << " mNtot=" << mNtot; return; } // Constant extrapolation at the beginning and at the end of the array if (i < TSNH) { // Assign value of first sample - mReco[ibeg].inter[itdc][i] = mFirstSample; + mReco[ibeg].inter[isig][i] = mFirstSample; } else if (i >= mIlast) { // Assign value of last sample int isam = i % nsbun; - mReco[iend].inter[itdc][isam] = mLastSample; + mReco[iend].inter[isig][isam] = mLastSample; } else { // Identification of the point to be assigned int ibun = ibeg + i / nsbun; int isam = i % nsbun; - mReco[ibun].inter[itdc][isam] = getPoint(itdc, ibeg, iend, i); + mReco[ibun].inter[isig][isam] = getPoint(isig, ibeg, iend, i); } } // setPoint + +void DigiReco::fullInterpolation(int isig, int ibeg, int iend) +{ + // Interpolation of signal isig, in consecutive bunches from ibeg to iend + // This function works for all signals and does not evaluate trigger + // You need to call interpolate(int itdc... for the TDC signals +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG + LOG(info) << __func__ << "(isig=" << isig << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif + // TODO: get data from preceding time frame in case there are bunches + // with signal at the beginning of the first orbit of a time frame + + constexpr int MaxTimeBin = NTimeBinsPerBC - 1; //< number of samples per BC + + // Set data members for interpolation of the current channel + mNbun = iend - ibeg + 1; // Number of adjacent bunches + mNsam = mNbun * NTimeBinsPerBC; // Number of acquired samples + mNtot = mNsam * TSN; // Total number of points in the interpolated arrays + mNint = (mNbun * NTimeBinsPerBC - 1) * TSN; // Total points in the interpolation region (-1) + mIlast = mNtot - TSNH; // Index of last acquired sample + + // At this level there should be no need to check if the channel is connected + // since a fatal should have been raised already + for (int ibun = ibeg; ibun <= iend; ibun++) { + auto ref = mReco[ibun].ref[isig]; + if (ref == ZDCRefInitVal) { + LOG(fatal) << "Missing information for bunch crossing"; + } + } + + mFirstSample = mReco[ibeg].data[isig][0]; + mLastSample = mReco[iend].data[isig][MaxTimeBin]; + + // Allocate and fill array of interpolated points + for (int ibun = ibeg; ibun <= iend; ibun++) { + mReco[ibun].allocate(isig); + } + for (int i = 0; i < mNtot; i++) { + setPoint(isig, ibeg, iend, i); + } +} + void DigiReco::interpolate(int itdc, int ibeg, int iend) { - // Interpolation of signal for TDC number itdc, in consecutive bunches from ibeg to iend -#ifdef O2_ZDC_DEBUG - LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[TDCSignal[itdc]] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; + // Interpolation of TDC channel itdc, in consecutive bunches from ibeg to iend + int isig = TDCSignal[itdc]; + +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG + LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif // TODO: get data from preceding time frame in case there are bunches @@ -1157,6 +1297,7 @@ void DigiReco::interpolate(int itdc, int ibeg, int iend) constexpr int MaxTimeBin = NTimeBinsPerBC - 1; //< number of samples per BC constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing + // Set data members for interpolation of the current TDC mNbun = iend - ibeg + 1; // Number of adjacent bunches mNsam = mNbun * NTimeBinsPerBC; // Number of acquired samples @@ -1166,37 +1307,33 @@ void DigiReco::interpolate(int itdc, int ibeg, int iend) constexpr int nsp = 5; // Number of points to be searched - // At this level there should be no need to check if the TDC channel is connected + // At this level there should be no need to check if the channel is connected // since a fatal should have been raised already for (int ibun = ibeg; ibun <= iend; ibun++) { - auto ref = mReco[ibun].ref[TDCSignal[itdc]]; + auto ref = mReco[ibun].ref[isig]; if (ref == ZDCRefInitVal) { LOG(fatal) << "Missing information for bunch crossing"; } } - int imod = mRopt->tmod[itdc]; // Module corresponding to TDC channel - // int ich = mRopt->tch[itdc]; // Hardware channel corresponding to TDC channel - int isig = TDCSignal[itdc]; // Signal corresponding to TDC - - auto ref_beg = mReco[ibeg].ref[isig]; - auto ref_end = mReco[iend].ref[isig]; + // auto ref_beg = mReco[ibeg].ref[isig]; + // auto ref_end = mReco[iend].ref[isig]; + // mFirstSample = mChData[ref_beg].data[0]; // Original points + // mLastSample = mChData[ref_end].data[MaxTimeBin]; // Original points -#ifdef O2_ZDC_RECO_FILTERING mFirstSample = mReco[ibeg].data[isig][0]; mLastSample = mReco[iend].data[isig][MaxTimeBin]; -#else - mFirstSample = mChData[ref_beg].data[0]; - mLastSample = mChData[ref_end].data[MaxTimeBin]; -#endif - // O2_ZDC_INTERP_DEBUG turns on full interpolation for debugging + // mFullInterpolation turns on full interpolation for debugging // otherwise the interpolation is performed only around actual signal -#ifdef O2_ZDC_INTERP_DEBUG - for (int i = 0; i < mNtot; i++) { - setPoint(itdc, ibeg, iend, i); + if (mFullInterpolation) { + for (int ibun = ibeg; ibun <= iend; ibun++) { + mReco[ibun].allocate(isig); + } + for (int i = 0; i < mNtot; i++) { + setPoint(isig, ibeg, iend, i); + } } -#endif // Looking for a local maximum in a search zone O2_ZDC_DIGIRECO_FLT amp = std::numeric_limits::infinity(); // Amplitude to be stored @@ -1337,13 +1474,14 @@ void DigiReco::interpolate(int itdc, int ibeg, int iend) } if (is_searchable) { int mysam = isam % nsbun; -#ifndef O2_ZDC_INTERP_DEBUG - // Perform interpolation for the searched point - // setPoint(itdc, ibeg, iend, isam); - O2_ZDC_DIGIRECO_FLT myval = getPoint(itdc, ibeg, iend, isam); -#else - O2_ZDC_DIGIRECO_FLT myval = mReco[ib_cur].inter[itdc][mysam]; -#endif + O2_ZDC_DIGIRECO_FLT myval; + if (mFullInterpolation) { + // Already interpolated + myval = mReco[ib_cur].inter[isig][mysam]; + } else { + // Perform interpolation for the searched point + myval = getPoint(isig, ibeg, iend, isam); + } // Get local minimum of waveform if (myval < amp) { amp = myval; @@ -1438,7 +1576,7 @@ void DigiReco::assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float } else { rec.tdcPedMissing[isig] = true; } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << __func__ << " itdc=" << itdc << " " << ChannelNames[isig] << " @ ibun=" << ibun << " " << mReco[ibun].ir.orbit << "." << mReco[ibun].ir.bc << " " << " tdc=" << tdc << " -> " << TDCValCorr << " shift=" << tdc_shift[itdc] << " -> TDCVal=" << TDCVal << "=" << TDCVal * o2::zdc::FTDCVal << " mSource[" << isig << "] = " << unsigned(mSource[isig]) << " = " << mOffset[isig] @@ -1451,7 +1589,7 @@ void DigiReco::assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float void DigiReco::findSignals(int ibeg, int iend) { // N.B. findSignals is called after pile-up correction on TDCs -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << __func__ << "(" << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc; #endif // Identify TDC signals @@ -1459,7 +1597,7 @@ void DigiReco::findSignals(int ibeg, int iend) updateOffsets(ibun); // Get orbit pedestals or QC fallback auto& rec = mReco[ibun]; for (int itdc = 0; itdc < NTDCChannels; itdc++) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG bool msg = false; if (rec.fired[itdc] != 0x0) { msg = true; @@ -1471,7 +1609,7 @@ void DigiReco::findSignals(int ibeg, int iend) #endif rec.pattern[itdc] = 0; for (int32_t i = 0; i < rec.ntdc[itdc]; i++) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG msg = true; printf(" %d TDC A=%5.0f @ T=%5.0f", i, rec.TDCAmp[itdc][i], rec.TDCVal[itdc][i]); #endif @@ -1480,7 +1618,7 @@ void DigiReco::findSignals(int ibeg, int iend) if (std::abs(rec.TDCVal[itdc][i]) < mRopt->tdc_search[itdc]) { rec.pattern[itdc] = 1; } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG if (rec.pattern[itdc] == 1) { printf(" in_r"); } else { @@ -1488,14 +1626,14 @@ void DigiReco::findSignals(int ibeg, int iend) } #endif } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG if (msg) { printf("\n"); } #endif } -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG printf("%d %u.%-4u TDC PATTERN: ", ibun, mReco[ibun].ir.orbit, mReco[ibun].ir.bc); for (int itdc = 0; itdc < NTDCChannels; itdc++) { printf("%d", rec.pattern[itdc]); @@ -1577,7 +1715,7 @@ void DigiReco::correctTDCPile() // In case TDC correction parameters are missing (e.g. mTDCCorr==0) then // pile-up is flagged but not corrected for -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG LOG(info) << "________________________________________________________________________________"; LOG(info) << __func__; #endif @@ -1658,7 +1796,7 @@ int DigiReco::correctTDCSignal(int itdc, int16_t TDCVal, float TDCAmp, float& fT fTDCAmp = TDCAmp; if (mTDCCorr == nullptr) { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG printf("%21s itdc=%d TDC=%d AMP=%d MISSING mTDCCorr\n", __func__, itdc, TDCVal, TDCAmp); #endif return 1; @@ -1719,7 +1857,7 @@ int DigiReco::correctTDCSignal(int itdc, int16_t TDCVal, float TDCAmp, float& fT } } } else { -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG printf("%21s itdc=%d TDC=%d AMP=%d LONELY BUNCH\n", __func__, itdc, TDCVal, TDCAmp); #endif return 1; @@ -1738,7 +1876,7 @@ int DigiReco::correctTDCBackground(int ibc, int itdc, std::deque& t // therefore we refer just to TDC hit in position [0] float TDCValUnc = rec->TDCVal[itdc][0]; float TDCAmpUnc = rec->TDCAmp[itdc][0]; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG auto TDCValUncBck = rec->TDCVal[itdc][0]; auto TDCAmpUncBck = rec->TDCAmp[itdc][0]; #endif @@ -1905,7 +2043,7 @@ int DigiReco::correctTDCBackground(int ibc, int itdc, std::deque& t } // Loop on signal bucket position (ibuks) rec->TDCVal[itdc][0] = TDCValBest; rec->TDCAmp[itdc][0] = TDCAmpBest; -#ifdef O2_ZDC_DEBUG +#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG if (rec->TDCVal[itdc][0] != TDCValUnc || rec->TDCAmp[itdc][0] != TDCAmpUnc) { printf("%21s ibc=%d itdc=%d sn = %d", __func__, ibc, itdc, TDCSigBest); printf(" TDC=%f -> %f", TDCValUncBck, rec->TDCVal[itdc][0]); diff --git a/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx index 1fbc550c86c18..dd1ab13ffcfad 100644 --- a/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx +++ b/Detectors/ZDC/reconstruction/src/RecoConfigZDC.cxx @@ -86,6 +86,11 @@ void RecoConfigZDC::setPedThreshold(int32_t ich, float high, float low) void RecoConfigZDC::print() { + LOGF(info, "RecoConfigZDC:%s%s%s%s", + (low_pass_filter ? " LowPassFilter" : ""), + (full_interpolation ? " FullInterpolation" : ""), + (corr_signal ? " CorrSignal" : ""), + (corr_background ? " CorrBackground" : "")); for (int itdc = 0; itdc < NTDCChannels; itdc++) { LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << tdc_search[itdc] << " = " << tdc_search[itdc] * FTDCVal << " ns"; } diff --git a/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx b/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx index 7b8232149e689..17477d8dcf5b9 100644 --- a/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx +++ b/Detectors/ZDC/reconstruction/src/RecoParamZDC.cxx @@ -22,3 +22,103 @@ void o2::zdc::RecoParamZDC::setBit(uint32_t ibit, bool val) LOG(fatal) << __func__ << " bit " << ibit << " not in allowed range"; } } + +void o2::zdc::RecoParamZDC::print() +{ + bool printed = false; + if (low_pass_filter >= 0 || full_interpolation >= 0 || corr_signal >= 0 || corr_background >= 0) { + if (!printed) { + LOG(info) << "RecoParamZDC::print()"; + printed = true; + } + if (low_pass_filter >= 0) { + printf(" LowPassFilter=%d", low_pass_filter); + } + if (full_interpolation >= 0) { + printf(" FullInterpolation=%d", full_interpolation); + } + if (corr_signal >= 0) { + printf(" CorrSignal=%d", corr_signal); + } + if (corr_background >= 0) { + printf(" CorrBackground=%d", corr_background); + } + printf("\n"); + } + if (!printed) { + printed = true; + LOG(info) << "RecoParamZDC::print()"; + } + /* + Int_t tsh[NTDCChannels] = {4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; // Trigger shift + Int_t tth[NTDCChannels] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; // Trigger threshold + bool bitset[NTDCChannels] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Set bits in coincidence + void setBit(uint32_t ibit, bool val = true); + + // Signal processing + int low_pass_filter = -1; // Low pass filtering + int full_interpolation = -1; // Full interpolation of waveform + int corr_signal = -1; // TDC signal correction + int corr_background = -1; // TDC pile-up correction + + // TDC + Int_t tmod[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of TDC channel in raw data + Int_t tch[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of TDC channel in raw data + float tdc_shift[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Correction of TDC position (0-25 ns, units of ~10 ps) + float tdc_calib[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Correction of TDC amplitude + float tdc_search[NTDCChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Search zone for a TDC signal ideally 2.5 ns (units of ~10 ps) + + // Charge integration + Int_t amod[NChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of ADC channel in raw data + Int_t ach[NChannels] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; // Position of ADC channel in raw data + // Beginning and end of integration range: signal + Int_t beg_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + // Beginning and end of integration range: pedestal + Int_t beg_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + Int_t end_ped_int[NChannels] = {DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange, DummyIntRange}; + // Pedestal thresholds for pile-up detection + float ped_thr_hi[NChannels] = {ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange}; + float ped_thr_lo[NChannels] = {ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange, ADCRange}; + */ + bool modified = false; + for (int i = 0; i < o2::zdc::NChannels; i++) { + if (energy_calib[i] != 0) { + modified = true; + break; + } + } + if (modified) { + if (!printed) { + printed = true; + LOG(info) << "RecoParamZDC::print()"; + } + printf("energ_calib: "); + for (int i = 0; i < o2::zdc::NChannels; i++) { + if (energy_calib[i] != 0) { + printf(" %s=%f", o2::zdc::ChannelNames[i].data(), energy_calib[i]); + } + } + printf("\n"); + } + modified = false; + for (int i = 0; i < o2::zdc::NChannels; i++) { + if (tower_calib[i] != 0) { + modified = true; + break; + } + } + if (modified) { + if (!printed) { + printed = true; + LOG(info) << "RecoParamZDC::print()"; + } + printf("tower_calib: "); + for (int i = 0; i < o2::zdc::NChannels; i++) { + if (tower_calib[i] != 0) { + printf(" %s=%f", o2::zdc::ChannelNames[i].data(), tower_calib[i]); + } + } + printf("\n"); + } +} diff --git a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx index 4fdaec1c51a08..a1bd65fab4838 100644 --- a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx +++ b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx @@ -176,9 +176,11 @@ void DigitRecoSpec::run(ProcessingContext& pc) mDR.process(peds, bcdata, chans); const std::vector& recAux = mDR.getReco(); + // Transfer wafeform + bool fullinter = mDR.getFullInterpolation(); RecEvent recEvent; - LOG(info) << "BC processed during reconstruction " << recAux.size(); - uint32_t nte = 0, ntt = 0, nti = 0; + LOGF(info, "BC processed during reconstruction %d%s", recAux.size(), (fullinter ? " FullInterpolation" : "")); + uint32_t nte = 0, ntt = 0, nti = 0, ntw = 0; for (auto reca : recAux) { bool toAddBC = true; int32_t ne = reca.ezdc.size(); @@ -194,6 +196,19 @@ void DigitRecoSpec::run(ProcessingContext& pc) recEvent.addTDC(it, reca.TDCVal[it][ih], reca.TDCAmp[it][ih], reca.isBeg[it], reca.isEnd[it]); } } + // Add waveform information + if (fullinter) { + for (int32_t isig = 0; isig < o2::zdc::NChannels; isig++) { + if (reca.inter[isig].size() == NIS) { + if (toAddBC) { + recEvent.addBC(reca); + toAddBC = false; + } + recEvent.addWaveform(isig, reca.inter[isig]); + ntw++; + } + } + } if (ne > 0) { if (toAddBC) { recEvent.addBC(reca); @@ -206,19 +221,22 @@ void DigitRecoSpec::run(ProcessingContext& pc) } nte += ne; ntt += nt; - if (mVerbosity > 0 && (nt > 0 || ne > 0)) { - printf("Orbit %9u bc %4u ntdc %2d ne %2d\n", reca.ir.orbit, reca.ir.bc, nt, ne); + if (mVerbosity > 1 && (nt > 0 || ne > 0)) { + printf("Orbit %9u bc %4u ntdc %2d ne %2d channels=0x%08x\n", reca.ir.orbit, reca.ir.bc, nt, ne, reca.channels); } // Event information nti += recEvent.addInfos(reca); } - LOG(info) << "Reconstructed " << ntt << " signal TDCs and " << nte << " ZDC energies and " << nti << " info messages in " << recEvent.mRecBC.size() << "/" << recAux.size() << " b.c."; + LOG(info) << "Reconstructed " << ntt << " signal TDCs and " << nte << " ZDC energies and " + << nti << " info messages in " << recEvent.mRecBC.size() << "/" << recAux.size() << " b.c. and " + << ntw << " waveform chunks"; // TODO: rate information for all channels // TODO: summary of reconstruction to be collected by DQM? pc.outputs().snapshot(Output{"ZDC", "BCREC", 0, Lifetime::Timeframe}, recEvent.mRecBC); pc.outputs().snapshot(Output{"ZDC", "ENERGY", 0, Lifetime::Timeframe}, recEvent.mEnergy); pc.outputs().snapshot(Output{"ZDC", "TDCDATA", 0, Lifetime::Timeframe}, recEvent.mTDCData); pc.outputs().snapshot(Output{"ZDC", "INFO", 0, Lifetime::Timeframe}, recEvent.mInfo); + pc.outputs().snapshot(Output{"ZDC", "WAVE", 0, Lifetime::Timeframe}, recEvent.mWaveform); mTimer.Stop(); } @@ -241,6 +259,7 @@ framework::DataProcessorSpec getDigitRecoSpec(const int verbosity = 0, const boo outputs.emplace_back("ZDC", "ENERGY", 0, Lifetime::Timeframe); outputs.emplace_back("ZDC", "TDCDATA", 0, Lifetime::Timeframe); outputs.emplace_back("ZDC", "INFO", 0, Lifetime::Timeframe); + outputs.emplace_back("ZDC", "WAVE", 0, Lifetime::Timeframe); return DataProcessorSpec{ "zdc-digi-reco", diff --git a/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx b/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx index 5ecb4c5938e11..91fd924976dcd 100644 --- a/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx +++ b/Detectors/ZDC/workflow/src/ZDCRecoWriterDPLSpec.cxx @@ -17,8 +17,9 @@ #include "DataFormatsZDC/BCRecData.h" #include "DataFormatsZDC/ZDCEnergy.h" #include "DataFormatsZDC/ZDCTDCData.h" - +#include "DataFormatsZDC/ZDCWaveform.h" #include "ZDCWorkflow/ZDCRecoWriterDPLSpec.h" + using namespace o2::framework; namespace o2 @@ -42,7 +43,8 @@ DataProcessorSpec getZDCRecoWriterDPLSpec() BranchDefinition>{InputSpec{"bcrec", "ZDC", "BCREC"}, "ZDCRecBC"}, BranchDefinition>{InputSpec{"energy", "ZDC", "ENERGY"}, "ZDCRecE"}, BranchDefinition>{InputSpec{"tdcdata", "ZDC", "TDCDATA"}, "ZDCRecTDC"}, - BranchDefinition>{InputSpec{"info", "ZDC", "INFO"}, "ZDCRecInfo"})(); + BranchDefinition>{InputSpec{"info", "ZDC", "INFO"}, "ZDCRecInfo"}, + BranchDefinition>{InputSpec{"wave", "ZDC", "WAVE"}, "ZDCWaveform"})(); } } // namespace zdc