diff --git a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h index da1ca9d1d0292..916181030c583 100644 --- a/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h +++ b/DataFormats/Detectors/ZDC/include/DataFormatsZDC/BCData.h @@ -55,8 +55,9 @@ struct BCData { o2::dataformats::RangeRefComp<6> ref; o2::InteractionRecord ir; std::array moduleTriggers{}; + // N.B. channels and triggers have geographical addressing (0x1 << (NChPerModule * im + ic) uint32_t channels = 0; // pattern of channels it refers to - uint32_t triggers = 0; // pattern of triggered channels (not necessarily stored) in this BC + uint32_t triggers = 0; // pattern of triggered channels (not necessarily stored) in this BC (i.e. with Hit bit on) uint8_t ext_triggers = 0; // pattern of ALICE triggers BCData() = default; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h b/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h index 38416a3ec9d99..2e2b91e07482f 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/CalibParamZDC.h @@ -27,6 +27,7 @@ namespace o2 namespace zdc { struct CalibParamZDC : public o2::conf::ConfigurableParamHelper { + bool dumpCalib = false; // Dump partial calibration object bool debugOutput = false; // Debug output bool rootOutput = true; // Output histograms to EOS std::string outputDir = "./"; // ROOT files output directory diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h index d53d3ae1eec0f..6d625464c714b 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalib.h @@ -80,6 +80,8 @@ class InterCalib void setInterCalibConfig(const InterCalibConfig* param) { mInterCalibConfig = param; }; const InterCalibConfig* getInterCalibConfig() const { return mInterCalibConfig; }; + InterCalibData& getData() { return mData; }; + void setVerbosity(int v) { mVerbosity = v; } int getVerbosity() const { return mVerbosity; } diff --git a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibConfig.h b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibConfig.h index d9e729cd57f3f..3bf1e488abb3e 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/InterCalibConfig.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/InterCalibConfig.h @@ -36,9 +36,13 @@ struct InterCalibConfig { // Meaningful values are in the range of tower x centers i.e. from // 2.8 to 19.6 If one puts less than 2.8 then the computation will be // the same as for ZPA/ZPC with no cuts - double xcut_ZPA = 6; - double xcut_ZPC = 6; - double tower_cut_ZP = 0; + double xcut_ZPA = 0; + double xcut_ZPC = 0; + double rms_cut_ZP = 0; // RMS of ZP centroid can go from 0 to 8.4 cm + double towerCutLow_ZPA[4] = {0, 0, 0, 0}; // Applied to all ZP fits except ZPI + double towerCutLow_ZPC[4] = {0, 0, 0, 0}; // Applied to all ZP fits except ZPI + double towerCutHigh_ZPA[4] = {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; // Applied to all ZP fits except ZPI + double towerCutHigh_ZPC[4] = {std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity(), std::numeric_limits::infinity()}; // Applied to all ZP fits except ZPI bool cross_check = false; int nb1[NH] = {0}; /// 1D histogram: number of bins @@ -87,7 +91,7 @@ struct InterCalibConfig { enabled[7] = c7; enabled[8] = c8; } - ClassDefNV(InterCalibConfig, 4); + ClassDefNV(InterCalibConfig, 5); }; } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h index 2818146d75f32..8701e3667b74a 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibData.h @@ -87,6 +87,7 @@ struct WaveformCalibData { void setCreationTime(uint64_t ctime); void setN(int n); int saveDebugHistos(const std::string fn); + int dumpCalib(const std::string fn); ClassDefNV(WaveformCalibData, 1); }; diff --git a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h index 929190f09d162..86dff268ee0ad 100644 --- a/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h +++ b/Detectors/ZDC/calib/include/ZDCCalib/WaveformCalibEPN.h @@ -37,9 +37,11 @@ class WaveformCalibEPN const gsl::span& wave); int endOfRun(); int saveDebugHistos(const std::string fn = "ZDCWaveformCalibEPN.root"); + int dumpCalib(const std::string fn = "ZDCWaveformCalibEPNDump.root"); void setConfig(const WaveformCalibConfig* param) { mConfig = param; }; const WaveformCalibConfig* getConfig() const { return mConfig; }; void setSaveDebugHistos() { mSaveDebugHistos = true; } + void setDumpCalib() { mDumpCalib = true; } void setDontSaveDebugHistos() { mSaveDebugHistos = false; } void setVerbosity(int val) { mVerbosity = val; } WaveformCalibData mData; @@ -48,6 +50,7 @@ class WaveformCalibEPN private: bool mInitDone = false; bool mSaveDebugHistos = false; + bool mDumpCalib = false; int32_t mNBin = 0; int32_t mVerbosity = DbgMinimal; const WaveformCalibConfig* mConfig = nullptr; /// Configuration of intercalibration diff --git a/Detectors/ZDC/calib/src/InterCalib.cxx b/Detectors/ZDC/calib/src/InterCalib.cxx index dc75b172a3aca..150bc36a22a63 100644 --- a/Detectors/ZDC/calib/src/InterCalib.cxx +++ b/Detectors/ZDC/calib/src/InterCalib.cxx @@ -210,12 +210,12 @@ void InterCalib::assign(int ih, bool ismod) } else if (ih == 5) { nid = 1; id = id_5; - LOG(warn) << "InterCalib::assign unimplemented coefficient ih = " << ih; + LOG(warn) << "InterCalib::assign is not implemented for coefficient ih = " << ih; return; } else if (ih == 6) { nid = 1; id = id_6; - LOG(warn) << "InterCalib::assign unimplemented coefficient ih = " << ih; + LOG(warn) << "InterCalib::assign is not implemented for coefficient ih = " << ih; return; } else if (ih == 7 || ih == 8) { nid = 4; @@ -246,15 +246,23 @@ void InterCalib::assign(int ih, bool ismod) if (oldval > 0) { val = val * mPar[ih][iid + 1]; } - if (mVerbosity > DbgZero) { + if (mTowerParamUpd.modified[ich]) { + LOGF(warn, "%s OVERWRITING MODIFIED PARAMETER %8.6f", ChannelNames[ich].data(), mTowerParamUpd.getTowerCalib(ich)); + LOGF(info, "%s updated %8.6f -> %8.6f", ChannelNames[ich].data(), oldval, val); + } else if (mVerbosity > DbgZero) { LOGF(info, "%s updated %8.6f -> %8.6f", ChannelNames[ich].data(), oldval, val); } mTowerParamUpd.setTowerCalib(ich, val, true); } else { - if (mVerbosity > DbgZero) { - LOGF(info, "%s NOT CHANGED %8.6f", ChannelNames[ich].data(), oldval); + // Check if another fit has already modified the parameters + if (mTowerParamUpd.modified[ich]) { + LOGF(warn, "%s NOT OVERWRITING MODIFIED PARAMETER %8.6f", ChannelNames[ich].data(), mTowerParamUpd.getTowerCalib(ich)); + } else { + if (mVerbosity > DbgZero) { + LOGF(info, "%s NOT CHANGED %8.6f", ChannelNames[ich].data(), oldval); + } + mTowerParamUpd.setTowerCalib(ich, oldval, false); } - mTowerParamUpd.setTowerCalib(ich, oldval, false); } } } @@ -294,6 +302,10 @@ int InterCalib::process(const char* hname, int ic) ih = HidZNI; } else if (hn.EqualTo("hZPI")) { ih = HidZPI; + } else if (hn.EqualTo("hZPAX")) { + ih = HidZPAX; + } else if (hn.EqualTo("hZPCX")) { + ih = HidZPCX; } else { LOGF(error, "Not recognized histogram name: %s\n", hname); return -1; @@ -434,18 +446,32 @@ void InterCalib::add(int ih, o2::dataformats::FlatHisto2D& h2) void InterCalib::cumulate(int ih, double tc, double t1, double t2, double t3, double t4, double w = 1) { + constexpr double minfty = -std::numeric_limits::infinity(); if (tc < mInterCalibConfig->cutLow[ih] || tc > mInterCalibConfig->cutHigh[ih]) { return; } - double val[NPAR] = {0, 0, 0, 0, 0, 1}; - val[0] = tc; - val[1] = t1; - val[2] = t2; - val[3] = t3; - val[4] = t4; - for (int32_t i = 0; i < NPAR; i++) { - for (int32_t j = i; j < NPAR; j++) { - mData.mSum[ih][i][j] += val[i] * val[j] * w; + if ((ih == HidZPA || ih == HidZPAX)) { + if (t1 < mInterCalibConfig->towerCutLow_ZPA[0] || t2 < mInterCalibConfig->towerCutLow_ZPA[1] || t3 < mInterCalibConfig->towerCutLow_ZPA[2] || t4 < mInterCalibConfig->towerCutLow_ZPA[3]) { + return; + } + if (t1 > mInterCalibConfig->towerCutHigh_ZPA[0] || t2 > mInterCalibConfig->towerCutHigh_ZPA[1] || t3 > mInterCalibConfig->towerCutHigh_ZPA[2] || t4 > mInterCalibConfig->towerCutHigh_ZPA[3]) { + return; + } + } + if (ih == HidZPC || ih == HidZPCX) { + if (t1 < mInterCalibConfig->towerCutLow_ZPC[0] || t2 < mInterCalibConfig->towerCutLow_ZPC[1] || t3 < mInterCalibConfig->towerCutLow_ZPC[2] || t4 < mInterCalibConfig->towerCutLow_ZPC[3]) { + return; + } + if (t1 > mInterCalibConfig->towerCutHigh_ZPC[0] || t2 > mInterCalibConfig->towerCutHigh_ZPC[1] || t3 > mInterCalibConfig->towerCutHigh_ZPC[2] || t4 > mInterCalibConfig->towerCutHigh_ZPC[3]) { + return; + } + } + double val[NPAR] = {tc, t1, t2, t3, t4, 1}; + if (tc > minfty && t1 > minfty && t2 > minfty && t3 > minfty && t4 > minfty) { + for (int32_t i = 0; i < NPAR; i++) { + for (int32_t j = i; j < NPAR; j++) { + mData.mSum[ih][i][j] += val[i] * val[j] * w; + } } } // mData.mSum[ih][5][5] contains the number of analyzed events @@ -470,6 +496,9 @@ void InterCalib::fcn(int& npar, double* gin, double& chi, double* par, int iflag chi += (i == 0 ? par[i] : -par[i]) * (j == 0 ? par[j] : -par[j]) * mAdd[i][j]; } } + // Following line modifies the chisquare computation to perform orthogonal + // least squares instead of ordinary least squares minimization + chi = chi / (1 + par[1] * par[1] + par[2] * par[2] + par[3] * par[3] + par[4] * par[4]); } int InterCalib::mini(int ih) @@ -498,15 +527,11 @@ int InterCalib::mini(int ih) // Calibration cvoefficient is forced to and step is forced to zero mMn[ih]->mnparm(0, "c0", 1., 0., 1., 1., ierflg); - // Special fit for proton calorimeters: fit least exposed towers with using previous - // fit of all towers + // Special fit for proton calorimeters: fit least exposed towers + // starting from parameters of previous fit to all towers // Tower 1 - if (ih == HidZPCX) { - mMn[ih]->mnparm(1, "c1", mPar[HidZPC][1], 0, l_bnd, u_bnd, ierflg); - } else { - mMn[ih]->mnparm(1, "c1", start, step, l_bnd, u_bnd, ierflg); - } + mMn[ih]->mnparm(1, "c1", start, step, l_bnd, u_bnd, ierflg); // Tower 2 // Only two ZEM calorimeters: equalize response @@ -518,20 +543,11 @@ int InterCalib::mini(int ih) step = 0; } - if (ih == HidZPCX) { - mMn[ih]->mnparm(2, "c2", mPar[HidZPC][2], 0, l_bnd, u_bnd, ierflg); - } else { - mMn[ih]->mnparm(2, "c2", start, step, l_bnd, u_bnd, ierflg); - } + mMn[ih]->mnparm(2, "c2", start, step, l_bnd, u_bnd, ierflg); // Towers 3 and 4 - if (ih == HidZPAX) { - mMn[ih]->mnparm(3, "c3", mPar[HidZPA][3], 0, l_bnd, u_bnd, ierflg); - mMn[ih]->mnparm(4, "c4", mPar[HidZPA][4], 0, l_bnd, u_bnd, ierflg); - } else { - mMn[ih]->mnparm(3, "c3", start, step, l_bnd, u_bnd, ierflg); - mMn[ih]->mnparm(4, "c4", start, step, l_bnd, u_bnd, ierflg); - } + mMn[ih]->mnparm(3, "c3", start, step, l_bnd, u_bnd, ierflg); + mMn[ih]->mnparm(4, "c4", start, step, l_bnd, u_bnd, ierflg); // Offset l_bnd = mInterCalibConfig->l_bnd_o[ih]; @@ -551,13 +567,15 @@ int InterCalib::mini(int ih) l_bnd = mInterCalibConfig->l_bnd[ih]; u_bnd = mInterCalibConfig->u_bnd[ih]; for (int i = 1; i <= 4; i++) { - if (TMath::Abs(mPar[ih][i] - l_bnd) < 1e-3 || TMath::Abs(mPar[ih][i] - u_bnd) < 1e-3) { + if (TMath::Abs(mPar[ih][i] - l_bnd) < 1e-2 || TMath::Abs(mPar[ih][i] - u_bnd) < 1e-2) { retry = true; LOG(warn) << "ih=" << ih << " par " << i << " too close to boundaries"; if (ih == 1 || ih == 7) { - mMn[ih]->mnparm(i, parn[i], mTowerParam->tower_calib[IdZPAC + i], 0, l_bnd, u_bnd, ierflg); + // mMn[ih]->mnparm(i, parn[i], mTowerParam->tower_calib[IdZPAC + i], 0, l_bnd, u_bnd, ierflg); + mMn[ih]->mnparm(i, parn[i], mInterCalibConfig->start[ih], 0, l_bnd, u_bnd, ierflg); } else if (ih == 3 || ih == 8) { - mMn[ih]->mnparm(i, parn[i], mTowerParam->tower_calib[IdZPCC + i], 0, l_bnd, u_bnd, ierflg); + // mMn[ih]->mnparm(i, parn[i], mTowerParam->tower_calib[IdZPCC + i], 0, l_bnd, u_bnd, ierflg); + mMn[ih]->mnparm(i, parn[i], mInterCalibConfig->start[ih], 0, l_bnd, u_bnd, ierflg); } else { LOG(fatal) << "ERROR on InterCalib minimization ih=" << ih; } diff --git a/Detectors/ZDC/calib/src/InterCalibConfig.cxx b/Detectors/ZDC/calib/src/InterCalibConfig.cxx index f70420eb6b67a..b65a060255be7 100644 --- a/Detectors/ZDC/calib/src/InterCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/InterCalibConfig.cxx @@ -28,7 +28,11 @@ void InterCalibConfig::print() const } LOG(info) << "xcut_ZPA = " << xcut_ZPA; LOG(info) << "xcut_ZPC = " << xcut_ZPC; - LOG(info) << "tower_cut_ZP = " << tower_cut_ZP; + LOG(info) << "towerCutLow_ZPA = {" << towerCutLow_ZPA[0] << ", " << towerCutLow_ZPA[1] << ", " << towerCutLow_ZPA[2] << ", " << towerCutLow_ZPA[3] << "};"; + LOG(info) << "towerCutHigh_ZPA = {" << towerCutHigh_ZPA[0] << ", " << towerCutHigh_ZPA[1] << ", " << towerCutHigh_ZPA[2] << ", " << towerCutHigh_ZPA[3] << "};"; + LOG(info) << "towerCutLow_ZPC = {" << towerCutLow_ZPC[0] << ", " << towerCutLow_ZPC[1] << ", " << towerCutLow_ZPC[2] << ", " << towerCutLow_ZPC[3] << "};"; + LOG(info) << "towerCutHigh_ZPC = {" << towerCutHigh_ZPC[0] << ", " << towerCutHigh_ZPC[1] << ", " << towerCutHigh_ZPC[2] << ", " << towerCutHigh_ZPC[3] << "};"; + LOG(info) << "rms_cut_ZP = " << rms_cut_ZP; if (cross_check) { LOG(warn) << "THIS IS A CROSS CHECK CONFIGURATION (vs SUM)"; } diff --git a/Detectors/ZDC/calib/src/InterCalibEPN.cxx b/Detectors/ZDC/calib/src/InterCalibEPN.cxx index 3f17d256c042f..1e0ff9587019a 100644 --- a/Detectors/ZDC/calib/src/InterCalibEPN.cxx +++ b/Detectors/ZDC/calib/src/InterCalibEPN.cxx @@ -106,7 +106,7 @@ int InterCalibEPN::process(const gsl::span& RecBC, float x, rms; ev.centroidZPA(x, rms); cumulate(HidZPA, ev.EZDC(IdZPAC), ev.EZDC(IdZPA1), ev.EZDC(IdZPA2), ev.EZDC(IdZPA3), ev.EZDC(IdZPA4), 1.); - if (x < -(mInterCalibConfig->xcut_ZPA)) { + if (x < -(mInterCalibConfig->xcut_ZPA) && rms >= mInterCalibConfig->rms_cut_ZP) { cumulate(HidZPAX, ev.EZDC(IdZPAC), ev.EZDC(IdZPA1), ev.EZDC(IdZPA2), ev.EZDC(IdZPA3), ev.EZDC(IdZPA4), 1.); } } @@ -117,7 +117,7 @@ int InterCalibEPN::process(const gsl::span& RecBC, float x, rms; ev.centroidZPC(x, rms); cumulate(HidZPC, ev.EZDC(IdZPCC), ev.EZDC(IdZPC1), ev.EZDC(IdZPC2), ev.EZDC(IdZPC3), ev.EZDC(IdZPC4), 1.); - if (x > (mInterCalibConfig->xcut_ZPC)) { + if (x > (mInterCalibConfig->xcut_ZPC) && rms >= mInterCalibConfig->rms_cut_ZP) { cumulate(HidZPCX, ev.EZDC(IdZPCC), ev.EZDC(IdZPC1), ev.EZDC(IdZPC2), ev.EZDC(IdZPC3), ev.EZDC(IdZPC4), 1.); } } @@ -266,22 +266,33 @@ void InterCalibEPN::clear(int ih) void InterCalibEPN::cumulate(int ih, double tc, double t1, double t2, double t3, double t4, double w = 1) { + constexpr double minfty = -std::numeric_limits::infinity(); // printf("%s: ih=%d tc=%g t1=%g t2=%g t3=%g t4=%g w=%g\n",__func__,ih, tc, t1, t2, t3, t4, w); fflush(stdout); if (tc < mInterCalibConfig->cutLow[ih] || tc > mInterCalibConfig->cutHigh[ih]) { return; } - if ((ih == 7 || ih == 8) && (t1 < mInterCalibConfig->tower_cut_ZP || t2 < mInterCalibConfig->tower_cut_ZP || t3 < mInterCalibConfig->tower_cut_ZP || t4 < mInterCalibConfig->tower_cut_ZP)) { - return; + if ((ih == HidZPA || ih == HidZPAX)) { + if (t1 < mInterCalibConfig->towerCutLow_ZPA[0] || t2 < mInterCalibConfig->towerCutLow_ZPA[1] || t3 < mInterCalibConfig->towerCutLow_ZPA[2] || t4 < mInterCalibConfig->towerCutLow_ZPA[4]) { + return; + } + if (t1 > mInterCalibConfig->towerCutHigh_ZPA[0] || t2 > mInterCalibConfig->towerCutHigh_ZPA[1] || t3 > mInterCalibConfig->towerCutHigh_ZPA[2] || t4 > mInterCalibConfig->towerCutHigh_ZPA[4]) { + return; + } } - double val[NPAR] = {0, 0, 0, 0, 0, 1}; - val[0] = tc; - val[1] = t1; - val[2] = t2; - val[3] = t3; - val[4] = t4; - for (int32_t i = 0; i < NPAR; i++) { - for (int32_t j = i; j < NPAR; j++) { - mData.mSum[ih][i][j] += val[i] * val[j] * w; + if (ih == HidZPC || ih == HidZPCX) { + if (t1 < mInterCalibConfig->towerCutLow_ZPC[0] || t2 < mInterCalibConfig->towerCutLow_ZPC[1] || t3 < mInterCalibConfig->towerCutLow_ZPC[2] || t4 < mInterCalibConfig->towerCutLow_ZPC[4]) { + return; + } + if (t1 > mInterCalibConfig->towerCutHigh_ZPC[0] || t2 > mInterCalibConfig->towerCutHigh_ZPC[1] || t3 > mInterCalibConfig->towerCutHigh_ZPC[2] || t4 > mInterCalibConfig->towerCutHigh_ZPC[4]) { + return; + } + } + double val[NPAR] = {tc, t1, t2, t3, t4, 1}; + if (tc > minfty && t1 > minfty && t2 > minfty && t3 > minfty && t4 > minfty) { + for (int32_t i = 0; i < NPAR; i++) { + for (int32_t j = i; j < NPAR; j++) { + mData.mSum[ih][i][j] += val[i] * val[j] * w; + } } } // mData.mSum[ih][5][5] contains the number of analyzed events diff --git a/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx index f0aeff5d53fc7..923d53f27f734 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibConfig.cxx @@ -20,9 +20,10 @@ WaveformCalibConfig::WaveformCalibConfig() cutLow[isig] = -std::numeric_limits::infinity(); cutHigh[isig] = std::numeric_limits::infinity(); } + // Firmware aligns signals within one sample for (int itdc = 0; itdc < NTDCChannels; itdc++) { - cutTimeLow[itdc] = -1.25; - cutTimeHigh[itdc] = 1.25; + cutTimeHigh[itdc] = o2::constants::lhc::LHCBunchSpacingNS / NTimeBinsPerBC; + cutTimeLow[itdc] = -cutTimeHigh[itdc]; } } diff --git a/Detectors/ZDC/calib/src/WaveformCalibData.cxx b/Detectors/ZDC/calib/src/WaveformCalibData.cxx index 759d85a6a0f88..a326242e21433 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibData.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibData.cxx @@ -187,6 +187,21 @@ int WaveformCalibData::saveDebugHistos(const std::string fn) return 0; } +//______________________________________________________________________________ +int WaveformCalibData::dumpCalib(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; + } + f->WriteObjectAny((void*)this, o2::zdc::WaveformCalibData::Class(), "WaveformCalibData"); + f->Close(); + cwd->cd(); + return 0; +} + //______________________________________________________________________________ void WaveformCalibData::clear() { diff --git a/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx index cda158e9f5b6a..02e9bc15a933f 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibEPN.cxx @@ -41,6 +41,10 @@ int WaveformCalibEPN::init() setSaveDebugHistos(); } + if (opt.dumpCalib == true) { + setDumpCalib(); + } + mQueue.configure(cfg); if (mVerbosity > DbgZero) { mQueue.printConf(); @@ -99,6 +103,7 @@ int WaveformCalibEPN::process(const gsl::span& RecBC, #endif if (mask != 0) { #ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + // Print last recorded event. Not the event at peak position ev.print(); ev.printDecodedMessages(); mQueue.print(); @@ -122,17 +127,25 @@ int WaveformCalibEPN::endOfRun() if (mVerbosity > DbgZero) { LOGF(info, "WaveformCalibEPN::endOfRun ts (%llu:%llu)", mData.mCTimeBeg, mData.mCTimeEnd); for (int is = 0; is < NChannels; is++) { + int itdc = SignalTDC[is]; if (mData.getEntries(is) > 0) { - int itdc = SignalTDC[is]; LOGF(info, "Waveform %2d %s with %10d events and cuts AMP:(%g:%g) TDC:%d:(%g:%g) Valid:[%d:%d:%d]", is, ChannelNames[is].data(), mData.getEntries(is), mConfig->cutLow[is], mConfig->cutHigh[is], itdc, mConfig->cutTimeLow[itdc], mConfig->cutTimeHigh[itdc], mData.getFirstValid(is), mData.mPeak, mData.getLastValid(is)); + } else { + LOGF(info, "Waveform %2d %s with %10d events and cuts AMP:(%g:%g) TDC:%d:(%g:%g)", is, ChannelNames[is].data(), + mData.getEntries(is), mConfig->cutLow[is], mConfig->cutHigh[is], + itdc, mConfig->cutTimeLow[itdc], mConfig->cutTimeHigh[itdc]); } } } + const auto& opt = CalibParamZDC::Instance(); if (mSaveDebugHistos) { - saveDebugHistos(); + saveDebugHistos(opt.outputDir + "ZDCWaveformCalibEPN.root"); + } + if (mDumpCalib) { + dumpCalib(opt.outputDir + "ZDCWaveformCalibEPNDump.root"); } return 0; } @@ -142,3 +155,9 @@ int WaveformCalibEPN::saveDebugHistos(const std::string fn) { return mData.saveDebugHistos(fn); } + +//______________________________________________________________________________ +int WaveformCalibEPN::dumpCalib(const std::string fn) +{ + return mData.dumpCalib(fn); +} diff --git a/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx index c62306f21b1ad..76d66c7577029 100644 --- a/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx +++ b/Detectors/ZDC/calib/src/WaveformCalibQueue.cxx @@ -201,6 +201,9 @@ int WaveformCalibQueue::hasData(int isig, const gsl::span& wave, WaveformCalibData& data) { +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << "WaveformCalibQueue::" << __func__ << " isig=" << isig << " " << ChannelNames[isig] << " tdcid=" << SignalTDC[isig] << " tdc_sig=" << TDCSignal[SignalTDC[isig]] << " " << ChannelNames[TDCSignal[SignalTDC[isig]]]; +#endif int ipkb = -1; // Bunch where peak is found int ipk = -1; // peak position within bunch float min = std::numeric_limits::infinity(); @@ -213,7 +216,7 @@ int WaveformCalibQueue::addData(int isig, const gsl::spancutLow[isig] || amp > mCfg->cutHigh[isig]) { // No warning messages for amplitude cuts on towers +#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG + LOG(info) << " isig = " << isig << " amplitude " << amp << " not in range " << mCfg->cutLow[isig] << " : " << mCfg->cutHigh[isig]; +#endif return -1; } if ((ppos - mPeak) < mTimeLow[itdc] || (ppos - mPeak) > mTimeHigh[itdc]) { diff --git a/Detectors/ZDC/reconstruction/CMakeLists.txt b/Detectors/ZDC/reconstruction/CMakeLists.txt index f06819f8e2cf8..ea4b4b60d22b5 100644 --- a/Detectors/ZDC/reconstruction/CMakeLists.txt +++ b/Detectors/ZDC/reconstruction/CMakeLists.txt @@ -13,6 +13,7 @@ o2_add_library(ZDCReconstruction SOURCES src/CTFCoder.cxx src/CTFHelper.cxx src/DigiReco.cxx + src/DigiParser.cxx src/RecoParamZDC.cxx src/ZDCTDCParam.cxx src/ZDCEnergyParam.cxx diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiParser.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiParser.h new file mode 100644 index 0000000000000..41e389403aa73 --- /dev/null +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/DigiParser.h @@ -0,0 +1,98 @@ +// 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 "Framework/Logger.h" +#include "ZDCBase/Constants.h" +#include "ZDCSimulation/ZDCSimParam.h" +#include "ZDCReconstruction/RecoParamZDC.h" +#include "ZDCReconstruction/ZDCTDCParam.h" +#include "ZDCReconstruction/ZDCTDCCorr.h" +#include "ZDCReconstruction/ZDCEnergyParam.h" +#include "ZDCReconstruction/ZDCTowerParam.h" +#include "ZDCReconstruction/BaselineParam.h" +#include "ZDCReconstruction/RecoConfigZDC.h" +#include "ZDCBase/ModuleConfig.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/RecEventAux.h" + +#ifndef ALICEO2_ZDC_DIGI_PARSER_H +#define ALICEO2_ZDC_DIGI_PARSER_H + +namespace o2 +{ +namespace zdc +{ + +class DigiParser +{ + public: + DigiParser() = default; + ~DigiParser() = default; + void init(); + int process(const gsl::span& orbitdata, + const gsl::span& bcdata, + const gsl::span& chdata); + void setVerbosity(int v) + { + mVerbosity = v; + } + int getVerbosity() const { return mVerbosity; } + void setOutput(std::string output) + { + mOutput = output; + } + void setRejectPileUp(bool op = true) + { + mRejectPileUp = op; + } + void eor(); + + void setModuleConfig(const ModuleConfig* moduleConfig) { mModuleConfig = moduleConfig; }; + const ModuleConfig* getModuleConfig() { return mModuleConfig; }; + + private: + const ModuleConfig* mModuleConfig = nullptr; /// Trigger/readout configuration object + const RecoParamZDC* mRopt = nullptr; + + void setStat(TH1* h); + void setModuleLabel(TH1* h); + void setModuleLabel(TAxis* ax); + + int32_t mVerbosity = DbgMinimal; + bool mRejectPileUp = true; + std::string mOutput = "ZDCDigiParser.root"; + uint32_t mTriggerMask = 0; /// Mask of triggering channels + uint32_t mChMask[NChannels] = {0}; /// Identify all channels in readout pattern + + std::unique_ptr mTransmitted = nullptr; + std::unique_ptr mFired = nullptr; + std::unique_ptr mBaseline[NChannels] = {nullptr}; + std::unique_ptr mCounts[NChannels] = {nullptr}; + std::unique_ptr mSignalTH[NChannels] = {nullptr}; + std::unique_ptr mBunchH[NChannels] = {nullptr}; // Bunch pattern Hit + std::unique_ptr mAlignment; + + int mNBC = 0; +}; +} // namespace zdc +} // namespace o2 +#endif diff --git a/Detectors/ZDC/reconstruction/src/DigiParser.cxx b/Detectors/ZDC/reconstruction/src/DigiParser.cxx new file mode 100644 index 0000000000000..7b85faec3490e --- /dev/null +++ b/Detectors/ZDC/reconstruction/src/DigiParser.cxx @@ -0,0 +1,298 @@ +// 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 "Framework/Logger.h" +#include "CommonConstants/LHCConstants.h" +#include "ZDCReconstruction/DigiParser.h" +#include "ZDCReconstruction/RecoParamZDC.h" + +namespace o2 +{ +namespace zdc +{ + +void DigiParser::init() +{ + LOG(info) << "Initialization of ZDC DigiParser"; + if (!mModuleConfig) { + LOG(fatal) << "Missing ModuleConfig configuration object"; + return; + } + + mTriggerMask = mModuleConfig->getTriggerMask(); + + // Update reconstruction parameters + o2::zdc::RecoParamZDC& ropt = const_cast(RecoParamZDC::Instance()); + ropt.print(); + mRopt = (o2::zdc::RecoParamZDC*)&ropt; + + // Fill maps channel maps for integration + for (int ich = 0; ich < NChannels; ich++) { + // If the reconstruction parameters were not manually set + if (ropt.amod[ich] < 0 || ropt.ach[ich] < 0) { + for (int im = 0; im < NModules; im++) { + for (uint32_t ic = 0; ic < NChPerModule; ic++) { + if (mModuleConfig->modules[im].channelID[ic] == ich && mModuleConfig->modules[im].readChannel[ic]) { + ropt.amod[ich] = im; + ropt.ach[ich] = ic; + // Fill mask to identify all channels + mChMask[ich] = (0x1 << (4 * im + ic)); + goto next_ich; + } + } + } + } else { + // Fill mask to identify all channels + mChMask[ich] = (0x1 << (4 * ropt.amod[ich] + ropt.ach[ich])); + } + next_ich:; + if (mVerbosity > DbgZero) { + LOG(info) << "Channel " << ich << "(" << ChannelNames[ich] << ") mod " << ropt.amod[ich] << " ch " << ropt.ach[ich] << " bit " << (4 * ropt.amod[ich] + ropt.ach[ich]); + } + } + + double xmin = -3 * NTimeBinsPerBC - 0.5; + double xmax = 2 * NTimeBinsPerBC - 0.5; + int nbx = std::round(xmax - xmin); + + if (mTransmitted == nullptr) { + mTransmitted = std::make_unique("ht", "Transmitted channels", NChannels, -0.5, NChannels - 0.5); + } + if (mFired == nullptr) { + mFired = std::make_unique("hfired", "Fired channels", NChannels, -0.5, NChannels - 0.5); + } + if (mAlignment == nullptr) { + mAlignment = std::make_unique("hmap", "Map of fired channels", o2::constants::lhc::LHCMaxBunches, -0.5, o2::constants::lhc::LHCMaxBunches-0.5, NChannels, -0.5, NChannels - 0.5); + } + for (uint32_t ich = 0; ich < NChannels; ich++) { + if (mBaseline[ich] == nullptr) { + TString hname = TString::Format("hp_%s", ChannelNames[ich].data()); + TString htit = TString::Format("Baseline %s;Average orbit baseline", ChannelNames[ich].data()); + mBaseline[ich] = std::make_unique(hname, htit, 65536, -32768.5, 32767.5); + } + if (mCounts[ich] == nullptr) { + TString hname = TString::Format("hc_%s", ChannelNames[ich].data()); + TString htit = TString::Format("Counts %s; Orbit hits", ChannelNames[ich].data()); + mCounts[ich] = std::make_unique(hname, htit, o2::constants::lhc::LHCMaxBunches + 1, -0.5, o2::constants::lhc::LHCMaxBunches + 0.5); + } + if (mSignalTH[ich] == nullptr) { + TString hname = TString::Format("hsth_%s", ChannelNames[ich].data()); + TString htit = TString::Format("Signal %s AUTOT & Hit; Sample; ADC", ChannelNames[ich].data()); + if (mRejectPileUp) { + mSignalTH[ich] = std::make_unique(hname, htit, 3 * NTimeBinsPerBC, -0.5 - 1 * NTimeBinsPerBC, 2 * NTimeBinsPerBC - 0.5, ADCRange, ADCMin - 0.5, ADCMax + 0.5); + } else { + mSignalTH[ich] = std::make_unique(hname, htit, 5 * NTimeBinsPerBC, -0.5 - 3 * NTimeBinsPerBC, 2 * NTimeBinsPerBC - 0.5, ADCRange, ADCMin - 0.5, ADCMax + 0.5); + } + } + if (mBunchH[ich] == nullptr) { + TString hname = TString::Format("hbh_%s", ChannelNames[ich].data()); + TString htit = TString::Format("Bunch %s AUTOT Hit; BC units; - BC hundreds", ChannelNames[ich].data()); + mBunchH[ich] = std::make_unique(hname, htit, 100, -0.5, 99.5, 36, -35.5, 0.5); + } + } +} // init + +void DigiParser::eor() +{ + TFile* f = new TFile(mOutput.data(), "recreate"); + if (f->IsZombie()) { + LOG(fatal) << "Cannot write to file " << f->GetName(); + return; + } + for (uint32_t i = 0; i < NChannels; i++) { + setStat(mBunchH[i].get()); + mBunchH[i]->Write(); + } + for (uint32_t i = 0; i < NChannels; i++) { + setStat(mBaseline[i].get()); + mBaseline[i]->Write(); + } + for (uint32_t i = 0; i < NChannels; i++) { + setStat(mCounts[i].get()); + mCounts[i]->Write(); + } + for (uint32_t i = 0; i < NChannels; i++) { + setStat(mSignalTH[i].get()); + mSignalTH[i]->Write(); + } + setModuleLabel(mTransmitted.get()); + mTransmitted->SetMinimum(0); + mTransmitted->Write(); + setModuleLabel(mFired.get()); + mFired->SetMinimum(0); + mFired->Write(); + setModuleLabel((mAlignment.get())->GetYaxis()); + mAlignment->SetMinimum(0); + mAlignment->Write(); + f->Close(); +} + +int DigiParser::process(const gsl::span& orbitdata, const gsl::span& bcdata, const gsl::span& chdata) +{ + // We assume that vectors contain data from a full time frame + int norb = orbitdata.size(); + + uint32_t scaler[NChannels] = {0}; + for (int iorb = 0; iorb < norb; iorb++) { + for (int ich = 0; ich < NChannels; ich++) { + if (orbitdata[iorb].scaler[ich] <= o2::constants::lhc::LHCMaxBunches) { + scaler[ich] += orbitdata[iorb].scaler[ich]; + mCounts[ich]->Fill(orbitdata[iorb].scaler[ich]); + auto myped = float(orbitdata[iorb].data[ich]) * mModuleConfig->baselineFactor; + if (myped >= ADCMin && myped <= ADCMax) { + // Pedestal information is present for this channel + mBaseline[ich]->Fill(myped); + } + } else { + LOG(warn) << "Corrupted scaler data for orbit " << orbitdata[iorb].ir.orbit; + } + } + } + + mNBC = bcdata.size(); + std::vector> chRef; /// Cache of references + chRef.resize(mNBC); + + // Assign data references + for (int ibc = 0; ibc < mNBC; ibc++) { + auto& bcd = bcdata[ibc]; + int chEnt = bcd.ref.getFirstEntry(); + for (int ich = 0; ich < NChannels; ich++) { + chRef[ibc][ich] = ZDCRefInitVal; + } + for (int ic = 0; ic < bcd.ref.getEntries(); ic++) { + auto& chd = chdata[chEnt]; + if (chd.id > IdDummy && chd.id < NChannels) { + chRef[ibc][chd.id] = chEnt; + mTransmitted->Fill(chd.id); + if ((bcdata[ibc].triggers & mChMask[chd.id]) != 0) { + mFired->Fill(chd.id); + } + } + chEnt++; + } + } + + for (uint32_t isig = 0; isig < NChannels; isig++) { + for (int ibc = 0; ibc < mNBC; ibc++) { + auto& ir = bcdata[ibc].ir; + // Identify pile-up + if (mRejectPileUp) { + int nsig = 0; + // Check previous bunches + for (int ibn = -4; ibn < 5; ibn++) { + int ibt = ibc + ibn; + if (ibt >= 0) { // Check backward and current bunch + if (ibt < mNBC) { + auto bcd = bcdata[ibt].ir.differenceInBC(ir); + if (bcd == ibn) { + if ((bcdata[ibt].triggers & mChMask[isig]) != 0) { + nsig++; + } + } + } else { + break; + } + } + } + if (nsig > 1) { + continue; + } + } + // Check previous, current and next bunch crossings + for (int ibn = -1; ibn < 4; ibn++) { + int ibt = ibc + ibn; + if (ibt >= 0) { // Check backward and current bunch + if (ibt < mNBC) { // Check forward bunches + auto bcd = bcdata[ibt].ir.differenceInBC(ir); + if (bcd == 0) { + // Fill bunch map + if ((bcdata[ibc].triggers & mChMask[isig]) != 0) { + double bc_d = uint32_t(ir.bc / 100); + double bc_m = uint32_t(ir.bc % 100); + mBunchH[isig]->Fill(bc_m, -bc_d); + mFired->Fill(isig); + mAlignment->Fill(ir.bc, isig); + } + } + if (bcd == ibn) { + if ((bcdata[ibt].triggers & mChMask[isig]) != 0) { + // Fill waveform + auto ref = chRef[ibc][isig]; + if (ref != ZDCRefInitVal) { + for (int is = 0; is < NTimeBinsPerBC; is++) { + mSignalTH[isig]->Fill(-ibn * NTimeBinsPerBC + is, chdata[ref].data[is]); + } + } + } + } + } else { + break; + } + } + } + } + } + return 0; +} // process + +void DigiParser::setStat(TH1* h) +{ + TString hn = h->GetName(); + h->Draw(); + gPad->Update(); + TPaveStats* st = (TPaveStats*)h->GetListOfFunctions()->FindObject("stats"); + st->SetFillStyle(1001); + st->SetBorderSize(1); + if (hn.BeginsWith("hp")) { + st->SetOptStat(111111); + st->SetX1NDC(0.1); + st->SetX2NDC(0.3); + st->SetY1NDC(0.640); + st->SetY2NDC(0.9); + } else if (hn.BeginsWith("hc")) { + st->SetOptStat(1111); + st->SetX1NDC(0.799); + st->SetX2NDC(0.999); + st->SetY1NDC(0.829); + st->SetY2NDC(0.999); + } else if (hn.BeginsWith("hs") || hn.BeginsWith("hb")) { + st->SetOptStat(11); + st->SetX1NDC(0.799); + st->SetX2NDC(0.9995); + st->SetY1NDC(0.904); + st->SetY2NDC(0.999); + } +} + +void DigiParser::setModuleLabel(TH1* h) +{ + for (uint32_t isig = 0; isig < NChannels; isig++) { + h->GetXaxis()->SetBinLabel(isig + 1, ChannelNames[isig].data()); + } +} + +void DigiParser::setModuleLabel(TAxis* ax) +{ + for (uint32_t isig = 0; isig < NChannels; isig++) { + ax->SetBinLabel(isig + 1, ChannelNames[isig].data()); + } +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/reconstruction/src/DigiReco.cxx b/Detectors/ZDC/reconstruction/src/DigiReco.cxx index 397e2aef63f1c..50a8ceeb13691 100644 --- a/Detectors/ZDC/reconstruction/src/DigiReco.cxx +++ b/Detectors/ZDC/reconstruction/src/DigiReco.cxx @@ -68,6 +68,9 @@ void DigiReco::init() } } } + } else { + // Fill mask to identify TDC channels + mTDCMask[itdc] = (0x1 << (4 * ropt.tmod[itdc] + ropt.tch[itdc])); } next_itdc:; if (mVerbosity > DbgZero) { @@ -356,6 +359,9 @@ void DigiReco::init() } } } + } else { + // Fill mask to identify all channels + mChMask[ich] = (0x1 << (4 * ropt.amod[ich] + ropt.ach[ich])); } next_ich:; if (mVerbosity > DbgZero) { diff --git a/Detectors/ZDC/workflow/CMakeLists.txt b/Detectors/ZDC/workflow/CMakeLists.txt index 90de7e1bc2659..21de8322a81fe 100644 --- a/Detectors/ZDC/workflow/CMakeLists.txt +++ b/Detectors/ZDC/workflow/CMakeLists.txt @@ -20,7 +20,9 @@ o2_add_library(ZDCWorkflow src/RecoWorkflow.cxx src/DigitRecoSpec.cxx src/DigitReaderSpec.cxx + src/DigitParserSpec.cxx src/RecoReaderSpec.cxx + src/ParserWorkflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsZDC O2::ZDCRaw @@ -64,3 +66,9 @@ o2_add_executable(digits-writer COMPONENT_NAME zdc SOURCES src/digits-writer-workflow.cxx PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCReconstruction) + +o2_add_executable(digits-parser + COMPONENT_NAME zdc + SOURCES src/zdc-parser-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::ZDCWorkflow O2::ZDCReconstruction) + diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitParserSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitParserSpec.h new file mode 100644 index 0000000000000..e7e64b52862e7 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitParserSpec.h @@ -0,0 +1,58 @@ +// 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 DigitRecoSpec.h +/// @brief Run ZDC digits reconstruction +/// @author pietro.cortese@cern.ch + +#ifndef O2_ZDC_DIGITPARSER_SPEC +#define O2_ZDC_DIGITPARSER_SPEC + +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataAllocator.h" +#include "Framework/DataSpecUtils.h" +#include "Framework/Task.h" +#include +#include "CommonUtils/NameConf.h" +#include "ZDCReconstruction/DigiParser.h" + +namespace o2 +{ +namespace zdc +{ + +class DigitParserSpec : public o2::framework::Task +{ + public: + DigitParserSpec(); + DigitParserSpec(const int verbosity); + ~DigitParserSpec() override = default; + void init(o2::framework::InitContext& ic) final; + void updateTimeDependentParams(o2::framework::ProcessingContext& pc); + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + private: + DigiParser mWorker; // Reconstruction object + int mVerbosity = 0; // Verbosity level during recostruction + bool mInitialized = false; // Connect once to CCDB during initialization + TStopwatch mTimer; +}; + +/// create a processor spec +framework::DataProcessorSpec getDigitParserSpec(const int verbosity); + +} // namespace zdc +} // namespace o2 + +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h index 8141fdeb46dfe..1d7f6ccfbc50b 100644 --- a/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/DigitRecoSpec.h @@ -34,8 +34,7 @@ class DigitRecoSpec : public o2::framework::Task { public: DigitRecoSpec(); - DigitRecoSpec(const int verbosity, const bool debugOut, - const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam); + DigitRecoSpec(const int verbosity, const bool debugOut, const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam); ~DigitRecoSpec() override = default; void init(o2::framework::InitContext& ic) final; void updateTimeDependentParams(o2::framework::ProcessingContext& pc); diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/ParserWorkflow.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/ParserWorkflow.h new file mode 100644 index 0000000000000..0aced0b444983 --- /dev/null +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/ParserWorkflow.h @@ -0,0 +1,26 @@ +// 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_PARSERWORKFLOW_H +#define O2_ZDC_PARSERWORKFLOW_H + +/// @file ParserWorkflow.h + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace zdc +{ +framework::WorkflowSpec getParserWorkflow(const int verbosity); +} // namespace zdc +} // namespace o2 +#endif diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h index a06e768377ad9..3df76af188c1b 100644 --- a/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/RecoWorkflow.h @@ -20,8 +20,7 @@ namespace o2 { namespace zdc { -framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut, - const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam); +framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut, const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam); } // namespace zdc } // namespace o2 #endif diff --git a/Detectors/ZDC/workflow/src/DigitParserSpec.cxx b/Detectors/ZDC/workflow/src/DigitParserSpec.cxx new file mode 100644 index 0000000000000..b761de6d2d9ff --- /dev/null +++ b/Detectors/ZDC/workflow/src/DigitParserSpec.cxx @@ -0,0 +1,128 @@ +// 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 DigitParserSpec.cxx +/// @brief ZDC digits parser +/// @author pietro.cortese@cern.ch + +#include +#include +#include +#include +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "Framework/Logger.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "ZDCWorkflow/DigitParserSpec.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsZDC/BCData.h" +#include "DataFormatsZDC/ChannelData.h" +#include "DataFormatsZDC/OrbitData.h" +#include "ZDCBase/ModuleConfig.h" +#include "CommonUtils/NameConf.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace zdc +{ + +DigitParserSpec::DigitParserSpec() +{ + mTimer.Stop(); + mTimer.Reset(); +} + +DigitParserSpec::DigitParserSpec(const int verbosity) : mVerbosity(verbosity) +{ + mTimer.Stop(); + mTimer.Reset(); +} + +void DigitParserSpec::init(o2::framework::InitContext& ic) +{ + mWorker.setOutput(ic.options().get("parser-output")); + mWorker.setRejectPileUp((ic.options().get("reject-pileup")) != 0); +} + +void DigitParserSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + // we call these methods just to trigger finaliseCCDB callback + pc.inputs().get("moduleconfig"); +} + +void DigitParserSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) +{ + if (matcher == ConcreteDataMatcher("ZDC", "MODULECONFIG", 0)) { + auto* config = (const o2::zdc::ModuleConfig*)obj; + if (mVerbosity > DbgZero) { + config->print(); + } + mWorker.setModuleConfig(config); + } +} + +void DigitParserSpec::run(ProcessingContext& pc) +{ + if (!mInitialized) { + LOG(info) << "DigitParserSpec::run initialization"; + mInitialized = true; + updateTimeDependentParams(pc); + mWorker.setVerbosity(mVerbosity); + mWorker.init(); + } + auto cput = mTimer.CpuTime(); + mTimer.Start(false); + + auto bcdata = pc.inputs().get>("trig"); + auto chans = pc.inputs().get>("chan"); + auto peds = pc.inputs().get>("peds"); + + int rval = mWorker.process(peds, bcdata, chans); + if (rval != 0) { + LOG(warning) << bcdata.size() << " BC " << chans.size() << " CH " << peds.size() << " OD -> processing ended in ERROR @ line " << rval; + } + mTimer.Stop(); +} + +void DigitParserSpec::endOfStream(EndOfStreamContext& ec) +{ + mWorker.eor(); + LOGF(info, "ZDC digits parsing total time: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); +} + +framework::DataProcessorSpec getDigitParserSpec(const int verbosity = 0) +{ + std::vector inputs; + inputs.emplace_back("trig", "ZDC", "DIGITSBC", 0, Lifetime::Timeframe); + inputs.emplace_back("chan", "ZDC", "DIGITSCH", 0, Lifetime::Timeframe); + inputs.emplace_back("peds", "ZDC", "DIGITSPD", 0, Lifetime::Timeframe); + inputs.emplace_back("moduleconfig", "ZDC", "MODULECONFIG", 0, Lifetime::Condition, o2::framework::ccdbParamSpec(o2::zdc::CCDBPathConfigModule.data())); + + std::vector outputs; + + return DataProcessorSpec{ + "zdc-digi-parser", + inputs, + outputs, + AlgorithmSpec{adaptFromTask(verbosity)}, + o2::framework::Options{{"parser-output", o2::framework::VariantType::String, "ZDCDigiParser.root", {"Output file name"}}, + {"reject-pileup", o2::framework::VariantType::Int, 1, {"Reject pile-up for signal shapes 0/1"}}}}; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx index e9b63c5b49d5b..8f0ab82fa5b9b 100644 --- a/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx +++ b/Detectors/ZDC/workflow/src/DigitRecoSpec.cxx @@ -275,12 +275,10 @@ void DigitRecoSpec::run(ProcessingContext& pc) void DigitRecoSpec::endOfStream(EndOfStreamContext& ec) { mWorker.eor(); - LOGF(info, "ZDC Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); + LOGF(info, "ZDC Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -framework::DataProcessorSpec getDigitRecoSpec(const int verbosity = 0, const bool enableDebugOut = true, - const bool enableZDCTDCCorr = true, const bool enableZDCEnergyParam = true, const bool enableZDCTowerParam = true, const bool enableBaselineParam = true) +framework::DataProcessorSpec getDigitRecoSpec(const int verbosity = 0, const bool enableDebugOut = true, const bool enableZDCTDCCorr = true, const bool enableZDCEnergyParam = true, const bool enableZDCTowerParam = true, const bool enableBaselineParam = true) { std::vector inputs; inputs.emplace_back("trig", "ZDC", "DIGITSBC", 0, Lifetime::Timeframe); diff --git a/Detectors/ZDC/workflow/src/ParserWorkflow.cxx b/Detectors/ZDC/workflow/src/ParserWorkflow.cxx new file mode 100644 index 0000000000000..bb8c193262627 --- /dev/null +++ b/Detectors/ZDC/workflow/src/ParserWorkflow.cxx @@ -0,0 +1,31 @@ +// 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 ParserWorkflow.cxx + +#include "ZDCWorkflow/ParserWorkflow.h" +#include "ZDCWorkflow/DigitReaderSpec.h" +#include "ZDCWorkflow/DigitParserSpec.h" + +namespace o2 +{ +namespace zdc +{ + +framework::WorkflowSpec getParserWorkflow(const int verbosity) +{ + framework::WorkflowSpec specs; + specs.emplace_back(o2::zdc::getDigitParserSpec(verbosity)); + return specs; +} + +} // namespace zdc +} // namespace o2 diff --git a/Detectors/ZDC/workflow/src/RecoReaderSpec.cxx b/Detectors/ZDC/workflow/src/RecoReaderSpec.cxx index ebea51c932c5c..33b2b59d8247b 100644 --- a/Detectors/ZDC/workflow/src/RecoReaderSpec.cxx +++ b/Detectors/ZDC/workflow/src/RecoReaderSpec.cxx @@ -22,6 +22,8 @@ #include "DataFormatsZDC/BCData.h" #include "DataFormatsZDC/ChannelData.h" #include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/RecEvent.h" +#include "DataFormatsZDC/ZDCWaveform.h" #include "CommonUtils/NameConf.h" using namespace o2::framework; @@ -33,8 +35,7 @@ namespace zdc void RecoReader::init(InitContext& ic) { - auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), - ic.options().get("zdc-reco-infile")); + auto filename = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), ic.options().get("zdc-reco-infile")); mFile.reset(TFile::Open(filename.c_str())); if (!mFile->IsOpen()) { LOG(error) << "Cannot open the " << filename.c_str() << " file !"; @@ -54,20 +55,24 @@ void RecoReader::run(ProcessingContext& pc) std::vector Energy, *EnergyPtr = &Energy; std::vector TDCData, *TDCDataPtr = &TDCData; std::vector Info, *InfoPtr = &Info; + std::vector WaveformData, *WaveformDataPtr = &WaveformData; mTree->SetBranchAddress("ZDCRecBC", &RecBCPtr); mTree->SetBranchAddress("ZDCRecE", &EnergyPtr); mTree->SetBranchAddress("ZDCRecTDC", &TDCDataPtr); mTree->SetBranchAddress("ZDCRecInfo", &InfoPtr); + mTree->SetBranchAddress("ZDCWaveform", &WaveformDataPtr); auto ent = mTree->GetReadEntry() + 1; assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(info) << "ZDCRecoReader pushed " << RecBC.size() << " b.c. " << Energy.size() << " Energies " << TDCData.size() << " TDCs " << Info.size() << " Infos"; + LOG(info) << "ZDCRecoReader pushed " << RecBC.size() << " b.c. " << Energy.size() << " Energies " << TDCData.size() << " TDCs " << Info.size() << " Infos " << WaveformData.size() << " Waveform chunks"; pc.outputs().snapshot(Output{"ZDC", "BCREC", 0}, RecBC); pc.outputs().snapshot(Output{"ZDC", "ENERGY", 0}, Energy); pc.outputs().snapshot(Output{"ZDC", "TDCDATA", 0}, TDCData); pc.outputs().snapshot(Output{"ZDC", "INFO", 0}, Info); + pc.outputs().snapshot(Output{"ZDC", "WAVE", 0}, WaveformData); + if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me); @@ -81,6 +86,8 @@ DataProcessorSpec getRecoReaderSpec() 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-reco-reader", Inputs{}, @@ -88,6 +95,7 @@ DataProcessorSpec getRecoReaderSpec() AlgorithmSpec{adaptFromTask()}, Options{ {"zdc-reco-infile", VariantType::String, "zdcreco.root", {"Name of the input file"}}, + {"enable-waveform", VariantType::Bool, false, {"Read waveform data"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } diff --git a/Detectors/ZDC/workflow/src/RecoWorkflow.cxx b/Detectors/ZDC/workflow/src/RecoWorkflow.cxx index b93a86f6237b5..3004f045d8237 100644 --- a/Detectors/ZDC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ZDC/workflow/src/RecoWorkflow.cxx @@ -22,8 +22,7 @@ namespace o2 namespace zdc { -framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut, - const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam) +framework::WorkflowSpec getRecoWorkflow(const bool useMC, const bool disableRootInp, const bool disableRootOut, const int verbosity, const bool enableDebugOut, const bool enableZDCTDCCorr, const bool enableZDCEnergyParam, const bool enableZDCTowerParam, const bool enableBaselineParam) { framework::WorkflowSpec specs; if (!disableRootInp) { diff --git a/Detectors/ZDC/workflow/src/zdc-parser-workflow.cxx b/Detectors/ZDC/workflow/src/zdc-parser-workflow.cxx new file mode 100644 index 0000000000000..19e31dfa48129 --- /dev/null +++ b/Detectors/ZDC/workflow/src/zdc-parser-workflow.cxx @@ -0,0 +1,60 @@ +// 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 "ZDCWorkflow/ParserWorkflow.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +void customize(std::vector& policies) +{ + // ordered policies for the writers + policies.push_back(CompletionPolicyHelpers::consumeWhenAllOrdered(".*(?:ZDC|zdc).*[W,w]riter.*")); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.push_back(ConfigParamSpec{"verbosity-level", VariantType::Int, 0, {"verbosity level"}}); + 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) +{ + LOG(info) << "WorkflowSpec defineDataProcessing"; + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + + auto verbosity = configcontext.options().get("verbosity-level"); + + auto wf = o2::zdc::getParserWorkflow(verbosity); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); + + return std::move(wf); +}