diff --git a/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt index 96ebf4ead4b7b..89775e22ed8d0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/base/CMakeLists.txt @@ -11,11 +11,13 @@ o2_add_library(TRKBase SOURCES src/GeometryTGeo.cxx + src/AlmiraParam.cxx src/TRKBaseParam.cxx src/SegmentationChip.cxx PUBLIC_LINK_LIBRARIES O2::DetectorsBase) o2_target_root_dictionary(TRKBase - HEADERS include/TRKBase/GeometryTGeo.h + HEADERS include/TRKBase/AlmiraParam.h + include/TRKBase/GeometryTGeo.h include/TRKBase/TRKBaseParam.h - include/TRKBase/SegmentationChip.h) \ No newline at end of file + include/TRKBase/SegmentationChip.h) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h new file mode 100644 index 0000000000000..2048666e21c00 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/AlmiraParam.h @@ -0,0 +1,48 @@ +// 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_TRK_ALMIRAPARAM_H +#define O2_TRK_ALMIRAPARAM_H + +#include "CommonConstants/LHCConstants.h" +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace trk +{ +constexpr float DEFAlmiraStrobeDelay = 0.f; ///< default strobe delay in ns wrt ROF start, to be tuned with the real chip response + +struct AlmiraParam : public o2::conf::ConfigurableParamHelper { + int roFrameLengthInBC = o2::constants::lhc::LHCMaxBunches / 198; ///< ROF length in BC for continuous mode + float strobeDelay = DEFAlmiraStrobeDelay; ///< strobe start in ns wrt ROF start + float strobeLengthCont = -1.; ///< if < 0, full ROF length minus delay + int roFrameBiasInBC = 0; ///< ROF start bias in BC wrt orbit start + + O2ParamDef(AlmiraParam, "TRKAlmiraParam"); +}; + +} // namespace trk + +namespace framework +{ +template +struct is_messageable; + +template <> +struct is_messageable : std::true_type { +}; +} // namespace framework + +} // namespace o2 + +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/AlmiraParam.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/AlmiraParam.cxx new file mode 100644 index 0000000000000..572c902fb23f1 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/AlmiraParam.cxx @@ -0,0 +1,14 @@ +// 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 "TRKBase/AlmiraParam.h" + +O2ParamImpl(o2::trk::AlmiraParam); diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h index eee9a23eaf5e7..e36955cdd150d 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/TRKBaseLinkDef.h @@ -15,10 +15,12 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::trk::AlmiraParam> + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::trk::TRKBaseParam> + ; +#pragma link C++ class o2::trk::AlmiraParam + ; #pragma link C++ class o2::trk::GeometryTGeo + #pragma link C++ class o2::trk::TRKBaseParam + ; #pragma link C++ class o2::trk::SegmentationChip + ; -#endif \ No newline at end of file +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt index edd9c785d89ce..54e42c6857249 100644 --- a/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt @@ -9,6 +9,18 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. + +o2_add_test_root_macro(CheckBandwidth.C + PUBLIC_LINK_LIBRARIES O2::ITSMFTBase + O2::ITSMFTSimulation + O2::TRKBase + O2::TRKSimulation + O2::MathUtils + O2::SimulationDataFormat + O2::DetectorsBase + O2::Steer + LABELS trk COMPILE_ONLY) + o2_add_test_root_macro(CheckDigits.C PUBLIC_LINK_LIBRARIES O2::ITSMFTBase O2::ITSMFTSimulation diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckBandwidth.C b/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckBandwidth.C new file mode 100644 index 0000000000000..2087f88a87d6b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckBandwidth.C @@ -0,0 +1,299 @@ +// 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 CheckDigits.C +/// \brief Simple macro to check TRK digits + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TRKBase/GeometryTGeo.h" +#include "DataFormatsITSMFT/Digit.h" +#include "MathUtils/Utils.h" +#include "DetectorsBase/GeometryManager.h" + +#include "DataFormatsITSMFT/ROFRecord.h" +#include "CommonDataFormat/InteractionRecord.h" +#include "SimulationDataFormat/DigitizationContext.h" + +#endif + +namespace +{ +constexpr double DigitBits = 16.; +constexpr double BunchCrossingNS = 25.; +constexpr int ReadoutCycleBC = 18; +constexpr int ReadoutCycleSimBC = 18; +constexpr double ReadoutCycleSeconds = ReadoutCycleBC * BunchCrossingNS * 1.e-9; +} // namespace + +void CheckBandwidth(std::string digifile = "trkdigits.root", std::string inputGeom = "o2sim_geometry.root", std::string collContextFile = "collisioncontext.root") +{ + gStyle->SetPalette(55); + gStyle->SetOptStat(0); + + auto drawSummary = [](double averageValue, double peakValue, const char* unit) { + TLatex latex; + latex.SetNDC(); + latex.SetTextSize(0.03); + latex.SetTextAlign(13); + latex.DrawLatex(0.04, 0.05, Form("avg: %.3f %s", averageValue, unit)); + latex.DrawLatex(0.34, 0.05, Form("peak: %.3f %s", peakValue, unit)); + }; + + auto drawCollisionSummary = [](double averageValue, double nonEmptyAverageValue, double peakValue) { + TLatex latex; + latex.SetNDC(); + latex.SetTextSize(0.03); + latex.SetTextAlign(13); + latex.DrawLatex(0.04, 0.025, Form("avg: %.3f collisions/ROF", averageValue)); + latex.DrawLatex(0.42, 0.025, Form("peak: %.3f collisions/ROF", peakValue)); + latex.DrawLatex(0.04, 0.06, Form("avg non-empty: %.3f collisions/ROF", nonEmptyAverageValue)); + }; + + using namespace o2::base; + using namespace o2::trk; + + TFile* f = TFile::Open("CheckBandwidth.root", "recreate"); + + // Geometry + o2::base::GeometryManager::loadGeometry(inputGeom); + auto* gman = o2::trk::GeometryTGeo::Instance(); + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); + + // Collision Context + TFile* ccFile = TFile::Open(collContextFile.data()); + auto* digiContext = (o2::steer::DigitizationContext*)ccFile->Get("DigitizationContext"); + const o2::InteractionRecord firstSampledIR{0, digiContext->getFirstOrbitForSampling()}; + std::vector collisionsPerROF; + + for (const auto& record : digiContext->getEventRecords()) { + auto nbc = record.differenceInBC(firstSampledIR); + if (record.getTimeOffsetWrtBC() < 0. && nbc > 0) { + --nbc; + } + if (nbc < 0) { + continue; + } + + const size_t rofID = nbc / ReadoutCycleSimBC; + if (rofID >= collisionsPerROF.size()) { + collisionsPerROF.resize(rofID + 1, 0u); + } + ++collisionsPerROF[rofID]; + } + + // Digits + TFile* digFile = TFile::Open(digifile.data()); + TTree* digTree = (TTree*)digFile->Get("o2sim"); + const int nDigitTreeEntries = digTree->GetEntries(); + + std::vector* digArr = nullptr; + digTree->SetBranchAddress("TRKDigit", &digArr); + + // Get Read Out Frame arrays + std::vector* ROFRecordArrray = nullptr; + digTree->SetBranchAddress("TRKDigitROF", &ROFRecordArrray); + std::vector& ROFRecordArrrayRef = *ROFRecordArrray; + + digTree->GetEntry(0); + + if (nDigitTreeEntries > 1) { + LOG(warning) << "Digit tree has " << nDigitTreeEntries << " entries, but this macro processes entry 0 only."; + } + + std::vector digitsPerChip(gman->getNumberOfChips(), 0ull); + std::vector maxDigitsPerROFPerChip(gman->getNumberOfChips(), 0u); + std::vector digitsInCurrentROFPerChip(gman->getNumberOfChips(), 0u); + + const int nROFRec = (int)ROFRecordArrrayRef.size(); + const int nCollisionROFBins = std::max(nROFRec, static_cast(collisionsPerROF.size())); + + if (nCollisionROFBins > 0) { + auto* hCollisionsPerROF = new TH1D("h_collisions_per_rof", "Collisions per ROF;ROF id;N collisions", nCollisionROFBins, -0.5, nCollisionROFBins - 0.5); + double totalCollisionsPerROF = 0.; + double peakCollisionsPerROF = 0.; + int nNonEmptyROFs = 0; + + for (int rofID = 0; rofID < nCollisionROFBins; ++rofID) { + const double nCollisions = rofID < static_cast(collisionsPerROF.size()) ? collisionsPerROF[rofID] : 0.; + hCollisionsPerROF->SetBinContent(rofID + 1, nCollisions); + totalCollisionsPerROF += nCollisions; + peakCollisionsPerROF = std::max(peakCollisionsPerROF, nCollisions); + if (nCollisions > 0.) { + ++nNonEmptyROFs; + } + } + + auto* canvCollisionsPerROF = new TCanvas("canvCollisionsPerROF", "Collisions per ROF", 1050, 1050); + canvCollisionsPerROF->SetTopMargin(0.08); + hCollisionsPerROF->Draw("hist"); + drawCollisionSummary(totalCollisionsPerROF / nCollisionROFBins, + nNonEmptyROFs > 0 ? totalCollisionsPerROF / nNonEmptyROFs : 0., + peakCollisionsPerROF); + canvCollisionsPerROF->SaveAs("trk_collisions_per_rof.png"); + } + + unsigned int rofIndex = 0; + unsigned int rofNEntries = 0; + + // LOOP on : ROFRecord array + for (unsigned int iROF = 0; iROF < ROFRecordArrrayRef.size(); iROF++) { + std::vector touchedChips; + + rofIndex = ROFRecordArrrayRef[iROF].getFirstEntry(); + rofNEntries = ROFRecordArrrayRef[iROF].getNEntries(); + + // LOOP on : digits array + for (unsigned int iDigit = rofIndex; iDigit < rofIndex + rofNEntries; iDigit++) { + if (iDigit % 1000 == 0) + std::cout << "Reading digit " << iDigit << " / " << digArr->size() << std::endl; + + Int_t iDetID = (*digArr)[iDigit].getChipIndex(); + Int_t disk = gman->getDisk(iDetID); + Int_t subDetID = gman->getSubDetID(iDetID); + + if (subDetID == 1 && disk == -1) { + if (digitsInCurrentROFPerChip[iDetID] == 0) { + touchedChips.push_back(iDetID); + } + digitsPerChip[iDetID]++; + ++digitsInCurrentROFPerChip[iDetID]; + } + + } // end loop on digits array + + for (const auto chipID : touchedChips) { + maxDigitsPerROFPerChip[chipID] = std::max(maxDigitsPerROFPerChip[chipID], digitsInCurrentROFPerChip[chipID]); + digitsInCurrentROFPerChip[chipID] = 0; + } + + } // end loop on ROFRecords array + + const double rofNorm = nROFRec > 0 ? 1. / nROFRec : 0.; + const double bitsToMbps = ReadoutCycleSeconds > 0. ? DigitBits / ReadoutCycleSeconds / 1.e6 : 0.; + const int nMLOTLayers = gman->getNumberOfLayersMLOT(); + + for (int layer = 0; layer < nMLOTLayers; ++layer) { + int nStaves = gman->extractNumberOfStavesMLOT(layer); + std::map>> chipsPerStave; + std::vector sensorIdPerChip(gman->getNumberOfChips(), -1); + int maxSensorsPerStave = 0; + + for (int chipID = 0; chipID < gman->getNumberOfChips(); ++chipID) { + if (gman->getSubDetID(chipID) != 1 || gman->getLayer(chipID) != layer) { + continue; + } + const int staveID = gman->getStave(chipID); + const auto sensorCenter = gman->getMatrixL2G(chipID)(o2::math_utils::Point3D(0.f, 0.f, 0.f)); + chipsPerStave[staveID].push_back({sensorCenter.Z(), chipID}); + } + + for (auto& [staveID, chips] : chipsPerStave) { + std::sort(chips.begin(), chips.end(), [](const auto& left, const auto& right) { + if (std::abs(left.first - right.first) > 1.e-4) { + return left.first < right.first; + } + return left.second < right.second; + }); + + for (size_t sensorIndex = 0; sensorIndex < chips.size(); ++sensorIndex) { + sensorIdPerChip[chips[sensorIndex].second] = sensorIndex; + } + + maxSensorsPerStave = std::max(maxSensorsPerStave, static_cast(chips.size())); + } + + if (maxSensorsPerStave == 0) { + continue; + } + + auto* hDigitsPerROF = new TH2F(Form("h_digits_per_rof_layer%d", layer), + Form("Layer %d average digits per ROF;stave id;sensor id in stave;digits / ROF", layer), + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); + auto* hMaxDigitsPerROF = new TH2F(Form("h_max_digits_per_rof_layer%d", layer), + Form("Layer %d max digits in one ROF;stave id;sensor id in stave;max digits / ROF", layer), + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); + auto* hBandwidth = new TH2F(Form("h_bandwidth_layer%d", layer), + Form("Layer %d bandwidth map;stave id;sensor id in stave;bandwidth (Mbit/s)", layer), + nStaves, -0.5, nStaves - 0.5, maxSensorsPerStave, -0.5, maxSensorsPerStave - 0.5); + double totalAvgDigitsPerROF = 0.; + double totalMaxDigitsPerROF = 0.; + double totalBandwidthMbps = 0.; + double peakAvgDigitsPerROF = 0.; + double peakMaxDigitsPerROF = 0.; + double peakBandwidthMbps = 0.; + int nFilledSensors = 0; + + for (int chipID = 0; chipID < gman->getNumberOfChips(); ++chipID) { + if (gman->getSubDetID(chipID) != 1 || gman->getLayer(chipID) != layer) { + continue; + } + + const int staveID = gman->getStave(chipID); + const int sensorID = sensorIdPerChip[chipID]; + const double avgDigitsPerROF = digitsPerChip[chipID] * rofNorm; + const double maxDigitsPerROF = maxDigitsPerROFPerChip[chipID]; + const double bandwidthMbps = avgDigitsPerROF * bitsToMbps; + + if (sensorID >= 0) { + hDigitsPerROF->Fill(staveID, sensorID, avgDigitsPerROF); + hMaxDigitsPerROF->Fill(staveID, sensorID, maxDigitsPerROF); + hBandwidth->Fill(staveID, sensorID, bandwidthMbps); + totalAvgDigitsPerROF += avgDigitsPerROF; + totalMaxDigitsPerROF += maxDigitsPerROF; + totalBandwidthMbps += bandwidthMbps; + peakAvgDigitsPerROF = std::max(peakAvgDigitsPerROF, avgDigitsPerROF); + peakMaxDigitsPerROF = std::max(peakMaxDigitsPerROF, maxDigitsPerROF); + peakBandwidthMbps = std::max(peakBandwidthMbps, bandwidthMbps); + ++nFilledSensors; + } + } + + auto* canvLayer = new TCanvas(Form("canvBandwidthLayer%d", layer), Form("Layer %d bandwidth", layer), 1050, 1050); + canvLayer->SetTopMargin(0.08); + canvLayer->SetRightMargin(0.18); + const double avgDigitsPerROFLayer = nFilledSensors > 0 ? totalAvgDigitsPerROF / nFilledSensors : 0.; + const double avgMaxDigitsPerROFLayer = nFilledSensors > 0 ? totalMaxDigitsPerROF / nFilledSensors : 0.; + const double avgBandwidthMbps = nFilledSensors > 0 ? totalBandwidthMbps / nFilledSensors : 0.; + hBandwidth->GetZaxis()->SetRangeUser(0., avgBandwidthMbps > 0. ? 3. * avgBandwidthMbps : 1.); + hBandwidth->Draw("colz"); + drawSummary(avgBandwidthMbps, peakBandwidthMbps, "Mbit/s"); + canvLayer->SaveAs(Form("trk_layer%d_bandwidth_map.png", layer)); + + auto* canvLayerDigits = new TCanvas(Form("canvDigitsLayer%d", layer), Form("Layer %d digits per ROF", layer), 1050, 1050); + canvLayerDigits->SetTopMargin(0.08); + canvLayerDigits->SetRightMargin(0.18); + hDigitsPerROF->Draw("colz"); + drawSummary(avgDigitsPerROFLayer, peakAvgDigitsPerROF, "digits/ROF"); + canvLayerDigits->SaveAs(Form("trk_layer%d_digits_per_rof_map.png", layer)); + + auto* canvLayerMaxDigits = new TCanvas(Form("canvMaxDigitsLayer%d", layer), Form("Layer %d max digits per ROF", layer), 1050, 1050); + canvLayerMaxDigits->SetTopMargin(0.08); + canvLayerMaxDigits->SetRightMargin(0.18); + hMaxDigitsPerROF->Draw("colz"); + drawSummary(avgMaxDigitsPerROFLayer, peakMaxDigitsPerROF, "digits/ROF"); + canvLayerMaxDigits->SaveAs(Form("trk_layer%d_max_digits_per_rof_map.png", layer)); + } + + f->Write(); + f->Close(); +} diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h index 168ae172f4b86..de839b27aefee 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DPLDigitizerParam.h @@ -32,9 +32,9 @@ struct DPLDigitizerParam : public o2::conf::ConfigurableParamHelper -infTime; } - const o2::trk::ChipSimResponse* getAlpSimResponse() const { return mAlpSimResponse.get(); } - void setAlpSimResponse(const o2::itsmft::AlpideSimResponse*); + const o2::trk::ChipSimResponse* getResponse() const { return mResponse.get(); } + void setResponse(const o2::itsmft::AlpideSimResponse*); const SignalShape& getSignalShape() const { return mSignalShape; } SignalShape& getSignalShape() { return (SignalShape&)mSignalShape; } @@ -123,7 +123,7 @@ class DigiParams o2::itsmft::AlpideSignalTrapezoid mSignalShape; ///< signal timeshape parameterization - std::unique_ptr mAlpSimResponse; //!< pointer on external response + std::unique_ptr mResponse; //!< pointer on external response // auxiliary precalculated parameters float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx index e2a78702204e5..d5d47b3658b04 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -72,7 +72,7 @@ void DigiParams::print() const mSignalShape.print(); } -void DigiParams::setAlpSimResponse(const o2::itsmft::AlpideSimResponse* resp) +void DigiParams::setResponse(const o2::itsmft::AlpideSimResponse* resp) { LOG(debug) << "Response function data path: " << resp->getDataPath(); LOG(debug) << "Response function info: "; @@ -80,5 +80,5 @@ void DigiParams::setAlpSimResponse(const o2::itsmft::AlpideSimResponse* resp) if (!resp) { LOGP(fatal, "cannot set response function from null"); } - mAlpSimResponse = std::make_unique(resp); + mResponse = std::make_unique(resp); } diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 31ef19a21cce9..31b9a25b7e5f8 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -50,7 +50,7 @@ void Digitizer::init() } // setting the correct response function (for the moment, for both VD and MLOT the same response function is used) - mChipSimResp = mParams.getAlpSimResponse(); + mChipSimResp = mParams.getResponse(); mChipSimRespVD = mChipSimResp; /// for the moment considering the same response mChipSimRespMLOT = mChipSimResp; /// for the moment considering the same response @@ -171,7 +171,13 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) nbc--; } - mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + if (nbc < 0) { + mNewROFrame = 0; + mIsBeforeFirstRO = true; + } else { + mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + mIsBeforeFirstRO = false; + } LOG(debug) << " NewROFrame " << mNewROFrame << " = " << nbc << "/" << mParams.getROFrameLengthInBC() << " (nbc/mParams.getROFrameLengthInBC()"; @@ -179,6 +185,7 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; } else { mNewROFrame = 0; + mIsBeforeFirstRO = false; } if (mNewROFrame < mROFrameMin) { diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx index b587ec24775b4..3801228422a62 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx @@ -427,7 +427,7 @@ DataProcessorSpec getTrackerSpec(bool useMC, const std::string& hitRecoConfig, o } // inputs.emplace_back("itscldict", "TRK", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - // inputs.emplace_back("itsalppar", "TRK", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + // inputs.emplace_back("TRK_almiraparam", "TRK", "ALMIRAPARAM", 0, Lifetime::Condition, ccdbParamSpec("TRK/Config/AlmiraParam")); // outputs.emplace_back("TRK", "TRACKCLSID", 0, Lifetime::Timeframe); // outputs.emplace_back("TRK", "TRKTrackROF", 0, Lifetime::Timeframe); diff --git a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx index 30f9d33983712..8957ebed223b2 100644 --- a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx @@ -21,19 +21,21 @@ #include "DataFormatsITSMFT/Digit.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "DetectorsBase/BaseDPLDigitizer.h" +#include "DetectorsRaw/HBFUtils.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsCommonDataFormats/SimTraits.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "TRKSimulation/Digitizer.h" #include "TRKSimulation/DPLDigitizerParam.h" -#include "ITSMFTBase/DPLAlpideParam.h" +#include "TRKBase/AlmiraParam.h" #include "TRKBase/GeometryTGeo.h" #include "TRKBase/TRKBaseParam.h" #include #include +#include #include #include @@ -77,6 +79,8 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer if (mFinished) { return; } + mFirstOrbitTF = pc.services().get().firstTForbit; + const o2::InteractionRecord firstIR(0, mFirstOrbitTF); updateTimeDependentParams(pc); // read collision context from input @@ -102,6 +106,11 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer // digits are directly put into DPL owned resource auto& digitsAccum = pc.outputs().make>(Output{mOrigin, "DIGITS", 0}); + const int roFrameLengthInBC = mDigitizer.getParams().getROFrameLengthInBC(); + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / roFrameLengthInBC; + const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF(); + mROFRecordsAccum.reserve(nROFsTF); + auto accumulate = [this, &digitsAccum]() { // accumulate result of single event processing, called after processing every event supplied // AND after the final flushing via digitizer::fillOutputContainer @@ -180,10 +189,62 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer accumulate(); // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) + std::vector expDigitRofVec(nROFsTF); + for (int iROF = 0; iROF < nROFsTF; ++iROF) { + auto& rof = expDigitRofVec[iROF]; + const int orb = iROF * roFrameLengthInBC / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF; + const int bc = iROF * roFrameLengthInBC % o2::constants::lhc::LHCMaxBunches; + rof.setBCData(o2::InteractionRecord(bc, orb)); + rof.setROFrame(iROF); + rof.setNEntries(0); + rof.setFirstEntry(-1); + } + + for (const auto& rof : mROFRecordsAccum) { + const auto& ir = rof.getBCData(); + const auto irToFirst = ir - firstIR; + const auto irROF = irToFirst.toLong() / roFrameLengthInBC; + if (irROF < 0 || irROF >= nROFsTF) { + continue; + } + auto& expROF = expDigitRofVec[irROF]; + expROF.setFirstEntry(rof.getFirstEntry()); + expROF.setNEntries(rof.getNEntries()); + if (expROF.getBCData() != rof.getBCData()) { + LOGP(fatal, "detected mismatch between expected {} and received {}", expROF.asString(), rof.asString()); + } + } - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mROFRecordsAccum); + int prevFirst = 0; + for (auto& rof : expDigitRofVec) { + if (rof.getFirstEntry() < 0) { + rof.setFirstEntry(prevFirst); + } + prevFirst = rof.getFirstEntry(); + } + + pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, expDigitRofVec); if (mWithMCTruth) { - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mMC2ROFRecordsAccum); + std::vector clippedMC2ROFRecords; + clippedMC2ROFRecords.reserve(mMC2ROFRecordsAccum.size()); + for (auto mc2rof : mMC2ROFRecordsAccum) { + if (mc2rof.rofRecordID < 0 || mc2rof.minROF >= static_cast(nROFsTF)) { + mc2rof.rofRecordID = -1; + mc2rof.minROF = 0; + mc2rof.maxROF = 0; + } else { + mc2rof.maxROF = std::min(mc2rof.maxROF, nROFsTF - 1); + if (mc2rof.minROF > mc2rof.maxROF) { + mc2rof.rofRecordID = -1; + mc2rof.minROF = 0; + mc2rof.maxROF = 0; + } else { + mc2rof.rofRecordID = mc2rof.minROF; + } + } + clippedMC2ROFRecords.push_back(mc2rof); + } + pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, clippedMC2ROFRecords); auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); mLabelsAccum.flatten_to(sharedlabels); // free space of existing label containers @@ -208,7 +269,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer if (!file) { LOG(fatal) << "Cannot open response file " << mLocalRespFile; } - mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1")); + mDigitizer.getParams().setResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1")); } void updateTimeDependentParams(ProcessingContext& pc) @@ -225,21 +286,15 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer mDigitizer.setGeometry(geom); const auto& dopt = o2::trk::DPLDigitizerParam::Instance(); - pc.inputs().get*>("ITS_alppar"); - const auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); - digipar.setContinuous(dopt.continuous); + // pc.inputs().get("TRK_almiraparam"); + const auto& aopt = o2::trk::AlmiraParam::Instance(); + auto frameNS = aopt.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS; + digipar.setContinuous(true); digipar.setROFrameBiasInBC(aopt.roFrameBiasInBC); - if (dopt.continuous) { - auto frameNS = aopt.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS; - digipar.setROFrameLengthInBC(aopt.roFrameLengthInBC); - digipar.setROFrameLength(frameNS); // RO frame in ns - digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns - digipar.setStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); // Strobe length in ns - } else { - digipar.setROFrameLength(aopt.roFrameLengthTrig); // RO frame in ns - digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns - digipar.setStrobeLength(aopt.strobeLengthTrig); // Strobe length in ns - } + digipar.setROFrameLengthInBC(aopt.roFrameLengthInBC); + digipar.setROFrameLength(frameNS); // RO frame in ns + digipar.setStrobeDelay(aopt.strobeDelay); + digipar.setStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); // parameters of signal time response: flat-top duration, max rise time and q @ which rise time is 0 digipar.getSignalShape().setParameters(dopt.strobeFlatTop, dopt.strobeMaxRiseTime, dopt.strobeQRiseTime0); digipar.setChargeThreshold(dopt.chargeThreshold); // charge threshold in electrons @@ -247,10 +302,8 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer digipar.setTimeOffset(dopt.timeOffset); digipar.setNSimSteps(dopt.nSimSteps); - mROMode = digipar.isContinuous() ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::PRESENT; - LOG(info) << mID.getName() << " simulated in " - << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED") - << " RO mode"; + mROMode = o2::parameters::GRPObject::CONTINUOUS; + LOG(info) << mID.getName() << " simulated in CONTINUOUS RO mode"; // if (oTRKParams::Instance().useDeadChannelMap) { // pc.inputs().get("TRK_dead"); // trigger final ccdb update @@ -265,9 +318,9 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) { - if (matcher == ConcreteDataMatcher(detectors::DetID::ITS, "ALPIDEPARAM", 0)) { - LOG(info) << mID.getName() << " Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + if (matcher == ConcreteDataMatcher(mOrigin, "ALMIRAPARAM", 0)) { + LOG(info) << mID.getName() << " Almira param updated"; + const auto& par = o2::trk::AlmiraParam::Instance(); par.printKeyValues(); return; } @@ -280,7 +333,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer LOG(info) << mID.getName() << " loaded APTSResponseData"; if (mLocalRespFile.empty()) { LOG(info) << "Using CCDB/APTS response file"; - mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)obj); + mDigitizer.getParams().setResponse((const o2::itsmft::AlpideSimResponse*)obj); mDigitizer.setResponseName("APTS"); } else { LOG(info) << "Response function will be loaded from local file: " << mLocalRespFile; @@ -294,6 +347,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer bool mWithMCTruth{true}; bool mFinished{false}; bool mDisableQED{false}; + unsigned long mFirstOrbitTF = 0x0; std::string mLocalRespFile{""}; const o2::detectors::DetID mID{o2::detectors::DetID::TRK}; const o2::header::DataOrigin mOrigin{o2::header::gDataOriginTRK}; @@ -318,7 +372,7 @@ DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth) auto detOrig = o2::header::gDataOriginTRK; std::vector inputs; inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); - inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + // inputs.emplace_back("TRK_almiraparam", "TRK", "ALMIRAPARAM", 0, Lifetime::Condition, ccdbParamSpec("TRK/Config/AlmiraParam")); // if (oTRKParams::Instance().useDeadChannelMap) { // inputs.emplace_back("TRK_dead", "TRK", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("TRK/Calib/DeadMap")); // }