From b3ab80efbc93943894f265ff2ded061fbadebf6e Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 4 Sep 2020 15:01:09 +0200 Subject: [PATCH 01/76] Interface and params for AEGIS Cosmics generator --- Generators/CMakeLists.txt | 9 ++- .../include/Generators/GenCosmicsParam.h | 56 +++++++++++++ Generators/share/external/GenCosmics.C | 80 +++++++++++++++++++ Generators/share/external/GenCosmicsLoader.C | 35 ++++++++ Generators/share/external/README.md | 14 +++- Generators/src/GenCosmicsParam.cxx | 15 ++++ Generators/src/GeneratorsLinkDef.h | 2 + cmake/O2RootMacroExclusionList.cmake | 2 + 8 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 Generators/include/Generators/GenCosmicsParam.h create mode 100644 Generators/share/external/GenCosmics.C create mode 100644 Generators/share/external/GenCosmicsLoader.C create mode 100644 Generators/src/GenCosmicsParam.cxx diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 178ed69529ab5..0fca05335777c 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -32,6 +32,7 @@ o2_add_library(Generators src/TriggerParticleParam.cxx src/BoxGunParam.cxx src/QEDGenParam.cxx + src/GenCosmicsParam.cxx src/GeneratorFactory.cxx $<$:src/GeneratorPythia6.cxx> $<$:src/GeneratorPythia6Param.cxx> @@ -70,7 +71,8 @@ set(headers include/Generators/TriggerParticleParam.h include/Generators/ConfigurationMacroHelper.h include/Generators/BoxGunParam.h - include/Generators/QEDGenParam.h) + include/Generators/QEDGenParam.h + include/Generators/GenCosmicsParam.h) if (pythia6_FOUND) list(APPEND headers include/Generators/GeneratorPythia6.h @@ -107,6 +109,11 @@ if(doBuildSimulation) PUBLIC_LINK_LIBRARIES O2::Generators O2::SimConfig LABELS generators) + + o2_add_test_root_macro(share/external/GenCosmicsLoader.C + PUBLIC_LINK_LIBRARIES O2::Generators + O2::SimConfig + LABELS generators) endif() o2_add_test_root_macro(share/external/tgenerator.C diff --git a/Generators/include/Generators/GenCosmicsParam.h b/Generators/include/Generators/GenCosmicsParam.h new file mode 100644 index 0000000000000..372bd9ec3b0a0 --- /dev/null +++ b/Generators/include/Generators/GenCosmicsParam.h @@ -0,0 +1,56 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 ALICEO2_GENCOSMICSPARAM_H +#define ALICEO2_GENCOSMICSPARAM_H + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +// @file GenCosmicsParam +// @author ruben.shahoyan@cern.ch +// @brief Parameters for cosmics generation + +namespace o2 +{ +namespace eventgen +{ +struct GenCosmicsParam : public o2::conf::ConfigurableParamHelper { + enum GenParamType : int { ParamMI, + ParamACORDE, + ParamTPC }; // source parameterizations + enum AccType : int { ITS0, + ITS1, + ITS2, + ITS3, + ITS4, + ITS5, + ITS6, + TPC, + Custom }; + GenParamType param = ParamTPC; + AccType accept = TPC; + int nPart = 1; ///< number of particles per event + int maxTrials = 10000000; ///< number of failed trials to abandon generation + float maxAngle = 45.; ///< max angle wrt azimuth to generate (in degrees) + float origin = 550.; ///< create particle at this radius + float pmin = 0.5; ///< min total momentum + float pmax = 100; ///< max total momentum + float customAccX = 250; ///< require particle to pass within this |X| at Y=0 if AccType=custom is selected + float customAccZ = 250; ///< require particle to pass within this |Z| at Y=0 if AccType=custom is selected + + // boilerplate stuff + make principal key + O2ParamDef(GenCosmicsParam, "cosmics"); +}; + +} // namespace eventgen +} // namespace o2 + +#endif diff --git a/Generators/share/external/GenCosmics.C b/Generators/share/external/GenCosmics.C new file mode 100644 index 0000000000000..493bfcf6c1311 --- /dev/null +++ b/Generators/share/external/GenCosmics.C @@ -0,0 +1,80 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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. + +//< Macro to run QED background generator, us it as e.g. +//< o2-sim -n10000 -m PIPE ITS TPC -g extgen --extGenFile $O2_ROOT/share/Generators/external/GenCosmicsLoader.C + +R__LOAD_LIBRARY(libGeneratorCosmics.so) + +using namespace o2::eventgen; + +o2::eventgen::GeneratorTGenerator* GenCosmics() +{ + auto genCosm = new GeneratorCosmics(); + auto& cosmParam = GenCosmicsParam::Instance(); + + if (cosmParam.param == GenCosmicsParam::ParamMI) { + genCosm->setParamMI(); + } else if (cosmParam.param == GenCosmicsParam::ParamACORDE) { + genCosm->setParamACORDE(); + } else if (cosmParam.param == GenCosmicsParam::ParamTPC) { + genCosm->setParamTPC(); + } else { + LOG(FATAL) << "Unknown cosmics param type " << cosmParam.param; + } + + genCosm->setNPart(cosmParam.nPart); + genCosm->setPRange(cosmParam.pmin, cosmParam.pmax); + + switch (cosmParam.accept) { + case GenCosmicsParam::ITS0: + genCosm->requireITS0(); + break; + case GenCosmicsParam::ITS1: + genCosm->requireITS1(); + break; + case GenCosmicsParam::ITS2: + genCosm->requireITS2(); + break; + case GenCosmicsParam::ITS3: + genCosm->requireITS3(); + break; + case GenCosmicsParam::ITS4: + genCosm->requireITS4(); + break; + case GenCosmicsParam::ITS5: + genCosm->requireITS5(); + break; + case GenCosmicsParam::ITS6: + genCosm->requireITS6(); + break; + case GenCosmicsParam::TPC: + genCosm->requireTPC(); + break; + case GenCosmicsParam::Custom: + genCosm->requireXZAccepted(cosmParam.customAccX, cosmParam.customAccZ); + break; + default: + LOG(FATAL) << "Unknown cosmics acceptance type " << cosmParam.accept; + break; + } + + genCosm->Init(); + + // instance and configure TGenerator interface + auto tgen = new o2::eventgen::GeneratorTGenerator(); + tgen->setMomentumUnit(1.); // [GeV/c] + tgen->setEnergyUnit(1.); // [GeV/c] + tgen->setPositionUnit(1.); // [cm] + tgen->setTimeUnit(1.); // [s] + tgen->setTGenerator(genCosm); + fg = tgen; + return tgen; +} diff --git a/Generators/share/external/GenCosmicsLoader.C b/Generators/share/external/GenCosmicsLoader.C new file mode 100644 index 0000000000000..fa646743e674e --- /dev/null +++ b/Generators/share/external/GenCosmicsLoader.C @@ -0,0 +1,35 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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. + +//< Loader macro to run QED background generator from QEDepem.C macro, use it as e.g. +//< o2-sim -n10000 -m PIPE ITS TPC -g extgen --extGenFile $O2_ROOT/share/Generators/external/GenCosmicsLoader.C +//< Generation options can be changed by providing --configKeyValues "cosmics.maxAngle=30.;cosmics.accept=ITS0" etc. +//< See GenCosmicsParam for available options + +#include + +FairGenerator* fg = nullptr; + +FairGenerator* GenCosmicsLoader() +{ + const TString macroName = "GenCosmics"; + gSystem->Load("libGeneratorCosmics.so"); + + // the path of the macro to load depends on where it was installed, we assume that its installation + // directory is the same as of the loader macro + std::ostringstream mstr; + mstr << __FILE__; + TString macroFullName = Form("%s/%s.C", gSystem->DirName(mstr.str().c_str()), macroName.Data()); + LOG(INFO) << "\nLoading " << macroFullName.Data() << "\n"; + + gROOT->LoadMacro(macroFullName.Data()); + gInterpreter->ProcessLine(Form("%s()", macroName.Data())); + return fg; +} diff --git a/Generators/share/external/README.md b/Generators/share/external/README.md index da3d956209bbb..959f4551b5c3d 100644 --- a/Generators/share/external/README.md +++ b/Generators/share/external/README.md @@ -8,7 +8,7 @@ ------------ -## qedbkg.C +## QEDLoader.C / QEDepem.C - Invokes TGenEpEmv1 generator from [AEGIS](https://github.com/AliceO2Group/AEGIS) package for Pb-Pb → e+e- generation. + optional parameters are rapidity and pT ranges to generate, can be provided as key/value option, e.g. @@ -17,4 +17,16 @@ o2-sim -n 1000 -m PIPE ITS -g extgen --extGenFile $O2_ROOT/share/Generators/exte `` The x-section of the process depends on the applied cuts, it is calculated on the fly and stored in the ``qedgenparam.ini`` file. +## GenCosmicsLoader.C / GenCosmics.C + +- Invokes GenerateCosmics generators from [AEGIS](https://github.com/AliceO2Group/AEGIS) package. + +``o2-sim -n1000 -m PIPE ITS TPC -g extgen --extGenFile $O2_ROOT/share/Generators/external/GenCosmicsLoader.C`` + +Generation options can be changed by providing ``--configKeyValues "cosmics.maxAngle=30.;cosmics.accept=ITS0"`` etc. +For instance, to generate track defined at radius 500 cm, with maximal angle wrt the azimuth of 40 degress and passing via ITS layer 0 at Y=0: + +``o2-sim -n100 -m PIPE ITS TPC --configKeyValues "cosmics.maxAngle=40.;cosmics.accept=ITS0;cosmics.origin=500" -g extgen --extGenFile $O2_ROOT/share/Generators/external/GenCosmicsLoader.C`` + +See GenCosmicsParam class for available options. ------------ diff --git a/Generators/src/GenCosmicsParam.cxx b/Generators/src/GenCosmicsParam.cxx new file mode 100644 index 0000000000000..6d23cdf0747fa --- /dev/null +++ b/Generators/src/GenCosmicsParam.cxx @@ -0,0 +1,15 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 "Generators/GenCosmicsParam.h" + +using namespace o2::eventgen; + +O2ParamImpl(o2::eventgen::GenCosmicsParam); diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 0d0d00c3a2064..93f83e72beb59 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -58,5 +58,7 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::BoxGunParam > +; #pragma link C++ class o2::eventgen::QEDGenParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::QEDGenParam > +; +#pragma link C++ class o2::eventgen::GenCosmicsParam + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GenCosmicsParam> + ; #endif diff --git a/cmake/O2RootMacroExclusionList.cmake b/cmake/O2RootMacroExclusionList.cmake index 7f00bd28c0b29..2842c256a7b08 100644 --- a/cmake/O2RootMacroExclusionList.cmake +++ b/cmake/O2RootMacroExclusionList.cmake @@ -46,6 +46,7 @@ list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Detectors/TOF/prototyping/ConvertRun2CalibrationToO2.C Generators/share/external/hijing.C Generators/share/external/QEDepem.C + Generators/share/external/GenCosmics.C macro/SetIncludePath.C macro/loadExtDepLib.C macro/load_all_libs.C @@ -61,6 +62,7 @@ if(NOT BUILD_SIMULATION) o2_get_list_of_macros(${CMAKE_SOURCE_DIR}/Detectors/gconfig macros) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST ${macros}) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/external/QEDLoader.C) + list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/external/GenCosmicsLoader.C) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/egconfig/pythia8_userhooks_charm.C) list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST Generators/share/external/trigger_mpi.C) endif() From 8802dbc0d48b2cf711c8adf5a657d4ff0c70dcbc Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer Date: Thu, 3 Sep 2020 13:03:10 +0200 Subject: [PATCH 02/76] TPCClusterFinder: Fix memory issue introduced in #4238. --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 947c8fc5b3d7b..0aa006aafcc80 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -1301,6 +1301,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) runKernel(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); GPUTPCCFMCLabelFlattener::setGlobalOffsetsAndAllocate(clusterer, mcLinearLabels); runKernel(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, &mcLinearLabels); + clusterer.clearMCMemory(); } if (buildNativeHost && buildNativeGPU && anyLaneHasData) { if (GetProcessingSettings().delayedOutput) { From dc484a8ef2d2006ee259bc7a530900df2c8a079b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 5 Sep 2020 17:29:20 +0200 Subject: [PATCH 03/76] Fix missing includes --- Analysis/Tutorials/src/partitions.cxx | 6 +++--- Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx | 1 + Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx | 1 + Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx | 1 + Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx | 1 + Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx | 1 + Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx | 1 + Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx | 1 + .../GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx | 1 + .../tofworkflow/src/CalibInfoReaderSpec.cxx | 1 + Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx | 1 + Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx | 1 + Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx | 1 + Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx | 1 + Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/ClusterSamplerSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/TrackFinderOriginalSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/TrackFitterSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/TrackSamplerSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/TrackSinkSpec.cxx | 1 + Detectors/MUON/MCH/Tracking/src/VertexSamplerSpec.cxx | 1 + .../MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx | 1 + Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx | 1 + Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx | 1 + Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx | 1 + Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx | 1 + Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h | 1 + Detectors/TOF/workflow/src/CompressedInspectorTask.cxx | 2 +- Detectors/TOF/workflow/src/DigitReaderSpec.cxx | 1 + Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx | 1 + Framework/Core/include/Framework/AODReaderHelpers.h | 1 + Framework/Core/include/Framework/runDataProcessing.h | 1 + Framework/Core/src/DataSamplingPolicy.cxx | 1 + Framework/Core/src/DataSpecUtils.cxx | 1 + Framework/Core/src/FrameworkGUIDeviceInspector.cxx | 1 + Framework/Core/src/FrameworkGUIDevicesGraph.cxx | 1 + Framework/Core/test/benchmark_TreeToTable.cxx | 1 + Framework/Core/test/test_DataOutputDirector.cxx | 2 +- Framework/Utils/include/DPLUtils/DPLRawParser.h | 1 + Framework/Utils/include/DPLUtils/RootTreeReader.h | 1 + Framework/Utils/include/DPLUtils/RootTreeWriter.h | 1 + Utilities/DataFlow/src/TimeframeValidationTool.cxx | 1 + Utilities/DataFlow/test/test_TimeframeParser.cxx | 1 + Utilities/Mergers/src/FullHistoryMerger.cxx | 2 +- Utilities/Mergers/src/IntegratingMerger.cxx | 1 + 46 files changed, 48 insertions(+), 6 deletions(-) diff --git a/Analysis/Tutorials/src/partitions.cxx b/Analysis/Tutorials/src/partitions.cxx index d0c5e10f1af45..6479356a48cfa 100644 --- a/Analysis/Tutorials/src/partitions.cxx +++ b/Analysis/Tutorials/src/partitions.cxx @@ -46,15 +46,15 @@ struct ATask { for (auto& track : leftPhi) { LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), etalow, track.eta(), etaup, track.phiraw(), philow, ptlow, track.pt(), ptup); + track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, track.phiraw(), (float)philow, (float)ptlow, track.pt(), (float)ptup); } for (auto& track : midPhi) { LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f <= %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), etalow, track.eta(), etaup, philow, track.phiraw(), phiup, ptlow, track.pt(), ptup); + track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, (float)philow, track.phiraw(), (float)phiup, (float)ptlow, track.pt(), (float)ptup); } for (auto& track : rightPhi) { LOGF(INFO, "id = %d, from collision: %d, collision: %d; eta: %.3f < %.3f < %.3f; phi: %.3f < %.3f; pt: %.3f < %.3f < %.3f", - track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), etalow, track.eta(), etaup, phiup, track.phiraw(), ptlow, track.pt(), ptup); + track.collisionId(), track.collision().globalIndex(), collision.globalIndex(), (float)etalow, track.eta(), (float)etaup, (float)phiup, track.phiraw(), (float)ptlow, track.pt(), (float)ptup); } } }; diff --git a/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx index 82b3e98d58d3a..819673b77a37e 100644 --- a/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/DigitReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FDDWorkflow/DigitReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx index baf223ac2b8f7..2fd688e96c490 100644 --- a/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecPointReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "FDDWorkflow/RecPointReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx index 9bbbf9086293b..3cacc248e5fda 100644 --- a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx @@ -13,6 +13,7 @@ #include #include "SimulationDataFormat/MCTruthContainer.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FDDWorkflow/ReconstructorSpec.h" #include "DataFormatsFDD/Digit.h" #include "DataFormatsFDD/MCLabel.h" diff --git a/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx index b1f99a2b598e4..ab683709b7269 100644 --- a/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/DigitReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FT0Workflow/DigitReaderSpec.h" #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" diff --git a/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx b/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx index 328447acfbd47..ef9c03c8b6618 100644 --- a/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecPointReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FT0Workflow/RecPointReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx index a38147e1f446b..c75caeb9b1c4f 100644 --- a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx @@ -13,6 +13,7 @@ #include #include "SimulationDataFormat/MCTruthContainer.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FT0Workflow/ReconstructionSpec.h" #include "DataFormatsFT0/Digit.h" #include "DataFormatsFT0/ChannelData.h" diff --git a/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx b/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx index 2643f32a13aa4..781950909edc1 100644 --- a/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/DigitReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "FV0Workflow/DigitReaderSpec.h" #include "DataFormatsFV0/BCData.h" #include "DataFormatsFV0/ChannelData.h" diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx index a9d518ded3827..55f1ef2a10048 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexReaderSpec.cxx @@ -14,6 +14,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx index dcbd9bd2f220c..b1ad021285f92 100644 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/CalibInfoReaderSpec.cxx @@ -18,6 +18,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "TOFWorkflow/CalibInfoReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx index cc5d7ab29a378..befc48e62071a 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/DigitReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ConfigParamRegistry.h" #include "Framework/ControlService.h" +#include "Framework/Logger.h" #include "ITSWorkflow/DigitReaderSpec.h" #include "DataFormatsITSMFT/Digit.h" #include "SimulationDataFormat/MCCompLabel.h" diff --git a/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx index 02c8b31ac169e..31a3d29dacfed 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/VertexReaderSpec.cxx @@ -14,6 +14,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "ITSWorkflow/VertexReaderSpec.h" using namespace o2::framework; diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx index 70c2af1ac969d..cb6318809c17a 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/ClusterReaderSpec.cxx @@ -17,6 +17,7 @@ #include "TTree.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "SimulationDataFormat/MCCompLabel.h" diff --git a/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx index 031133a161f23..31fdeb964b5d8 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/DigitReaderSpec.cxx @@ -17,6 +17,7 @@ #include "TTree.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "DataFormatsITSMFT/Digit.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx index b8ba2a8564306..5047a52807531 100644 --- a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "ITSMFTWorkflow/ClusterReaderSpec.h" #include diff --git a/Detectors/MUON/MCH/Tracking/src/ClusterSamplerSpec.cxx b/Detectors/MUON/MCH/Tracking/src/ClusterSamplerSpec.cxx index 04da59e121c1b..3d5b94503ed87 100644 --- a/Detectors/MUON/MCH/Tracking/src/ClusterSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/ClusterSamplerSpec.cxx @@ -27,6 +27,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/ClusterBlock.h" diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginalSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginalSpec.cxx index 661c0aa2d3d51..faf2ae3de8d15 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginalSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinderOriginalSpec.cxx @@ -26,6 +26,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/ClusterBlock.h" #include "MCHBase/TrackBlock.h" diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx index 00492d6f016c9..68da3ac602722 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFinderSpec.cxx @@ -27,6 +27,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/ClusterBlock.h" #include "MCHBase/TrackBlock.h" diff --git a/Detectors/MUON/MCH/Tracking/src/TrackFitterSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackFitterSpec.cxx index 52d2035aa75a7..8a9fb1bb0080a 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackFitterSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackFitterSpec.cxx @@ -24,6 +24,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/ClusterBlock.h" #include "MCHBase/TrackBlock.h" diff --git a/Detectors/MUON/MCH/Tracking/src/TrackSamplerSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackSamplerSpec.cxx index 2fe970caf4f6c..a18f533605003 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackSamplerSpec.cxx @@ -27,6 +27,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" namespace o2 { diff --git a/Detectors/MUON/MCH/Tracking/src/TrackSinkSpec.cxx b/Detectors/MUON/MCH/Tracking/src/TrackSinkSpec.cxx index eeb0b41b5dda0..ca1c7f954f124 100644 --- a/Detectors/MUON/MCH/Tracking/src/TrackSinkSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/TrackSinkSpec.cxx @@ -26,6 +26,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" +#include "Framework/Logger.h" namespace o2 { diff --git a/Detectors/MUON/MCH/Tracking/src/VertexSamplerSpec.cxx b/Detectors/MUON/MCH/Tracking/src/VertexSamplerSpec.cxx index 7a7422e27c4d3..a0cae8c3f10cb 100644 --- a/Detectors/MUON/MCH/Tracking/src/VertexSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Tracking/src/VertexSamplerSpec.cxx @@ -28,6 +28,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MathUtils/Cartesian3D.h" diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx index b45f9ff46ff93..1b18156c737b3 100644 --- a/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/ClusterFinderOriginalSpec.cxx @@ -29,6 +29,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/Digit.h" #include "MCHBase/PreCluster.h" diff --git a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx b/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx index d666faaceeb09..d8ed38121c68b 100644 --- a/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/ClusterSinkSpec.cxx @@ -28,6 +28,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/Digit.h" #include "MCHBase/ClusterBlock.h" diff --git a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx index 336232406092b..0d5338affcaaf 100644 --- a/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/DigitSamplerSpec.cxx @@ -31,6 +31,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/Digit.h" diff --git a/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx index 6784d39fe917a..3c50d2d9f2d3c 100644 --- a/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/PreClusterFinderSpec.cxx @@ -29,6 +29,7 @@ #include "Framework/Lifetime.h" #include "Framework/Output.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/Digit.h" #include "MCHBase/PreCluster.h" diff --git a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx index fccb8fe77cfb0..2721d8c624a2b 100644 --- a/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/PreClusterSinkSpec.cxx @@ -28,6 +28,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Lifetime.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "MCHBase/Digit.h" #include "MCHBase/PreCluster.h" diff --git a/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h b/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h index 1fa36db94a241..34b56e2ab5d01 100644 --- a/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h +++ b/Detectors/TOF/calibration/testWorkflow/DataGeneratorSpec.h @@ -21,6 +21,7 @@ #include "Framework/ControlService.h" #include "Framework/WorkflowSpec.h" #include "Framework/Task.h" +#include "Framework/Logger.h" #include "DataFormatsTOF/CalibInfoTOF.h" #include "TOFBase/Geo.h" #include "CommonConstants/MathConstants.h" diff --git a/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx b/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx index eb96808b91687..5753434153b2a 100644 --- a/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx +++ b/Detectors/TOF/workflow/src/CompressedInspectorTask.cxx @@ -16,7 +16,7 @@ #include "TOFWorkflow/CompressedInspectorTask.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" - +#include "Framework/Logger.h" #include "Headers/RAWDataHeader.h" #include "DataFormatsTOF/CompressedDataFormat.h" diff --git a/Detectors/TOF/workflow/src/DigitReaderSpec.cxx b/Detectors/TOF/workflow/src/DigitReaderSpec.cxx index 39c1872d39af4..bfee442814a24 100644 --- a/Detectors/TOF/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/TOF/workflow/src/DigitReaderSpec.cxx @@ -16,6 +16,7 @@ #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "TOFWorkflow/DigitReaderSpec.h" #include "DataFormatsParameters/GRPObject.h" diff --git a/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx b/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx index f98d83ae1b92f..858b71717bbc5 100644 --- a/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx +++ b/Detectors/TOF/workflow/src/TOFRawWriterSpec.cxx @@ -13,6 +13,7 @@ #include "TOFWorkflow/TOFRawWriterSpec.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" +#include "Framework/Logger.h" #include "DetectorsRaw/HBFUtils.h" #include "TOFBase/Geo.h" #include "CommonUtils/StringUtils.h" diff --git a/Framework/Core/include/Framework/AODReaderHelpers.h b/Framework/Core/include/Framework/AODReaderHelpers.h index ef0460febe28c..90c4e2af04fec 100644 --- a/Framework/Core/include/Framework/AODReaderHelpers.h +++ b/Framework/Core/include/Framework/AODReaderHelpers.h @@ -13,6 +13,7 @@ #include "Framework/TableBuilder.h" #include "Framework/AlgorithmSpec.h" +#include "Framework/Logger.h" #include namespace o2 diff --git a/Framework/Core/include/Framework/runDataProcessing.h b/Framework/Core/include/Framework/runDataProcessing.h index 2ee228f1e8be6..d4807a782b646 100644 --- a/Framework/Core/include/Framework/runDataProcessing.h +++ b/Framework/Core/include/Framework/runDataProcessing.h @@ -20,6 +20,7 @@ #include "Framework/BoostOptionsRetriever.h" #include "Framework/CustomWorkflowTerminationHook.h" #include "Framework/CommonServices.h" +#include "Framework/Logger.h" #include #include diff --git a/Framework/Core/src/DataSamplingPolicy.cxx b/Framework/Core/src/DataSamplingPolicy.cxx index 2a6684a16397c..e4d55b41803cb 100644 --- a/Framework/Core/src/DataSamplingPolicy.cxx +++ b/Framework/Core/src/DataSamplingPolicy.cxx @@ -18,6 +18,7 @@ #include "Framework/DataSamplingConditionFactory.h" #include "Framework/DataSpecUtils.h" #include "Framework/DataDescriptorQueryBuilder.h" +#include "Framework/Logger.h" #include diff --git a/Framework/Core/src/DataSpecUtils.cxx b/Framework/Core/src/DataSpecUtils.cxx index 6cdf4faaf6d43..73080bc144e93 100644 --- a/Framework/Core/src/DataSpecUtils.cxx +++ b/Framework/Core/src/DataSpecUtils.cxx @@ -11,6 +11,7 @@ #include "Framework/DataDescriptorMatcher.h" #include "Framework/DataMatcherWalker.h" #include "Framework/VariantHelpers.h" +#include "Framework/Logger.h" #include #include diff --git a/Framework/Core/src/FrameworkGUIDeviceInspector.cxx b/Framework/Core/src/FrameworkGUIDeviceInspector.cxx index 1822dc750b31e..058c998e75ac7 100644 --- a/Framework/Core/src/FrameworkGUIDeviceInspector.cxx +++ b/Framework/Core/src/FrameworkGUIDeviceInspector.cxx @@ -16,6 +16,7 @@ #include "Framework/DeviceInfo.h" #include "Framework/DeviceMetricsInfo.h" #include "Framework/ChannelSpec.h" +#include "Framework/Logger.h" #include "DebugGUI/imgui.h" #include diff --git a/Framework/Core/src/FrameworkGUIDevicesGraph.cxx b/Framework/Core/src/FrameworkGUIDevicesGraph.cxx index 28550e67600ee..7b81fd8618f28 100644 --- a/Framework/Core/src/FrameworkGUIDevicesGraph.cxx +++ b/Framework/Core/src/FrameworkGUIDevicesGraph.cxx @@ -15,6 +15,7 @@ #include "Framework/LogParsingHelpers.h" #include "Framework/PaletteHelpers.h" #include "FrameworkGUIDeviceInspector.h" +#include "Framework/Logger.h" #include "../src/WorkflowHelpers.h" #include "DebugGUI/imgui.h" #if __has_include("DebugGUI/icons_font_awesome.h") diff --git a/Framework/Core/test/benchmark_TreeToTable.cxx b/Framework/Core/test/benchmark_TreeToTable.cxx index dd2275c93ac51..3224d31ccf484 100644 --- a/Framework/Core/test/benchmark_TreeToTable.cxx +++ b/Framework/Core/test/benchmark_TreeToTable.cxx @@ -10,6 +10,7 @@ #include "Framework/CommonDataProcessors.h" #include "Framework/TableTreeHelpers.h" +#include "Framework/Logger.h" #include #include #include diff --git a/Framework/Core/test/test_DataOutputDirector.cxx b/Framework/Core/test/test_DataOutputDirector.cxx index 7fde2c6fc7977..e6f198197618e 100644 --- a/Framework/Core/test/test_DataOutputDirector.cxx +++ b/Framework/Core/test/test_DataOutputDirector.cxx @@ -12,9 +12,9 @@ #define BOOST_TEST_DYN_LINK #include - #include "Headers/DataHeader.h" #include "Framework/DataOutputDirector.h" +#include BOOST_AUTO_TEST_CASE(TestDataOutputDirector) { diff --git a/Framework/Utils/include/DPLUtils/DPLRawParser.h b/Framework/Utils/include/DPLUtils/DPLRawParser.h index 9548eba2c2b19..a227ebaa753a9 100644 --- a/Framework/Utils/include/DPLUtils/DPLRawParser.h +++ b/Framework/Utils/include/DPLUtils/DPLRawParser.h @@ -19,6 +19,7 @@ #include "Framework/InputRecord.h" #include "Framework/DataRef.h" #include "Framework/DataRefUtils.h" +#include "Framework/Logger.h" #include "Headers/DataHeader.h" #include // std::declval diff --git a/Framework/Utils/include/DPLUtils/RootTreeReader.h b/Framework/Utils/include/DPLUtils/RootTreeReader.h index d5a20d708c9dd..3e60052df8b30 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeReader.h +++ b/Framework/Utils/include/DPLUtils/RootTreeReader.h @@ -18,6 +18,7 @@ #include "Framework/RootSerializationSupport.h" #include "Framework/Output.h" #include "Framework/ProcessingContext.h" +#include "Framework/Logger.h" #include "Headers/DataHeader.h" #include #include diff --git a/Framework/Utils/include/DPLUtils/RootTreeWriter.h b/Framework/Utils/include/DPLUtils/RootTreeWriter.h index 5161c5c77028c..9722f8e0b918e 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeWriter.h +++ b/Framework/Utils/include/DPLUtils/RootTreeWriter.h @@ -18,6 +18,7 @@ #include "Framework/RootSerializationSupport.h" #include "Framework/InputRecord.h" #include "Framework/DataRef.h" +#include "Framework/Logger.h" #include #include #include diff --git a/Utilities/DataFlow/src/TimeframeValidationTool.cxx b/Utilities/DataFlow/src/TimeframeValidationTool.cxx index 71a5904b76447..81ff1038ff78a 100644 --- a/Utilities/DataFlow/src/TimeframeValidationTool.cxx +++ b/Utilities/DataFlow/src/TimeframeValidationTool.cxx @@ -10,6 +10,7 @@ #include "DataFlow/TimeframeParser.h" #include "fairmq/FairMQParts.h" +#include "Framework/Logger.h" #include #include #include diff --git a/Utilities/DataFlow/test/test_TimeframeParser.cxx b/Utilities/DataFlow/test/test_TimeframeParser.cxx index 338d491c25ac8..37e6f5af09c36 100644 --- a/Utilities/DataFlow/test/test_TimeframeParser.cxx +++ b/Utilities/DataFlow/test/test_TimeframeParser.cxx @@ -11,6 +11,7 @@ #include "DataFlow/TimeframeParser.h" #include "DataFlow/FakeTimeframeBuilder.h" #include "Headers/DataHeader.h" +#include "Framework/Logger.h" #include #include #include diff --git a/Utilities/Mergers/src/FullHistoryMerger.cxx b/Utilities/Mergers/src/FullHistoryMerger.cxx index be2569545b8b4..9504e603e2246 100644 --- a/Utilities/Mergers/src/FullHistoryMerger.cxx +++ b/Utilities/Mergers/src/FullHistoryMerger.cxx @@ -20,7 +20,7 @@ #include "Headers/DataHeader.h" #include "Framework/InputRecordWalker.h" - +#include "Framework/Logger.h" #include using namespace o2::header; diff --git a/Utilities/Mergers/src/IntegratingMerger.cxx b/Utilities/Mergers/src/IntegratingMerger.cxx index 046b804496b3a..0607e0e78888b 100644 --- a/Utilities/Mergers/src/IntegratingMerger.cxx +++ b/Utilities/Mergers/src/IntegratingMerger.cxx @@ -21,6 +21,7 @@ #include #include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" //#include "Framework/DataRef.h" //using namespace o2; From a0e03ea86fc87fc7deebdf550c6ee02d542c861c Mon Sep 17 00:00:00 2001 From: mfasel Date: Fri, 4 Sep 2020 15:29:08 +0200 Subject: [PATCH 04/76] [EMCAL-610] Circumvent out-of-bounds error The iterator mCurrentTrigger seems to be incorrectly initialized on linux systems, leading to corrupted trigger recond entries creating an out-of-bounds exception when iterating over the range in the digits vector. Circumvented by passing the current trigger directly to the process method and not storing the trigger records. --- .../include/EMCALSimulation/RawWriter.h | 26 ++++------ Detectors/EMCAL/simulation/src/RawWriter.cxx | 49 ++++++++----------- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h index 5eff51302fe83..1ba5f43562e16 100644 --- a/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h +++ b/Detectors/EMCAL/simulation/include/EMCALSimulation/RawWriter.h @@ -89,17 +89,13 @@ class RawWriter void setOutputLocation(const char* outputdir) { mOutputLocation = outputdir; } void setDigits(gsl::span digits) { mDigits = digits; } void setFileFor(FileFor_t filefor) { mFileFor = filefor; } - void setTriggerRecords(gsl::span triggers); void setNumberOfADCSamples(int nsamples) { mNADCSamples = nsamples; } void setPedestal(int pedestal) { mPedestal = pedestal; } void setGeometry(o2::emcal::Geometry* geo) { mGeometry = geo; } - bool hasNextTrigger() const { return mCurrentTrigger != mTriggers.end(); } - void init(); - void process(); void digitsToRaw(gsl::span digits, gsl::span triggers); - bool processNextTrigger(); + bool processTrigger(const o2::emcal::TriggerRecord& trg); int carryOverMethod(const header::RDHAny* rdh, const gsl::span data, const char* ptr, int maxSize, int splitID, @@ -115,17 +111,15 @@ class RawWriter std::vector encodeBunchData(const std::vector& data); private: - int mNADCSamples = 15; ///< Number of time samples - int mPedestal = 0; ///< Pedestal - FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files - o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry - std::string mOutputLocation; ///< Rawfile name - std::unique_ptr mMappingHandler; ///< Mapping handler - gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response - gsl::span mTriggers; ///< Trigger records, separating the data from different triggers - std::vector mSRUdata; ///< Internal helper of digits assigned to SRUs - gsl::span::iterator mCurrentTrigger; ///< Current trigger in the trigger records - std::unique_ptr mRawWriter; ///< Raw writer + int mNADCSamples = 15; ///< Number of time samples + int mPedestal = 0; ///< Pedestal + FileFor_t mFileFor = FileFor_t::kFullDet; ///< Granularity of the output files + o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry + std::string mOutputLocation; ///< Rawfile name + std::unique_ptr mMappingHandler; ///< Mapping handler + gsl::span mDigits; ///< Digits input vector - must be in digitized format including the time response + std::vector mSRUdata; ///< Internal helper of digits assigned to SRUs + std::unique_ptr mRawWriter; ///< Raw writer ClassDefNV(RawWriter, 1); }; diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index 2bac5412c1e0c..292ddb2dd9501 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -20,12 +20,6 @@ using namespace o2::emcal; -void RawWriter::setTriggerRecords(gsl::span triggers) -{ - mTriggers = triggers; - mCurrentTrigger = triggers.begin(); -} - void RawWriter::init() { mRawWriter = std::make_unique(o2::header::gDataOriginEMC, false); @@ -69,31 +63,26 @@ void RawWriter::init() } } -void RawWriter::process() -{ - while (processNextTrigger()) - ; -} - void RawWriter::digitsToRaw(gsl::span digitsbranch, gsl::span triggerbranch) { setDigits(digitsbranch); - setTriggerRecords(triggerbranch); - process(); + for (auto trg : triggerbranch) { + processTrigger(trg); + } } -bool RawWriter::processNextTrigger() +bool RawWriter::processTrigger(const o2::emcal::TriggerRecord& trg) { - if (mCurrentTrigger == mTriggers.end()) - return false; for (auto srucont : mSRUdata) srucont.mChannels.clear(); std::vector* bunchDigits; int lasttower = -1; - for (auto& dig : gsl::span(mDigits.data() + mCurrentTrigger->getFirstEntry(), mCurrentTrigger->getNumberOfObjects())) { + for (auto& dig : gsl::span(mDigits.data() + trg.getFirstEntry(), trg.getNumberOfObjects())) { auto tower = dig.getTower(); if (tower != lasttower) { lasttower = tower; + if (tower > 20000) + std::cout << "Wrong cell ID " << tower << std::endl; auto onlineindices = getOnlineID(tower); int sruID = std::get<0>(onlineindices); auto towerdata = mSRUdata[sruID].mChannels.find(tower); @@ -104,19 +93,21 @@ bool RawWriter::processNextTrigger() } else { bunchDigits = &(towerdata->second.mDigits); } - // Get time sample of the digit: - // Digitizer stores the time sample in ns, needs to be converted to time sample dividing - // by the length of the time sample - auto timesample = int(dig.getTimeStamp() / emcal::constants::EMCAL_TIMESAMPLE); - if (timesample >= mNADCSamples) { - LOG(ERROR) << "Digit time sample " << timesample << " outside range [0," << mNADCSamples << "]"; - continue; - } - (*bunchDigits)[timesample] = &dig; } + + // Get time sample of the digit: + // Digitizer stores the time sample in ns, needs to be converted to time sample dividing + // by the length of the time sample + auto timesample = int(dig.getTimeStamp() / emcal::constants::EMCAL_TIMESAMPLE); + if (timesample >= mNADCSamples) { + LOG(ERROR) << "Digit time sample " << timesample << " outside range [0," << mNADCSamples << "]"; + continue; + } + (*bunchDigits)[timesample] = &dig; } // Create and fill DMA pages for each channel + std::cout << "encode data" << std::endl; std::vector payload; for (auto srucont : mSRUdata) { @@ -153,9 +144,9 @@ bool RawWriter::processNextTrigger() auto ddlid = srucont.mSRUid; auto [crorc, link] = getLinkAssignment(ddlid); LOG(DEBUG1) << "Adding payload with size " << payload.size() << " (" << payload.size() / 4 << " ALTRO words)"; - mRawWriter->addData(ddlid, crorc, link, 0, mCurrentTrigger->getBCData(), payload); + mRawWriter->addData(ddlid, crorc, link, 0, trg.getBCData(), payload); } - mCurrentTrigger++; + std::cout << "Done" << std::endl; return true; } From daa15b4358215fbe2b2c3f6dda2a608474380b3e Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 4 Sep 2020 18:29:07 +0200 Subject: [PATCH 05/76] Fix in output file names --- Detectors/EMCAL/simulation/src/RawCreator.cxx | 2 +- Detectors/EMCAL/simulation/src/RawWriter.cxx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Detectors/EMCAL/simulation/src/RawCreator.cxx b/Detectors/EMCAL/simulation/src/RawCreator.cxx index 01bdcc1fabad0..57c60140cea4e 100644 --- a/Detectors/EMCAL/simulation/src/RawCreator.cxx +++ b/Detectors/EMCAL/simulation/src/RawCreator.cxx @@ -109,5 +109,5 @@ int main(int argc, const char** argv) for (auto en : *treereader) { rawwriter.digitsToRaw(*digitbranch, *triggerbranch); } - rawwriter.getWriter().writeConfFile("EMC", "RAWDATA", o2::utils::concat_string(outputdir, "raw.cfg")); + rawwriter.getWriter().writeConfFile("EMC", "RAWDATA", o2::utils::concat_string(outputdir, "/EMCraw.cfg")); } diff --git a/Detectors/EMCAL/simulation/src/RawWriter.cxx b/Detectors/EMCAL/simulation/src/RawWriter.cxx index 292ddb2dd9501..b4c6d3b202b4b 100644 --- a/Detectors/EMCAL/simulation/src/RawWriter.cxx +++ b/Detectors/EMCAL/simulation/src/RawWriter.cxx @@ -35,7 +35,7 @@ void RawWriter::init() std::string rawfilename = mOutputLocation; switch (mFileFor) { case FileFor_t::kFullDet: - rawfilename += "/emcal.root"; + rawfilename += "/emcal.raw"; break; case FileFor_t::kSubDet: { std::string detstring; @@ -43,11 +43,11 @@ void RawWriter::init() detstring = "emcal"; else detstring = "dcal"; - rawfilename += fmt::format("/%s", detstring.data()); + rawfilename += fmt::format("/{:s}.raw", detstring.data()); break; }; case FileFor_t::kLink: - rawfilename += fmt::format("/emcal_%d_%d.root", crorc, link); + rawfilename += fmt::format("/emcal_{:d}_{:d}.raw", crorc, link); } mRawWriter->registerLink(iddl, crorc, link, 0, rawfilename.data()); } @@ -298,4 +298,4 @@ int RawWriter::carryOverMethod(const header::RDHAny* rdh, const gsl::span actualSize = sizeNoTrailer; } return actualSize; -} \ No newline at end of file +} From ac30578813e37eedd65af94f9b9434e844955cd5 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 31 Aug 2020 12:42:15 +0200 Subject: [PATCH 06/76] GPU: Remove duplicate compile option --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 22a2ba4e7fc4e..ab29f84956224 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -32,8 +32,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") ${targetName} PUBLIC GPUCA_GPULIBRARY=CUDA $) - target_compile_options(${targetName} PUBLIC --expt-relaxed-constexpr) - set_target_properties(${targetName} PROPERTIES LINKER_LANGUAGE CXX) install(FILES ${HDRS} DESTINATION include/GPU) From 4405bce1a9f94e036dce61440bcdcb6e6be749d8 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 30 Aug 2020 12:47:07 +0200 Subject: [PATCH 07/76] GPU: Add RTC compilation feature for CUDA --- GPU/Common/GPUCommonAlgorithm.h | 4 +- GPU/GPUTracking/Base/GPUGeneralKernels.h | 12 +- GPU/GPUTracking/Base/GPUSettingsList.h | 1 + GPU/GPUTracking/Base/cuda/CMakeLists.txt | 77 +++++++++++ .../Base/cuda/GPUReconstructionCUDA.cu | 127 +++++++++++++++--- .../cuda/GPUReconstructionCUDAInternals.h | 13 +- .../Base/cuda/GPUReconstructionCUDArtc.cu | 20 ++- .../Base/cuda/GPUReconstructionCUDArtcPre.h | 17 +-- .../Base/cuda/GPUReconstructionCUDArtcPre2.h | 23 ++++ GPU/GPUTracking/Base/opencl2/CMakeLists.txt | 10 +- GPU/GPUTracking/Standalone/standalone.cxx | 2 - .../Standalone/tools/rtc/rtcsource.sh | 7 +- 12 files changed, 251 insertions(+), 62 deletions(-) create mode 100644 GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h diff --git a/GPU/Common/GPUCommonAlgorithm.h b/GPU/Common/GPUCommonAlgorithm.h index b4822e1cf441a..4893eb99a07c2 100644 --- a/GPU/Common/GPUCommonAlgorithm.h +++ b/GPU/Common/GPUCommonAlgorithm.h @@ -212,7 +212,7 @@ typedef GPUCommonAlgorithm CAAlgo; } // namespace gpu } // namespace GPUCA_NAMESPACE -#if ((defined(__CUDACC__) && !defined(__clang__)) || defined(__HIPCC__)) && !defined(GPUCA_GPUCODE_GENRTC) +#if ((defined(__CUDACC__) && !defined(__clang__)) || defined(__HIPCC__)) #include "GPUCommonAlgorithmThrust.h" @@ -332,7 +332,7 @@ GPUdi() void GPUCommonAlgorithm::swap(T& a, T& b) #ifdef __OPENCL__ // Nothing to do, work_group functions available -#elif (defined(__CUDACC__) || defined(__HIPCC__)) && !defined(GPUCA_GPUCODE_GENRTC) +#elif (defined(__CUDACC__) || defined(__HIPCC__)) // CUDA and HIP work the same way using cub, need just different header #ifndef GPUCA_GPUCODE_GENRTC diff --git a/GPU/GPUTracking/Base/GPUGeneralKernels.h b/GPU/GPUTracking/Base/GPUGeneralKernels.h index f9e7d8a9e6a52..250a0420ad19f 100644 --- a/GPU/GPUTracking/Base/GPUGeneralKernels.h +++ b/GPU/GPUTracking/Base/GPUGeneralKernels.h @@ -17,14 +17,18 @@ #include "GPUDef.h" #include "GPUDataTypes.h" +#if defined(__HIPCC__) +#define GPUCA_CUB hipcub +#else +#define GPUCA_CUB cub +#endif + #ifndef GPUCA_GPUCODE_GENRTC #ifdef GPUCA_GPUCODE #ifdef __CUDACC__ #include -#define GPUCA_CUB cub #elif defined(__HIPCC__) #include -#define GPUCA_CUB hipcub #endif #endif #endif @@ -54,7 +58,7 @@ class GPUKernelTemplate template struct GPUSharedMemoryScan64 { // Provides the shared memory resources for CUB collectives -#if (defined(__CUDACC__) || defined(__HIPCC__)) && defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) +#if (defined(__CUDACC__) || defined(__HIPCC__)) && defined(GPUCA_GPUCODE) typedef GPUCA_CUB::BlockScan BlockScan; typedef GPUCA_CUB::BlockReduce BlockReduce; typedef GPUCA_CUB::WarpScan WarpScan; @@ -98,4 +102,6 @@ class GPUMemClean16 : public GPUKernelTemplate } // namespace gpu } // namespace GPUCA_NAMESPACE +#undef GPUCA_CUB + #endif diff --git a/GPU/GPUTracking/Base/GPUSettingsList.h b/GPU/GPUTracking/Base/GPUSettingsList.h index 526b7eab68458..a7e91bd89d488 100644 --- a/GPU/GPUTracking/Base/GPUSettingsList.h +++ b/GPU/GPUTracking/Base/GPUSettingsList.h @@ -113,6 +113,7 @@ AddOption(deviceTimers, bool, true, "", 0, "Use device timers instead of host-ba AddOption(registerStandaloneInputMemory, bool, false, "registerInputMemory", 0, "Automatically register input memory buffers for the GPU") AddOption(memoryScalingFactor, float, 1.f, "", 0, "Factor to apply to all memory scalers") AddOption(alternateBorderSort, int, -1, "", 0, "Alternative implementation for sorting of border tracks") +AddOption(enableRTC, bool, false, "", 0, "Use RTC to optimize GPU code") AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayBackend*, nullptr) AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index ab29f84956224..a185a87cbe279 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -18,6 +18,83 @@ message(STATUS "Building GPUTracking with CUDA support ${TMP_TARGET}") set(SRCS GPUReconstructionCUDA.cu) set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h) +# -------------------------------- Prepare RTC ------------------------------------------------------- +if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") + set(CURTC_DEFINES "-D$,$-D>" + "-I$,$-I>" + -DGPUCA_GPUCODE_GENRTC -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPULIBRARY=CUDA + ) + + set(CUDARTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -std=c++${CMAKE_CUDA_STANDARD}") + if(CUDA_COMPUTETARGET) + set(CUDARTC_FLAGS "${CUDARTC_FLAGS} -gencode arch=compute_${CUDA_COMPUTETARGET},code=sm_${CUDA_COMPUTETARGET}") + endif() + separate_arguments(CUDARTC_FLAGS) + + # convenience variables + if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + get_filename_component(GPUDIR ${CMAKE_SOURCE_DIR}/../ ABSOLUTE) + else() + set(GPUDIR ${CMAKE_SOURCE_DIR}/GPU/GPUTracking) + endif() + set(CURTC_SRC ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtc.cu) + set(CURTC_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionCUDArtc) + + # cmake-format: off + add_custom_command( + OUTPUT ${CURTC_BIN}.src + COMMAND echo "\\# 1 \"\\\"\"${GPUDIR}/Base/cuda/GPUReconstructionCUDArtc.cu\"\\\"\"" > ${CURTC_BIN}.src + COMMAND echo "\\# 1 \"\\\"\"${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre.h\"\\\"\" 1" >> ${CURTC_BIN}.src + COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre2.h >> ${CURTC_BIN}.src + COMMAND ${CMAKE_CUDA_COMPILER} ${CURTC_DEFINES} ${CUDARTC_FLAGS} -E ${CURTC_SRC} > ${CURTC_BIN}.src.tmp + COMMAND cat ${CURTC_BIN}.src.tmp | sed '1,/^\# 1 \".*GPUReconstructionCUDArtcPre.h\" 1$$/d' >> ${CURTC_BIN}.src + MAIN_DEPENDENCY ${CURTC_SRC} + IMPLICIT_DEPENDS CXX ${CURTC_SRC} + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + OUTPUT ${CURTC_BIN}.src.S + COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_src/g" | sed "s/FILENAMENORMAL/GPUReconstructionCUDArtc.src/g" > ${CURTC_BIN}.src.S + MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + ) + + add_custom_command( + OUTPUT ${CURTC_BIN}.command + COMMAND echo -n "${CMAKE_CUDA_COMPILER} ${CUDARTC_FLAGS}" > ${CURTC_BIN}.command + COMMAND_EXPAND_LISTS + VERBATIM + ) + + add_custom_command( + OUTPUT ${CURTC_BIN}.command.S + COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_command/g" | sed "s/FILENAMENORMAL/GPUReconstructionCUDArtc.command/g" > ${CURTC_BIN}.command.S + MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S + DEPENDS ${CURTC_BIN}.command + ) + # cmake-format: on + + # make cmake compile the assembler file, add proper dependency on included + # binary code + set_source_files_properties( + ${CURTC_BIN}.src.S + PROPERTIES + LANGUAGE + CXX + OBJECT_DEPENDS + "${CURTC_BIN}.src;${GPUDIR}/Standalone/makefiles/include.S") + + set_source_files_properties( + ${CURTC_BIN}.command.S + PROPERTIES + LANGUAGE + CXX + ) + + set(SRCS ${SRCS} ${CURTC_BIN}.src.S ${CURTC_BIN}.command.S) +endif() +# -------------------------------- End RTC ------------------------------------------------------- + if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_library( ${MODULE} diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index dcaabc9bc781d..665749aed3ddc 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -22,6 +22,7 @@ #include #include #pragma GCC diagnostic pop +#include #ifdef __clang__ #define assert(...) @@ -114,6 +115,10 @@ class GPUDebugTiming #include "GPUReconstructionIncludesDevice.h" +extern "C" char _curtc_GPUReconstructionCUDArtc_cu_src[]; +extern "C" unsigned int _curtc_GPUReconstructionCUDArtc_cu_src_size; +extern "C" char _curtc_GPUReconstructionCUDArtc_cu_command[]; + /* // Not using templated kernel any more, since nvidia profiler does not resolve template names template @@ -137,6 +142,16 @@ GPUg() void runKernelCUDA(GPUCA_CONSMEM_PTR int iSlice_internal, Args... args) #include "GPUReconstructionKernels.h" #undef GPUCA_KRNL +template +int GPUReconstructionCUDAInternals::getRTCkernelNum(int k) +{ + static int num = k; + if (num < 0) { + throw std::runtime_error("Invalid kernel"); + } + return num; +} + template <> void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) { @@ -144,11 +159,36 @@ void GPUReconstructionCUDABackend::runKernelBackendInternal(kr GPUFailedMsg(cudaMemsetAsync(ptr, 0, size, mInternals->Streams[_xyz.x.stream])); } +static void getArgPtrs(const void** pArgs) {} +template +static void getArgPtrs(const void** pArgs, const T& arg, const Args&... args) +{ + *pArgs = &arg; + getArgPtrs(pArgs + 1, args...); +} + template void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, const Args&... args) { GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (void**)mDebugEvents, mInternals->Streams, _xyz); - backendInternal::runKernelBackendMacro(_xyz, this, args...); + if (mProcessingSettings.enableRTC) { + auto& x = _xyz.x; + auto& y = _xyz.y; + if (y.num <= 1) { + const void* pArgs[sizeof...(Args) + 1]; + pArgs[0] = &y.start; + getArgPtrs(&pArgs[1], args...); + GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); + } else { + const void* pArgs[sizeof...(Args) + 2]; + pArgs[0] = &y.start; + pArgs[1] = &y.num; + getArgPtrs(&pArgs[2], args...); + GPUFailedMsg(cuLaunchKernel(*mInternals->rtcFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); + } + } else { + backendInternal::runKernelBackendMacro(_xyz, this, args...); + } } template @@ -409,25 +449,68 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() } } + dummyInitKernel<<>>(mDeviceMemoryBase); + GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, + (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); + + if (mProcessingSettings.enableRTC) { + GPUInfo("Starting CUDA RTC Compilation"); + HighResTimer rtcTimer; + rtcTimer.ResetStart(); + std::string filename = "/tmp/o2cagpu_rtc_"; + filename += std::to_string(getpid()); + filename += "_"; + filename += std::to_string(rand()); + if (mProcessingSettings.debugLevel >= 3) { + printf("Writing to %s\n", filename.c_str()); + } + FILE* fp = fopen((filename + ".cu").c_str(), "w+b"); + if (fp == nullptr) { + throw std::runtime_error("Error opening file"); + } + if (fwrite(_curtc_GPUReconstructionCUDArtc_cu_src, 1, _curtc_GPUReconstructionCUDArtc_cu_src_size, fp) != _curtc_GPUReconstructionCUDArtc_cu_src_size) { + throw std::runtime_error("Error writing file"); + } + fclose(fp); + std::string command = _curtc_GPUReconstructionCUDArtc_cu_command; + command += " -cubin -c " + filename + ".cu -o " + filename + ".o"; + if (mProcessingSettings.debugLevel >= 3) { + printf("Running command %s\n", command.c_str()); + } + if (system(command.c_str())) { + throw std::runtime_error("Runtime compilation failed"); + } + GPUFailedMsg(cuModuleLoad(&mInternals->rtcModule, (filename + ".o").c_str())); + +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ + mInternals->getRTCkernelNum(mInternals->rtcFunctions.size()); \ + mInternals->rtcFunctions.emplace_back(new CUfunction); \ + GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), mInternals->rtcModule, GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))))); +#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ + mInternals->getRTCkernelNum(mInternals->rtcFunctions.size()); \ + mInternals->rtcFunctions.emplace_back(new CUfunction); \ + GPUFailedMsg(cuModuleGetFunction(mInternals->rtcFunctions.back().get(), mInternals->rtcModule, GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)))); +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL +#undef GPUCA_KRNL_LOAD_single +#undef GPUCA_KRNL_LOAD_multi + + remove((filename + ".cu").c_str()); + remove((filename + ".o").c_str()); + GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); + } void* devPtrConstantMem; #ifndef GPUCA_NO_CONSTANT_MEMORY - if (GPUFailedMsgI(cudaGetSymbolAddress(&devPtrConstantMem, gGPUConstantMemBuffer))) { - GPUError("Error getting ptr to constant memory"); - GPUFailedMsgI(cudaDeviceReset()); - return 1; + if (mProcessingSettings.enableRTC) { + GPUFailedMsg(cuModuleGetGlobal((CUdeviceptr*)&devPtrConstantMem, nullptr, mInternals->rtcModule, "gGPUConstantMemBuffer")); + } else { + GPUFailedMsg(cudaGetSymbolAddress(&devPtrConstantMem, gGPUConstantMemBuffer)); } #else - if (GPUFailedMsgI(cudaMalloc(&devPtrConstantMem, gGPUConstantMemBufferSize))) { - GPUError("CUDA Memory Allocation Error"); - GPUFailedMsgI(cudaDeviceReset()); - return (1); - } + GPUFailedMsg(cudaMalloc(&devPtrConstantMem, gGPUConstantMemBufferSize)); #endif mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; - - dummyInitKernel<<>>(mDeviceMemoryBase); - GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, - (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); } else { GPUReconstructionCUDABackend* master = dynamic_cast(mMaster); mDeviceId = master->mDeviceId; @@ -546,15 +629,15 @@ size_t GPUReconstructionCUDABackend::WriteToConstantMemory(size_t offset, const } else { GPUFailedMsg(cudaMemcpyToSymbolAsync(gGPUConstantMemBuffer, src, size, offset, cudaMemcpyHostToDevice, mInternals->Streams[stream])); } - -#else - if (stream == -1) { - GPUFailedMsg(cudaMemcpy(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice)); - } else { - GPUFailedMsg(cudaMemcpyAsync(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice, mInternals->Streams[stream])); - } - + if (mProcessingSettings.enableRTC) #endif + { + if (stream == -1) { + GPUFailedMsg(cudaMemcpy(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice)); + } else { + GPUFailedMsg(cudaMemcpyAsync(((char*)mDeviceConstantMem) + offset, src, size, cudaMemcpyHostToDevice, mInternals->Streams[stream])); + } + } if (ev && stream != -1) { GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream])); } diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h index a02f6133ee354..11a41fdb4fba7 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h @@ -17,15 +17,22 @@ #define GPURECONSTRUCTIONCUDAINTERNALS_H #include "GPULogging.h" +#include +#include namespace GPUCA_NAMESPACE { namespace gpu { struct GPUReconstructionCUDAInternals { - CUcontext CudaContext; // Pointer to CUDA context - unsigned int cudaContextObtained = 0; // If multiple instances of GPUThreadContextCUDA are obtained, we count them and return the context only after all are destroyed - cudaStream_t Streams[GPUCA_MAX_STREAMS]; // Pointer to array of CUDA Streams + CUcontext CudaContext; // CUDA context + CUmodule rtcModule; // module for RTC compilation + std::vector> rtcFunctions; // vector of ptrs to RTC kernels + unsigned int cudaContextObtained = 0; // If multiple instances of GPUThreadContextCUDA are obtained, we count them and return the context only after all are destroyed + cudaStream_t Streams[GPUCA_MAX_STREAMS]; // Pointer to array of CUDA Streams + + template + static int getRTCkernelNum(int k = -1); }; #define GPUFailedMsg(x) GPUFailedMsgA(x, __FILE__, __LINE__) diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu index 52ebaf6fb9a03..797e4078a453f 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu @@ -19,9 +19,19 @@ #define GPUCA_GPUTYPE_TURING #include "GPUReconstructionIncludesDevice.h" -extern "C" __global__ void foo() -{ - if (threadIdx.x || blockIdx.x) - return; - printf("test\n"); +#ifndef GPUCA_GPUCODE_DEVICE +#error RTC Preprocessing must run on device code +#endif +#ifdef GPUCA_NO_CONSTANT_MEMORY +#error CUDA RTC does not support processing without constant memory +#endif + +extern "C" { +#undef GPUCA_KRNL_REG +#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) +#include "GPUReconstructionKernels.h" +#undef GPUCA_KRNL } diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h index d994f04c93a1e..016c4ee84401e 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h @@ -11,21 +11,6 @@ /// \file GPUReconstructionCUDArtcPre.h /// \author David Rohr -//#include -//#include -//#include -//#include +// Included during RTC preprocessing #define GPUCA_CONSMEM (gGPUConstantMemBuffer.v) -using uint64_t = unsigned long; -using uint32_t = unsigned int; -using uint16_t = unsigned short; -using uint8_t = unsigned char; -using uint = unsigned int; -using ushort = unsigned short; -using ulong = unsigned long; -#undef assert -#define assert(...) -void printf(...) -{ -} diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h new file mode 100644 index 0000000000000..a9c54f55c9a5f --- /dev/null +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h @@ -0,0 +1,23 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 GPUReconstructionCUDArtcPre2.h +/// \author David Rohr + +// Included during RTC compilation + +#define GPUCA_CONSMEM_PTR +#define GPUCA_CONSMEM_CALL + +#include +#include +#include +#include +#include diff --git a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt index 2a97b94f6e5ee..df3dc5eb959d4 100644 --- a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt @@ -25,7 +25,7 @@ set(CL_SRC ${GPUDIR}/Base/opencl-common/GPUReconstructionOCL.cl) set(CL_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCL2Code) set(OCL_FLAGS -cl-denorms-are-zero -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Xclang -finclude-default-header -Dcl_clang_storage_class_specifiers -Wno-invalid-constexpr -Wno-unused-command-line-argument -cl-std=clc++) -set(OCL_DEFINCL "-D$,$-D>" +set(OCL_DEFINECL "-D$,$-D>" "-I$,$-I>" -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src -I${CMAKE_SOURCE_DIR}/Detectors/Base/src @@ -47,7 +47,7 @@ if(OPENCL2_ENABLED_AMD) # BUILD OpenCL2 binaries for AMD target OUTPUT ${CL_BIN}.amd COMMAND ${CLANG_OCL} ${OCL_FLAGS} - ${OCL_DEFINCL} + ${OCL_DEFINECL} -mcpu=${OCL2_GPUTARGET} -o ${CL_BIN}.amd ${CL_SRC} MAIN_DEPENDENCY ${CL_SRC} @@ -82,7 +82,7 @@ if(OPENCL2_ENABLED_SPIRV) # BUILD OpenCL2 intermediate code for SPIR-V target COMMAND clang -emit-llvm --target=spir64-unknown-unknown ${OCL_FLAGS} - ${OCL_DEFINCL} + ${OCL_DEFINECL} -o ${CL_BIN}.bc -c ${CL_SRC} MAIN_DEPENDENCY ${CL_SRC} IMPLICIT_DEPENDS CXX ${CL_SRC} @@ -116,11 +116,11 @@ if(OPENCL2_ENABLED_SPIRV) # BUILD OpenCL2 intermediate code for SPIR-V target endif() if(OPENCL2_ENABLED) # BUILD OpenCL2 source code for runtime compilation target - # executes clang to create llvm IL code + # executes clang to preprocess add_custom_command( OUTPUT ${CL_BIN}.src COMMAND clang - ${OCL_DEFINCL} + ${OCL_DEFINECL} -E ${CL_SRC} > ${CL_BIN}.src MAIN_DEPENDENCY ${CL_SRC} IMPLICIT_DEPENDS CXX ${CL_SRC} diff --git a/GPU/GPUTracking/Standalone/standalone.cxx b/GPU/GPUTracking/Standalone/standalone.cxx index 10f48ca9e0439..f0b3e67f6896e 100644 --- a/GPU/GPUTracking/Standalone/standalone.cxx +++ b/GPU/GPUTracking/Standalone/standalone.cxx @@ -734,8 +734,6 @@ int main(int argc, char** argv) pipelineThread.reset(new std::thread([]() { rec->RunPipelineWorker(); })); } - // hlt.SetRunMerger(configStandalone.merger); //TODO! - if (configStandalone.seed == -1) { std::random_device rd; configStandalone.seed = (int)rd(); diff --git a/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh b/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh index a23e8a23e1a78..6eeb456d272c1 100755 --- a/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh +++ b/GPU/GPUTracking/Standalone/tools/rtc/rtcsource.sh @@ -2,15 +2,14 @@ cat < source.cu # 1 "/home/qon/alice/O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu" # 1 "/home/qon/alice/O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h" 1 -#include -int main(int, char**) {return 0;} EOT -nvcc -E \ +cat src/Base/cuda/GPUReconstructionCUDArtcPre2.h >> source.cu +nvcc -std=c++17 -gencode arch=compute_75,code=sm_75 -E \ -I src/ -I src/Common/ -I src/Base/ -I src/SliceTracker/ -I src/Merger/ -I src/TRDTracking/ -I src/TPCClusterFinder/ -I src/TPCConvert/ -I src/Global/ -I src/dEdx/ -I src/TPCFastTransformation/ -I src/GPUUtils/ -I src/DataCompression -I src/ITS \ -I$HOME/alice/O2/DataFormats/Detectors/TPC/include -I$HOME/alice/O2/Detectors/Base/include -I$HOME/alice/O2/Detectors/Base/src -I$HOME/alice/O2/Common/MathUtils/include -I$HOME/alice/O2/DataFormats/Headers/include \ -I$HOME/alice/O2/Detectors/TRD/base/include -I$HOME/alice/O2/Detectors/TRD/base/src -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/include -I$HOME/alice/O2/Detectors/ITSMFT/ITS/tracking/cuda/include -I$HOME/alice/O2/Common/Constants/include \ -I$HOME/alice/O2/DataFormats/common/include -I$HOME/alice/O2/DataFormats/Detectors/TRD/include -I$HOME/alice/O2/Detectors/Raw/include \ - -DHAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2 -DGPUCA_STANDALONE -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPUCODE_GENRTC -D__CUDA_ARCH__=750 \ + -DHAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2 -DGPUCA_STANDALONE -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPUCODE_GENRTC \ ~/alice/O2/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu \ | sed '1,/^# 1 ".*GPUReconstructionCUDArtcPre.h" 1$/d' \ >> source.cu From 9adbb6de666467f736a871de4deb87875a4ec06f Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 30 Aug 2020 23:05:49 +0200 Subject: [PATCH 08/76] GPU: Use CMAKE_CXX_COMPILER instead of CMAKE_CUDA_COMPILER for preprocessing RTC code to avoid automatic CUDA includes --- GPU/Common/GPUCommonMath.h | 2 +- GPU/GPUTracking/Base/GPUDataTypes.h | 2 +- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 10 +++++----- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu | 8 ++++++-- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu | 3 --- .../Base/cuda/GPUReconstructionCUDArtcPre2.h | 3 +++ GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx | 2 +- GPU/GPUTracking/Standalone/utils/bitfield.h | 2 +- GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx | 2 +- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/GPU/Common/GPUCommonMath.h b/GPU/Common/GPUCommonMath.h index 924b045feff75..71fc0517c2afd 100644 --- a/GPU/Common/GPUCommonMath.h +++ b/GPU/Common/GPUCommonMath.h @@ -16,7 +16,7 @@ #include "GPUCommonDef.h" -#if defined(__CUDACC__) && !defined(__clang__) +#if defined(__CUDACC__) && !defined(__clang__) && !defined(GPUCA_GPUCODE_GENRTC) #include #endif diff --git a/GPU/GPUTracking/Base/GPUDataTypes.h b/GPU/GPUTracking/Base/GPUDataTypes.h index de0e15928f535..bea67a6f06113 100644 --- a/GPU/GPUTracking/Base/GPUDataTypes.h +++ b/GPU/GPUTracking/Base/GPUDataTypes.h @@ -20,10 +20,10 @@ // Please add complex data types required on the host but not GPU to GPUHostDataTypes.h and forward-declare! #ifndef GPUCA_GPUCODE_DEVICE #include -#endif #ifdef GPUCA_NOCOMPAT_ALLOPENCL #include #endif +#endif #ifdef GPUCA_NOCOMPAT #include "GPUTRDDef.h" diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index a185a87cbe279..d8a8bcd0a7d5f 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -28,6 +28,9 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(CUDARTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -std=c++${CMAKE_CUDA_STANDARD}") if(CUDA_COMPUTETARGET) set(CUDARTC_FLAGS "${CUDARTC_FLAGS} -gencode arch=compute_${CUDA_COMPUTETARGET},code=sm_${CUDA_COMPUTETARGET}") + set(RTC_CUDA_ARCH "${CUDA_COMPUTETARGET}0") + else() + set(RTC_CUDA_ARCH "750") endif() separate_arguments(CUDARTC_FLAGS) @@ -43,11 +46,8 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") # cmake-format: off add_custom_command( OUTPUT ${CURTC_BIN}.src - COMMAND echo "\\# 1 \"\\\"\"${GPUDIR}/Base/cuda/GPUReconstructionCUDArtc.cu\"\\\"\"" > ${CURTC_BIN}.src - COMMAND echo "\\# 1 \"\\\"\"${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre.h\"\\\"\" 1" >> ${CURTC_BIN}.src - COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre2.h >> ${CURTC_BIN}.src - COMMAND ${CMAKE_CUDA_COMPILER} ${CURTC_DEFINES} ${CUDARTC_FLAGS} -E ${CURTC_SRC} > ${CURTC_BIN}.src.tmp - COMMAND cat ${CURTC_BIN}.src.tmp | sed '1,/^\# 1 \".*GPUReconstructionCUDArtcPre.h\" 1$$/d' >> ${CURTC_BIN}.src + COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre2.h > ${CURTC_BIN}.src + COMMAND ${CMAKE_CXX_COMPILER} ${CURTC_DEFINES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -D__CUDACC__ -x c++ -E ${CURTC_SRC} >> ${CURTC_BIN}.src MAIN_DEPENDENCY ${CURTC_SRC} IMPLICIT_DEPENDS CXX ${CURTC_SRC} COMMAND_EXPAND_LISTS diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index 665749aed3ddc..7234ecb3cf20b 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -454,7 +454,9 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); if (mProcessingSettings.enableRTC) { - GPUInfo("Starting CUDA RTC Compilation"); + if (mProcessingSettings.debugLevel >= 0) { + GPUInfo("Starting CUDA RTC Compilation"); + } HighResTimer rtcTimer; rtcTimer.ResetStart(); std::string filename = "/tmp/o2cagpu_rtc_"; @@ -498,7 +500,9 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() remove((filename + ".cu").c_str()); remove((filename + ".o").c_str()); - GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); + if (mProcessingSettings.debugLevel >= 0) { + GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); + } } void* devPtrConstantMem; #ifndef GPUCA_NO_CONSTANT_MEMORY diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu index 797e4078a453f..5df857bd136be 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu @@ -11,9 +11,6 @@ /// \file GPUReconstructionCUDArtc.cu /// \author David Rohr -#include -#include - #include "GPUReconstructionCUDArtcPre.h" #define GPUCA_GPUTYPE_TURING diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h index a9c54f55c9a5f..060d1ece7aaca 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h @@ -17,7 +17,10 @@ #define GPUCA_CONSMEM_CALL #include +#include +#include #include #include #include #include +#include diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx index 5b3262825749f..310f77dcb5230 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGrid.cxx @@ -15,7 +15,7 @@ #include "GPUCommonMath.h" using namespace GPUCA_NAMESPACE::gpu; -#ifndef assert +#if !defined(assert) && !defined(GPUCA_GPUCODE) #include #endif diff --git a/GPU/GPUTracking/Standalone/utils/bitfield.h b/GPU/GPUTracking/Standalone/utils/bitfield.h index 366de17584713..bf102cee5e343 100644 --- a/GPU/GPUTracking/Standalone/utils/bitfield.h +++ b/GPU/GPUTracking/Standalone/utils/bitfield.h @@ -14,7 +14,7 @@ #ifndef Q_BITFIELD_H #define Q_BITFIELD_H -#ifdef GPUCA_NOCOMPAT_ALLOPENCL +#if !defined(GPUCA_NOCOMPAT_ALLOPENCL) && !defined(GPUCA_GPUCODE_GENRTC) #include #endif diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx index 1a899c409620d..f12833a6ddb9f 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackletWord.cxx @@ -13,7 +13,7 @@ #include "GPUTRDTrackletWord.h" using namespace GPUCA_NAMESPACE::gpu; -#ifndef __OPENCL__ +#ifndef GPUCA_GPUCODE_DEVICE #include #endif From 8ede5658ec5e279c39a11a013aaa562107546e07 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 31 Aug 2020 11:42:43 +0200 Subject: [PATCH 09/76] GPU: Merge CUDA normal compile and rtc defs and includes into header files --- .../Base/GPUReconstructionIncludes.h | 6 ---- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 13 +++---- .../Base/cuda/GPUReconstructionCUDA.cu | 28 ++------------- .../Base/cuda/GPUReconstructionCUDADef.h | 34 +++++++++++++++++++ ...Pre2.h => GPUReconstructionCUDAIncludes.h} | 14 +++++--- .../Base/cuda/GPUReconstructionCUDArtc.cu | 4 +-- .../Base/cuda/GPUReconstructionCUDArtcPre.h | 16 --------- 7 files changed, 53 insertions(+), 62 deletions(-) create mode 100644 GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h rename GPU/GPUTracking/Base/cuda/{GPUReconstructionCUDArtcPre2.h => GPUReconstructionCUDAIncludes.h} (73%) delete mode 100644 GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h index d08ed50241ac7..8ba82395794b3 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h @@ -14,12 +14,6 @@ #ifndef GPURECONSTRUCTIONINCLUDES_H #define GPURECONSTRUCTIONINCLUDES_H -// Disable assertions since they produce errors in GPU Code -#ifdef assert -#undef assert -#endif -#define assert(param) - #ifndef WIN32 #include #include diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index d8a8bcd0a7d5f..cad6a7ae40d11 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -16,14 +16,15 @@ endif() message(STATUS "Building GPUTracking with CUDA support ${TMP_TARGET}") set(SRCS GPUReconstructionCUDA.cu) -set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h) +set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDIncludes.h) # -------------------------------- Prepare RTC ------------------------------------------------------- if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(CURTC_DEFINES "-D$,$-D>" - "-I$,$-I>" - -DGPUCA_GPUCODE_GENRTC -DGPUCA_NO_ITS_TRAITS -DGPUCA_GPULIBRARY=CUDA + -DGPUCA_GPUCODE_GENRTC -DGPUCA_GPULIBRARY=CUDA ) + set(CURTC_INCLUDES "-I$,$-I>") + #set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -keep") set(CUDARTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -std=c++${CMAKE_CUDA_STANDARD}") if(CUDA_COMPUTETARGET) @@ -46,8 +47,8 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") # cmake-format: off add_custom_command( OUTPUT ${CURTC_BIN}.src - COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtcPre2.h > ${CURTC_BIN}.src - COMMAND ${CMAKE_CXX_COMPILER} ${CURTC_DEFINES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -D__CUDACC__ -x c++ -E ${CURTC_SRC} >> ${CURTC_BIN}.src + COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludes.h > ${CURTC_BIN}.src + COMMAND ${CMAKE_CXX_COMPILER} ${CURTC_DEFINES} ${CURTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -D__CUDACC__ -x c++ -E ${CURTC_SRC} >> ${CURTC_BIN}.src MAIN_DEPENDENCY ${CURTC_SRC} IMPLICIT_DEPENDS CXX ${CURTC_SRC} COMMAND_EXPAND_LISTS @@ -61,7 +62,7 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_custom_command( OUTPUT ${CURTC_BIN}.command - COMMAND echo -n "${CMAKE_CUDA_COMPILER} ${CUDARTC_FLAGS}" > ${CURTC_BIN}.command + COMMAND echo -n "${CMAKE_CUDA_COMPILER} ${CUDARTC_FLAGS} ${CURTC_DEFINES}" > ${CURTC_BIN}.command COMMAND_EXPAND_LISTS VERBATIM ) diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index 7234ecb3cf20b..83a30d81c8f30 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -11,36 +11,12 @@ /// \file GPUReconstructionCUDA.cu /// \author David Rohr -#define GPUCA_GPUTYPE_TURING -#define GPUCA_UNROLL(CUDA, HIP) GPUCA_M_UNROLL_##CUDA -#define GPUdic(CUDA, HIP) GPUCA_GPUdic_select_##CUDA() +#include "GPUReconstructionCUDADef.h" +#include "GPUReconstructionCUDAIncludes.h" -#include #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" -#include -#include -#pragma GCC diagnostic pop #include -#ifdef __clang__ -#define assert(...) -#endif - -#include "GPUDef.h" - -#ifndef GPUCA_NO_CONSTANT_MEMORY -#define GPUCA_CONSMEM_PTR -#define GPUCA_CONSMEM_CALL -#define GPUCA_CONSMEM (gGPUConstantMemBuffer.v) -#else -#define GPUCA_CONSMEM_PTR const GPUConstantMem *gGPUConstantMemBuffer, -#define GPUCA_CONSMEM_CALL me->mDeviceConstantMem, -#define GPUCA_CONSMEM ((GPUConstantMem&)(*gGPUConstantMemBuffer)) -#endif -#define GPUCA_KRNL_BACKEND_CLASS GPUReconstructionCUDABackend - #include "GPUReconstructionCUDA.h" #include "GPUReconstructionCUDAInternals.h" #include "GPUReconstructionIncludes.h" diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h new file mode 100644 index 0000000000000..ce3d0c53b4d78 --- /dev/null +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDADef.h @@ -0,0 +1,34 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 GPUReconstructionCUDDef.h +/// \author David Rohr + +#ifndef O2_GPU_GPURECONSTRUCTIONCUDADEF_H +#define O2_GPU_GPURECONSTRUCTIONCUDADEF_H + +#define GPUCA_GPUTYPE_TURING +#define GPUCA_UNROLL(CUDA, HIP) GPUCA_M_UNROLL_##CUDA +#define GPUdic(CUDA, HIP) GPUCA_GPUdic_select_##CUDA() + +#include "GPUDef.h" + +#ifndef GPUCA_NO_CONSTANT_MEMORY +#define GPUCA_CONSMEM_PTR +#define GPUCA_CONSMEM_CALL +#define GPUCA_CONSMEM (gGPUConstantMemBuffer.v) +#else +#define GPUCA_CONSMEM_PTR const GPUConstantMem *gGPUConstantMemBuffer, +#define GPUCA_CONSMEM_CALL me->mDeviceConstantMem, +#define GPUCA_CONSMEM ((GPUConstantMem&)(*gGPUConstantMemBuffer)) +#endif +#define GPUCA_KRNL_BACKEND_CLASS GPUReconstructionCUDABackend + +#endif diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h similarity index 73% rename from GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h rename to GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h index 060d1ece7aaca..fff90de9349f8 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre2.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAIncludes.h @@ -8,19 +8,23 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file GPUReconstructionCUDArtcPre2.h +/// \file GPUReconstructionCUDIncludes.h /// \author David Rohr -// Included during RTC compilation - -#define GPUCA_CONSMEM_PTR -#define GPUCA_CONSMEM_CALL +#ifndef O2_GPU_GPURECONSTRUCTIONCUDAINCLUDES_H +#define O2_GPU_GPURECONSTRUCTIONCUDAINCLUDES_H #include #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include #include #include #include #include +#pragma GCC diagnostic pop #include + +#endif diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu index 5df857bd136be..194093439f34b 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtc.cu @@ -11,9 +11,7 @@ /// \file GPUReconstructionCUDArtc.cu /// \author David Rohr -#include "GPUReconstructionCUDArtcPre.h" - -#define GPUCA_GPUTYPE_TURING +#include "GPUReconstructionCUDADef.h" #include "GPUReconstructionIncludesDevice.h" #ifndef GPUCA_GPUCODE_DEVICE diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h deleted file mode 100644 index 016c4ee84401e..0000000000000 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDArtcPre.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 GPUReconstructionCUDArtcPre.h -/// \author David Rohr - -// Included during RTC preprocessing - -#define GPUCA_CONSMEM (gGPUConstantMemBuffer.v) From c834c0f7a1eaa1b7326dde0da4f6c9e543b1c8c1 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 31 Aug 2020 12:39:37 +0200 Subject: [PATCH 10/76] GPU: Fix CUDA run time compilation for AliRoot compilation and with tpc-reco-workflow --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 14 ++++++++++---- GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu | 4 ++++ GPU/GPUTracking/Global/GPUChainTracking.cxx | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index cad6a7ae40d11..5d5e41b5fa28d 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -16,14 +16,20 @@ endif() message(STATUS "Building GPUTracking with CUDA support ${TMP_TARGET}") set(SRCS GPUReconstructionCUDA.cu) -set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDIncludes.h) +set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDAIncludes.h) # -------------------------------- Prepare RTC ------------------------------------------------------- if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(CURTC_DEFINES "-D$,$-D>" -DGPUCA_GPUCODE_GENRTC -DGPUCA_GPULIBRARY=CUDA ) - set(CURTC_INCLUDES "-I$,$-I>") + set(CURTC_INCLUDES "-I$,$-I>" + -I${CMAKE_SOURCE_DIR}/Detectors/Base/src + -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src + ) + if(ALIGPU_BUILD_TYPE STREQUAL "O2") + set(CURTC_INCLUDES ${CURTC_INCLUDES} "-I$,$-I>") + endif() #set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -keep") set(CUDARTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -std=c++${CMAKE_CUDA_STANDARD}") @@ -56,7 +62,7 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_custom_command( OUTPUT ${CURTC_BIN}.src.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_src/g" | sed "s/FILENAMENORMAL/GPUReconstructionCUDArtc.src/g" > ${CURTC_BIN}.src.S + COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_src/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.src,g" > ${CURTC_BIN}.src.S MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S ) @@ -69,7 +75,7 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") add_custom_command( OUTPUT ${CURTC_BIN}.command.S - COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_command/g" | sed "s/FILENAMENORMAL/GPUReconstructionCUDArtc.command/g" > ${CURTC_BIN}.command.S + COMMAND cat ${GPUDIR}/Standalone/makefiles/include.S | sed "s/FILENAMEMOD/_curtc_GPUReconstructionCUDArtc_cu_command/g" | sed "s,FILENAMENORMAL,${CURTC_BIN}.command,g" > ${CURTC_BIN}.command.S MAIN_DEPENDENCY ${GPUDIR}/Standalone/makefiles/include.S DEPENDS ${CURTC_BIN}.command ) diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index 83a30d81c8f30..0e0d0636b1e4a 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -91,9 +91,11 @@ class GPUDebugTiming #include "GPUReconstructionIncludesDevice.h" +#ifndef GPUCA_ALIROOT_LIB extern "C" char _curtc_GPUReconstructionCUDArtc_cu_src[]; extern "C" unsigned int _curtc_GPUReconstructionCUDArtc_cu_src_size; extern "C" char _curtc_GPUReconstructionCUDArtc_cu_command[]; +#endif /* // Not using templated kernel any more, since nvidia profiler does not resolve template names @@ -429,6 +431,7 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); +#ifndef GPUCA_ALIROOT_LIB if (mProcessingSettings.enableRTC) { if (mProcessingSettings.debugLevel >= 0) { GPUInfo("Starting CUDA RTC Compilation"); @@ -480,6 +483,7 @@ int GPUReconstructionCUDABackend::InitDevice_Runtime() GPUInfo("RTC Compilation finished (%f seconds)", rtcTimer.GetCurrentElapsedTime()); } } +#endif void* devPtrConstantMem; #ifndef GPUCA_NO_CONSTANT_MEMORY if (mProcessingSettings.enableRTC) { diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 0aa006aafcc80..a8b4268b277be 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -2075,12 +2075,14 @@ int GPUChainTracking::RunTPCCompression() runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); TransferMemoryResourcesToHost(myStep, &Compressor, 0); +#ifdef GPUCA_TPC_GEOMETRY_O2 if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { SynchronizeEvents(&mEvents->single); ReleaseEvent(&mEvents->single); ((GPUChainTracking*)GetNextChainInQueue())->RunTPCClusterizer_prepare(false); ((GPUChainTracking*)GetNextChainInQueue())->mCFContext->ptrClusterNativeSave = processorsShadow()->ioPtrs.clustersNative; } +#endif SynchronizeStream(0); o2::tpc::CompressedClusters* O = Compressor.mOutput; memset((void*)O, 0, sizeof(*O)); From 5bafbc32614453fa11fa53a22ac095bf1230cd34 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 28 Aug 2020 16:04:12 +0200 Subject: [PATCH 11/76] TPC: Remove obsolete functionality --- .../reconstruction/include/TPCReconstruction/GPUCATracking.h | 2 -- Detectors/TPC/reconstruction/src/GPUCATracking.cxx | 2 -- 2 files changed, 4 deletions(-) diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h index 9ec0e70bdfca8..7ff7d2d0e8729 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/GPUCATracking.h @@ -59,7 +59,6 @@ class GPUCATracking int runTracking(o2::gpu::GPUO2InterfaceIOPtrs* data, o2::gpu::GPUInterfaceOutputs* outputs = nullptr); float getPseudoVDrift(); //Return artificial VDrift used to convert time to Z - int getNTracksASide() { return mNTracksASide; } void GetClusterErrors2(int row, float z, float sinPhi, float DzDs, short clusterState, float& ErrY2, float& ErrZ2) const; int registerMemoryForGPU(const void* ptr, size_t size); @@ -71,7 +70,6 @@ class GPUCATracking //The GPUCATracking class interfaces this library via this pointer to GPUTPCO2Interface class. static constexpr float sTrackMCMaxFake = 0.1; - int mNTracksASide = 0; }; } // namespace tpc diff --git a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx b/Detectors/TPC/reconstruction/src/GPUCATracking.cxx index d5c3ea09f2deb..2a572c58a2703 100644 --- a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx +++ b/Detectors/TPC/reconstruction/src/GPUCATracking.cxx @@ -164,8 +164,6 @@ int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* std::sort(trackSort.data() + tmp2, trackSort.data() + tmp, [](const auto& a, const auto& b) { return (a.second > b.second); }); tmp2 = tmp; - if (cside == 0) - mNTracksASide = tmp; } nTracks = tmp; outputTracks->resize(nTracks); From 6a1c8d5c3561a86c12331ce655b27e6b6a6d5fea Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 5 Sep 2020 13:25:05 +0200 Subject: [PATCH 12/76] Fix compiler warning about initialization order --- .../Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h index e39917d94afe2..4799d43fa7d2d 100644 --- a/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h +++ b/DataFormats/Detectors/ITSMFT/ITS/include/DataFormatsITS/TrackITS.h @@ -43,7 +43,7 @@ class TrackITS : public o2::track::TrackParCov TrackITS(const TrackITS& t) = default; TrackITS(const o2::track::TrackParCov& parcov) : TrackParCov{parcov} {} TrackITS(const o2::track::TrackParCov& parCov, float chi2, const o2::track::TrackParCov& outer) - : o2::track::TrackParCov{parCov}, mChi2{chi2}, mParamOut{outer} {} + : o2::track::TrackParCov{parCov}, mParamOut{outer}, mChi2{chi2} {} TrackITS& operator=(const TrackITS& tr) = default; ~TrackITS() = default; From 93323ec9355d91e86206f6030e7d976d0be7ea20 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 4 Sep 2020 22:46:37 +0200 Subject: [PATCH 13/76] RawPixelDecoder will fill chip decoding errors/statistics When AlpideCoder is compiled with ALPIDE_DECODING_STAT defined, the chip decoding statistics and errors will be filled in the ChipStat chipStat stuct of every GBT link. All counters (also those of GBTLink::statistics for the link level errors) can be reset via RawPixelDecoder::clearStat(). Note that in ALPIDE_DECODING_STAT the decoding will add a chip to the list of non-empty chips (i.e. it will be accessible by RawPixelDecoder::getNextChipData) even if it had no any hit but had at least 1 error set. These errors on the single trigger level can be accessed via uint32_t ChipPixelData::getErrorFlags() method, with each bit corresponding to ChipStat::DecErrors enum --- .../common/reconstruction/CMakeLists.txt | 4 +- .../ITSMFTReconstruction/AlpideCoder.h | 77 +++++++-- .../ITSMFTReconstruction/DecodingStat.h | 155 ++++++++++++++++++ .../include/ITSMFTReconstruction/GBTLink.h | 67 +------- .../include/ITSMFTReconstruction/PixelData.h | 10 ++ .../ITSMFTReconstruction/RUDecodeData.h | 35 ++-- .../ITSMFTReconstruction/RawPixelDecoder.h | 9 +- .../common/reconstruction/src/AlpideCoder.cxx | 5 + .../reconstruction/src/DecodingStat.cxx | 68 ++++++++ .../common/reconstruction/src/GBTLink.cxx | 112 +++++-------- .../src/ITSMFTReconstructionLinkDef.h | 1 + .../reconstruction/src/RUDecodeData.cxx | 8 + .../reconstruction/src/RawPixelDecoder.cxx | 21 ++- 13 files changed, 402 insertions(+), 170 deletions(-) create mode 100644 Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h create mode 100644 Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx diff --git a/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt index 6d5b8f97fd9eb..a1de05e673e1a 100644 --- a/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/common/reconstruction/CMakeLists.txt @@ -27,6 +27,7 @@ o2_add_library(ITSMFTReconstruction src/RUDecodeData.cxx src/RawPixelDecoder.cxx src/CTFCoder.cxx + src/DecodingStat.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTBase O2::CommonDataFormat O2::DetectorsRaw @@ -55,7 +56,8 @@ o2_target_root_dictionary( include/ITSMFTReconstruction/AlpideCoder.h include/ITSMFTReconstruction/GBTWord.h include/ITSMFTReconstruction/PayLoadCont.h - include/ITSMFTReconstruction/PayLoadSG.h + include/ITSMFTReconstruction/PayLoadSG.h + include/ITSMFTReconstruction/DecodingStat.h include/ITSMFTReconstruction/RUInfo.h) if (OpenMP_CXX_FOUND) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index 824393966a625..fa0a5f0aaf921 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -17,14 +17,17 @@ #include #include #include -#include -#include +#include "Framework/Logger.h" #include "PayLoadCont.h" #include +#include #include "ITSMFTReconstruction/PixelData.h" +#include "ITSMFTReconstruction/DecodingStat.h" #include "DataFormatsITSMFT/NoiseMap.h" +#define ALPIDE_DECODING_STAT + /// \file AlpideCoder.h /// \brief class for the ALPIDE data decoding/encoding /// \author Ruben Shahoyan, ruben.shahoyan@cern.ch @@ -68,6 +71,7 @@ class AlpideCoder static constexpr uint32_t ExpectChipEmpty = 0x1 << 2; static constexpr uint32_t ExpectRegion = 0x1 << 3; static constexpr uint32_t ExpectData = 0x1 << 4; + static constexpr uint32_t ExpectBUSY = 0x1 << 5; static constexpr int NRows = 512; static constexpr int NCols = 1024; static constexpr int NRegions = 32; @@ -80,7 +84,10 @@ class AlpideCoder static constexpr uint32_t MaskDColID = MaskEncoder | MaskPixID; // mask for encoder + dcolumn combination static constexpr uint32_t MaskRegion = 0x1f; // region ID takes 5 bits max (0:31) static constexpr uint32_t MaskChipID = 0x0f; // chip id in module takes 4 bit max - static constexpr uint32_t MaskROFlags = 0x0f; // RO flags in chip header takes 4 bit max + static constexpr uint32_t MaskROFlags = 0x0f; // RO flags in chip trailer takes 4 bit max + static constexpr uint8_t MaskErrBusyViolation = 0x1 << 3; + static constexpr uint8_t MaskErrDataOverrun = 0x3 << 2; + static constexpr uint8_t MaskErrFatal = 0x7 << 1; static constexpr uint32_t MaskTimeStamp = 0xff; // Time stamps as BUNCH_COUNTER[10:3] bits static constexpr uint32_t MaskReserved = 0xff; // mask for reserved byte static constexpr uint32_t MaskHitMap = 0x7f; // mask for hit map: at most 7 hits in bits (0:6) @@ -92,6 +99,8 @@ class AlpideCoder static constexpr uint32_t CHIPEMPTY = 0xe0; // flag for empty chip static constexpr uint32_t DATALONG = 0x0000; // flag for DATALONG static constexpr uint32_t DATASHORT = 0x4000; // flag for DATASHORT + static constexpr uint32_t BUSYOFF = 0xf0; // flag for BUSY_OFF + static constexpr uint32_t BUSYON = 0xf1; // flag for BUSY_ON // true if corresponds to DATALONG or DATASHORT: highest bit must be 0 static bool isData(uint16_t v) { return (v & (0x1 << 15)) == 0; } @@ -132,8 +141,11 @@ class AlpideCoder uint8_t dataCM = dataC & (~MaskChipID); // if ((expectInp & ExpectChipEmpty) && dataCM == CHIPEMPTY) { // empty chip was expected - //chipData.setChipID(dataC & MaskChipID); // here we set the chip ID within the module + //chipData.setChipID(dataC & MaskChipID); // here we set the chip ID within the module // now set upstream if (!buffer.next(timestamp)) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::TruncatedChipEmpty); +#endif return unexpectedEOF("CHIP_EMPTY:Timestamp"); } expectInp = ExpectChipHeader | ExpectChipEmpty; @@ -141,8 +153,11 @@ class AlpideCoder } if ((expectInp & ExpectChipHeader) && dataCM == CHIPHEADER) { // chip header was expected - //chipData.setChipID(dataC & MaskChipID); // here we set the chip ID within the module + //chipData.setChipID(dataC & MaskChipID); // here we set the chip ID within the module // now set upstream if (!buffer.next(timestamp)) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::TruncatedChipHeader); +#endif return unexpectedEOF("CHIP_HEADER"); } expectInp = ExpectRegion; // now expect region info @@ -159,6 +174,18 @@ class AlpideCoder if ((expectInp & ExpectChipTrailer) && dataCM == CHIPTRAILER) { // chip trailer was expected expectInp = ExpectChipHeader | ExpectChipEmpty; chipData.setROFlags(dataC & MaskROFlags); +#ifdef ALPIDE_DECODING_STAT + uint8_t roErr = dataC & MaskROFlags; + if (roErr) { + if (roErr == MaskErrBusyViolation) { + chipData.setError(ChipStat::BusyViolation); + } else if (roErr == MaskErrDataOverrun) { + chipData.setError(ChipStat::DataOverrun); + } else if (roErr == MaskErrFatal) { + chipData.setError(ChipStat::Fatal); + } + } +#endif // in case there are entries in the "right" columns buffer, add them to the container if (nRightCHits) { colDPrev++; @@ -175,6 +202,9 @@ class AlpideCoder // note that here we are checking on the byte rather than the short, need complete to ushort dataS = dataC << 8; if (!buffer.next(dataC)) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::TruncatedRegion); +#endif return unexpectedEOF("CHIPDATA"); } dataS |= dataC; @@ -211,8 +241,16 @@ class AlpideCoder if ((dataS & (~MaskDColID)) == DATALONG) { // multiple hits ? uint8_t hitsPattern = 0; if (!buffer.next(hitsPattern)) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::TruncatedLondData); +#endif return unexpectedEOF("CHIP_DATA_LONG:Pattern"); } +#ifdef ALPIDE_DECODING_STAT + if (hitsPattern & (~MaskHitMap)) { + chipData.setError(ChipStat::WrongDataLongPattern); + } +#endif for (int ip = 0; ip < HitMapSize; ip++) { if (hitsPattern & (0x1 << ip)) { uint16_t addr = pixID + ip + 1, rowE = addr >> 1; @@ -227,6 +265,9 @@ class AlpideCoder } } } else { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::NoDataFound); +#endif LOG(ERROR) << "Expected DataShort or DataLong mask, got : " << dataS; return Error; } @@ -234,13 +275,27 @@ class AlpideCoder continue; // end of DATA(SHORT or LONG) processing } + if (dataC == BUSYON) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::BusyOn); +#endif + continue; + } + if (dataC == BUSYOFF) { +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::BusyOff); +#endif + continue; + } + if (!dataC) { buffer.clear(); // 0 padding reached (end of the cable data), no point in continuing break; } - std::stringstream stream; - stream << "Unknown word 0x" << std::hex << int(dataC) << " [mode = 0x" << int(expectInp) << "]"; - return unexpectedEOF(stream.str().c_str()); // error +#ifdef ALPIDE_DECODING_STAT + chipData.setError(ChipStat::UnknownWord); +#endif + return unexpectedEOF(fmt::format("Unknown word 0x{:x} [expectation = 0x{:x}]", int(dataC), int(expectInp))); // error } return chipData.getData().size(); @@ -362,11 +417,7 @@ class AlpideCoder void resetMap(); ///< error message on unexpected EOF - static int unexpectedEOF(const char* message) - { - printf("Error: unexpected EOF on %s\n", message); - return Error; - } + static int unexpectedEOF(const std::string& message); // ===================================================================== // diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h new file mode 100644 index 0000000000000..c6f5cebb672a8 --- /dev/null +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DecodingStat.h @@ -0,0 +1,155 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 DecodingStat.h +/// \brief Alpide Chip and GBT link decoding statistics + +#ifndef _ALICEO2_DECODINGSTAT_H_ +#define _ALICEO2_DECODINGSTAT_H_ + +#include +#include +#include +#include "ITSMFTReconstruction/GBTWord.h" + +namespace o2 +{ +namespace itsmft +{ + +struct ChipStat { + + enum DecErrors : int { + BusyViolation, + DataOverrun, + Fatal, + BusyOn, + BusyOff, + TruncatedChipEmpty, // Data was truncated after ChipEmpty + TruncatedChipHeader, // Data was truncated after ChipHeader + TruncatedRegion, // Data was truncated after Region record + TruncatedLondData, // Data was truncated in the LongData record + WrongDataLongPattern, // LongData pattern has highest bit set + NoDataFound, // Region is not followed by Short or Long data + UnknownWord, // Unknow word was seen + NErrorsDefined + }; + + static constexpr std::array ErrNames = { + "BusyViolation flag ON", // BusyViolation + "DataOverrun flag ON", // DataOverrun + "Fatal flag ON", // Fatal + "BusyON", // BusyOn + "BusyOFF", // BusyOff + "Data truncated after ChipEmpty", // TruncatedChipEmpty + "Data truncated after ChipHeader", // TruncatedChipHeader + "Data truncated after Region", // TruncatedRegion + "Data truncated after LongData", // TruncatedLondData + "LongData pattern has highest bit set", // WrongDataLongPattern + "Region is not followed by Short or Long data", // NoDataFound + "Unknow word" // UnknownWord + }; + + uint16_t chipID = 0; + size_t nHits = 0; + std::array errorCounts = {}; + ChipStat() = default; + ChipStat(uint16_t id) : chipID(id) {} + + void clear() + { + memset(errorCounts.data(), 0, sizeof(uint32_t) * errorCounts.size()); + nHits = 0; + } + + uint32_t getNErrors() const; + + void addErrors(uint32_t mask) + { + if (mask) { + for (int i = NErrorsDefined; i--;) { + if (mask & (0x1 << i)) { + errorCounts[i]++; + } + } + } + } + + void print(bool skipEmpty = true) const; + + ClassDefNV(ChipStat, 1); +}; + +/// Statistics for per-link decoding +struct GBTLinkDecodingStat { + /// counters for format checks + + enum DecErrors : int { + ErrNoRDHAtStart, // page does not start with RDH + ErrPageNotStopped, // new HB/trigger page started w/o stopping previous one + ErrStopPageNotEmpty, // Page with RDH.stop is not empty + ErrPageCounterDiscontinuity, // RDH page counters for the same RU/trigger are not continuous + ErrRDHvsGBTHPageCnt, // RDH and GBT header page counters are not consistent + ErrMissingGBTTrigger, // GBT trigger word was expected but not found + ErrMissingGBTHeader, // GBT payload header was expected but not found + ErrMissingGBTTrailer, // GBT payload trailer was expected but not found + ErrNonZeroPageAfterStop, // all lanes were stopped but the page counter in not 0 + ErrUnstoppedLanes, // end of FEE data reached while not all lanes received stop + ErrDataForStoppedLane, // data was received for stopped lane + ErrNoDataForActiveLane, // no data was seen for lane (which was not in timeout) + ErrIBChipLaneMismatch, // chipID (on module) was different from the lane ID on the IB stave + ErrCableDataHeadWrong, // cable data does not start with chip header or empty chip + ErrInvalidActiveLanes, // active lanes pattern conflicts with expected for given RU type + ErrPacketCounterJump, // jump in RDH.packetCounter + ErrPacketDoneMissing, // packet done is missing in the trailer while CRU page is not over + NErrorsDefined + }; + static constexpr std::array ErrNames = { + "Page data not start with expected RDH", // ErrNoRDHAtStart + "New HB/trigger page started w/o stopping previous one", // ErrPageNotStopped + "Page with RDH.stop is not empty", // ErrStopPageNotEmpty + "RDH page counters for the same RU/trigger are not continuous", // ErrPageCounterDiscontinuity + "RDH and GBT header page counters are not consistent", // ErrRDHvsGBTHPageCnt + "GBT trigger word was expected but not found", // ErrMissingGBTTrigger + "GBT payload header was expected but not found", // ErrMissingGBTHeader + "GBT payload trailer was expected but not found", // ErrMissingGBTTrailer + "All lanes were stopped but the page counter in not 0", // ErrNonZeroPageAfterStop + "End of FEE data reached while not all lanes received stop", // ErrUnstoppedLanes + "Data was received for stopped lane", // ErrDataForStoppedLane + "No data was seen for lane (which was not in timeout)", // ErrNoDataForActiveLane + "ChipID (on module) was different from the lane ID on the IB stave", // ErrIBChipLaneMismatch + "Cable data does not start with chip header or empty chip", // ErrCableDataHeadWrong + "Active lanes pattern conflicts with expected for given RU type", // ErrInvalidActiveLanes + "Jump in RDH_packetCounter", // ErrPacketCounterJump + "Packet done is missing in the trailer while CRU page is not over" // ErrPacketDoneMissing + }; + + uint32_t ruLinkID = 0; // Link ID within RU + + // Note: packet here is meant as a group of CRU pages belonging to the same trigger + uint32_t nPackets = 0; // total number of packets + std::array errorCounts = {}; // error counters + std::array packetStates = {}; // packet status from the trailer + + void clear() + { + nPackets = 0; + errorCounts.fill(0); + packetStates.fill(0); + } + + void print(bool skipEmpty = true) const; + + ClassDefNV(GBTLinkDecodingStat, 1); +}; + +} // namespace itsmft +} // namespace o2 +#endif diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h index 54f77b739362d..85e05b6db5227 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.h @@ -23,6 +23,7 @@ #include "ITSMFTReconstruction/PayLoadSG.h" #include "ITSMFTReconstruction/GBTWord.h" #include "ITSMFTReconstruction/RUDecodeData.h" +#include "ITSMFTReconstruction/DecodingStat.h" #include "ITSMFTReconstruction/RUInfo.h" #include "Headers/RAWDataHeader.h" #include "DetectorsRaw/RDHUtils.h" @@ -39,69 +40,6 @@ namespace o2 namespace itsmft { -/// Statistics for per-link decoding -struct GBTLinkDecodingStat { - /// counters for format checks - - enum DecErrors : int { - ErrNoRDHAtStart, // page does not start with RDH - ErrPageNotStopped, // new HB/trigger page started w/o stopping previous one - ErrStopPageNotEmpty, // Page with RDH.stop is not empty - ErrPageCounterDiscontinuity, // RDH page counters for the same RU/trigger are not continuous - ErrRDHvsGBTHPageCnt, // RDH and GBT header page counters are not consistent - ErrMissingGBTTrigger, // GBT trigger word was expected but not found - ErrMissingGBTHeader, // GBT payload header was expected but not found - ErrMissingGBTTrailer, // GBT payload trailer was expected but not found - ErrNonZeroPageAfterStop, // all lanes were stopped but the page counter in not 0 - ErrUnstoppedLanes, // end of FEE data reached while not all lanes received stop - ErrDataForStoppedLane, // data was received for stopped lane - ErrNoDataForActiveLane, // no data was seen for lane (which was not in timeout) - ErrIBChipLaneMismatch, // chipID (on module) was different from the lane ID on the IB stave - ErrCableDataHeadWrong, // cable data does not start with chip header or empty chip - ErrInvalidActiveLanes, // active lanes pattern conflicts with expected for given RU type - ErrPacketCounterJump, // jump in RDH.packetCounter - ErrPacketDoneMissing, // packet done is missing in the trailer while CRU page is not over - NErrorsDefined - }; - static constexpr std::array ErrNames = { - "Page data not start with expected RDH", // ErrNoRDHAtStart - "New HB/trigger page started w/o stopping previous one", // ErrPageNotStopped - "Page with RDH.stop is not empty", // ErrStopPageNotEmpty - "RDH page counters for the same RU/trigger are not continuous", // ErrPageCounterDiscontinuity - "RDH and GBT header page counters are not consistent", // ErrRDHvsGBTHPageCnt - "GBT trigger word was expected but not found", // ErrMissingGBTTrigger - "GBT payload header was expected but not found", // ErrMissingGBTHeader - "GBT payload trailer was expected but not found", // ErrMissingGBTTrailer - "All lanes were stopped but the page counter in not 0", // ErrNonZeroPageAfterStop - "End of FEE data reached while not all lanes received stop", // ErrUnstoppedLanes - "Data was received for stopped lane", // ErrDataForStoppedLane - "No data was seen for lane (which was not in timeout)", // ErrNoDataForActiveLane - "ChipID (on module) was different from the lane ID on the IB stave", // ErrIBChipLaneMismatch - "Cable data does not start with chip header or empty chip", // ErrCableDataHeadWrong - "Active lanes pattern conflicts with expected for given RU type", // ErrInvalidActiveLanes - "Jump in RDH_packetCounter", // ErrPacketCounterJump - "Packet done is missing in the trailer while CRU page is not over" // ErrPacketDoneMissing - }; - - uint32_t ruLinkID = 0; // Link ID within RU - - // Note: packet here is meant as a group of CRU pages belonging to the same trigger - uint32_t nPackets = 0; // total number of packets - std::array errorCounts = {}; // error counters - std::array packetStates = {}; // packet status from the trailer - - void clear() - { - nPackets = 0; - errorCounts.fill(0); - packetStates.fill(0); - } - - void print(bool skipEmpty = true) const; - - ClassDefNV(GBTLinkDecodingStat, 1); -}; - struct RUDecodeData; // forward declaration to allow its linking in the GBTlink struct GBTHeader; struct GBTTrailer; @@ -159,7 +97,8 @@ struct GBTLink { uint32_t errorBits = 0; // bits of the error code of last frame decoding (if any) const RDH* lastRDH = nullptr; o2::InteractionRecord ir; // interaction record - GBTLinkDecodingStat statistics; // decoding statistics + GBTLinkDecodingStat statistics; // link decoding statistics + ChipStat chipStat; // chip decoding statistics RUDecodeData* ruPtr = nullptr; // pointer on the parent RU PayLoadSG rawData; // scatter-gatter buffer for cached CRU pages, each starting with RDH diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h index 43548be90a3c7..9472b40263bfd 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/PixelData.h @@ -15,6 +15,8 @@ #include "DataFormatsITSMFT/Digit.h" #include "CommonDataFormat/InteractionRecord.h" +#include "ITSMFTReconstruction/DecodingStat.h" + #include #include #include @@ -116,11 +118,18 @@ class ChipPixelData void setFirstUnmasked(uint32_t n) { mFirstUnmasked = n; } void setTrigger(uint32_t t) { mTrigger = t; } + void setError(ChipStat::DecErrors i) { mErrors |= 0x1 << i; } + void setErrorFlags(uint32_t f) { mErrors |= f; } + bool isErrorSet(ChipStat::DecErrors i) const { return mErrors & (0x1 << i); } + bool isErrorSet() const { return mErrors != 0; } + uint32_t getErrorFlags() const { return mErrors; } + void clear() { mPixels.clear(); mROFlags = 0; mFirstUnmasked = 0; + mErrors = 0; } void swap(ChipPixelData& other) @@ -222,6 +231,7 @@ class ChipPixelData uint32_t mFirstUnmasked = 0; // first unmasked entry in the mPixels uint32_t mStartID = 0; // entry of the 1st pixel data in the whole detector data, for MCtruth access uint32_t mTrigger = 0; // trigger pattern + uint32_t mErrors = 0; // errors set during decoding o2::InteractionRecord mInteractionRecord = {}; // interaction record std::vector mPixels; // vector of pixeld diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h index 0a43f63cc9617..1000a9e258e05 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h @@ -37,7 +37,7 @@ struct RUDecodeData { std::array links; // link entry RSTODO: consider removing this and using pointer std::array cableHWID; // HW ID of cable whose data is in the corresponding slot of cableData std::array cableLinkID; // ID of the GBT link transmitting this cable data - std::array cableLinkPtr; // Ptr of the GBT link transmitting this cable data + std::array cableLinkPtr; // Ptr of the GBT link transmitting this cable data int ruSWID = -1; // SW (stave) ID int nCables = 0; // total number of cables decoded for single trigger @@ -55,6 +55,7 @@ struct RUDecodeData { void setROFInfo(ChipPixelData* chipData, const GBTLink* lnk); template int decodeROF(const Mapping& mp); + void fillChipStatistics(int icab, const ChipPixelData* chipData); ClassDefNV(RUDecodeData, 1); }; @@ -72,28 +73,28 @@ int RUDecodeData::decodeROF(const Mapping& mp) if (!cableData[icab].getSize()) { continue; } - int nhits = 0; int cid = AlpideCoder::getChipID(cableData[icab]); if (cid < 0) { continue; } chipData->setChipID(mp.getGlobalChipID(cid, cableHWID[icab], *ruInfo)); - while ((nhits = AlpideCoder::decodeChip(*chipData, cableData[icab]))) { // we register only chips with hits or errors flags set - if (nhits > 0) { - // convert HW chip id within the module to absolute chip id - //chipData->setChipID(mp.getGlobalChipID(chipData->getChipID(), cableHWID[icab], *ruInfo)); - setROFInfo(chipData, cableLinkPtr[icab]); - ntot += nhits; - if (++nChipsFired < chipsData.size()) { // fetch next free chip - chipData = &chipsData[nChipsFired]; - cid = AlpideCoder::getChipID(cableData[icab]); - if (cid < 0) { - continue; - } - chipData->setChipID(mp.getGlobalChipID(cid, cableHWID[icab], *ruInfo)); - } else { - break; // last chip decoded + while (AlpideCoder::decodeChip(*chipData, cableData[icab]) || chipData->isErrorSet()) { // we register only chips with hits or errors flags set + // convert HW chip id within the module to absolute chip id + //chipData->setChipID(mp.getGlobalChipID(chipData->getChipID(), cableHWID[icab], *ruInfo)); + setROFInfo(chipData, cableLinkPtr[icab]); + ntot += chipData->getData().size(); +#ifdef ALPIDE_DECODING_STAT + fillChipStatistics(icab, chipData); +#endif + if (++nChipsFired < chipsData.size()) { // fetch next free chip + chipData = &chipsData[nChipsFired]; + cid = AlpideCoder::getChipID(cableData[icab]); + if (cid < 0) { + continue; } + chipData->setChipID(mp.getGlobalChipID(cid, cableHWID[icab], *ruInfo)); + } else { + break; // last chip decoded } } } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h index 5208f564bfb46..1eb3c7b2057c5 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h @@ -76,7 +76,9 @@ class RawPixelDecoder final : public PixelReader void setVerbosity(int v); int getVerbosity() const { return mVerbosity; } - void printReport() const; + void printReport(bool decstat = false, bool skipEmpty = true) const; + + void clearStat(); TStopwatch& getTimerTFStart() { return mTimerTFStart; } TStopwatch& getTimerDecode() { return mTimerDecode; } @@ -101,9 +103,8 @@ class RawPixelDecoder final : public PixelReader std::vector mGBTLinks; // active links pool std::unordered_map mSubsSpec2LinkID; // link subspec to link entry in the pool mapping - - std::vector mRUDecodeVec; // set of active RUs - std::array mRUEntry; // entry of the RU with given SW ID in the mRUDecodeVec + std::vector mRUDecodeVec; // set of active RUs + std::array mRUEntry; // entry of the RU with given SW ID in the mRUDecodeVec std::string mSelfName; // self name header::DataOrigin mUserDataOrigin = o2::header::gDataOriginInvalid; // alternative user-provided data origin to pick uint16_t mCurRUDecodeID = NORUDECODED; // index of currently processed RUDecode container diff --git a/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx index 05376a1298ae4..f9a62ac0667fa 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/AlpideCoder.cxx @@ -149,3 +149,8 @@ void AlpideCoder::resetMap() } //_____________________________________ +int AlpideCoder::unexpectedEOF(const std::string& message) +{ + LOG(ERROR) << message; + return Error; +} diff --git a/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx b/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx new file mode 100644 index 0000000000000..270b6bd129c44 --- /dev/null +++ b/Detectors/ITSMFT/common/reconstruction/src/DecodingStat.cxx @@ -0,0 +1,68 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 ChipStat.cxx +/// \brief Alpide Chip decoding statistics + +#include +#include "ITSMFTReconstruction/DecodingStat.h" +#include "Framework/Logger.h" + +using namespace o2::itsmft; +constexpr std::array ChipStat::ErrNames; + +///_________________________________________________________________ +/// print chip decoding statistics +void ChipStat::print(bool skipEmpty) const +{ + uint32_t nErr = 0; + for (int i = NErrorsDefined; i--;) { + nErr += errorCounts[i]; + } + LOGF(INFO, "Chip#%5d NHits: %9zu errors: %u", chipID, nHits, nErr); + for (int i = 0; i < NErrorsDefined; i++) { + if (!skipEmpty || errorCounts[i]) { + LOGF(INFO, "%-70s: %u", ErrNames[i].data(), errorCounts[i]); + } + } +} + +///_________________________________________________________________ +uint32_t ChipStat::getNErrors() const +{ + uint32_t nerr = 0; + for (int i = NErrorsDefined; i--;) { + nerr += errorCounts[i]; + } + return nerr; +} + +///_________________________________________________________________ +/// print link decoding statistics +void GBTLinkDecodingStat::print(bool skipEmpty) const +{ + int nErr = 0; + for (int i = NErrorsDefined; i--;) { + nErr += errorCounts[i]; + } + LOGF(INFO, "GBTLink#0x%d Packet States Statistics (total packets: %d)", ruLinkID, nPackets); + for (int i = 0; i < GBTDataTrailer::MaxStateCombinations; i++) { + if (packetStates[i]) { + std::bitset patt(i); + LOGF(INFO, "counts for triggers B[%s] : %d", patt.to_string().c_str(), packetStates[i]); + } + } + LOGF(INFO, "Decoding errors: %u", nErr); + for (int i = 0; i < NErrorsDefined; i++) { + if (!skipEmpty || errorCounts[i]) { + LOGF(INFO, "%-70s: %u", ErrNames[i].data(), errorCounts[i]); + } + } +} diff --git a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx index dc9e5dc3009b0..18eee05516f20 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/GBTLink.cxx @@ -21,37 +21,9 @@ using namespace o2::itsmft; -///====================================================================== -/// Decoding statistics for a single GBT link -///====================================================================== -using GBTS = GBTLinkDecodingStat; using RDHUtils = o2::raw::RDHUtils; using RDH = o2::header::RAWDataHeader; -constexpr std::array GBTS::ErrNames; - -///_________________________________________________________________ -/// print link decoding statistics -void GBTS::print(bool skipEmpty) const -{ - int nErr = 0; - for (int i = NErrorsDefined; i--;) { - nErr += errorCounts[i]; - } - printf("GBTLink#0x%d Packet States Statistics (total packets: %d)\n", ruLinkID, nPackets); - for (int i = 0; i < GBTDataTrailer::MaxStateCombinations; i++) { - if (packetStates[i]) { - std::bitset patt(i); - printf("counts for triggers B[%s] : %d\n", patt.to_string().c_str(), packetStates[i]); - } - } - printf("Decoding errors: %d\n", nErr); - for (int i = 0; i < NErrorsDefined; i++) { - if (!skipEmpty || errorCounts[i]) { - printf("%-70s: %d\n", ErrNames[i].data(), errorCounts[i]); - } - } -} ///====================================================================== /// GBT Link data decoding class @@ -127,11 +99,11 @@ void GBTLink::printTrailer(const GBTDataTrailer* gbtT) GBTLink::ErrorType GBTLink::checkErrorsRDH(const RDH& rdh) { if (!RDHUtils::checkRDH(rdh, true)) { - statistics.errorCounts[GBTS::ErrNoRDHAtStart]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrNoRDHAtStart]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrNoRDHAtStart]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNoRDHAtStart]; } - errorBits |= 0x1 << int(GBTS::ErrNoRDHAtStart); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrNoRDHAtStart); return Abort; // fatal error } if (format == OldFormat && RDHUtils::getVersion(rdh) > 4) { @@ -142,12 +114,12 @@ GBTLink::ErrorType GBTLink::checkErrorsRDH(const RDH& rdh) return Abort; } if ((RDHUtils::getPacketCounter(rdh) > packetCounter + 1) && packetCounter >= 0) { - statistics.errorCounts[GBTS::ErrPacketCounterJump]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrPacketCounterJump] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump] << " : jump from " << int(packetCounter) << " to " << int(RDHUtils::getPacketCounter(rdh)); } - errorBits |= 0x1 << int(GBTS::ErrPacketCounterJump); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrPacketCounterJump); return Warning; } packetCounter = RDHUtils::getPacketCounter(rdh); @@ -160,13 +132,13 @@ GBTLink::ErrorType GBTLink::checkErrorsRDHStop(const RDH& rdh) { if (format == NewFormat && lastRDH && RDHUtils::getHeartBeatOrbit(*lastRDH) != RDHUtils::getHeartBeatOrbit(rdh) // new HB starts && !RDHUtils::getStop(*lastRDH)) { - statistics.errorCounts[GBTS::ErrPageNotStopped]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrPageNotStopped]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrPageNotStopped]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPageNotStopped]; RDHUtils::printRDH(*lastRDH); RDHUtils::printRDH(rdh); } - errorBits |= 0x1 << int(GBTS::ErrPageNotStopped); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrPageNotStopped); return Warning; } return NoError; @@ -177,12 +149,12 @@ GBTLink::ErrorType GBTLink::checkErrorsRDHStop(const RDH& rdh) GBTLink::ErrorType GBTLink::checkErrorsRDHStopPageEmpty(const RDH& rdh) { if (format == NewFormat && RDHUtils::getStop(rdh) && RDHUtils::getMemorySize(rdh) != sizeof(RDH)) { - statistics.errorCounts[GBTS::ErrStopPageNotEmpty]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrStopPageNotEmpty]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrStopPageNotEmpty]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrStopPageNotEmpty]; RDHUtils::printRDH(rdh); } - errorBits |= 0x1 << int(GBTS::ErrStopPageNotEmpty); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrStopPageNotEmpty); return Warning; } return NoError; @@ -194,11 +166,11 @@ GBTLink::ErrorType GBTLink::checkErrorsTriggerWord(const GBTTrigger* gbtTrg) { if (!gbtTrg->isTriggerWord()) { // check trigger word gbtTrg->printX(); - statistics.errorCounts[GBTS::ErrMissingGBTTrigger]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrigger]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrMissingGBTTrigger]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTTrigger]; } - errorBits |= 0x1 << int(GBTS::ErrMissingGBTTrigger); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTTrigger); return Abort; } return NoError; @@ -209,35 +181,35 @@ GBTLink::ErrorType GBTLink::checkErrorsTriggerWord(const GBTTrigger* gbtTrg) GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeader* gbtH) { if (!gbtH->isDataHeader()) { // check header word - statistics.errorCounts[GBTS::ErrMissingGBTHeader]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++; gbtH->printX(); if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrMissingGBTHeader]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTHeader]; } - errorBits |= 0x1 << int(GBTS::ErrMissingGBTHeader); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTHeader); return Abort; } int cnt = RDHUtils::getPageCounter(*lastRDH); // RSTODO: this makes sense only for old format, where every trigger has its RDH if (format == OldFormat && gbtH->packetIdx != cnt) { - statistics.errorCounts[GBTS::ErrRDHvsGBTHPageCnt]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrRDHvsGBTHPageCnt] << ": diff in GBT header " + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt] << ": diff in GBT header " << gbtH->packetIdx << " and RDH page " << cnt << " counters"; } - errorBits |= 0x1<packetIdx) { - statistics.errorCounts[GBTS::ErrNonZeroPageAfterStop]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrNonZeroPageAfterStop] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNonZeroPageAfterStop] << ": Non-0 page counter (" << cnt << ") while all lanes were stopped"; } - errorBits |= 0x1 << int(GBTS::ErrNonZeroPageAfterStop); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrNonZeroPageAfterStop); return Warning; } } @@ -249,13 +221,13 @@ GBTLink::ErrorType GBTLink::checkErrorsHeaderWord(const GBTDataHeader* gbtH) GBTLink::ErrorType GBTLink::checkErrorsActiveLanes(int cbl) { if (~cbl & lanesActive) { // are there wrong lanes? - statistics.errorCounts[GBTS::ErrInvalidActiveLanes]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrInvalidActiveLanes]++; std::bitset<32> expectL(cbl), gotL(lanesActive); if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrInvalidActiveLanes] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrInvalidActiveLanes] << gotL << " vs " << expectL << " skip page"; } - errorBits |= 0x1 << int(GBTS::ErrInvalidActiveLanes); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrInvalidActiveLanes); return Warning; } return NoError; @@ -267,12 +239,12 @@ GBTLink::ErrorType GBTLink::checkErrorsGBTData(int cablePos) { lanesWithData |= 0x1 << cablePos; // flag that the data was seen on this lane if (lanesStop & (0x1 << cablePos)) { // make sure stopped lanes do not transmit the data - statistics.errorCounts[GBTS::ErrDataForStoppedLane]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrDataForStoppedLane] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrDataForStoppedLane] << cablePos; } - errorBits |= 0x1 << int(GBTS::ErrDataForStoppedLane); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrDataForStoppedLane); return Warning; } @@ -285,11 +257,11 @@ GBTLink::ErrorType GBTLink::checkErrorsTrailerWord(const GBTDataTrailer* gbtT) { if (!gbtT->isDataTrailer()) { gbtT->printX(); - statistics.errorCounts[GBTS::ErrMissingGBTTrailer]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrMissingGBTTrailer]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrMissingGBTTrailer]; } - errorBits |= 0x1 << int(GBTS::ErrMissingGBTTrailer); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrMissingGBTTrailer); return Abort; } lanesTimeOut |= gbtT->lanesTimeout; // register timeouts @@ -302,11 +274,11 @@ GBTLink::ErrorType GBTLink::checkErrorsTrailerWord(const GBTDataTrailer* gbtT) GBTLink::ErrorType GBTLink::checkErrorsPacketDoneMissing(const GBTDataTrailer* gbtT, bool notEnd) { if (!gbtT->packetDone && notEnd) { // Done may be missing only in case of carry-over to new CRU page - statistics.errorCounts[GBTS::ErrPacketDoneMissing]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrPacketDoneMissing]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrPacketDoneMissing]; + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrPacketDoneMissing]; } - errorBits |= 0x1 << int(GBTS::ErrPacketDoneMissing); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrPacketDoneMissing); return Warning; } return NoError; @@ -320,25 +292,25 @@ GBTLink::ErrorType GBTLink::checkErrorsLanesStops() auto err = NoError; if ((lanesActive & ~lanesStop)) { if (RDHUtils::getTriggerType(*lastRDH) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes? - statistics.errorCounts[GBTS::ErrUnstoppedLanes]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++; std::bitset<32> active(lanesActive), stopped(lanesStop); if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrUnstoppedLanes] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrUnstoppedLanes] << " | active: " << active << " stopped: " << stopped; } - errorBits |= 0x1 << int(GBTS::ErrUnstoppedLanes); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrUnstoppedLanes); } err = Warning; } // make sure all active lanes (except those in time-out) have sent some data if ((~lanesWithData & lanesActive) != lanesTimeOut) { std::bitset<32> withData(lanesWithData), active(lanesActive), timeOut(lanesTimeOut); - statistics.errorCounts[GBTS::ErrNoDataForActiveLane]++; + statistics.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++; if (verbosity >= VerboseErrors) { - LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTS::ErrNoDataForActiveLane] + LOG(ERROR) << describe() << ' ' << statistics.ErrNames[GBTLinkDecodingStat::ErrNoDataForActiveLane] << " | with data: " << withData << " active: " << active << " timeOut: " << timeOut; } - errorBits |= 0x1 << int(GBTS::ErrNoDataForActiveLane); + errorBits |= 0x1 << int(GBTLinkDecodingStat::ErrNoDataForActiveLane); err = Warning; } return err; diff --git a/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h b/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h index 19d2a85352fd2..4c84473abfcaa 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h +++ b/Detectors/ITSMFT/common/reconstruction/src/ITSMFTReconstructionLinkDef.h @@ -41,6 +41,7 @@ #pragma link C++ class o2::itsmft::GBTLink + ; #pragma link C++ class o2::itsmft::RUDecodeData + ; #pragma link C++ class o2::itsmft::RawDecodingStat + ; +#pragma link C++ class o2::itsmft::ChipStat + ; #pragma link C++ class std::map < unsigned long, std::pair < o2::itsmft::ClusterTopology, unsigned long>> + ; diff --git a/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx b/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx index 4006892dfaaa0..3641991899487 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RUDecodeData.cxx @@ -47,5 +47,13 @@ void RUDecodeData::setROFInfo(ChipPixelData* chipData, const GBTLink* lnk) chipData->setInteractionRecord(lnk->ir); } +///_________________________________________________________________ +/// fill chip decoding statistics +void RUDecodeData::fillChipStatistics(int icab, const ChipPixelData* chipData) +{ + cableLinkPtr[icab]->chipStat.nHits += chipData->getData().size(); + cableLinkPtr[icab]->chipStat.addErrors(chipData->getErrorFlags()); +} + } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx index 5d88c8ae54ea1..f84c11ceb2bc0 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx @@ -39,7 +39,7 @@ RawPixelDecoder::RawPixelDecoder() ///______________________________________________________________ /// template -void RawPixelDecoder::printReport() const +void RawPixelDecoder::printReport(bool decstat, bool skipEmpty) const { LOGF(INFO, "%s Decoded %zu hits in %zu non-empty chips in %u ROFs with %d threads", mSelfName, mNPixelsFired, mNChipsFired, mROFCounter, mNThreads); double cpu = 0, real = 0; @@ -57,6 +57,15 @@ void RawPixelDecoder::printReport() const real += tmrF.RealTime(); LOGF(INFO, "%s Timing Total: CPU = %.3e Real = %.3e in %d slots in %s mode", mSelfName, cpu, real, tmrS.Counter() - 1, mDecodeNextAuto ? "AutoDecode" : "ExternalCall"); + + if (decstat) { + LOG(INFO) << "GBT Links decoding statistics"; + for (auto& lnk : mGBTLinks) { + LOG(INFO) << lnk.describe(); + lnk.statistics.print(skipEmpty); + lnk.chipStat.print(skipEmpty); + } + } } ///______________________________________________________________ @@ -300,5 +309,15 @@ void RawPixelDecoder::setFormat(GBTLink::Format f) mFormat = f; } +///______________________________________________________________________ +template +void RawPixelDecoder::clearStat() +{ + // clear statistics + for (auto& lnk : mGBTLinks) { + lnk.clear(true, false); + } +} + template class o2::itsmft::RawPixelDecoder; template class o2::itsmft::RawPixelDecoder; From b62f04f8a24e1114c0ee20b0358c658764798295 Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 4 Sep 2020 18:01:39 +0200 Subject: [PATCH 14/76] Speedup navigation to need TF in RawFileReader --- .../Raw/include/DetectorsRaw/RawFileReader.h | 1 + Detectors/Raw/src/RawFileReader.cxx | 64 +++++++++++++------ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h index af651f51744b7..40e521e2c3f81 100644 --- a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h +++ b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h @@ -147,6 +147,7 @@ class RawFileReader std::string fairMQChannel{}; //! name of the fairMQ channel for the output int nErrors = 0; //! std::vector blocks; //! + std::vector> tfStartBlock; // // transient info during processing bool openHB = false; //! diff --git a/Detectors/Raw/src/RawFileReader.cxx b/Detectors/Raw/src/RawFileReader.cxx index a10217ee73dd5..ba55b5f6196c9 100644 --- a/Detectors/Raw/src/RawFileReader.cxx +++ b/Detectors/Raw/src/RawFileReader.cxx @@ -104,10 +104,12 @@ size_t RawFileReader::LinkData::getNextHBFSize() const // estimate the memory size of the next HBF to read // The blocks are guaranteed to not cover more than 1 HB size_t sz = 0; - int ibl = nextBlock2Read, nbl = blocks.size(); - while (ibl < nbl && (blocks[ibl].ir == blocks[nextBlock2Read].ir)) { - sz += blocks[ibl].size; - ibl++; + if (nextBlock2Read >= 0) { // negative nextBlock2Read signals absence of data + int ibl = nextBlock2Read, nbl = blocks.size(); + while (ibl < nbl && (blocks[ibl].ir == blocks[nextBlock2Read].ir)) { + sz += blocks[ibl].size; + ibl++; + } } return sz; } @@ -117,6 +119,9 @@ size_t RawFileReader::LinkData::readNextHBF(char* buff) { // read data of the next complete HB, buffer of getNextHBFSize() must be allocated in advance size_t sz = 0; + if (nextBlock2Read < 0) { // negative nextBlock2Read signals absence of data + return sz; + } int ibl = nextBlock2Read, nbl = blocks.size(); bool error = false; while (ibl < nbl) { @@ -149,6 +154,9 @@ size_t RawFileReader::LinkData::skipNextHBF() { // skip next complete HB size_t sz = 0; + if (nextBlock2Read < 0) { // negative nextBlock2Read signals absence of data + return sz; + } int ibl = nextBlock2Read, nbl = blocks.size(); while (ibl < nbl) { const auto& blc = blocks[ibl]; @@ -168,10 +176,12 @@ size_t RawFileReader::LinkData::getNextTFSize() const // estimate the memory size of the next TF to read // (assuming nextBlock2Read is at the start of the TF) size_t sz = 0; - int ibl = nextBlock2Read, nbl = blocks.size(); - while (ibl < nbl && (blocks[ibl].tfID == blocks[nextBlock2Read].tfID)) { - sz += blocks[ibl].size; - ibl++; + if (nextBlock2Read >= 0) { // negative nextBlock2Read signals absence of data + int ibl = nextBlock2Read, nbl = blocks.size(); + while (ibl < nbl && (blocks[ibl].tfID == blocks[nextBlock2Read].tfID)) { + sz += blocks[ibl].size; + ibl++; + } } return sz; } @@ -181,6 +191,9 @@ size_t RawFileReader::LinkData::readNextTF(char* buff) { // read next complete TF, buffer of getNextTFSize() must be allocated in advance size_t sz = 0; + if (nextBlock2Read < 0) { // negative nextBlock2Read signals absence of data + return sz; + } int ibl0 = nextBlock2Read, nbl = blocks.size(); bool error = false; while (nextBlock2Read < nbl && (blocks[nextBlock2Read].tfID == blocks[ibl0].tfID)) { // nextBlock2Read is incremented by the readNextHBF! @@ -198,6 +211,9 @@ size_t RawFileReader::LinkData::skipNextTF() { // skip next complete TF size_t sz = 0; + if (nextBlock2Read < 0) { // negative nextBlock2Read signals absence of data + return sz; + } int ibl0 = nextBlock2Read, nbl = blocks.size(); bool error = false; while (nextBlock2Read < nbl && (blocks[nextBlock2Read].tfID == blocks[ibl0].tfID)) { // nextBlock2Read is incremented by the readNextHBF! @@ -214,9 +230,11 @@ size_t RawFileReader::LinkData::skipNextTF() void RawFileReader::LinkData::rewindToTF(uint32_t tf) { // go to given TF - nextBlock2Read = 0; - for (uint32_t i = 0; i < tf; i++) { - skipNextTF(); + if (tf < tfStartBlock.size()) { + nextBlock2Read = tfStartBlock[tf].first; + } else { + LOG(WARNING) << "No TF " << tf << " for link " << describe(); + nextBlock2Read = -1; } } @@ -225,11 +243,13 @@ int RawFileReader::LinkData::getNHBFinTF() const { // estimate number of HBFs left in the TF int ibl = nextBlock2Read, nbl = blocks.size(), nHB = 0; - while (ibl < nbl && (blocks[ibl].tfID == blocks[nextBlock2Read].tfID)) { - if (blocks[ibl].testFlag(LinkBlock::StartHB)) { - nHB++; + if (nextBlock2Read >= 0) { // negative nextBlock2Read signals absence of data + while (ibl < nbl && (blocks[ibl].tfID == blocks[nextBlock2Read].tfID)) { + if (blocks[ibl].testFlag(LinkBlock::StartHB)) { + nHB++; + } + ibl++; } - ibl++; } return nHB; } @@ -239,6 +259,9 @@ size_t RawFileReader::LinkData::readNextSuperPage(char* buff, const RawFileReade { // read data of the next complete HB, buffer of getNextHBFSize() must be allocated in advance size_t sz = 0; + if (nextBlock2Read < 0) { // negative nextBlock2Read signals absence of data + return sz; + } int ibl = nextBlock2Read, nbl = blocks.size(); auto tfID = blocks[nextBlock2Read].tfID; bool error = false; @@ -424,8 +447,12 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage } if (newTF || newSPage || newHB) { + int nbl = blocks.size(); auto& bl = blocks.emplace_back(reader->mCurrentFileID, reader->mPosInFile); + bl.ir = hbIR; + bl.tfID = HBU.getTF(hbIR); // nTimeFrames - 1; if (newTF) { + tfStartBlock.emplace_back(nbl, bl.tfID); nTimeFrames++; bl.setFlag(LinkBlock::StartTF); if (reader->mCheckErrors & (0x1 << ErrNoSuperPageForTF) && cruDetector) { @@ -436,8 +463,6 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage } } // end of check errors } - bl.ir = hbIR; - bl.tfID = HBU.getTF(hbIR); // nTimeFrames - 1; if (newSPage) { nSPages++; @@ -658,7 +683,7 @@ bool RawFileReader::init() LOGF(INFO, "Summary of preprocessing:"); for (int i = 0; i < int(mLinksData.size()); i++) { - const auto& link = getLink(i); + auto& link = getLink(i); auto msp = link.getLargestSuperPage(); auto mtf = link.getLargestTF(); if (maxSP < msp) { @@ -681,6 +706,9 @@ bool RawFileReader::init() if (link.blocks.back().ir.orbit > mOrbitMax) { mOrbitMax = link.blocks.back().ir.orbit; } + if (link.tfStartBlock.empty() && !link.blocks.empty()) { + link.tfStartBlock.emplace_back(0, 0); + } if ((mCheckErrors & (0x1 << ErrWrongNumberOfTF)) && (mNTimeFrames != link.nTimeFrames)) { LOGF(ERROR, "%s for %s: %u TFs while %u were seen for other links", ErrNames[ErrWrongNumberOfTF], link.describe(), link.nTimeFrames, mNTimeFrames); From c2fe6d3a2f75ebc283dc59c13abddbef565f7bd0 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 5 Sep 2020 16:05:09 +0200 Subject: [PATCH 15/76] With --detect-tf0 raw-reader will autodetect HBFUtils 1st IR --- Detectors/Raw/README.md | 6 +- .../Raw/include/DetectorsRaw/RawFileReader.h | 18 ++++-- Detectors/Raw/src/RawFileReader.cxx | 55 +++++++++++++------ Detectors/Raw/src/RawFileReaderWorkflow.cxx | 11 ++-- Detectors/Raw/src/RawFileReaderWorkflow.h | 2 +- Detectors/Raw/src/rawfile-reader-workflow.cxx | 4 +- Detectors/Raw/src/rawfileCheck.cxx | 4 +- 7 files changed, 68 insertions(+), 32 deletions(-) diff --git a/Detectors/Raw/README.md b/Detectors/Raw/README.md index a04841f24c3aa..a364302317016 100644 --- a/Detectors/Raw/README.md +++ b/Detectors/Raw/README.md @@ -312,7 +312,7 @@ o2-raw-file-reader-workflow --part-per-hbf FMQ parts per superpage (default) of HBF --raw-channel-config arg optional raw FMQ channel for non-DPL output --cache-data cache data at 1st reading, may require excessive memory!!! - + --detect-tf0 autodetect HBFUtils start Orbit/BC from 1st TF seen --configKeyValues arg semicolon separated key=value strings # to suppress various error checks / reporting @@ -362,7 +362,9 @@ Options: -m [ --max-tf] arg (=0xffffffff) max. TF ID to read (counts from 0) -v [ --verbosity ] arg (=0) 1: long report, 2 or 3: print or dump all RDH -s [ --spsize ] arg (=1048576) nominal super-page size in bytes - -t [ --hbfpertf ] arg (=256) nominal number of HBFs per TF + --detect-tf0 autodetect HBFUtils start Orbit/BC from 1st TF seen + --rorc impose RORC as default detector mode + --configKeyValues arg semicolon separated key=value strings --nocheck-packet-increment ignore /Wrong RDH.packetCounter increment/ --nocheck-page-increment ignore /Wrong RDH.pageCnt increment/ --check-stop-on-page0 check /RDH.stop set of 1st HBF page/ diff --git a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h index 40e521e2c3f81..643834c485d37 100644 --- a/Detectors/Raw/include/DetectorsRaw/RawFileReader.h +++ b/Detectors/Raw/include/DetectorsRaw/RawFileReader.h @@ -54,6 +54,11 @@ class RawFileReader ErrNoSuperPageForTF, NErrorsDefined }; + + enum class FirstTFDetection : int { Disabled, + Pending, + Done }; + static constexpr std::string_view ErrNames[] = { // long names for error codes "Wrong RDH.packetCounter increment", // ErrWrongPacketCounterIncrement @@ -156,7 +161,7 @@ class RawFileReader LinkData() = default; template - LinkData(const H& rdh, const RawFileReader* r) : rdhl(rdh), reader(r) + LinkData(const H& rdh, RawFileReader* r) : rdhl(rdh), reader(r) { } bool preprocessCRUPage(const RDHAny& rdh, bool newSPage); @@ -174,12 +179,11 @@ class RawFileReader size_t skipNextTF(); void rewindToTF(uint32_t tf); - void print(bool verbose = false, const std::string& pref = "") const; std::string describe() const; private: - const RawFileReader* reader = nullptr; //! + RawFileReader* reader = nullptr; //! }; //===================================================================================== @@ -237,6 +241,10 @@ class RawFileReader o2::header::DataDescription getDefaultDataSpecification() const { return mDefDataDescription; } ReadoutCardType getDefaultReadoutCardType() const { return mDefCardType; } + void imposeFirstTF(uint32_t orbit, uint16_t bc); + void setTFAutodetect(FirstTFDetection v) { mFirstTFAutodetect = v; } + FirstTFDetection getTFAutodetect() const { return mFirstTFAutodetect; } + static o2::header::DataOrigin getDataOrigin(const std::string& ors); static o2::header::DataDescription getDataDescription(const std::string& ors); static InputsMap parseInput(const std::string& confUri); @@ -277,8 +285,8 @@ class RawFileReader bool mMultiLinkFile = false; //! was > than 1 link seen in the file? bool mCacheData = false; //! cache data to block after 1st scan (may require excessive memory, use with care) uint32_t mCheckErrors = 0; //! mask for errors to check - int mVerbosity = 0; - + FirstTFDetection mFirstTFAutodetect = FirstTFDetection::Disabled; //! + int mVerbosity = 0; //! ClassDefNV(RawFileReader, 1); }; diff --git a/Detectors/Raw/src/RawFileReader.cxx b/Detectors/Raw/src/RawFileReader.cxx index ba55b5f6196c9..635ff5927e9ae 100644 --- a/Detectors/Raw/src/RawFileReader.cxx +++ b/Detectors/Raw/src/RawFileReader.cxx @@ -76,24 +76,24 @@ size_t RawFileReader::LinkData::getNextTFSuperPagesStat(std::vector nextBlock2Read && (blocks[ibl].testFlag(LinkBlock::StartSP) || - (sz + blocks[ibl].size) > reader->mNominalSPageSize || - (blocks[ibl - 1].offset + blocks[ibl - 1].size) < blocks[ibl].offset)) { // new superpage + if (nextBlock2Read >= 0) { // negative nextBlock2Read signals absence of data + int sz = 0, nSP = 0, ibl = nextBlock2Read, nbl = blocks.size(), nblPart = 0; + parts.clear(); + while (ibl < nbl && (blocks[ibl].tfID == blocks[nextBlock2Read].tfID)) { + if (ibl > nextBlock2Read && (blocks[ibl].testFlag(LinkBlock::StartSP) || + (sz + blocks[ibl].size) > reader->mNominalSPageSize || + (blocks[ibl - 1].offset + blocks[ibl - 1].size) < blocks[ibl].offset)) { // new superpage + parts.emplace_back(RawFileReader::PartStat{sz, nblPart}); + sz = 0; + nblPart = 0; + } + sz += blocks[ibl].size; + nblPart++; + ibl++; + } + if (sz) { parts.emplace_back(RawFileReader::PartStat{sz, nblPart}); - sz = 0; - nblPart = 0; } - sz += blocks[ibl].size; - nblPart++; - ibl++; - } - if (sz) { - parts.emplace_back(RawFileReader::PartStat{sz, nblPart}); } return parts.size(); } @@ -452,6 +452,14 @@ bool RawFileReader::LinkData::preprocessCRUPage(const RDHAny& rdh, bool newSPage bl.ir = hbIR; bl.tfID = HBU.getTF(hbIR); // nTimeFrames - 1; if (newTF) { + if (reader->getTFAutodetect() == FirstTFDetection::Pending) { // impose first TF + if (cruDetector) { + reader->imposeFirstTF(hbIR.orbit, hbIR.bc); + bl.tfID = HBU.getTF(hbIR); // update + } else { + throw std::runtime_error("HBFUtil first orbit/bc autodetection cannot be done with first link from CRORC detector"); + } + } tfStartBlock.emplace_back(nbl, bl.tfID); nTimeFrames++; bl.setFlag(LinkBlock::StartTF); @@ -714,7 +722,7 @@ bool RawFileReader::init() link.describe(), link.nTimeFrames, mNTimeFrames); } } - LOGF(INFO, "First orbit: %d, Last orbit: %d", mOrbitMin, mOrbitMax); + LOGF(INFO, "First orbit: %u, Last orbit: %u", mOrbitMin, mOrbitMax); LOGF(INFO, "Largest super-page: %zu B, largest TF: %zu B", maxSP, maxTF); if (!mCheckErrors) { LOGF(INFO, "Detailed data format check was disabled"); @@ -865,6 +873,19 @@ RawFileReader::InputsMap RawFileReader::parseInput(const std::string& confUri) return entries; } +void RawFileReader::imposeFirstTF(uint32_t orbit, uint16_t bc) +{ + if (mFirstTFAutodetect != FirstTFDetection::Pending) { + throw std::runtime_error("reader was not expecting imposing first TF"); + } + auto& hbu = o2::raw::HBFUtils::Instance(); + o2::raw::HBFUtils::setValue("HBFUtils", "orbitFirst", orbit); + o2::raw::HBFUtils::setValue("HBFUtils", "bcFirst", bc); + LOG(INFO) << "Imposed data-driven TF start"; + mFirstTFAutodetect = FirstTFDetection::Done; + hbu.printKeyValues(); +} + std::string RawFileReader::nochk_opt(RawFileReader::ErrTypes e) { std::string opt = ErrCheckDefaults[e] ? "nocheck-" : "check-"; diff --git a/Detectors/Raw/src/RawFileReaderWorkflow.cxx b/Detectors/Raw/src/RawFileReaderWorkflow.cxx index f8ff628bf2412..a10f5fff61cf9 100644 --- a/Detectors/Raw/src/RawFileReaderWorkflow.cxx +++ b/Detectors/Raw/src/RawFileReaderWorkflow.cxx @@ -46,7 +46,7 @@ class RawReaderSpecs : public o2f::Task { public: explicit RawReaderSpecs(const std::string& config, int loop = 1, uint32_t delay_us = 0, - uint32_t errmap = 0xffffffff, uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, + uint32_t errmap = 0xffffffff, uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, bool autodetectTF0 = false, size_t spSize = 1024L * 1024L, size_t buffSize = 5 * 1024UL, const std::string& rawChannelName = "") : mLoop(loop < 0 ? INT_MAX : (loop < 1 ? 1 : loop)), mDelayUSec(delay_us), mMinTFID(minTF), mMaxTFID(maxTF), mPartPerSP(partPerSP), mReader(std::make_unique(config, 0, buffSize)), mRawChannelName(rawChannelName) @@ -55,6 +55,7 @@ class RawReaderSpecs : public o2f::Task mReader->setMaxTFToRead(maxTF); mReader->setNominalSPageSize(spSize); mReader->setCacheData(cache); + mReader->setTFAutodetect(autodetectTF0 ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); LOG(INFO) << "Will preprocess files with buffer size of " << buffSize << " bytes"; LOG(INFO) << "Number of loops over whole data requested: " << mLoop; for (int i = NTimers; i--;) { @@ -246,7 +247,7 @@ class RawReaderSpecs : public o2f::Task }; o2f::DataProcessorSpec getReaderSpec(std::string config, int loop, uint32_t delay_us, uint32_t errmap, - uint32_t minTF, uint32_t maxTF, bool partPerSP, bool cache, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) + uint32_t minTF, uint32_t maxTF, bool partPerSP, bool cache, bool autodetectTF0, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) { // check which inputs are present in files to read o2f::DataProcessorSpec spec; @@ -277,15 +278,15 @@ o2f::DataProcessorSpec getReaderSpec(std::string config, int loop, uint32_t dela LOG(INFO) << "Will send output to non-DPL channel " << rawChannelConfig; } - spec.algorithm = o2f::adaptFromTask(config, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, spSize, buffSize, rawChannelName); + spec.algorithm = o2f::adaptFromTask(config, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelName); return spec; } o2f::WorkflowSpec o2::raw::getRawFileReaderWorkflow(std::string inifile, int loop, uint32_t delay_us, uint32_t errmap, uint32_t minTF, uint32_t maxTF, - bool partPerSP, bool cache, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) + bool partPerSP, bool cache, bool autodetectTF0, size_t spSize, size_t buffSize, const std::string& rawChannelConfig) { o2f::WorkflowSpec specs; - specs.emplace_back(getReaderSpec(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, spSize, buffSize, rawChannelConfig)); + specs.emplace_back(getReaderSpec(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelConfig)); return specs; } diff --git a/Detectors/Raw/src/RawFileReaderWorkflow.h b/Detectors/Raw/src/RawFileReaderWorkflow.h index 731921eb46a5d..c209fd088f573 100644 --- a/Detectors/Raw/src/RawFileReaderWorkflow.h +++ b/Detectors/Raw/src/RawFileReaderWorkflow.h @@ -22,7 +22,7 @@ namespace raw { framework::WorkflowSpec getRawFileReaderWorkflow(std::string inifile, int loop = 1, uint32_t delay_us = 0, uint32_t errMap = 0xffffffff, - uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, + uint32_t minTF = 0, uint32_t maxTF = 0xffffffff, bool partPerSP = true, bool cache = false, bool autodetectTF0 = false, size_t spSize = 1024L * 1024L, size_t bufferSize = 1024L * 1024L, const std::string& rawChannelConfig = ""); diff --git a/Detectors/Raw/src/rawfile-reader-workflow.cxx b/Detectors/Raw/src/rawfile-reader-workflow.cxx index 5a752cfd07fd9..7f1062969e6b8 100644 --- a/Detectors/Raw/src/rawfile-reader-workflow.cxx +++ b/Detectors/Raw/src/rawfile-reader-workflow.cxx @@ -33,6 +33,7 @@ void customize(std::vector& workflowOptions) options.push_back(ConfigParamSpec{"part-per-hbf", VariantType::Bool, false, {"FMQ parts per superpage (default) of HBF"}}); options.push_back(ConfigParamSpec{"raw-channel-config", VariantType::String, "", {"optional raw FMQ channel for non-DPL output"}}); options.push_back(ConfigParamSpec{"cache-data", VariantType::Bool, false, {"cache data at 1st reading, may require excessive memory!!!"}}); + options.push_back(ConfigParamSpec{"detect-tf0", VariantType::Bool, false, {"autodetect HBFUtils start Orbit/BC from 1st TF seen"}}); options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"semicolon separated key=value strings"}}); // options for error-check suppression @@ -57,6 +58,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) uint64_t spSize = uint64_t(configcontext.options().get("super-page-size")); bool partPerSP = !configcontext.options().get("part-per-hbf"); bool cache = configcontext.options().get("cache-data"); + bool autodetectTF0 = configcontext.options().get("detect-tf0"); std::string rawChannelConfig = configcontext.options().get("raw-channel-config"); uint32_t errmap = 0; for (int i = RawFileReader::NErrorsDefined; i--;) { @@ -69,5 +71,5 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); uint32_t delay_us = uint32_t(1e6 * configcontext.options().get("delay")); // delay in microseconds - return std::move(o2::raw::getRawFileReaderWorkflow(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, spSize, buffSize, rawChannelConfig)); + return std::move(o2::raw::getRawFileReaderWorkflow(inifile, loop, delay_us, errmap, minTF, maxTF, partPerSP, cache, autodetectTF0, spSize, buffSize, rawChannelConfig)); } diff --git a/Detectors/Raw/src/rawfileCheck.cxx b/Detectors/Raw/src/rawfileCheck.cxx index 7f2400acec9c9..cb29425cc7250 100644 --- a/Detectors/Raw/src/rawfileCheck.cxx +++ b/Detectors/Raw/src/rawfileCheck.cxx @@ -39,6 +39,7 @@ int main(int argc, char* argv[]) desc_add_option("verbosity,v", bpo::value()->default_value(reader.getVerbosity()), "1: long report, 2 or 3: print or dump all RDH"); desc_add_option("spsize,s", bpo::value()->default_value(reader.getNominalSPageSize()), "nominal super-page size in bytes"); desc_add_option("buffer-size,b", bpo::value()->default_value(reader.getNominalSPageSize()), "buffer size for files preprocessing"); + desc_add_option("detect-tf0", "autodetect HBFUtils start Orbit/BC from 1st TF seen"); desc_add_option("rorc", "impose RORC as default detector mode"); desc_add_option("configKeyValues", bpo::value(&configKeyValues)->default_value(""), "semicolon separated key=value strings"); for (int i = 0; i < RawFileReader::NErrorsDefined; i++) { @@ -84,13 +85,14 @@ int main(int argc, char* argv[]) RawFileReader::RDH rdh; LOG(INFO) << "RawDataHeader v" << int(rdh.version) << " is assumed"; - o2::raw::RawFileReader::ReadoutCardType rocard = vm.count("rorc") ? o2::raw::RawFileReader::ReadoutCardType::RORC : o2::raw::RawFileReader::ReadoutCardType::CRU; + RawFileReader::ReadoutCardType rocard = vm.count("rorc") ? o2::raw::RawFileReader::ReadoutCardType::RORC : o2::raw::RawFileReader::ReadoutCardType::CRU; reader.setVerbosity(vm["verbosity"].as()); reader.setNominalSPageSize(vm["spsize"].as()); reader.setMaxTFToRead(vm["max-tf"].as()); reader.setBufferSize(vm["buffer-size"].as()); reader.setDefaultReadoutCardType(rocard); + reader.setTFAutodetect(vm.count("detect-tf0") ? RawFileReader::FirstTFDetection::Pending : RawFileReader::FirstTFDetection::Disabled); uint32_t errmap = 0; for (int i = RawFileReader::NErrorsDefined; i--;) { auto ei = RawFileReader::ErrTypes(i); From bfa374b441b97d77fa610c217898bf506c7ee8c8 Mon Sep 17 00:00:00 2001 From: Roberto Preghenella Date: Fri, 28 Aug 2020 16:37:24 +0200 Subject: [PATCH 16/76] Add more decay configurations in share --- .../share/pythia8/decays/force_hadronic_D.cfg | 96 +++++++++++++++++++ .../force_hadronic_D_forceLcChannel1.cfg | 12 +++ .../force_hadronic_D_forceLcChannel2.cfg | 12 +++ .../decays/force_hadronic_D_use4bodies.cfg | 15 +++ .../decays/force_hadronic_D_useDtoV0.cfg | 13 +++ .../share/pythia8/decays/hypertriton.cfg | 12 +++ 6 files changed, 160 insertions(+) create mode 100644 Generators/share/pythia8/decays/force_hadronic_D.cfg create mode 100644 Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel1.cfg create mode 100644 Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel2.cfg create mode 100644 Generators/share/pythia8/decays/force_hadronic_D_use4bodies.cfg create mode 100644 Generators/share/pythia8/decays/force_hadronic_D_useDtoV0.cfg create mode 100644 Generators/share/pythia8/decays/hypertriton.cfg diff --git a/Generators/share/pythia8/decays/force_hadronic_D.cfg b/Generators/share/pythia8/decays/force_hadronic_D.cfg new file mode 100644 index 0000000000000..e51167aae4398 --- /dev/null +++ b/Generators/share/pythia8/decays/force_hadronic_D.cfg @@ -0,0 +1,96 @@ +### author: Roberto Preghenella (preghenella@bo.infn.it) +### since: July 2020 + +### Force golden D decay modes +### the origin is from AliRoot AliDecayerPythia8::ForceHadronicD (Latest commit c509466 on May 17) +### +### This file reproduces the configuration achieved with ForceHadronicD(0,0,0) + +### add D+ decays absent in PYTHIA8 decay table and set BRs from PDG for other +411:oneChannel = 1 0.0752 0 -321 211 211 +411:addChannel = 1 0.0104 0 -313 211 +411:addChannel = 1 0.0156 0 311 211 +411:addChannel = 1 0.00276 0 333 211 +## add Lc decays absent in PYTHIA8 decay table and set BRs from PDG for other +4122:oneChannel = 1 0.0196 100 2212 -313 +4122:addChannel = 1 0.0108 100 2224 -321 +4122:addChannel = 1 0.022 100 3124 211 +4122:addChannel = 1 0.035 0 2212 -321 211 +4122:addChannel = 1 0.0159 0 2212 311 +4122:addChannel = 1 0.0130 0 3122 211 +### add Xic+ decays absent in PYTHIA8 decay table +4232:addChannel = 1 0.2 0 2212 -313 +4232:addChannel = 1 0.2 0 2212 -321 211 +4232:addChannel = 1 0.2 0 3324 211 +4232:addChannel = 1 0.2 0 3312 211 211 +### add Xic0 decays absent in PYTHIA8 decay table +4132:addChannel = 1 0.2 0 3312 211 + +### K* -> K pi +313:onMode = off +313:onIfAll = 321 211 +### for Ds -> Phi pi+ +333:onMode = off +333:onIfAll = 321 321 +### for D0 -> rho0 pi+ k- +113:onMode = off +113:onIfAll = 211 211 +### for Lambda_c -> Delta++ K- +2224:onMode = off +2224:onIfAll = 2212 211 +### for Lambda_c -> Lambda(1520) K- +3124:onMode = off +3124:onIfAll = 2212 321 + +### Omega_c -> Omega pi +4332:onMode = off +4332:onIfMatch = 3334 211 + +### switch off all decay channels +411:onMode = off +421:onMode = off +431:onMode = off +4112:onMode = off +4122:onMode = off +4232:onMode = off +4132:onMode = off + +### D+/- -> K pi pi +411:onIfMatch = 321 211 211 +### D+/- -> K* pi +411:onIfMatch = 313 211 +### D+/- -> phi pi +411:onIfMatch = 333 211 + +### D0 -> K pi +421:onIfMatch = 321 211 + +### D_s -> K K* +431:onIfMatch = 321 313 +### D_s -> Phi pi +431:onIfMatch = 333 211 + +### Lambda_c -> p K* +4122:onIfMatch = 2212 313 +### Lambda_c -> Delta K +4122:onIfMatch = 2224 321 +### Lambda_c -> Lambda(1520) pi +4122:onIfMatch = 3124 211 +### Lambda_c -> p K pi +4122:onIfMatch = 2212 321 211 +### Lambda_c -> Lambda pi +4122:onIfMatch = 3122 211 +### Lambda_c -> p K0 +4122:onIfMatch = 2212 311 + +### Xic+ -> pK*0 +4232:onIfMatch = 2212 313 +### Xic+ -> p K- pi+ +4232:onIfMatch = 2212 321 211 +### Xic+ -> Xi*0 pi+, Xi*->Xi- pi+ +4232:onIfMatch = 3324 211 +### Xic+ -> Xi- pi+ pi+ +4232:onIfMatch = 3312 211 211 + +### Xic0 -> Xi- pi+ +4132:onIfMatch = 3312 211 diff --git a/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel1.cfg b/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel1.cfg new file mode 100644 index 0000000000000..33abbb1b6f340 --- /dev/null +++ b/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel1.cfg @@ -0,0 +1,12 @@ +### author: Roberto Preghenella (preghenella@bo.infn.it) +### since: July 2020 + +### Force golden D decay modes (force Lc channel 1) +### the origin is from AliRoot AliDecayerPythia8::ForceHadronicD (Latest commit c509466 on May 17) +### +### This file has to be used in conjunction with force_hadronic_D.cfg and loaded +### afterwards to reproduce the configuration achieved with ForceHadronicD(0,0,1) + +### force Lc -> p K pi +4122:onMode = off +4122:onIfMatch = 2212 321 211 diff --git a/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel2.cfg b/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel2.cfg new file mode 100644 index 0000000000000..d79dec4d8b88f --- /dev/null +++ b/Generators/share/pythia8/decays/force_hadronic_D_forceLcChannel2.cfg @@ -0,0 +1,12 @@ +### author: Roberto Preghenella (preghenella@bo.infn.it) +### since: July 2020 + +### Force golden D decay modes (force Lc channel 2) +### the origin is from AliRoot AliDecayerPythia8::ForceHadronicD (Latest commit c509466 on May 17) +### +### This file has to be used in conjunction with force_hadronic_D.cfg and loaded +### afterwards to reproduce the configuration achieved with ForceHadronicD(0,0,2) + +### force Lc -> p K0s +4122:onMode = off +4122:onIfMatch = 2212 311 diff --git a/Generators/share/pythia8/decays/force_hadronic_D_use4bodies.cfg b/Generators/share/pythia8/decays/force_hadronic_D_use4bodies.cfg new file mode 100644 index 0000000000000..3178dad7d368b --- /dev/null +++ b/Generators/share/pythia8/decays/force_hadronic_D_use4bodies.cfg @@ -0,0 +1,15 @@ +### author: Roberto Preghenella (preghenella@bo.infn.it) +### since: July 2020 + +### Force golden D decay modes (use 4 bodies option) +### the origin is from AliRoot AliDecayerPythia8::ForceHadronicD (Latest commit c509466 on May 17) +### +### This file has to be used in conjunction with force_hadronic_D.cfg and loaded +### afterwards to reproduce the configuration achieved with ForceHadronicD(1,0,0) + +### D0 -> K pi pi pi +421:onIfMatch = 321 211 211 211 +### D0 -> K pi rho +421:onIfMatch = 321 211 113 +### D0 -> K*0 pi pi +421:onIfMatch = 313 211 211 diff --git a/Generators/share/pythia8/decays/force_hadronic_D_useDtoV0.cfg b/Generators/share/pythia8/decays/force_hadronic_D_useDtoV0.cfg new file mode 100644 index 0000000000000..5b50c59e0130c --- /dev/null +++ b/Generators/share/pythia8/decays/force_hadronic_D_useDtoV0.cfg @@ -0,0 +1,13 @@ +### author: Roberto Preghenella (preghenella@bo.infn.it) +### since: July 2020 + +### Force golden D decay modes (use D to V0 option) +### the origin is from AliRoot AliDecayerPythia8::ForceHadronicD (Latest commit c509466 on May 17) +### +### This file has to be used in conjunction with force_hadronic_D.cfg and loaded +### afterwards to reproduce the configuration achieved with ForceHadronicD(0,1,0) + +### Ds -> K0K +431:onIfMatch = 311 321 +### Ds -> K0pi +411:onIfMatch = 311 211 diff --git a/Generators/share/pythia8/decays/hypertriton.cfg b/Generators/share/pythia8/decays/hypertriton.cfg new file mode 100644 index 0000000000000..518fbbf6418ba --- /dev/null +++ b/Generators/share/pythia8/decays/hypertriton.cfg @@ -0,0 +1,12 @@ +### particle definition +### id:all = name antiName spinType chargeType colType m0 mWidth mMin mMax tau0 + +### helium-3 +1000020030:all = helium3 helium3_bar 0 6 0 2.80923 0. 0. 0. 0. +1000020030:mayDecay = off + +### hypertriton +1010010030:all = hypertriton hypertriton_bar 0 3 0 2.99131 0. 0. 0. 78.9 +1010010030:mayDecay = on +1010010030:oneChannel = 1 1. 0 1000020030 -211 + From 329a1e9625b8d9083f443dd63a241f9cae72edcd Mon Sep 17 00:00:00 2001 From: Ionut Cristian Arsene Date: Mon, 7 Sep 2020 10:44:54 +0200 Subject: [PATCH 17/76] Changed the workflow of the tableReader task (#4291) * optimizations to the DQ table-reader task * optimizations for the table-reader task * table reader task modified to use Partition for candidate track-leg selection * Added a task for dilepton - hadron combinations in the tableReader workflow --- Analysis/Core/include/Analysis/VarManager.h | 60 +- Analysis/Core/src/VarManager.cxx | 12 +- .../include/Analysis/ReducedInfoTables.h | 4 +- Analysis/Tasks/PWGDQ/tableReader.cxx | 601 ++++++++++++------ 4 files changed, 483 insertions(+), 194 deletions(-) diff --git a/Analysis/Core/include/Analysis/VarManager.h b/Analysis/Core/include/Analysis/VarManager.h index 9438ec0e3cfae..95df64631efd3 100644 --- a/Analysis/Core/include/Analysis/VarManager.h +++ b/Analysis/Core/include/Analysis/VarManager.h @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include @@ -43,7 +45,8 @@ class VarManager : public TObject ReducedTrackBarrel = BIT(4), ReducedTrackBarrelCov = BIT(5), ReducedTrackBarrelPID = BIT(6), - ReducedTrackMuon = BIT(7) + ReducedTrackMuon = BIT(7), + Pair = BIT(8) }; public: @@ -132,8 +135,13 @@ class VarManager : public TObject kNPairVariables, // Candidate-track correlation variables + kPairMass, + kPairPt, + kPairEta, + kPairPhi, kDeltaEta, kDeltaPhi, + kDeltaPhiSym, kNCorrelationVariables, kNVars @@ -177,6 +185,8 @@ class VarManager : public TObject static void FillTrack(T const& track, float* values = nullptr); template static void FillPair(T const& t1, T const& t2, float* values = nullptr); + template + static void FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values = nullptr, float hadronMass = 0.0f); public: VarManager(); @@ -354,6 +364,10 @@ void VarManager::FillTrack(T const& track, float* values) values[kMuonChi2MatchTrigger] = track.chi2MatchTrigger(); } + if constexpr ((fillMap & Pair) > 0) { + values[kMass] = track.mass(); + } + FillTrackDerived(values); } @@ -363,10 +377,46 @@ void VarManager::FillPair(T const& t1, T const& t2, float* values) if (!values) values = fgValues; - // TODO: build the mass using the (pt,eta,phi) which are pre-calculated - values[kMass] = fgkElectronMass * fgkElectronMass; - values[kMass] = 2.0 * values[kMass] + 2.0 * (sqrt(values[kMass] + t1.pmom() * t1.pmom()) * sqrt(values[kMass] + t2.pmom() * t2.pmom()) - - t1.px() * t2.px() - t1.py() * t2.py() - t1.pz() * t2.pz()); + ROOT::Math::PtEtaPhiMVector v1(t1.pt(), t1.eta(), t1.phi(), fgkElectronMass); + ROOT::Math::PtEtaPhiMVector v2(t2.pt(), t2.eta(), t2.phi(), fgkElectronMass); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + values[kMass] = v12.M(); + values[kPt] = v12.Pt(); + values[kEta] = v12.Eta(); + values[kPhi] = v12.Phi(); +} + +template +void VarManager::FillDileptonHadron(T1 const& dilepton, T2 const& hadron, float* values, float hadronMass) +{ + if (!values) + values = fgValues; + + if (fgUsedVars[kPairMass] || fgUsedVars[kPairPt] || fgUsedVars[kPairEta] || fgUsedVars[kPairPhi]) { + ROOT::Math::PtEtaPhiMVector v1(dilepton.pt(), dilepton.eta(), dilepton.phi(), dilepton.mass()); + ROOT::Math::PtEtaPhiMVector v2(hadron.pt(), hadron.eta(), hadron.phi(), hadronMass); + ROOT::Math::PtEtaPhiMVector v12 = v1 + v2; + values[kPairMass] = v12.M(); + values[kPairPt] = v12.Pt(); + values[kPairEta] = v12.Eta(); + values[kPairPhi] = v12.Phi(); + } + if (fgUsedVars[kDeltaPhi]) { + double delta = dilepton.phi() - hadron.phi(); + if (delta > 3.0 / 2.0 * TMath::Pi()) + delta -= 2.0 * TMath::Pi(); + if (delta < -0.5 * TMath::Pi()) + delta += 2.0 * TMath::Pi(); + values[kDeltaPhi] = delta; + } + if (fgUsedVars[kDeltaPhiSym]) { + double delta = TMath::Abs(dilepton.phi() - hadron.phi()); + if (delta > TMath::Pi()) + delta = 2 * TMath::Pi() - delta; + values[kDeltaPhiSym] = delta; + } + if (fgUsedVars[kDeltaEta]) + values[kDeltaEta] = dilepton.eta() - hadron.eta(); } #endif diff --git a/Analysis/Core/src/VarManager.cxx b/Analysis/Core/src/VarManager.cxx index b942531ac2046..837a6a76dce00 100644 --- a/Analysis/Core/src/VarManager.cxx +++ b/Analysis/Core/src/VarManager.cxx @@ -213,8 +213,18 @@ void VarManager::SetDefaultVarNames() fgVariableUnits[kPairType] = ""; fgVariableNames[kPairLxy] = "Pair Lxy"; fgVariableUnits[kPairLxy] = "cm"; + fgVariableNames[kPairMass] = "mass"; + fgVariableUnits[kPairMass] = "GeV/c2"; + fgVariableNames[kPairPt] = "p_{T}"; + fgVariableUnits[kPairPt] = "GeV/c"; + fgVariableNames[kPairEta] = "#eta"; + fgVariableUnits[kPairEta] = ""; + fgVariableNames[kPairPhi] = "#varphi"; + fgVariableUnits[kPairPhi] = "rad."; fgVariableNames[kDeltaEta] = "#Delta#eta"; fgVariableUnits[kDeltaEta] = ""; fgVariableNames[kDeltaPhi] = "#Delta#phi"; - fgVariableUnits[kDeltaPhi] = ""; + fgVariableUnits[kDeltaPhi] = "rad."; + fgVariableNames[kDeltaPhiSym] = "#Delta#phi"; + fgVariableUnits[kDeltaPhiSym] = "rad."; } diff --git a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h b/Analysis/DataModel/include/Analysis/ReducedInfoTables.h index 5d78f05e48b7a..77015e807bbf9 100644 --- a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h +++ b/Analysis/DataModel/include/Analysis/ReducedInfoTables.h @@ -59,7 +59,7 @@ DECLARE_SOA_COLUMN(FilteringFlags, filteringFlags, uint64_t); DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, short); +DECLARE_SOA_COLUMN(Charge, charge, int); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); @@ -113,7 +113,7 @@ DECLARE_SOA_COLUMN(FilteringFlags, filteringFlags, uint64_t); DECLARE_SOA_COLUMN(Pt, pt, float); DECLARE_SOA_COLUMN(Eta, eta, float); DECLARE_SOA_COLUMN(Phi, phi, float); -DECLARE_SOA_COLUMN(Charge, charge, short); +DECLARE_SOA_COLUMN(Charge, charge, int); DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); diff --git a/Analysis/Tasks/PWGDQ/tableReader.cxx b/Analysis/Tasks/PWGDQ/tableReader.cxx index 8d372398c052e..34ff149099222 100644 --- a/Analysis/Tasks/PWGDQ/tableReader.cxx +++ b/Analysis/Tasks/PWGDQ/tableReader.cxx @@ -13,6 +13,7 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" #include "Analysis/ReducedInfoTables.h" #include "Analysis/VarManager.h" #include "Analysis/HistogramManager.h" @@ -23,46 +24,81 @@ #include #include #include -#include -#include using std::cout; using std::endl; -using std::vector; using namespace o2; using namespace o2::framework; //using namespace o2::framework::expressions; using namespace o2::aod; -struct TableReader { - +// Some definitions +namespace o2::aod +{ +namespace reducedtrack +{ +DECLARE_SOA_COLUMN(IsBarrelSelected, isBarrelSelected, int); +DECLARE_SOA_COLUMN(IsMuonSelected, isMuonSelected, int); +} // namespace reducedtrack +namespace reducedpair +{ +DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Charge, charge, int); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +} // namespace reducedpair + +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "BARRELTRACKCUTS", reducedtrack::IsBarrelSelected); +DECLARE_SOA_TABLE(MuonTrackCuts, "AOD", "MUONTRACKCUTS", reducedtrack::IsMuonSelected); +DECLARE_SOA_TABLE(Dileptons, "AOD", "DILEPTON", reducedtrack::ReducedEventId, reducedpair::Mass, reducedpair::Pt, reducedpair::Eta, reducedpair::Phi, reducedpair::Charge, + reducedpair::Px, reducedpair::Py, + reducedpair::Pz, reducedpair::Pmom); +using Dilepton = Dileptons::iterator; +} // namespace o2::aod + +using MyEvent = soa::Join::iterator; +using MyEventVtxCov = soa::Join::iterator; +using MyBarrelTracks = soa::Join; +using MyBarrelTracksSelected = soa::Join; +using MyMuonTracks = soa::Join; +using MyMuonTracksSelected = soa::Join; + +void DefineHistograms(o2::framework::OutputObj histMan, TString histClasses); + +// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions +// a constexpr static bit map must be defined and sent as template argument +// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes +// Additionally, one should make sure that the requested tables are actually provided in the process() function, +// otherwise a compile time error will be thrown. +// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible +// to automatically detect the object types transmitted to the VarManager +constexpr static uint32_t fgEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t fgTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; +constexpr static uint32_t fgMuonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackMuon; + +struct BarrelTrackSelection { + Produces trackSel; OutputObj fHistMan{"output"}; - AnalysisCompositeCut* fEventCut; AnalysisCompositeCut* fTrackCut; - AnalysisCompositeCut* fMuonCut; - - // HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions - // a constexpr static bit map must be defined and sent as template argument - // The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes - // Additionally, one should make sure that the requested tables are actually provided in the process() function, - // otherwise a compile time error will be thrown. - // This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible - // to automatically detect the object types transmitted to the VarManager - constexpr static uint32_t fgEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended | VarManager::ObjTypes::ReducedEventVtxCov; - constexpr static uint32_t fgEventMuonFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; - constexpr static uint32_t fgTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; - constexpr static uint32_t fgMuonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackMuon; + + float* fValues; // array to be used by the VarManager void init(o2::framework::InitContext&) { + fValues = new float[VarManager::kNVars]; VarManager::SetDefaultVarNames(); fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); - fHistMan->SetUseDefaultVariableNames(kTRUE); fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); - DefineHistograms("Event_BeforeCuts;Event_AfterCuts;TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts;TrackMuon_BeforeCuts;TrackMuon_AfterCuts;PairsBarrel;PairsMuon;"); // define all histograms + DefineHistograms(fHistMan, "TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts;"); // define all histograms VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill DefineCuts(); @@ -70,21 +106,9 @@ struct TableReader { void DefineCuts() { - fEventCut = new AnalysisCompositeCut(true); - - AnalysisCut* varCut = new AnalysisCut(); - varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); - - TF1* cutLow = new TF1("cutLow", "pol1", 0., 0.1); - cutLow->SetParameters(0.2635, 1.0); - //varCut->AddCut(VarManager::kVtxY, cutLow, 0.335, false, VarManager::kVtxX, 0.067, 0.070); - - //varCut->AddCut(VarManager::kVtxY, 0.0, 0.335); - fEventCut->AddCut(varCut); - fTrackCut = new AnalysisCompositeCut(true); // true: use AND AnalysisCut* cut1 = new AnalysisCut(); - cut1->AddCut(VarManager::kPt, 0.15, 20.0); + cut1->AddCut(VarManager::kPt, 1.5, 20.0); cut1->AddCut(VarManager::kEta, -0.9, 0.9); cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); cut1->AddCut(VarManager::kITSchi2, 0.0, 36.0); @@ -95,21 +119,128 @@ struct TableReader { fTrackCut->AddCut(cut1); //fTrackCut->AddCut(cut2); - fMuonCut = new AnalysisCompositeCut(true); + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + void process(MyEvent event, MyBarrelTracks const& tracks) + { + for (int i = 0; i < VarManager::kNVars; ++i) + fValues[i] = -9999.0f; + // fill event information which might be needed in histograms that combine track and event properties + VarManager::FillEvent(event, fValues); + + for (auto& track : tracks) { + for (int i = VarManager::kNEventWiseVariables; i < VarManager::kNMuonTrackVariables; ++i) + fValues[i] = -9999.0f; + VarManager::FillTrack(track, fValues); + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); + + if (fTrackCut->IsSelected(fValues)) { + trackSel(1); + fHistMan->FillHistClass("TrackBarrel_AfterCuts", fValues); + } else + trackSel(0); + } + } +}; + +struct MuonTrackSelection { + Produces trackSel; + OutputObj fHistMan{"output"}; + AnalysisCompositeCut* fTrackCut; + + float* fValues; + + void init(o2::framework::InitContext&) + { + fValues = new float[VarManager::kNVars]; + VarManager::SetDefaultVarNames(); + fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, "TrackMuon_BeforeCuts;TrackMuon_AfterCuts;"); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + + DefineCuts(); + } + + void DefineCuts() + { + fTrackCut = new AnalysisCompositeCut(true); AnalysisCut kineMuonCut; kineMuonCut.AddCut(VarManager::kPt, 1.5, 10.0); - fMuonCut->AddCut(&kineMuonCut); + fTrackCut->AddCut(&kineMuonCut); + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + void process(MyEvent event, MyMuonTracks const& muons) + { + for (int i = 0; i < VarManager::kNVars; ++i) + fValues[i] = -9999.0f; + VarManager::FillEvent(event, fValues); + + for (auto& muon : muons) { + for (int i = VarManager::kNBarrelTrackVariables; i < VarManager::kNMuonTrackVariables; ++i) + fValues[i] = -9999.0f; + VarManager::FillTrack(muon, fValues); + fHistMan->FillHistClass("TrackMuon_BeforeCuts", fValues); + + if (fTrackCut->IsSelected(fValues)) { + trackSel(1); + fHistMan->FillHistClass("TrackMuon_AfterCuts", fValues); + } else + trackSel(0); + } + } +}; + +struct TableReader { + Produces dileptonList; + OutputObj fHistMan{"output"}; + AnalysisCompositeCut* fEventCut; + //NOTE: one could define also a dilepton cut, but for now basic selections can be supported using Partition + + Partition posTracks = aod::reducedtrack::charge > 0 && aod::reducedtrack::isBarrelSelected == 1; + Partition negTracks = aod::reducedtrack::charge < 0 && aod::reducedtrack::isBarrelSelected == 1; + Partition posMuons = aod::reducedtrack::charge > 0 && aod::reducedtrack::isMuonSelected == 1; + Partition negMuons = aod::reducedtrack::charge < 0 && aod::reducedtrack::isMuonSelected == 1; + + void init(o2::framework::InitContext&) + { + VarManager::SetDefaultVarNames(); + fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;PairsBarrelPM;PairsBarrelPP;PairsBarrelMM;PairsMuon;"); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + + DefineCuts(); + } + + void DefineCuts() + { + fEventCut = new AnalysisCompositeCut(true); + + AnalysisCut* varCut = new AnalysisCut(); + varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + + TF1* cutLow = new TF1("cutLow", "pol1", 0., 0.1); + cutLow->SetParameters(0.2635, 1.0); + //varCut->AddCut(VarManager::kVtxY, cutLow, 0.335, false, VarManager::kVtxX, 0.067, 0.070); + + //varCut->AddCut(VarManager::kVtxY, 0.0, 0.335); + fEventCut->AddCut(varCut); VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill } - void process(soa::Join::iterator event, - soa::Join const& tracks, - soa::Join const& muons) + void process(MyEventVtxCov event, MyBarrelTracksSelected const& tracks, MyMuonTracksSelected const& muons) { - // Reset the fgValues array - // TODO: reseting will have to be done selectively, for example run-wise variables don't need to be reset every event, but just updated if the run changes - // The reset can be done selectively, using arguments in the ResetValues() function + // Reset the VarManager::fgValues array + // The reset can be done selectively, using arguments in the ResetValues() function VarManager::ResetValues(); VarManager::FillEvent(event); @@ -118,173 +249,271 @@ struct TableReader { return; fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); - // loop over barrel tracks and store positive and negative tracks in separate arrays - // TODO: use Partition initiaslized by vector of track indices when this will be available - std::vector::iterator> selectedTracksPos; - std::vector::iterator> selectedTracksNeg; - for (auto& track : tracks) { - - VarManager::ResetValues(VarManager::kNEventWiseVariables, VarManager::kNMuonTrackVariables); - - VarManager::FillTrack(track); - fHistMan->FillHistClass("TrackBarrel_BeforeCuts", VarManager::fgValues); - if (!fTrackCut->IsSelected(VarManager::fgValues)) - continue; - fHistMan->FillHistClass("TrackBarrel_AfterCuts", VarManager::fgValues); - - if (track.charge() < 0) - selectedTracksNeg.push_back(track); - if (track.charge() > 0) - selectedTracksPos.push_back(track); + // Run the same event pairing for barrel tracks + // TODO: Use combinations() when this will work for Partitions + /* e.g. + * for (auto& [tpos, tneg] : combinations(posTracks, negTracks)) { + VarManager::FillPair(tpos, tneg); + fHistMan->FillHistClass("PairsBarrelPM", VarManager::fgValues); } + */ - // run the same event pairing for barrel tracks - for (auto& tpos : selectedTracksPos) { - for (auto& tneg : selectedTracksNeg) { + for (auto tpos : posTracks) { + for (auto tneg : negTracks) { // +- pairs VarManager::FillPair(tpos, tneg); - fHistMan->FillHistClass("PairsBarrel", VarManager::fgValues); + dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], 0); + fHistMan->FillHistClass("PairsBarrelPM", VarManager::fgValues); + } + for (auto tpos2 = tpos + 1; tpos2 != posTracks.end(); ++tpos2) { // ++ pairs + VarManager::FillPair(tpos, tpos2); + dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], 2); + fHistMan->FillHistClass("PairsBarrelPP", VarManager::fgValues); } } - - // loop over muon tracks - std::vector::iterator> selectedMuonsPos; - std::vector::iterator> selectedMuonsNeg; - for (auto& muon : muons) { - VarManager::FillTrack(muon); - fHistMan->FillHistClass("TrackMuon_BeforeCuts", VarManager::fgValues); - if (!fMuonCut->IsSelected(VarManager::fgValues)) - continue; - fHistMan->FillHistClass("TrackMuon_AfterCuts", VarManager::fgValues); - - if (muon.charge() < 0) - selectedMuonsNeg.push_back(muon); - if (muon.charge() > 0) - selectedMuonsPos.push_back(muon); + for (auto tneg : negTracks) { // -- pairs + for (auto tneg2 = tneg + 1; tneg2 != negTracks.end(); ++tneg2) { + VarManager::FillPair(tneg, tneg2); + dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], -2); + fHistMan->FillHistClass("PairsBarrelMM", VarManager::fgValues); + } } // same event pairing for muons - for (auto& tpos : selectedMuonsNeg) { - for (auto& tneg : selectedMuonsPos) { + for (auto& tpos : posMuons) { + for (auto& tneg : negMuons) { + //dileptonList(event, VarManager::fgValues[VarManager::kMass], VarManager::fgValues[VarManager::kPt], VarManager::fgValues[VarManager::kEta], VarManager::fgValues[VarManager::kPhi], 1); VarManager::FillPair(tpos, tneg); fHistMan->FillHistClass("PairsMuon", VarManager::fgValues); } } } +}; + +struct DileptonHadronAnalysis { + // + // This task combines dilepton candidates with a track and could be used for example + // in analyses with the dilepton as one of the decay products of a higher mass resonance (e.g. B0 -> Jpsi + K) + // or in dilepton + hadron correlations, etc. + // It requires the TableReader task to be in the workflow and produce the dilepton table + // + OutputObj fHistMan{"output"}; + AnalysisCompositeCut* fHadronCut; + //NOTE: no cut has been included for dileptons because that can be controlled via the TableReader task and the partition below + + // use two values array to avoid mixing up the quantities + float* fValuesDilepton; + float* fValuesHadron; + + Partition selDileptons = aod::reducedpair::charge == 0 && aod::reducedpair::mass > 2.92f && aod::reducedpair::mass<3.16f && aod::reducedpair::pt> 5.0f; + + constexpr static uint32_t fgDileptonFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::Pair; + + void init(o2::framework::InitContext&) + { + fValuesDilepton = new float[VarManager::kNVars]; + fValuesHadron = new float[VarManager::kNVars]; + VarManager::SetDefaultVarNames(); + fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, "DileptonsSelected;HadronsSelected;DileptonHadronInvMass;DileptonHadronCorrelation"); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + + DefineCuts(); + } - void DefineHistograms(TString histClasses) + void DefineCuts() { - const int kNRuns = 2; - int runs[kNRuns] = {244918, 244919}; - TString runsStr; - for (int i = 0; i < kNRuns; i++) - runsStr += Form("%d;", runs[i]); - VarManager::SetRunNumbers(kNRuns, runs); - - TObjArray* arr = histClasses.Tokenize(";"); - for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { - TString classStr = arr->At(iclass)->GetName(); - - if (classStr.Contains("Event")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, - kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram - fHistMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram - fHistMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram - fHistMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, - 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, - "", "", "", VarManager::kVtxNcontrib); // TProfile3D - - double vtxXbinLims[10] = {0.055, 0.06, 0.062, 0.064, 0.066, 0.068, 0.070, 0.072, 0.074, 0.08}; - double vtxYbinLims[7] = {0.31, 0.32, 0.325, 0.33, 0.335, 0.34, 0.35}; - double vtxZbinLims[13] = {-15.0, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 15.0}; - double nContribbinLims[9] = {0.0, 100.0, 200.0, 400.0, 600.0, 1000.0, 1500.0, 2000.0, 4000.0}; - - fHistMan->AddHistogram(classStr.Data(), "VtxX_VtxY_nonEqualBinning", "Vtx X vs Vtx Y", false, 9, vtxXbinLims, VarManager::kVtxX, 6, vtxYbinLims, VarManager::kVtxY); // THnF histogram with custom non-equal binning - - fHistMan->AddHistogram(classStr.Data(), "VtxZ_weights", "Vtx Z", false, - 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, 10, 0., 0., VarManager::kNothing, - "", "", "", VarManager::kNothing, VarManager::kVtxNcontrib); // TH1F histogram, filled with weights using the vtx n-contributors - - Int_t vars[4] = {VarManager::kVtxX, VarManager::kVtxY, VarManager::kVtxZ, VarManager::kVtxNcontrib}; - TArrayD binLimits[4]; - binLimits[0] = TArrayD(10, vtxXbinLims); - binLimits[1] = TArrayD(7, vtxYbinLims); - binLimits[2] = TArrayD(13, vtxZbinLims); - binLimits[3] = TArrayD(9, nContribbinLims); - fHistMan->AddHistogram(classStr.Data(), "vtxHisto", "n contrib vs (x,y,z)", 4, vars, binLimits); - - fHistMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram - - fHistMan->AddHistogram(classStr.Data(), "VtxChi2", "Vtx chi2", false, 100, 0.0, 100.0, VarManager::kVtxChi2); // TH1F histogram + fHadronCut = new AnalysisCompositeCut(true); // true: use AND + AnalysisCut* cut1 = new AnalysisCut(); + cut1->AddCut(VarManager::kPt, 4.0, 20.0); + cut1->AddCut(VarManager::kEta, -0.9, 0.9); + cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut1->AddCut(VarManager::kITSchi2, 0.0, 36.0); + cut1->AddCut(VarManager::kITSncls, 2.5, 7.5); + cut1->AddCut(VarManager::kTPCncls, 69.5, 159.5); + fHadronCut->AddCut(cut1); + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + void process(MyEvent event, MyBarrelTracks const& hadrons, aod::Dileptons const& dileptons) + { + for (int i = 0; i < VarManager::kNVars; ++i) + fValuesHadron[i] = -9999.0f; + // fill event information which might be needed in histograms that combine track/pair and event properties + VarManager::FillEvent(event, fValuesHadron); + + // loop once over dileptons for QA purposes + for (auto dilepton : selDileptons) { + for (int i = VarManager::kNEventWiseVariables; i < VarManager::kNMuonTrackVariables; ++i) + fValuesDilepton[i] = -9999.0f; + VarManager::FillTrack(dilepton, fValuesDilepton); + fHistMan->FillHistClass("DileptonsSelected", fValuesDilepton); + } + + // loop over hadrons + for (auto& hadron : hadrons) { + for (int i = VarManager::kNEventWiseVariables; i < VarManager::kNMuonTrackVariables; ++i) + fValuesHadron[i] = -9999.0f; + VarManager::FillTrack(hadron, fValuesHadron); + if (!fHadronCut->IsSelected(fValuesHadron)) continue; - } // end if(Event) - - if (classStr.Contains("Track")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "P", "p distribution", false, 200, 0.0, 20.0, VarManager::kP); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); - fHistMan->AddHistogram(classStr.Data(), "Py", "p_{y} distribution", false, 200, 0.0, 20.0, VarManager::kPy); - fHistMan->AddHistogram(classStr.Data(), "Pz", "p_{z} distribution", false, 400, -20.0, 20.0, VarManager::kPz); - - if (classStr.Contains("Barrel")) { - - fHistMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram - fHistMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram - - //for TPC PID - fHistMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_pIN", "TPC dE/dx n#sigma_{e} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_Eta", "TPC dE/dx n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_pIN", "TPC dE/dx n#sigma_{#pi} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_Eta", "TPC dE/dx n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_pIN", "TPC dE/dx n#sigma_{K} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_Eta", "TPC dE/dx n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_pIN", "TPC dE/dx n#sigma_{p} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_Eta", "TPC dE/dx n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram - - //for TOF PID - fHistMan->AddHistogram(classStr.Data(), "TOFbeta_pIN", "TOF #beta vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 120, 0.0, 1.2, VarManager::kTOFbeta); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_pIN", "TOF #beta n#sigma_{e} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_Eta", "TOF #beta n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_pIN", "TOF #beta n#sigma_{#pi} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_Eta", "TOF #beta n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_pIN", "TOF #beta n#sigma_{K} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_Eta", "TOF #beta n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_pIN", "TOF #beta n#sigma_{p} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram - fHistMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_Eta", "TOF #beta n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram - - fHistMan->AddHistogram(classStr.Data(), "Cov1Pt_Pt", "cov(1/pt,1/pt) vs p_{T} distribution", false, 20, 0.0, 5.0, VarManager::kPt, 100, 0.0, 1.0, VarManager::kTrackC1Pt21Pt2); // TH2F histogram - } - - if (classStr.Contains("Muon")) { - fHistMan->AddHistogram(classStr.Data(), "InvBendingMom", "", false, 100, 0.0, 1.0, VarManager::kMuonInvBendingMomentum); - fHistMan->AddHistogram(classStr.Data(), "ThetaX", "", false, 100, -1.0, 1.0, VarManager::kMuonThetaX); - fHistMan->AddHistogram(classStr.Data(), "ThetaY", "", false, 100, -2.0, 2.0, VarManager::kMuonThetaY); - fHistMan->AddHistogram(classStr.Data(), "ZMu", "", false, 100, -30.0, 30.0, VarManager::kMuonZMu); - fHistMan->AddHistogram(classStr.Data(), "BendingCoor", "", false, 100, 0.32, 0.35, VarManager::kMuonBendingCoor); - fHistMan->AddHistogram(classStr.Data(), "NonBendingCoor", "", false, 100, 0.065, 0.07, VarManager::kMuonNonBendingCoor); - fHistMan->AddHistogram(classStr.Data(), "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); - fHistMan->AddHistogram(classStr.Data(), "Chi2MatchTrigger", "", false, 100, 0.0, 20.0, VarManager::kMuonChi2MatchTrigger); - } - } - if (classStr.Contains("Pairs")) { - fHistMan->AddHistClass(classStr.Data()); - fHistMan->AddHistogram(classStr.Data(), "Mass", "", false, 100, 0.0, 5.0, VarManager::kMass); + fHistMan->FillHistClass("HadronsSelected", fValuesHadron); + + for (auto dilepton : selDileptons) { + // TODO: At the moment there is no check on whether this hadron is one of the dilepton daughters + VarManager::FillDileptonHadron(dilepton, hadron, fValuesHadron); + fHistMan->FillHistClass("DileptonHadronInvMass", fValuesHadron); + fHistMan->FillHistClass("DileptonHadronCorrelation", fValuesHadron); } - } // end loop over histogram classes + } } }; WorkflowSpec defineDataProcessing(ConfigContext const&) { return WorkflowSpec{ - adaptAnalysisTask("table-reader")}; + adaptAnalysisTask("barrel-track-selection"), + adaptAnalysisTask("muon-track-selection"), + adaptAnalysisTask("table-reader"), + adaptAnalysisTask("dilepton-hadron")}; +} + +void DefineHistograms(o2::framework::OutputObj histMan, TString histClasses) +{ + // + // Define here the histograms for all the classes required in analysis. + // The histogram classes are provided in the histClasses string, separated by semicolon ";" + // The histogram classes and their components histograms are defined below depending on the name of the histogram class + // + const int kNRuns = 2; + int runs[kNRuns] = {244918, 244919}; + TString runsStr; + for (int i = 0; i < kNRuns; i++) + runsStr += Form("%d;", runs[i]); + VarManager::SetRunNumbers(kNRuns, runs); + + TObjArray* arr = histClasses.Tokenize(";"); + for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { + TString classStr = arr->At(iclass)->GetName(); + + if (classStr.Contains("Event")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, + kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram + histMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram + histMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram + histMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, + 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, + "", "", "", VarManager::kVtxNcontrib); // TProfile3D + + double vtxXbinLims[10] = {0.055, 0.06, 0.062, 0.064, 0.066, 0.068, 0.070, 0.072, 0.074, 0.08}; + double vtxYbinLims[7] = {0.31, 0.32, 0.325, 0.33, 0.335, 0.34, 0.35}; + double vtxZbinLims[13] = {-15.0, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 15.0}; + double nContribbinLims[9] = {0.0, 100.0, 200.0, 400.0, 600.0, 1000.0, 1500.0, 2000.0, 4000.0}; + + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_nonEqualBinning", "Vtx X vs Vtx Y", false, 9, vtxXbinLims, VarManager::kVtxX, 6, vtxYbinLims, VarManager::kVtxY); // THnF histogram with custom non-equal binning + + histMan->AddHistogram(classStr.Data(), "VtxZ_weights", "Vtx Z", false, + 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, 10, 0., 0., VarManager::kNothing, + "", "", "", VarManager::kNothing, VarManager::kVtxNcontrib); // TH1F histogram, filled with weights using the vtx n-contributors + + Int_t vars[4] = {VarManager::kVtxX, VarManager::kVtxY, VarManager::kVtxZ, VarManager::kVtxNcontrib}; + TArrayD binLimits[4]; + binLimits[0] = TArrayD(10, vtxXbinLims); + binLimits[1] = TArrayD(7, vtxYbinLims); + binLimits[2] = TArrayD(13, vtxZbinLims); + binLimits[3] = TArrayD(9, nContribbinLims); + histMan->AddHistogram(classStr.Data(), "vtxHisto", "n contrib vs (x,y,z)", 4, vars, binLimits); + + histMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram + + histMan->AddHistogram(classStr.Data(), "VtxChi2", "Vtx chi2", false, 100, 0.0, 100.0, VarManager::kVtxChi2); // TH1F histogram + + continue; + } // end if(Event) + + if (classStr.Contains("Track")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 200, 0.0, 20.0, VarManager::kPt); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 500, -5.0, 5.0, VarManager::kEta); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -5.0, 5.0, VarManager::kEta, 200, -6.3, 6.3, VarManager::kPhi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "P", "p distribution", false, 200, 0.0, 20.0, VarManager::kP); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); + histMan->AddHistogram(classStr.Data(), "Py", "p_{y} distribution", false, 200, 0.0, 20.0, VarManager::kPy); + histMan->AddHistogram(classStr.Data(), "Pz", "p_{z} distribution", false, 400, -20.0, 20.0, VarManager::kPz); + + if (classStr.Contains("Barrel")) { + histMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram + //for TPC PID + histMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_pIN", "TPC dE/dx n#sigma_{e} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_Eta", "TPC dE/dx n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_pIN", "TPC dE/dx n#sigma_{#pi} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_Eta", "TPC dE/dx n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_pIN", "TPC dE/dx n#sigma_{K} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_Eta", "TPC dE/dx n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_pIN", "TPC dE/dx n#sigma_{p} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_Eta", "TPC dE/dx n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram + + //for TOF PID + histMan->AddHistogram(classStr.Data(), "TOFbeta_pIN", "TOF #beta vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 120, 0.0, 1.2, VarManager::kTOFbeta); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_pIN", "TOF #beta n#sigma_{e} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_Eta", "TOF #beta n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_pIN", "TOF #beta n#sigma_{#pi} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_Eta", "TOF #beta n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_pIN", "TOF #beta n#sigma_{K} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_Eta", "TOF #beta n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_pIN", "TOF #beta n#sigma_{p} vs pIN", false, 200, 0.0, 20.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_Eta", "TOF #beta n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram + + histMan->AddHistogram(classStr.Data(), "Cov1Pt_Pt", "cov(1/pt,1/pt) vs p_{T} distribution", false, 20, 0.0, 5.0, VarManager::kPt, 100, 0.0, 1.0, VarManager::kTrackC1Pt21Pt2); // TH2F histogram + } + + if (classStr.Contains("Muon")) { + histMan->AddHistogram(classStr.Data(), "InvBendingMom", "", false, 100, 0.0, 1.0, VarManager::kMuonInvBendingMomentum); + histMan->AddHistogram(classStr.Data(), "ThetaX", "", false, 100, -1.0, 1.0, VarManager::kMuonThetaX); + histMan->AddHistogram(classStr.Data(), "ThetaY", "", false, 100, -2.0, 2.0, VarManager::kMuonThetaY); + histMan->AddHistogram(classStr.Data(), "ZMu", "", false, 100, -30.0, 30.0, VarManager::kMuonZMu); + histMan->AddHistogram(classStr.Data(), "BendingCoor", "", false, 100, 0.32, 0.35, VarManager::kMuonBendingCoor); + histMan->AddHistogram(classStr.Data(), "NonBendingCoor", "", false, 100, 0.065, 0.07, VarManager::kMuonNonBendingCoor); + histMan->AddHistogram(classStr.Data(), "Chi2", "", false, 100, 0.0, 200.0, VarManager::kMuonChi2); + histMan->AddHistogram(classStr.Data(), "Chi2MatchTrigger", "", false, 100, 0.0, 20.0, VarManager::kMuonChi2MatchTrigger); + } + } + + if (classStr.Contains("DileptonsSelected")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 100, 0.0, 5.0, VarManager::kMass, 100, 0.0, 20.0, VarManager::kPt); + } + + if (classStr.Contains("HadronsSelected")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Eta_Pt", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, 0.0, 20.0, VarManager::kPt); + histMan->AddHistogram(classStr.Data(), "Eta_Phi", "", false, 20, -1.0, 1.0, VarManager::kEta, 100, -8.0, 8.0, VarManager::kPhi); + } + + if (classStr.Contains("Pairs")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 100, 0.0, 5.0, VarManager::kMass, 100, 0.0, 20.0, VarManager::kPt); + } + + if (classStr.Contains("DileptonHadronInvMass")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 40, 0.0, 20.0, VarManager::kPairMass, 40, 0.0, 20.0, VarManager::kPairPt); + } + + if (classStr.Contains("DileptonHadronCorrelation")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "DeltaEta_DeltaPhi", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhi); + histMan->AddHistogram(classStr.Data(), "DeltaEta_DeltaPhiSym", "", false, 20, -2.0, 2.0, VarManager::kDeltaEta, 50, -8.0, 8.0, VarManager::kDeltaPhiSym); + } + } // end loop over histogram classes } From 5c38e3e971d95a1e05300fa118ab0cabad3e91bf Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 7 Sep 2020 12:11:57 +0200 Subject: [PATCH 18/76] DPL Analysis: redefine extended tables as Join (#4283) --- Analysis/DataModel/src/dumpDataModel.cxx | 8 +- Framework/Core/include/Framework/ASoA.h | 100 +++++++++------- .../Core/include/Framework/AnalysisHelpers.h | 88 ++++++++++---- .../Core/include/Framework/AnalysisTask.h | 1 - .../Core/include/Framework/TableBuilder.h | 10 +- Framework/Core/src/AODReaderHelpers.cxx | 8 +- Framework/Core/src/AnalysisManagers.h | 6 +- Framework/Core/src/WorkflowHelpers.cxx | 8 +- Framework/Core/src/verifyAODFile.cxx | 10 +- Framework/Core/test/benchmark_ASoA.cxx | 107 ++---------------- Framework/Core/test/benchmark_ASoAHelpers.cxx | 52 ++++----- .../Core/test/test_AnalysisDataModel.cxx | 39 ++++--- Framework/Core/test/test_AnalysisTask.cxx | 31 ++--- Framework/Core/test/test_Expressions.cxx | 1 + Framework/Core/test/test_SimpleTracksED.cxx | 10 +- Framework/Foundation/include/Framework/Pack.h | 39 +++++++ .../test/test_FunctionalHelpers.cxx | 6 + .../src/o2SimpleTracksAnalysis.cxx | 20 ++-- 18 files changed, 283 insertions(+), 261 deletions(-) diff --git a/Analysis/DataModel/src/dumpDataModel.cxx b/Analysis/DataModel/src/dumpDataModel.cxx index b549f53a0af81..70652b71f9d76 100644 --- a/Analysis/DataModel/src/dumpDataModel.cxx +++ b/Analysis/DataModel/src/dumpDataModel.cxx @@ -143,19 +143,19 @@ edge[dir=back, arrowtail=empty] (dumpIndex(typename Ts::iterator::external_index_columns_t{}), ...); } -int main(int argc, char** argv) +int main(int, char**) { fmt::printf("%s", R"(digraph hierarchy { size="5,5" node[shape=plain,style=filled,fillcolor=gray95] edge[dir=back, arrowtail=empty] )"); - dumpCluster(); + /// FIXME: topology should account for predefined Joins + dumpCluster(); dumpTable(); dumpTable(); dumpTable(); - dumpTable(); - dumpTable(); + dumpCluster(); dumpTable(); dumpTable(); dumpTable(); diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 8072b53168f42..d4d503fac778e 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1032,16 +1032,10 @@ struct PackToTable> { using table = o2::soa::Table; }; -template -struct FilterPersistentColumns { - static_assert(framework::always_static_assert_v, "Not a soa::Table"); -}; - -template -struct FilterPersistentColumns> { - using columns = typename soa::Table::columns; - using persistent_columns_pack = framework::selected_pack; - using persistent_table_t = typename PackToTable::table; +template +struct TableWrap { + using all_columns = framework::concatenated_pack_unique_t; + using table_t = typename PackToTable::table; }; /// Template trait which allows to map a given @@ -1056,11 +1050,47 @@ class TableMetadata }; template -constexpr auto join(o2::soa::Table const& t1, o2::soa::Table const& t2) +constexpr auto joinTables(o2::soa::Table const& t1, o2::soa::Table const& t2) { return o2::soa::Table(ArrowHelpers::joinTables({t1.asArrowTable(), t2.asArrowTable()})); } +template +constexpr auto joinLeft(T const& t1, o2::soa::Table const& t2, framework::pack) +{ + return typename o2::soa::TableWrap>::table_t(ArrowHelpers::joinTables({t1.asArrowTable(), t2.asArrowTable()})); +} + +template +constexpr auto joinRight(o2::soa::Table const& t1, T const& t2, framework::pack) +{ + return typename o2::soa::TableWrap, O...>::table_t(ArrowHelpers::joinTables({t1.asArrowTable(), t2.asArrowTable()})); +} + +template +constexpr auto joinBoth(T1 const& t1, T2 const& t2, framework::pack, framework::pack) +{ + return typename o2::soa::TableWrap::table_t(ArrowHelpers::joinTables({t1.asArrowTable(), t2.asArrowTable()})); +} + +template +constexpr auto join(T1 const& t1, T2 const& t2) +{ + if constexpr (soa::is_type_with_originals_v) { + if constexpr (soa::is_type_with_originals_v) { + return joinBoth(t1, t2, typename T1::originals{}, typename T2::originals{}); + } else { + return joinLeft(t1, t2, typename T1::originals{}); + } + } else { + if constexpr (soa::is_type_with_originals_v) { + return joinRight(t1, t2, typename T2::originals{}); + } else { + return joinTables(t1, t2); + } + } +} + template constexpr auto join(T1 const& t1, T2 const& t2, Ts const&... ts) { @@ -1306,27 +1336,23 @@ using ConcatBase = decltype(concat(std::declval(), std::declval())); #define DECLARE_SOA_TABLE(_Name_, _Origin_, _Description_, ...) \ DECLARE_SOA_TABLE_FULL(_Name_, #_Name_, _Origin_, _Description_, __VA_ARGS__); -#define DECLARE_SOA_EXTENDED_TABLE_FULL(_Name_, _Table_, _Origin_, _Description_, ...) \ - using _Name_ = o2::soa::JoinBase>; \ - \ - struct _Name_##Metadata : o2::soa::TableMetadata<_Name_##Metadata> { \ - using table_t = _Name_; \ - using base_table_t = _Table_; \ - using expression_pack_t = framework::pack<__VA_ARGS__>; \ - using originals = soa::originals_pack_t<_Table_>; \ - static constexpr char const* mLabel = #_Name_; \ - static constexpr char const mOrigin[4] = _Origin_; \ - static constexpr char const mDescription[16] = _Description_; \ - }; \ - \ - template <> \ - struct MetadataTrait<_Name_> { \ - using metadata = _Name_##Metadata; \ - }; \ - \ - template <> \ - struct MetadataTrait<_Name_::unfiltered_iterator> { \ - using metadata = _Name_##Metadata; \ +#define DECLARE_SOA_EXTENDED_TABLE_FULL(_Name_, _Table_, _Origin_, _Description_, ...) \ + using _Name_##Extension = o2::soa::Table<__VA_ARGS__>; \ + using _Name_ = o2::soa::Join<_Name_##Extension, _Table_>; \ + \ + struct _Name_##ExtensionMetadata : o2::soa::TableMetadata<_Name_##ExtensionMetadata> { \ + using table_t = _Name_##Extension; \ + using base_table_t = typename _Table_::table_t; \ + using expression_pack_t = framework::pack<__VA_ARGS__>; \ + using originals = soa::originals_pack_t<_Table_>; \ + static constexpr char const* mLabel = #_Name_ "Extension"; \ + static constexpr char const mOrigin[4] = _Origin_; \ + static constexpr char const mDescription[16] = _Description_; \ + }; \ + \ + template <> \ + struct MetadataTrait<_Name_##Extension> { \ + using metadata = _Name_##ExtensionMetadata; \ }; #define DECLARE_SOA_EXTENDED_TABLE(_Name_, _Table_, _Description_, ...) \ @@ -1745,16 +1771,12 @@ auto spawner(framework::pack columns, arrow::Table* atable) arrays[i] = std::make_shared(chunks[i]); } - auto extra_schema = o2::soa::createSchemaFromColumns(columns); - auto original_fields = atable->schema()->fields(); - auto original_columns = atable->columns(); - std::vector> new_fields(original_fields); - std::vector> new_columns(original_columns); + auto new_schema = o2::soa::createSchemaFromColumns(columns); + std::vector> new_columns; for (auto i = 0u; i < sizeof...(C); ++i) { - new_fields.emplace_back(extra_schema->field(i)); new_columns.push_back(arrays[i]); } - return arrow::Table::Make(std::make_shared(new_fields), new_columns); + return arrow::Table::Make(new_schema, new_columns); } /// On-the-fly adding of expression columns diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 0749cd0dcc2f6..457c3d5b139c0 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -97,7 +97,7 @@ struct Produces { /// means of the WritingCursor helper class, from which produces actually /// derives. template -struct Produces> : WritingCursor>::persistent_table_t> { +struct Produces> : WritingCursor::persistent_columns_t>::table> { using table_t = soa::Table; using metadata = typename aod::MetadataTrait::metadata; @@ -113,12 +113,19 @@ struct Produces> : WritingCursor -struct TransformTable { - using metadata = typename aod::MetadataTrait::metadata; - using originals = typename metadata::originals; +struct Spawns { + using extension_t = framework::pack_head_t; + using metadata = typename aod::MetadataTrait::metadata; + using sources = typename metadata::originals; + using expression_pack_t = typename metadata::expression_pack_t; + constexpr auto pack() + { + return expression_pack_t{}; + } template InputSpec const base_spec() { @@ -137,7 +144,7 @@ struct TransformTable { std::vector const base_specs() { - return base_specs_impl(originals{}); + return base_specs_impl(sources{}); } OutputSpec const spec() const @@ -161,23 +168,10 @@ struct TransformTable { auto asArrowTable() { - return table->asArrowTable(); - } - std::shared_ptr table = nullptr; -}; - -/// This helper struct allows you to declare extended tables which should be -/// created by the task (as opposed to those pre-defined by data model) -template -struct Spawns : TransformTable { - using metadata = typename TransformTable::metadata; - using originals = typename metadata::originals; - using expression_pack_t = typename metadata::expression_pack_t; - - constexpr auto pack() - { - return expression_pack_t{}; + return extension->asArrowTable(); } + std::shared_ptr table = nullptr; + std::shared_ptr extension = nullptr; }; /// Policy to control index building @@ -305,14 +299,60 @@ struct IndexSparse { /// This helper struct allows you to declare index tables to be created in a task template -struct Builds : TransformTable { - using metadata = typename TransformTable::metadata; +struct Builds { + using metadata = typename aod::MetadataTrait::metadata; using originals = typename metadata::originals; using Key = typename T::indexing_t; using H = typename T::first_t; using Ts = typename T::rest_t; using index_pack_t = typename metadata::index_pack_t; + template + InputSpec const base_spec() + { + using o_metadata = typename aod::MetadataTrait::metadata; + return InputSpec{ + o_metadata::tableLabel(), + header::DataOrigin{o_metadata::origin()}, + header::DataDescription{o_metadata::description()}}; + } + + template + std::vector const base_specs_impl(framework::pack) + { + return {base_spec()...}; + } + + std::vector const base_specs() + { + return base_specs_impl(originals{}); + } + + OutputSpec const spec() const + { + return OutputSpec{OutputLabel{metadata::tableLabel()}, metadata::origin(), metadata::description()}; + } + + OutputRef ref() const + { + return OutputRef{metadata::tableLabel(), 0}; + } + + T* operator->() + { + return table.get(); + } + T& operator*() + { + return *table.get(); + } + + auto asArrowTable() + { + return table->asArrowTable(); + } + std::shared_ptr table = nullptr; + constexpr auto pack() { return index_pack_t{}; diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 426a7f56a4483..9c83d8ee38763 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -45,7 +45,6 @@ namespace o2::framework // FIXME: for the moment this needs to stay outside AnalysisTask // because we cannot inherit from it due to a C++17 bug // in GCC 7.3. We need to move to 7.4+ - struct AnalysisTask { }; diff --git a/Framework/Core/include/Framework/TableBuilder.h b/Framework/Core/include/Framework/TableBuilder.h index 9cc22025c0d46..3d8d3cdc1209c 100644 --- a/Framework/Core/include/Framework/TableBuilder.h +++ b/Framework/Core/include/Framework/TableBuilder.h @@ -511,19 +511,17 @@ class TableBuilder template auto cursor() { - using persistent_filter = soa::FilterPersistentColumns; - using persistent_columns_pack = typename persistent_filter::persistent_columns_pack; + using persistent_columns_pack = typename T::table_t::persistent_columns_t; constexpr auto persistent_size = pack_size(persistent_columns_pack{}); - return cursorHelper(std::make_index_sequence()); + return cursorHelper::table>(std::make_index_sequence()); } template auto cursor() { - using persistent_filter = soa::FilterPersistentColumns; - using persistent_columns_pack = typename persistent_filter::persistent_columns_pack; + using persistent_columns_pack = typename T::table_t::persistent_columns_t; constexpr auto persistent_size = pack_size(persistent_columns_pack{}); - return cursorHelper(std::make_index_sequence()); + return cursorHelper::table, E>(std::make_index_sequence()); } template diff --git a/Framework/Core/src/AODReaderHelpers.cxx b/Framework/Core/src/AODReaderHelpers.cxx index ca839bb14cdfa..2a614f356a6d5 100644 --- a/Framework/Core/src/AODReaderHelpers.cxx +++ b/Framework/Core/src/AODReaderHelpers.cxx @@ -116,7 +116,7 @@ uint64_t getMask(header::DataDescription description) } } -uint64_t calculateReadMask(std::vector const& routes, header::DataOrigin const& origin) +uint64_t calculateReadMask(std::vector const& routes, header::DataOrigin const&) { uint64_t readMask = None; for (auto& route : routes) { @@ -176,11 +176,11 @@ AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(std::vector reques }; if (description == header::DataDescription{"TRACKPAR"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::TracksMetadata{})); + outputs.adopt(Output{origin, description}, maker(o2::aod::TracksExtensionMetadata{})); } else if (description == header::DataDescription{"TRACKPARCOV"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::TracksCovMetadata{})); + outputs.adopt(Output{origin, description}, maker(o2::aod::TracksCovExtensionMetadata{})); } else if (description == header::DataDescription{"MUON"}) { - outputs.adopt(Output{origin, description}, maker(o2::aod::MuonsMetadata{})); + outputs.adopt(Output{origin, description}, maker(o2::aod::MuonsExtensionMetadata{})); } else { throw std::runtime_error("Not an extended table"); } diff --git a/Framework/Core/src/AnalysisManagers.h b/Framework/Core/src/AnalysisManagers.h index b0473f96780ed..d40e8aebce8bd 100644 --- a/Framework/Core/src/AnalysisManagers.h +++ b/Framework/Core/src/AnalysisManagers.h @@ -233,9 +233,9 @@ struct OutputManager> { static bool prepare(ProcessingContext& pc, Spawns& what) { - using metadata = typename std::decay_t::metadata; - auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(typename metadata::originals{}, pc)); - what.table = std::make_shared(o2::soa::spawner(what.pack(), original_table.get())); + auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(typename Spawns::sources{}, pc)); + what.extension = std::make_shared::extension_t>(o2::soa::spawner(what.pack(), original_table.get())); + what.table = std::make_shared(soa::ArrowHelpers::joinTables({what.extension->asArrowTable(), original_table})); return true; } diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 275f4746cac23..9ffaaf1af00b3 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -335,7 +335,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // This is to inject a file sink so that any dangling ATSK object is written // to a ROOT file. - if (providedOutputObj.size() != 0) { + if (providedOutputObj.empty() == false) { auto rootSink = CommonDataProcessors::getOutputObjSink(outObjMap, outTskMap); extraSpecs.push_back(rootSink); } @@ -356,7 +356,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // select outputs of type AOD std::vector OutputsInputsAOD; std::vector isdangling; - for (int ii = 0; ii < OutputsInputs.size(); ii++) { + for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { if ((outputtypes[ii] & 2) == 2) { // temporarily also request to be dangling @@ -379,7 +379,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // select dangling outputs which are not of type AOD std::vector OutputsInputsDangling; - for (int ii = 0; ii < OutputsInputs.size(); ii++) { + for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { if ((outputtypes[ii] & 1) == 1 && (outputtypes[ii] & 2) == 0) OutputsInputsDangling.emplace_back(OutputsInputs[ii]); } @@ -783,7 +783,7 @@ std::vector WorkflowHelpers::computeDanglingOutputs(WorkflowSpec cons auto [OutputsInputs, outputtypes] = analyzeOutputs(workflow); std::vector results; - for (int ii = 0; ii < OutputsInputs.size(); ii++) { + for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { if ((outputtypes[ii] & 1) == 1) { results.emplace_back(OutputsInputs[ii]); } diff --git a/Framework/Core/src/verifyAODFile.cxx b/Framework/Core/src/verifyAODFile.cxx index 2864a259d2b45..6c4d8aa23f163 100644 --- a/Framework/Core/src/verifyAODFile.cxx +++ b/Framework/Core/src/verifyAODFile.cxx @@ -43,11 +43,11 @@ int main(int argc, char** argv) return 1; } - verifyTable(infile.get(), "O2collisions"); - verifyTable(infile.get(), "O2tracks"); - verifyTable(infile.get(), "O2tracks"); - verifyTable(infile.get(), "O2tracks"); + verifyTable(infile.get(), "O2collision"); + verifyTable(infile.get(), "O2track"); + verifyTable(infile.get(), "O2track"); + verifyTable(infile.get(), "O2track"); verifyTable(infile.get(), "O2calo"); - verifyTable(infile.get(), "O2muon"); + verifyTable(infile.get(), "O2muon"); return 0; } diff --git a/Framework/Core/test/benchmark_ASoA.cxx b/Framework/Core/test/benchmark_ASoA.cxx index 88448f5e04dd0..941187159c9cb 100644 --- a/Framework/Core/test/benchmark_ASoA.cxx +++ b/Framework/Core/test/benchmark_ASoA.cxx @@ -19,6 +19,7 @@ using namespace o2::framework; using namespace arrow; using namespace o2::soa; +DECLARE_SOA_STORE(); namespace test { DECLARE_SOA_COLUMN_FULL(X, x, float, "x"); @@ -27,6 +28,8 @@ DECLARE_SOA_COLUMN_FULL(Z, z, float, "z"); DECLARE_SOA_DYNAMIC_COLUMN(Sum, sum, [](float x, float y) { return x + y; }); } // namespace test +DECLARE_SOA_TABLE(TestTable, "AOD", "TESTTBL", test::X, test::Y, test::Z, test::Sum); + #ifdef __APPLE__ constexpr unsigned int maxrange = 10; #else @@ -47,13 +50,13 @@ static void BM_SimpleForLoop(benchmark::State& state) std::default_random_engine e1(1234567891); std::uniform_real_distribution uniform_dist(0, 1); - for (size_t i = 0; i < state.range(0); ++i) { + for (auto i = 0; i < state.range(0); ++i) { foo[i] = XYZ{uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)}; } for (auto _ : state) { float sum = 0; - for (auto& xyz : foo) { + for (auto& _ : foo) { benchmark::DoNotOptimize(sum++); } } @@ -79,7 +82,7 @@ static void BM_TrackForLoop(benchmark::State& state) std::default_random_engine e1(1234567891); std::uniform_real_distribution uniform_dist(0, 1); - for (size_t i = 0; i < state.range(0); ++i) { + for (auto i = 0; i < state.range(0); ++i) { foo[i] = TestTrack{ uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)}; @@ -114,7 +117,7 @@ static void BM_WholeTrackForLoop(benchmark::State& state) std::default_random_engine e1(1234567891); std::uniform_real_distribution uniform_dist(0, 1); - for (auto i = 0u; i < state.range(0); ++i) { + for (auto i = 0; i < state.range(0); ++i) { foo[i] = TestTrack{ uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)}; @@ -149,7 +152,7 @@ static void BM_TrackForPhi(benchmark::State& state) std::default_random_engine e1(1234567891); std::uniform_real_distribution uniform_dist(0, 1); - for (auto i = 0u; i < state.range(0); ++i) { + for (auto i = 0; i < state.range(0); ++i) { foo[i] = TestTrack{ uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)}; @@ -183,7 +186,7 @@ static void BM_SimpleForLoopWithOp(benchmark::State& state) std::default_random_engine e1(1234567891); std::uniform_real_distribution uniform_dist(0, 1); - for (auto i = 0u; i < state.range(0); ++i) { + for (auto i = 0; i < state.range(0); ++i) { foo[i] = XYZ{uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)}; } @@ -308,98 +311,6 @@ static void BM_ASoADynamicColumnCall(benchmark::State& state) } state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(float) * 2); } - BENCHMARK(BM_ASoADynamicColumnCall)->Range(8, 8 << maxrange); -static void BM_ASoAGettersPhi(benchmark::State& state) -{ - // Seed with a real random value, if available - std::default_random_engine e1(1234567891); - std::uniform_real_distribution uniform_dist(0, 1); - - TableBuilder builder; - auto rowWriter = builder.cursor(); - for (auto i = 0; i < state.range(0); ++i) { - rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); - } - auto table = builder.finalize(); - - o2::aod::Tracks tracks{table}; - for (auto _ : state) { - state.PauseTiming(); - std::vector out; - out.resize(state.range(0)); - float* result = out.data(); - state.ResumeTiming(); - for (auto& track : tracks) { - *result++ = asin(track.snp()) + track.alpha() + M_PI; - } - benchmark::DoNotOptimize(result); - } - state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(float) * 2); -} - -BENCHMARK(BM_ASoAGettersPhi)->Range(8, 8 << maxrange); - -static void BM_ASoAWholeTrackForLoop(benchmark::State& state) -{ - // Seed with a real random value, if available - std::default_random_engine e1(1234567891); - std::uniform_real_distribution uniform_dist(0, 1); - - TableBuilder builder; - auto rowWriter = builder.cursor(); - for (auto i = 0; i < state.range(0); ++i) { - rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); - } - auto table = builder.finalize(); - - o2::aod::Tracks tracks{table}; - for (auto _ : state) { - float sum = 0; - for (auto& track : tracks) { - sum += track.x() + track.alpha() + track.y() + track.z() + track.snp() + track.tgl() + track.signed1Pt(); - } - benchmark::DoNotOptimize(sum); - } - state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(float) * 6); -} - -BENCHMARK(BM_ASoAWholeTrackForLoop)->Range(8, 8 << maxrange); - -static void BM_ASoADynamicColumnPhi(benchmark::State& state) -{ - // Seed with a real random value, if available - std::default_random_engine e1(1234567891); - std::uniform_real_distribution uniform_dist(0, 1); - - TableBuilder builder; - auto rowWriter = builder.cursor(); - for (auto i = 0; i < state.range(0); ++i) { - rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); - } - auto table = builder.finalize(); - - o2::aod::Tracks tracks{table}; - for (auto _ : state) { - state.PauseTiming(); - std::vector out; - out.resize(state.range(0)); - float* result = out.data(); - state.ResumeTiming(); - for (auto& track : tracks) { - *result++ = track.phi(); - } - benchmark::DoNotOptimize(result); - } - state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(float) * 2); -} -BENCHMARK(BM_ASoADynamicColumnPhi)->Range(8, 8 << maxrange); - BENCHMARK_MAIN(); diff --git a/Framework/Core/test/benchmark_ASoAHelpers.cxx b/Framework/Core/test/benchmark_ASoAHelpers.cxx index 3e17b294ab340..4c8bb53a0c0b9 100644 --- a/Framework/Core/test/benchmark_ASoAHelpers.cxx +++ b/Framework/Core/test/benchmark_ASoAHelpers.cxx @@ -19,6 +19,8 @@ using namespace o2::framework; using namespace arrow; using namespace o2::soa; +/// FIXME: do not use data model tables + namespace test { DECLARE_SOA_COLUMN_FULL(X, x, float, "x"); @@ -162,21 +164,20 @@ static void BM_ASoAHelpersNaiveTracksPairs(benchmark::State& state) std::uniform_real_distribution uniform_dist(0, 1); TableBuilder builder; - auto rowWriter = builder.cursor(); + auto rowWriter = builder.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); - o2::aod::Tracks tracks{table}; + o2::aod::Calos Calos{table}; int64_t count = 0; for (auto _ : state) { count = 0; - for (auto t0 = tracks.begin(); t0 + 1 != tracks.end(); ++t0) { - for (auto t1 = t0 + 1; t1 != tracks.end(); ++t1) { + for (auto t0 = Calos.begin(); t0 + 1 != Calos.end(); ++t0) { + for (auto t1 = t0 + 1; t1 != Calos.end(); ++t1) { auto comb = std::make_tuple(t0, t1); count++; benchmark::DoNotOptimize(comb); @@ -197,24 +198,23 @@ static void BM_ASoAHelpersNaiveTracksFives(benchmark::State& state) std::uniform_real_distribution uniform_dist(0, 1); TableBuilder builder; - auto rowWriter = builder.cursor(); + auto rowWriter = builder.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); - o2::aod::Tracks tracks{table}; + o2::aod::Calos calos{table}; int64_t count = 0; for (auto _ : state) { count = 0; - for (auto t0 = tracks.begin(); t0 + 4 != tracks.end(); ++t0) { - for (auto t1 = t0 + 1; t1 + 3 != tracks.end(); ++t1) { - for (auto t2 = t1 + 1; t2 + 2 != tracks.end(); ++t2) { - for (auto t3 = t2 + 1; t3 + 1 != tracks.end(); ++t3) { - for (auto t4 = t3 + 1; t4 != tracks.end(); ++t4) { + for (auto t0 = calos.begin(); t0 + 4 != calos.end(); ++t0) { + for (auto t1 = t0 + 1; t1 + 3 != calos.end(); ++t1) { + for (auto t2 = t1 + 1; t2 + 2 != calos.end(); ++t2) { + for (auto t3 = t2 + 1; t3 + 1 != calos.end(); ++t3) { + for (auto t4 = t3 + 1; t4 != calos.end(); ++t4) { auto comb = std::make_tuple(t0, t1, t2, t3, t4); count++; benchmark::DoNotOptimize(comb); @@ -300,21 +300,20 @@ static void BM_ASoAHelpersCombGenTracksPairs(benchmark::State& state) std::uniform_real_distribution uniform_dist(0, 1); TableBuilder builder; - auto rowWriter = builder.cursor(); + auto rowWriter = builder.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); - o2::aod::Tracks tracks{table}; + o2::aod::Calos calos{table}; int64_t count = 0; for (auto _ : state) { count = 0; - for (auto& comb : combinations(tracks, tracks)) { + for (auto& comb : combinations(calos, calos)) { count++; } benchmark::DoNotOptimize(count); @@ -332,21 +331,20 @@ static void BM_ASoAHelpersCombGenTracksFives(benchmark::State& state) std::uniform_real_distribution uniform_dist(0, 1); TableBuilder builder; - auto rowWriter = builder.cursor(); + auto rowWriter = builder.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriter(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto table = builder.finalize(); - o2::aod::Tracks tracks{table}; + o2::aod::Calos calos{table}; int64_t count = 0; for (auto _ : state) { count = 0; - for (auto& comb : combinations(tracks, tracks, tracks, tracks, tracks)) { + for (auto& comb : combinations(calos, calos, calos, calos, calos)) { count++; } benchmark::DoNotOptimize(count); @@ -405,32 +403,30 @@ static void BM_ASoAHelpersCombGenTracksFivesMultipleChunks(benchmark::State& sta std::uniform_real_distribution uniform_dist(0, 1); TableBuilder builderA; - auto rowWriterA = builderA.cursor(); + auto rowWriterA = builderA.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriterA(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto tableA = builderA.finalize(); TableBuilder builderB; - auto rowWriterB = builderB.cursor(); + auto rowWriterB = builderB.cursor(); for (auto i = 0; i < state.range(0); ++i) { rowWriterB(0, uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), - uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1), uniform_dist(e1)); } auto tableB = builderB.finalize(); - using ConcatTest = Concat; + using ConcatTest = Concat; - ConcatTest tracks{tableA, tableB}; + ConcatTest calos{tableA, tableB}; int64_t count = 0; for (auto _ : state) { count = 0; - for (auto& comb : combinations(tracks, tracks, tracks, tracks, tracks)) { + for (auto& comb : combinations(calos, calos, calos, calos, calos)) { count++; } benchmark::DoNotOptimize(count); diff --git a/Framework/Core/test/test_AnalysisDataModel.cxx b/Framework/Core/test/test_AnalysisDataModel.cxx index c517d571875bd..77b4264b289db 100644 --- a/Framework/Core/test/test_AnalysisDataModel.cxx +++ b/Framework/Core/test/test_AnalysisDataModel.cxx @@ -22,30 +22,41 @@ using namespace o2::framework; using namespace arrow; -using namespace o2::soa; -using namespace o2::aod; + +DECLARE_SOA_STORE(); + +namespace col +{ +DECLARE_SOA_COLUMN(X, x, float); +DECLARE_SOA_COLUMN(Y, y, float); +DECLARE_SOA_COLUMN(Z, z, float); +DECLARE_SOA_COLUMN(D, d, float); +} // namespace col + +DECLARE_SOA_TABLE(XY, "AOD", "XY", col::X, col::Y); +DECLARE_SOA_TABLE(ZD, "AOD", "ZD", col::Z, col::D); BOOST_AUTO_TEST_CASE(TestJoinedTables) { - TableBuilder trackBuilder; + TableBuilder XYBuilder; //FIXME: using full tracks, instead of stored because of unbound dynamic // column (normalized phi) - auto trackWriter = trackBuilder.cursor(); - trackWriter(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - auto tracks = trackBuilder.finalize(); + auto xyWriter = XYBuilder.cursor(); + xyWriter(0, 0, 0); + auto tXY = XYBuilder.finalize(); - TableBuilder trackParCovBuilder; - auto trackParCovWriter = trackParCovBuilder.cursor(); - trackParCovWriter(0, 7, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4); - auto covs = trackParCovBuilder.finalize(); + TableBuilder ZDBuilder; + auto zdWriter = ZDBuilder.cursor(); + zdWriter(0, 7, 1); + auto tZD = ZDBuilder.finalize(); - using Test = Join; + using Test = o2::soa::Join; - Test tests{0, tracks, covs}; + Test tests{0, tXY, tZD}; BOOST_REQUIRE(tests.asArrowTable()->num_columns() != 0); BOOST_REQUIRE_EQUAL(tests.asArrowTable()->num_columns(), - tracks->num_columns() + covs->num_columns()); - auto tests2 = join(Tracks{tracks}, StoredTracksCov{covs}); + tXY->num_columns() + tZD->num_columns()); + auto tests2 = join(XY{tXY}, ZD{tZD}); static_assert(std::is_same_v, "Joined tables should have the same type, regardless how we construct them"); } diff --git a/Framework/Core/test/test_AnalysisTask.cxx b/Framework/Core/test/test_AnalysisTask.cxx index 4043351815d10..fb4a0e70cd13b 100644 --- a/Framework/Core/test/test_AnalysisTask.cxx +++ b/Framework/Core/test/test_AnalysisTask.cxx @@ -146,29 +146,34 @@ struct JTask { BOOST_AUTO_TEST_CASE(AdaptorCompilation) { auto task1 = adaptAnalysisTask("test1"); - BOOST_CHECK_EQUAL(task1.inputs.size(), 1); + BOOST_CHECK_EQUAL(task1.inputs.size(), 2); BOOST_CHECK_EQUAL(task1.outputs.size(), 1); - BOOST_CHECK_EQUAL(task1.inputs[0].binding, std::string("Tracks")); + BOOST_CHECK_EQUAL(task1.inputs[0].binding, std::string("TracksExtension")); + BOOST_CHECK_EQUAL(task1.inputs[1].binding, std::string("Tracks")); BOOST_CHECK_EQUAL(task1.outputs[0].binding.value, std::string("FooBars")); auto task2 = adaptAnalysisTask("test2"); - BOOST_CHECK_EQUAL(task2.inputs.size(), 7); + BOOST_CHECK_EQUAL(task2.inputs.size(), 9); BOOST_CHECK_EQUAL(task2.inputs[0].binding, "Collisions"); - BOOST_CHECK_EQUAL(task2.inputs[1].binding, "Tracks"); - BOOST_CHECK_EQUAL(task2.inputs[2].binding, "TracksExtra"); - BOOST_CHECK_EQUAL(task2.inputs[3].binding, "TracksCov"); - BOOST_CHECK_EQUAL(task2.inputs[4].binding, "UnassignedTracks"); - BOOST_CHECK_EQUAL(task2.inputs[5].binding, "Calos"); - BOOST_CHECK_EQUAL(task2.inputs[6].binding, "CaloTriggers"); + BOOST_CHECK_EQUAL(task2.inputs[1].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task2.inputs[2].binding, "Tracks"); + BOOST_CHECK_EQUAL(task2.inputs[3].binding, "TracksExtra"); + BOOST_CHECK_EQUAL(task2.inputs[4].binding, "TracksCovExtension"); + BOOST_CHECK_EQUAL(task2.inputs[5].binding, "TracksCov"); + BOOST_CHECK_EQUAL(task2.inputs[6].binding, "UnassignedTracks"); + BOOST_CHECK_EQUAL(task2.inputs[7].binding, "Calos"); + BOOST_CHECK_EQUAL(task2.inputs[8].binding, "CaloTriggers"); auto task3 = adaptAnalysisTask("test3"); - BOOST_CHECK_EQUAL(task3.inputs.size(), 2); + BOOST_CHECK_EQUAL(task3.inputs.size(), 3); BOOST_CHECK_EQUAL(task3.inputs[0].binding, "Collisions"); - BOOST_CHECK_EQUAL(task3.inputs[1].binding, "Tracks"); + BOOST_CHECK_EQUAL(task3.inputs[1].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task3.inputs[2].binding, "Tracks"); auto task4 = adaptAnalysisTask("test4"); - BOOST_CHECK_EQUAL(task4.inputs.size(), 1); - BOOST_CHECK_EQUAL(task4.inputs[0].binding, "Tracks"); + BOOST_CHECK_EQUAL(task4.inputs.size(), 2); + BOOST_CHECK_EQUAL(task4.inputs[0].binding, "TracksExtension"); + BOOST_CHECK_EQUAL(task4.inputs[1].binding, "Tracks"); auto task5 = adaptAnalysisTask("test5"); BOOST_CHECK_EQUAL(task5.inputs.size(), 1); diff --git a/Framework/Core/test/test_Expressions.cxx b/Framework/Core/test/test_Expressions.cxx index c95db424ef650..c188a5710af99 100644 --- a/Framework/Core/test/test_Expressions.cxx +++ b/Framework/Core/test/test_Expressions.cxx @@ -29,6 +29,7 @@ static BindingNode eta{"eta", atype::FLOAT}; static BindingNode tgl{"tgl", atype::FLOAT}; static BindingNode signed1Pt{"signed1Pt", atype::FLOAT}; +static BindingNode testInt{"testInt", atype::INT32}; } // namespace nodes namespace o2::aod::track diff --git a/Framework/Core/test/test_SimpleTracksED.cxx b/Framework/Core/test/test_SimpleTracksED.cxx index 57a10996970c9..35d113a0e85a2 100644 --- a/Framework/Core/test/test_SimpleTracksED.cxx +++ b/Framework/Core/test/test_SimpleTracksED.cxx @@ -33,7 +33,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) return WorkflowSpec{ {"trackDisplay", Inputs{ - {"tracks", "AOD", "TRACKPAR"}}, + {"Collisions", "AOD", "COLLISION"}}, Outputs{}, AlgorithmSpec{adaptStateful( [](CallbackService& callbacks) { @@ -51,12 +51,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) [count, window, guiCallback]() { (*count)++; window ? pollGUI(window, guiCallback) : false; }); return adaptStateless([count](InputRecord& inputs, ControlService& control) { - auto input = inputs.get("tracks"); + auto input = inputs.get("Collisions"); - o2::aod::Tracks myTracks{input->asArrowTable()}; + o2::aod::Collisions myCollisions{{input->asArrowTable()}}; - for (auto& track : myTracks) { - LOGF(info, "CollisionId %d", track.collisionId()); + for (auto& collision : myCollisions) { + LOGF(info, "CollisionId %d", collision.globalIndex()); } if (*count > 1000) { diff --git a/Framework/Foundation/include/Framework/Pack.h b/Framework/Foundation/include/Framework/Pack.h index 983a256b6e7b9..b8b5f4806a2a0 100644 --- a/Framework/Foundation/include/Framework/Pack.h +++ b/Framework/Foundation/include/Framework/Pack.h @@ -48,6 +48,15 @@ struct pack_element<0, pack> { template using pack_element_t = typename pack_element::type; +template +using pack_head_t = typename pack_element<0, T>::type; + +template +constexpr auto pack_tail(pack) +{ + return pack{}; +} + /// Templates for manipulating type lists in pack /// (see https://codereview.stackexchange.com/questions/201209/filter-template-meta-function/201222#201222) /// Example of use: @@ -161,6 +170,36 @@ struct intersect_pack { template using intersected_pack_t = typename intersect_pack::type; +/// Subtract two packs +template +struct subtract_pack { + template + static constexpr auto make_subtraction(std::index_sequence) + { + return filtered_pack, S2>, + pack_element_t, void>...>{}; + } + using type = decltype(make_subtraction(std::make_index_sequence{})); +}; + +template +constexpr auto concatenate_pack_unique(pack, pack) +{ + using p1 = typename subtract_pack, pack>::type; + return concatenate_pack(p1{}, pack{}); +} + +template +constexpr auto concatenate_pack_unique(P1 p1, P2 p2, Ps... ps) +{ + return concatenate_pack_unique(p1, concatenate_pack_unique(p2, ps...)); +} + +template +using concatenated_pack_unique_t = decltype(concatenate_pack_unique(Ps{}...)); + } // namespace o2::framework #endif // O2_FRAMEWORK_PACK_H_ diff --git a/Framework/Foundation/test/test_FunctionalHelpers.cxx b/Framework/Foundation/test/test_FunctionalHelpers.cxx index db6ff3449274b..af49a4c3ce7c8 100644 --- a/Framework/Foundation/test/test_FunctionalHelpers.cxx +++ b/Framework/Foundation/test/test_FunctionalHelpers.cxx @@ -44,6 +44,12 @@ BOOST_AUTO_TEST_CASE(TestOverride) static_assert(std::is_same_v, pack>, pack>, "pack should be concatenated"); static_assert(std::is_same_v, pack, pack>, pack>, "pack should be concatenated"); + using p1 = pack; + using p2 = pack; + using p3 = concatenated_pack_unique_t; + print_pack(); + static_assert(std::is_same_v>, "pack should not have duplicated types"); + struct ForwardDeclared; static_assert(is_type_complete_v == false, "This should not be complete because the struct is simply forward declared."); diff --git a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx index eaa6eb2d081aa..f19c808aa221b 100644 --- a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx +++ b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx @@ -20,9 +20,7 @@ using namespace ROOT::RDF; using namespace o2; using namespace o2::framework; -namespace o2 -{ -namespace aod +namespace o2::aod { namespace tracks { @@ -31,9 +29,7 @@ DECLARE_SOA_COLUMN(Phi, phi, float); } // namespace tracks using TracksDerived = o2::soa::Table; - -} // namespace aod -} // namespace o2 +} // namespace o2::aod // A dummy workflow which creates a few of the tables proposed by Ruben, // using ARROW @@ -57,8 +53,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& specs) // in Ruben's table. The first string is just a label so that the // algorithm can be in principle be reused for different kind of // tracks. - InputSpec{"tracks", "AOD", "TRACKPAR"}, - }, + InputSpec{"Tracks", "DYN", "TRACKPAR"}, + InputSpec{"TracksExtension", "AOD", "TRACKPAR"}}, // No outputs for the time being. Outputs{ OutputSpec{{"derived"}, "AOD", "TRACKDERIVED"}}, @@ -68,15 +64,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& specs) // FIXME: Too much boilerplate. adaptStateless([](InputRecord& inputs, DataAllocator& outputs) { /// Get the input from the converter. - auto input = inputs.get("tracks"); + auto input1 = inputs.get("Tracks"); + auto input2 = inputs.get("TracksExtension"); /// Get a table builder to build the results auto& etaPhiBuilder = outputs.make(Output{"AOD", "TRACKDERIVED"}); auto etaPhiWriter = etaPhiBuilder.cursor(); - /// Documentation for arrow at: - /// - /// https://arrow.apache.org/docs/cpp/namespacearrow.html - auto tracks = aod::Tracks(input->asArrowTable()); + auto tracks = aod::Tracks({input1->asArrowTable(), input2->asArrowTable()}); for (auto& track : tracks) { auto phi = asin(track.snp()) + track.alpha() + M_PI; From e0cff40c286ac38dda54ff89f1630d8cb2a0e0ae Mon Sep 17 00:00:00 2001 From: jgrosseo Date: Mon, 7 Sep 2020 12:36:32 +0200 Subject: [PATCH 19/76] configurable cuts (#4284) --- Analysis/Tasks/correlations.cxx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Analysis/Tasks/correlations.cxx b/Analysis/Tasks/correlations.cxx index 560c8cbd006df..4b53c581c88f7 100644 --- a/Analysis/Tasks/correlations.cxx +++ b/Analysis/Tasks/correlations.cxx @@ -30,16 +30,11 @@ using namespace o2::framework::expressions; struct CorrelationTask { - // Filters and input definitions - Filter trackFilter = (aod::track::eta > -0.8f) && (aod::track::eta < 0.8f) && (aod::track::pt > 0.5f) && (aod::track::isGlobalTrack == (uint8_t)1); - using myTracks = soa::Filtered>; - - // Output definitions - OutputObj same{"sameEvent"}; - OutputObj mixed{"mixedEvent"}; - //OutputObj qaOutput{"qa"}; - // Configuration + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 7.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPt, float, 0.5f, "Minimal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + O2_DEFINE_CONFIGURABLE(cfgTriggerCharge, int, 0, "Select on charge of trigger particle: 0 = all; 1 = positive; -1 = negative"); O2_DEFINE_CONFIGURABLE(cfgAssociatedCharge, int, 0, "Select on charge of associated particle: 0 = all; 1 = positive; -1 = negative"); O2_DEFINE_CONFIGURABLE(cfgPairCharge, int, 0, "Select on charge of particle pair: 0 = all; 1 = like sign; -1 = unlike sign"); @@ -53,6 +48,16 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgPairCutPhi, float, -1, "Pair cut on Phi: -1 = off; >0 otherwise distance value") O2_DEFINE_CONFIGURABLE(cfgPairCutRho, float, -1, "Pair cut on Rho: -1 = off; >0 otherwise distance value") + // Filters and input definitions + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPt) && (aod::track::isGlobalTrack == (uint8_t)1); + using myTracks = soa::Filtered>; + + // Output definitions + OutputObj same{"sameEvent"}; + OutputObj mixed{"mixedEvent"}; + //OutputObj qaOutput{"qa"}; + enum PairCuts { Photon = 0, K0, Lambda, From 86122ef3f32be97bcb8e0835a7443b3806095286 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 1 Sep 2020 08:35:54 +0200 Subject: [PATCH 20/76] replace halfchamber id with struct of supermodule, stack, layer,side --- .../TRD/include/DataFormatsTRD/LinkRecord.h | 45 +++++++++++++++---- .../TRD/include/DataFormatsTRD/RawData.h | 23 ++++++---- DataFormats/Detectors/TRD/src/LinkRecord.cxx | 36 +++++++++++++-- DataFormats/Detectors/TRD/src/RawData.cxx | 30 +++++++++++-- Detectors/TRD/simulation/src/Trap2CRU.cxx | 20 ++++----- .../TRDWorkflow/TRDTrapSimulatorSpec.h | 3 +- .../TRD/workflow/src/TRDTrapSimulatorSpec.cxx | 21 +++++---- 7 files changed, 132 insertions(+), 46 deletions(-) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h index a7cbef0dc42bf..8b2498de7425e 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/LinkRecord.h @@ -23,6 +23,19 @@ namespace o2 namespace trd { +struct LinkId { + public: + union { + uint16_t word; + struct { + uint16_t spare : 4; + uint16_t side : 1; + uint16_t layer : 3; + uint16_t stack : 3; + uint16_t supermodule : 5; + }; + }; +}; /// \class LinkRecord /// \brief Header for data corresponding to the indexing of the links in the raw data output /// adapted from DataFormatsTRD/TriggerRecord @@ -32,32 +45,46 @@ class LinkRecord public: LinkRecord() = default; - LinkRecord(const uint32_t hcid, int firstentry, int nentries) : mLinkId(hcid), mDataRange(firstentry, nentries) {} + LinkRecord(const uint32_t linkid, int firstentry, int nentries) : mDataRange(firstentry, nentries) { mLinkId.word = linkid; } + // LinkRecord(const LinkRecord::LinkId linkid, int firstentry, int nentries) : mDataRange(firstentry, nentries) {mLinkId.word=linkid.word;} + LinkRecord(uint32_t sector, int stack, int layer, int side, int firstentry, int nentries) : mDataRange(firstentry, nentries) { setLinkId(sector, stack, layer, side); } + ~LinkRecord() = default; - void setLinkId(const uint32_t linkid) { mLinkId = linkid; } + void setLinkId(const uint32_t linkid) { mLinkId.word = linkid; } + void setLinkId(const LinkId linkid) { mLinkId.word = linkid.word; } + void setLinkId(const uint32_t sector, const uint32_t stack, const uint32_t layer, const uint32_t side); void setDataRange(int firstentry, int nentries) { mDataRange.set(firstentry, nentries); } void setIndexFirstObject(int firstentry) { mDataRange.setFirstEntry(firstentry); } void setNumberOfObjects(int nentries) { mDataRange.setEntries(nentries); } - uint32_t getLinkId() { return mLinkId; } - uint32_t getLinkHCID() { return mLinkId & 0x7ff; } // the last 11 bits. + const uint32_t getLinkId() { return mLinkId.word; } + //TODO come backwith a ccdb lookup. const uint32_t getLinkHCID() { return mLinkId & 0x7ff; } // the last 11 bits. + const uint32_t getSector() { return mLinkId.supermodule; } + const uint32_t getStack() { return mLinkId.stack; } + const uint32_t getLayer() { return mLinkId.layer; } + const uint32_t getSide() { return mLinkId.side; } int getNumberOfObjects() const { return mDataRange.getEntries(); } int getFirstEntry() const { return mDataRange.getFirstEntry(); } + static uint32_t getHalfChamberLinkId(uint32_t detector, uint32_t rob); + static uint32_t getHalfChamberLinkId(uint32_t sector, uint32_t stack, uint32_t layer, uint32_t side); - void printStream(std::ostream& stream) const; + void printStream(std::ostream& stream); private: - uint32_t mLinkId; /// The link ID for this set of data, hcid as well + LinkId mLinkId; DataRange mDataRange; /// Index of the triggering event (event index and first entry in the container) - - ClassDefNV(LinkRecord, 1); + ClassDefNV(LinkRecord, 2); }; -std::ostream& operator<<(std::ostream& stream, const LinkRecord& trg); +std::ostream& operator<<(std::ostream& stream, LinkRecord& trg); +extern void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format); +extern void buildTrakcletHCHeader(TrackletHCHeader& header, int detector, int rob, int chipclock, int format); } // namespace trd } // namespace o2 #endif +//extern void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format) +//extern void buildTrakcletlHCHeader(TrackletHCHeader& header, int detector, int rob, int chipclock, int format) diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h index 226ee073932ce..678138301c9d6 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RawData.h @@ -123,18 +123,23 @@ struct TrackletHCHeader { union { // 10987654321098765432109876543210 // uint32_t: 00000000000000000000000000000000 - // cccccccccccccccc iiiiiiiiiii - // ffff| y| - // | | |------ 0-10 half chamber id - // | | ------------- 11 always 0x1 - // | ----------------------------- 12-72 MCM Clock counter + // cccccccccccccccX LLL SSSSS + // ffff| |y| sss| + // | | ||| | |----- 0-4 supermodule + // | | ||| |-------- 5-7 stack + // | | ||------------ 8-10 layer + // | | |------------- 11 always 0x1 + // | | |------------- 12 side of chamber + // | ----------------------------- 13-72 MCM Clock counter // --------------------------------- 28-31 tracklet data format number uint32_t word; - struct { - uint32_t HCID : 11; // half chamber id 0:1079 + uint32_t supermodule : 5; + uint32_t stack : 3; + uint32_t layer : 3; uint32_t one : 1; //always 1 - uint32_t MCLK : 16; // MCM clock counter 120MHz ... for simulation -- incrementing, and same number in all for each event. + uint32_t side : 1; // side of chamber + uint32_t MCLK : 15; // MCM clock counter 120MHz ... for simulation -- incrementing, and same number in all for each event. uint32_t format : 4; // 0 baseline PID 3 time slices, 7 bit each // 1 DO NOT USE ! reserved for tracklet end marker disambiguation @@ -213,6 +218,8 @@ struct TRDFeeID { }; }; +void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format); +void buildTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int chipclock, int format); uint16_t buildTRDFeeID(int supermodule, int side, int endpoint); uint32_t setHalfCRUHeader(HalfCRUHeader& cruhead, int crurdhversion, int bunchcrossing, int stopbits, int endpoint, int eventtype, int feeid, int cruid); uint32_t setHalfCRUHeaderLinkData(HalfCRUHeader& cruhead, int link, int size, int errors); diff --git a/DataFormats/Detectors/TRD/src/LinkRecord.cxx b/DataFormats/Detectors/TRD/src/LinkRecord.cxx index bafdbcf73d15d..e78b564277dc5 100644 --- a/DataFormats/Detectors/TRD/src/LinkRecord.cxx +++ b/DataFormats/Detectors/TRD/src/LinkRecord.cxx @@ -10,6 +10,7 @@ #include #include "DataFormatsTRD/LinkRecord.h" +#include "DataFormatsTRD/Constants.h" namespace o2 { @@ -17,12 +18,41 @@ namespace o2 namespace trd { -void LinkRecord::printStream(std::ostream& stream) const +uint32_t LinkRecord::getHalfChamberLinkId(uint32_t detector, uint32_t rob) { - stream << "Data for link 0x" << std::hex << mLinkId << std::dec << ", starting from entry " << getFirstEntry() << " with " << getNumberOfObjects() << " objects"; + int sector = (detector % (constants::NLAYER * constants::NSTACK)); + int stack = (detector % constants::NLAYER); + int layer = ((detector % (constants::NLAYER * constants::NSTACK)) / constants::NLAYER); + int side = rob % 2; + return getHalfChamberLinkId(sector, stack, layer, side); } -std::ostream& operator<<(std::ostream& stream, const LinkRecord& trg) +uint32_t LinkRecord::getHalfChamberLinkId(uint32_t sector, uint32_t stack, uint32_t layer, uint32_t side) +{ + LinkId tmplinkid; + tmplinkid.supermodule = sector; + tmplinkid.stack = stack; + tmplinkid.layer = layer; + ; + tmplinkid.side = side; + return tmplinkid.word; +} + +void LinkRecord::setLinkId(const uint32_t sector, const uint32_t stack, const uint32_t layer, const uint32_t side) +{ + mLinkId.supermodule = sector; + mLinkId.stack = stack; + mLinkId.layer = layer; + ; + mLinkId.side = side; +} + +void LinkRecord::printStream(std::ostream& stream) +{ + stream << "Data for link from supermodule:" << this->getSector() << " stack:" << this->getStack() << " layer:" << this->getLayer() << "side :" << this->getSide() << ", starting from entry " << this->getFirstEntry() << " with " << this->getNumberOfObjects() << " objects"; +} + +std::ostream& operator<<(std::ostream& stream, LinkRecord& trg) { trg.printStream(stream); return stream; diff --git a/DataFormats/Detectors/TRD/src/RawData.cxx b/DataFormats/Detectors/TRD/src/RawData.cxx index 80b2ac4a1aad1..189ffb2126b67 100644 --- a/DataFormats/Detectors/TRD/src/RawData.cxx +++ b/DataFormats/Detectors/TRD/src/RawData.cxx @@ -12,6 +12,8 @@ #include #include #include "DataFormatsTRD/RawData.h" +#include "DataFormatsTRD/LinkRecord.h" +#include "DataFormatsTRD/Constants.h" namespace o2 { @@ -19,6 +21,26 @@ namespace o2 namespace trd { +void buildTrackletHCHeader(TrackletHCHeader& header, int sector, int stack, int layer, int side, int chipclock, int format) +{ + header.MCLK = chipclock; + header.format = format; + header.one = 1; + header.supermodule = sector; + header.stack = stack; + header.layer = layer; + header.side = side; +} + +void buildTrackletHCHeaderd(TrackletHCHeader& header, int detector, int rob, int chipclock, int format) +{ + int sector = (detector % (constants::NLAYER * constants::NSTACK)); + int stack = (detector % constants::NLAYER); + int layer = ((detector % (constants::NLAYER * constants::NSTACK)) / constants::NLAYER); + int side = rob % 2; + buildTrackletHCHeader(header, sector, stack, layer, side, chipclock, format); +} + uint16_t buildTRDFeeID(int supermodule, int side, int endpoint) { TRDFeeID feeid; @@ -93,7 +115,9 @@ std::ostream& operator<<(std::ostream& stream, const TrackletHCHeader halfchambe { stream << "TrackletHCHeader : Raw:0x" << std::hex << halfchamberheader.word << " " << halfchamberheader.format << " ;; " << halfchamberheader.MCLK << " :: " - << halfchamberheader.one << " :: " << halfchamberheader.HCID << std::endl; + << halfchamberheader.one << " :: (" << halfchamberheader.supermodule << "," + << halfchamberheader.stack << "," << halfchamberheader.layer << ") on side :" + << halfchamberheader.side << std::endl; return stream; } @@ -129,8 +153,8 @@ std::ostream& operator<<(std::ostream& stream, const TrackletMCMHeader& mcmhead) void printHalfChamber(o2::trd::TrackletHCHeader const& halfchamber) { - LOGF(INFO, "TrackletHCHeader: Raw:0x%08x HCID : 0x%0x MCLK: 0x%0x Format: 0x%0x Always1:0x%0x", - halfchamber.HCID, halfchamber.MCLK, halfchamber.format, halfchamber.one); + LOGF(INFO, "TrackletHCHeader: Raw:0x%08x SM : %d stack %d layer %d side : %d MCLK: 0x%0x Format: 0x%0x Always1:0x%0x", + halfchamber.supermodule, halfchamber.stack, halfchamber.layer, halfchamber.side, halfchamber.MCLK, halfchamber.format, halfchamber.one); } void dumpHalfChamber(o2::trd::TrackletHCHeader const& halfchamber) diff --git a/Detectors/TRD/simulation/src/Trap2CRU.cxx b/Detectors/TRD/simulation/src/Trap2CRU.cxx index 688bb2cb0881e..c1279c29395af 100644 --- a/Detectors/TRD/simulation/src/Trap2CRU.cxx +++ b/Detectors/TRD/simulation/src/Trap2CRU.cxx @@ -173,10 +173,10 @@ uint32_t Trap2CRU::buildCRUHeader(HalfCRUHeader& header, uint32_t bc, uint32_t h int linkrecord = startlinkrecord; int totallinkdatasize = 0; //in units of 256bits for (int link = 0; link < NLinksPerHalfCRU; link++) { - int hcid = link + halfcru * NLinksPerHalfCRU; // TODO this might have to change to a lut I dont think the mapping is linear. + int linkid = link + halfcru * NLinksPerHalfCRU; // TODO this might have to change to a lut I dont think the mapping is linear. int errors = 0; int linksize = 0; // linkSizePadding will convert it to 1 for the no data case. - if (mLinkRecords[linkrecord].getLinkHCID() == hcid) { + if (mLinkRecords[linkrecord].getLinkId() == linkid) { linksize = mLinkRecords[linkrecord].getNumberOfObjects(); // this can be done differently by keeping a pointer to halfcruheader and setting it after reading it all in and going back per link to set the size. LOG(debug3) << "setting CRU HEADER for halfcru : " << halfcru << "and link : " << link << " contents" << header << ":" << link << ":" << linksize << ":" << errors; @@ -234,26 +234,26 @@ void Trap2CRU::convertTrapData(o2::trd::TriggerRecord const& TrigRecord) int linkdatasize = 0; // in 32 bit words int link = halfcru / 2; for (int halfcrulink = 0; halfcrulink < NLinksPerHalfCRU; halfcrulink++) { - //links run from 0 to 14, so hcid offset is halfcru*15; - int hcid = halfcrulink + halfcru * NLinksPerHalfCRU; - LOG(debug) << "Currently checking for data on hcid : " << hcid << " from halfcru=" << halfcru << " and halfcrulink:" << halfcrulink << " ?? " << hcid << "==" << mLinkRecords[currentlinkrecord].getLinkHCID(); + //links run from 0 to 14, so linkid offset is halfcru*15; + int linkid = halfcrulink + halfcru * NLinksPerHalfCRU; + LOG(debug) << "Currently checking for data on linkid : " << linkid << " from halfcru=" << halfcru << " and halfcrulink:" << halfcrulink << " ?? " << linkid << "==" << mLinkRecords[currentlinkrecord].getLinkId(); int errors = 0; // put no errors in for now. int size = 0; // in 32 bit words int datastart = 0; // in 32 bit words int dataend = 0; // in 32 bit words uint32_t paddingsize = 0; // in 32 bit words uint32_t crudatasize = 0; // in 256 bit words. - if (mLinkRecords[currentlinkrecord].getLinkHCID() == hcid) { + if (mLinkRecords[currentlinkrecord].getLinkId() == linkid) { //this link has data in the stream. - LOG(debug) << "+++ We have data on hcid = " << hcid << " halfcrulink : " << halfcrulink; + LOG(debug) << "+++ We have data on linkid = " << linkid << " halfcrulink : " << halfcrulink; linkdatasize = mLinkRecords[currentlinkrecord].getNumberOfObjects(); datastart = mLinkRecords[currentlinkrecord].getFirstEntry(); dataend = datastart + size; - LOG(debug) << "We have data on hcid = " << hcid << " and linksize : " << linkdatasize << " so :" << linkdatasize / 8 << " 256 bit words"; + LOG(debug) << "We have data on linkid = " << linkid << " and linksize : " << linkdatasize << " so :" << linkdatasize / 8 << " 256 bit words"; currentlinkrecord++; } else { - assert(mLinkRecords[currentlinkrecord].getLinkId() < hcid); - LOG(debug) << "---We do not have data on hcid = " << hcid << " halfcrulink : " << halfcrulink; + assert(mLinkRecords[currentlinkrecord].getLinkId() < linkid); + LOG(debug) << "---We do not have data on linkid = " << linkid << " halfcrulink : " << halfcrulink; //blank data for this link // put in a 1 256 bit word of data for the link and padd with 0xeeee x 8 linkdatasize = 0; diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h index a69092e7c64bb..a1aa8b1f443a1 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDTrapSimulatorSpec.h @@ -86,13 +86,12 @@ class TRDDPLTrapSimulatorTask : public o2::framework::Task std::chrono::duration mSortingTime{0}; ///< full timer uint64_t mTotalRawWordsWritten = 0; // words written for the raw format of 4x32bits, where 4 can be 2 to 4 depending on # of tracklets in the block. - int32_t mOldHalfChamberID = 0; + int32_t mOldHalfChamberLinkId = 0; bool mNewTrackletHCHeaderHasBeenWritten{false}; TrackletHCHeader mTrackletHCHeader; // the current half chamber header, that will be written if a first tracklet is found for this halfchamber. TrapConfig* getTrapConfig(); void loadTrapConfig(); void setOnlineGainTables(); - uint32_t getHalfChamberID(uint32_t detector, uint32_t rob) { return detector * 2 + rob % 2; }; }; o2::framework::DataProcessorSpec getTRDTrapSimulatorSpec(); diff --git a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx index a4bcbd2803a25..46d4cd760a2a8 100644 --- a/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDTrapSimulatorSpec.cxx @@ -456,7 +456,7 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) << digit.getDetector() << ":" << digit.getRow() << ":" << digit.getPad() << ":" << mFeeParam->getROBfromPad(digit.getRow(), digit.getPad()) << ":" << mFeeParam->getMCMfromPad(digit.getRow(), digit.getPad()) - << " HCID:" << getHalfChamberID(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) << "\t\t SM:stack:layer:side " + << " LinkId:" << LinkRecord::getHalfChamberLinkId(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) << "\t\t SM:stack:layer:side " << digit.getDetector() / 30 << ":" << TRDGeometry::getStack(digit.getDetector()) << ":" << TRDGeometry::getLayer(digit.getDetector()) << ":" << FeeParam::instance()->getRobSide(mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) << " with ORI# : " << mFeeParam->getORI(digit.getDetector(), mFeeParam->getROBfromPad(digit.getRow(), digit.getPad())) @@ -473,7 +473,7 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) double trackletrate; unsigned long oldtrackletcount = 0; mTotalRawWordsWritten = 0; // words written for the raw format of 4x32bits, where 4 can be 2 to 4 depending on # of tracklets in the block. - mOldHalfChamberID = 0; + mOldHalfChamberLinkId = 0; mNewTrackletHCHeaderHasBeenWritten = false; // now to loop over the incoming digits. @@ -495,9 +495,10 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) int trdstack = TRDGeometry::getStack(detector); int trdlayer = TRDGeometry::getLayer(detector); int fibreside = FeeParam::instance()->getRobSide(rob); + LOG(debug) << "calculated rob and mcm at top of loop with detector:row:pad:rob:mcm ::" << detector << ":" << row << ":" << pad << ":" << rob << ":" << mcm - << " HCID:" << getHalfChamberID(detector, rob) << "\t\t SM:stack:layer:side " << detector / 30 << ":" << trdstack << ":" << trdlayer << ":" << fibreside + << " LinkId:" << LinkRecord::getHalfChamberLinkId(detector, rob) << "\t\t SM:stack:layer:side " << detector / 30 << ":" << trdstack << ":" << trdlayer << ":" << fibreside << " with ORI : " << mFeeParam->getORI(detector, rob) << " and within supermodule ori index:" << mFeeParam->getORIinSM(detector, rob); LOG(debug) << "digit time : " << digittime; if (row == 4 && pad == 17 && rob == 2 & mcm == 0) { @@ -509,14 +510,12 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) olddetector = detector; } //Are we on a new half chamber ? - if (mOldHalfChamberID != getHalfChamberID(detector, rob)) { + if (mOldHalfChamberLinkId != LinkRecord::getHalfChamberLinkId(detector, rob)) { // hcid= detector*2 + robpos%2; // new half chamber so add the header to the raw data stream. - mTrackletHCHeader.HCID = getHalfChamberID(detector, rob); - mTrackletHCHeader.one = 1; - mTrackletHCHeader.MCLK = currentTriggerRecord * 42; // 42 because its the universally true answer, this is fake in anycase, so long as its always bigger than the previous one and increasing. - mTrackletHCHeader.format = 4; - mOldHalfChamberID = getHalfChamberID(detector, rob); + buildTrackletHCHeaderd(mTrackletHCHeader, detector, rob, currentTriggerRecord * 42, 4); + //buildTrackletHCHeader(mTrackletHCHeader,sector,stack,layer,side,currentTriggerRecord*42,4); + mOldHalfChamberLinkId = LinkRecord::getHalfChamberLinkId(detector, rob); // now we have a problem. We must only write the halfchamberheader if a tracklet is written i.e. if the digits for this half chamber actually produce 1 or more tracklets! mNewTrackletHCHeaderHasBeenWritten = false; } @@ -557,10 +556,10 @@ void TRDDPLTrapSimulatorTask::run(o2::framework::ProcessingContext& pc) // .. fix the previous linkrecord to note its end of range. if (mLinkRecords.size() == 0) { // special case for the first entry into the linkrecords vector. mLinkRecords.emplace_back(mTrackletHCHeader.word, 0, -1); - LOG(debug) << " added HCID :[record.size==0] " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); + // LOG(debug) << " added HCID :[record.size==0] " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); } else { mLinkRecords.back().setNumberOfObjects(mTotalRawWordsWritten - mLinkRecords.back().getFirstEntry()); // current number of words written - the start of this index record. - LOG(debug) << " added HCID : " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); + // LOG(debug) << " added HCID : " << mTrackletHCHeader.HCID << " with number of bytes : " << mTotalRawWordsWritten << "-" << mLinkRecords.back().getFirstEntry(); //..... so write the new one thing mLinkRecords.emplace_back(mTrackletHCHeader.word, mTotalRawWordsWritten, -1); // set the number of elements to -1 for an error condition } From 6d741e78d9595d04902ab63185c5bf7b91c02636 Mon Sep 17 00:00:00 2001 From: Valentina Zaccolo Date: Mon, 7 Sep 2020 16:05:53 +0200 Subject: [PATCH 21/76] v1 of run2 tracklets multiplicity task (#4244) --- Analysis/Tasks/PWGMM/CMakeLists.txt | 14 +++++ Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx | 64 ++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Analysis/Tasks/PWGMM/CMakeLists.txt create mode 100644 Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx diff --git a/Analysis/Tasks/PWGMM/CMakeLists.txt b/Analysis/Tasks/PWGMM/CMakeLists.txt new file mode 100644 index 0000000000000..b0a6b6fadcc0f --- /dev/null +++ b/Analysis/Tasks/PWGMM/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# 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. + +o2_add_dpl_workflow(dNdetaRun2Tracklets-analysis + SOURCES dNdetaRun2Tracklets.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::AnalysisDataModel + COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx b/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx new file mode 100644 index 0000000000000..ac949f823fcb5 --- /dev/null +++ b/Analysis/Tasks/PWGMM/dNdetaRun2Tracklets.cxx @@ -0,0 +1,64 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Analysis/Multiplicity.h" +#include "Analysis/EventSelection.h" +#include "Analysis/Centrality.h" +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct PseudorapidityDensity { + + Configurable etaBinWidth{"etaBinWidth", 0.1, "eta bin width"}; + Configurable etaMax{"etaMax", 1.5, "max eta value"}; + Configurable etaMin{"etaMin", -1.5, "min eta value"}; + Configurable vtxZMax{"vtxZMax", 10, "max z vertex"}; + Configurable vtxZMin{"vtxZMin", -10, "min z vertex"}; + int etaBins = TMath::Nint((etaMax - etaMin) / etaBinWidth); + int vtxZBins = TMath::Nint(vtxZMax - vtxZMin); + + OutputObj hStat{TH1F("hStat", "TotalEvents", 1, 0.5, 1.5)}; + OutputObj hdNdeta{TH1F("hdNdeta", "dNdeta", 50, -2.5, 2.5)}; + OutputObj vtxZEta{TH2F("vtxZEta", ";#eta;vtxZ", 50, -2.5, 2.5, 60, -30, 30)}; + OutputObj phiEta{TH2F("phiEta", ";#eta;#varphi", 50, -2.5, 2.5, 200, 0., 2 * TMath::Pi())}; + + // TODO remove static casts for configurables when fixed + Filter etaFilter = (aod::track::eta < (float)etaMax) && (aod::track::eta > (float)etaMin); + Filter trackTypeFilter = (aod::track::trackType == static_cast(aod::track::TrackTypeEnum::Run2Tracklet)); + Filter posZFilter = (aod::collision::posZ < (float)vtxZMax) && (aod::collision::posZ > (float)vtxZMin); + + void process(soa::Filtered>::iterator const& collisions, soa::Filtered const& tracklets) + { + // TODO change to sel7 filter expression when implemented + if (!collisions.sel7()) + return; + hStat->Fill(collisions.size()); + auto vtxZ = collisions.posZ(); + for (auto& track : tracklets) { + vtxZEta->Fill(track.eta(), vtxZ); + phiEta->Fill(track.eta(), track.phi()); + hdNdeta->Fill(track.eta()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + return WorkflowSpec{ + adaptAnalysisTask("dNdetaRun2Tracklets-analysis")}; +} From 70aee0b41d9d0dd9e1a33f7a9b69b84f3519b0f9 Mon Sep 17 00:00:00 2001 From: dstocco Date: Mon, 7 Sep 2020 16:41:29 +0200 Subject: [PATCH 22/76] Correctly initialize pointer function (#4271) --- Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h b/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h index 79a06f830da9a..52fa2a0b8eee2 100644 --- a/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h +++ b/Detectors/MUON/MID/Tracking/include/MIDTracking/Tracker.h @@ -89,7 +89,7 @@ class Tracker GeometryTransformer mTransformer{}; ///< Geometry transformer typedef bool (Tracker::*TrackerMemFn)(const Track&, bool, bool); - TrackerMemFn mFollowTrack{nullptr}; ///! Choice of the function to follow the track + TrackerMemFn mFollowTrack{&Tracker::followTrackKeepBest}; ///! Choice of the function to follow the track }; } // namespace mid } // namespace o2 From e2e6ef340aa4621db1fa175bb0a4e28ffd0c0245 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 7 Sep 2020 21:32:11 +0200 Subject: [PATCH 23/76] DPL: do proper endOfStream for test_RegionInfoCallbackService (#4296) Somehow breaks only during the threading setup --- Framework/Core/test/test_RegionInfoCallbackService.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Framework/Core/test/test_RegionInfoCallbackService.cxx b/Framework/Core/test/test_RegionInfoCallbackService.cxx index a357583194840..571da32501584 100644 --- a/Framework/Core/test/test_RegionInfoCallbackService.cxx +++ b/Framework/Core/test/test_RegionInfoCallbackService.cxx @@ -34,6 +34,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) AlgorithmSpec{ [](ProcessingContext& ctx) { auto& out = ctx.outputs().make(OutputRef{"test", 0}); + ctx.services().get().endOfStream(); + ctx.services().get().readyToQuit(QuitRequest::Me); }}}, {"dest", Inputs{ From de840a921bd1ca99fec233ea4f41a8d5eaf999e1 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 8 Sep 2020 07:47:23 +0200 Subject: [PATCH 24/76] DPL Analysis: reintroduce TableTransform base class (#4295) --- .../Core/include/Framework/AnalysisHelpers.h | 96 ++++++++----------- Framework/Core/src/AnalysisManagers.h | 15 ++- 2 files changed, 47 insertions(+), 64 deletions(-) diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 457c3d5b139c0..8d4c3c03b77fd 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -18,6 +18,7 @@ #include "Framework/InputSpec.h" #include "Framework/OutputObjHeader.h" #include "Framework/StringHelpers.h" +#include "Framework/Output.h" #include #include @@ -113,23 +114,23 @@ struct Produces> : WritingCursor -struct Spawns { - using extension_t = framework::pack_head_t; - using metadata = typename aod::MetadataTrait::metadata; - using sources = typename metadata::originals; - using expression_pack_t = typename metadata::expression_pack_t; +/// Helper template for table transformations +template +struct TableTransform { + using SOURCES = typename METADATA::originals; - constexpr auto pack() + using metadata = METADATA; + using sources = SOURCES; + + constexpr auto sources_pack() const { - return expression_pack_t{}; + return SOURCES{}; } - template - InputSpec const base_spec() + + template + constexpr auto base_spec() const { - using o_metadata = typename aod::MetadataTrait::metadata; + using o_metadata = typename aod::MetadataTrait::metadata; return InputSpec{ o_metadata::tableLabel(), header::DataOrigin{o_metadata::origin()}, @@ -137,24 +138,42 @@ struct Spawns { } template - std::vector const base_specs_impl(framework::pack) + std::vector base_specs_impl(framework::pack) const { return {base_spec()...}; } - std::vector const base_specs() + std::vector base_specs() const { - return base_specs_impl(sources{}); + return base_specs_impl(sources_pack()); } - OutputSpec const spec() const + constexpr auto spec() const { - return OutputSpec{OutputLabel{metadata::tableLabel()}, metadata::origin(), metadata::description()}; + return OutputSpec{OutputLabel{METADATA::tableLabel()}, METADATA::origin(), METADATA::description()}; } - OutputRef ref() const + constexpr auto output() const { - return OutputRef{metadata::tableLabel(), 0}; + return Output{METADATA::origin(), METADATA::description()}; + } + + constexpr auto ref() const + { + return OutputRef{METADATA::tableLabel(), 0}; + } +}; + +/// This helper struct allows you to declare extended tables which should be +/// created by the task (as opposed to those pre-defined by data model) +template +struct Spawns : TableTransform>::metadata> { + using extension_t = framework::pack_head_t; + using expression_pack_t = typename aod::MetadataTrait::metadata::expression_pack_t; + + constexpr auto pack() + { + return expression_pack_t{}; } T* operator->() @@ -299,44 +318,11 @@ struct IndexSparse { /// This helper struct allows you to declare index tables to be created in a task template -struct Builds { - using metadata = typename aod::MetadataTrait::metadata; - using originals = typename metadata::originals; +struct Builds : TableTransform::metadata> { using Key = typename T::indexing_t; using H = typename T::first_t; using Ts = typename T::rest_t; - using index_pack_t = typename metadata::index_pack_t; - - template - InputSpec const base_spec() - { - using o_metadata = typename aod::MetadataTrait::metadata; - return InputSpec{ - o_metadata::tableLabel(), - header::DataOrigin{o_metadata::origin()}, - header::DataDescription{o_metadata::description()}}; - } - - template - std::vector const base_specs_impl(framework::pack) - { - return {base_spec()...}; - } - - std::vector const base_specs() - { - return base_specs_impl(originals{}); - } - - OutputSpec const spec() const - { - return OutputSpec{OutputLabel{metadata::tableLabel()}, metadata::origin(), metadata::description()}; - } - - OutputRef ref() const - { - return OutputRef{metadata::tableLabel(), 0}; - } + using index_pack_t = typename aod::MetadataTrait::metadata::index_pack_t; T* operator->() { diff --git a/Framework/Core/src/AnalysisManagers.h b/Framework/Core/src/AnalysisManagers.h index d40e8aebce8bd..e5045f3c81bc7 100644 --- a/Framework/Core/src/AnalysisManagers.h +++ b/Framework/Core/src/AnalysisManagers.h @@ -233,7 +233,7 @@ struct OutputManager> { static bool prepare(ProcessingContext& pc, Spawns& what) { - auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(typename Spawns::sources{}, pc)); + auto original_table = soa::ArrowHelpers::joinTables(extractOriginals(what.sources_pack(), pc)); what.extension = std::make_shared::extension_t>(o2::soa::spawner(what.pack(), original_table.get())); what.table = std::make_shared(soa::ArrowHelpers::joinTables({what.extension->asArrowTable(), original_table})); return true; @@ -246,8 +246,7 @@ struct OutputManager> { static bool postRun(EndOfStreamContext& eosc, Spawns& what) { - using metadata = typename std::decay_t::metadata; - eosc.outputs().adopt(Output{metadata::origin(), metadata::description()}, what.asArrowTable()); + eosc.outputs().adopt(what.output(), what.asArrowTable()); return true; } }; @@ -276,10 +275,9 @@ struct OutputManager> { static bool prepare(ProcessingContext& pc, Builds& what) { - using metadata = typename std::decay_t::metadata; - return what.build(typename metadata::index_pack_t{}, - extractTypedOriginal(pc), - extractOriginalsTuple(typename metadata::originals{}, pc)); + return what.build(what.pack(), + extractTypedOriginal::Key>(pc), + extractOriginalsTuple(what.sources_pack(), pc)); } static bool finalize(ProcessingContext&, Builds&) @@ -289,8 +287,7 @@ struct OutputManager> { static bool postRun(EndOfStreamContext& eosc, Builds& what) { - using metadata = typename std::decay_t::metadata; - eosc.outputs().adopt(Output{metadata::origin(), metadata::description()}, what.asArrowTable()); + eosc.outputs().adopt(what.output(), what.asArrowTable()); return true; } }; From 0ac009b964335bc59c7a4d137c38a5ac44b64cd9 Mon Sep 17 00:00:00 2001 From: dsekihat Date: Tue, 8 Sep 2020 15:53:10 +0900 Subject: [PATCH 25/76] add dilepton ee task (#4276) --- .../include/Analysis/ReducedInfoTables.h | 1 - Analysis/Tasks/PWGDQ/CMakeLists.txt | 5 + Analysis/Tasks/PWGDQ/dileptonEE.cxx | 350 ++++++++++++++++++ 3 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 Analysis/Tasks/PWGDQ/dileptonEE.cxx diff --git a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h b/Analysis/DataModel/include/Analysis/ReducedInfoTables.h index 77015e807bbf9..a04365bd5cae1 100644 --- a/Analysis/DataModel/include/Analysis/ReducedInfoTables.h +++ b/Analysis/DataModel/include/Analysis/ReducedInfoTables.h @@ -82,7 +82,6 @@ DECLARE_SOA_TABLE(ReducedTracksBarrel, "AOD", "RTBARREL", track::ITSClusterMap, track::ITSChi2NCl, track::TPCNClsFindable, track::TPCNClsFindableMinusFound, track::TPCNClsFindableMinusCrossedRows, track::TPCNClsShared, track::TPCChi2NCl, - // track::TPCSignal, track::TRDSignal, track::TOFSignal, track::TRDChi2, track::TOFChi2, track::Length, track::TPCNClsFound, track::TPCNClsCrossedRows); diff --git a/Analysis/Tasks/PWGDQ/CMakeLists.txt b/Analysis/Tasks/PWGDQ/CMakeLists.txt index 9eac2e83b667b..c1e200173f10f 100644 --- a/Analysis/Tasks/PWGDQ/CMakeLists.txt +++ b/Analysis/Tasks/PWGDQ/CMakeLists.txt @@ -7,3 +7,8 @@ o2_add_dpl_workflow(table-reader SOURCES tableReader.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore COMPONENT_NAME Analysis) + +o2_add_dpl_workflow(dilepton-ee + SOURCES dileptonEE.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel O2::DetectorsBase O2::AnalysisCore + COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGDQ/dileptonEE.cxx b/Analysis/Tasks/PWGDQ/dileptonEE.cxx new file mode 100644 index 0000000000000..dcc2afb1dcc2f --- /dev/null +++ b/Analysis/Tasks/PWGDQ/dileptonEE.cxx @@ -0,0 +1,350 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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. +// +// Contact: iarsene@cern.ch, i.c.arsene@fys.uio.no +// +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Analysis/ReducedInfoTables.h" +#include "Analysis/VarManager.h" +#include "Analysis/HistogramManager.h" +#include "Analysis/AnalysisCut.h" +#include "Analysis/AnalysisCompositeCut.h" +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; + +using namespace o2; +using namespace o2::framework; +//using namespace o2::framework::expressions; +using namespace o2::aod; + +// Some definitions +namespace o2::aod +{ +namespace reducedtrack +{ +DECLARE_SOA_COLUMN(IsBarrelSelected, isBarrelSelected, int); +} // namespace reducedtrack +namespace reducedpair +{ +DECLARE_SOA_INDEX_COLUMN(ReducedEvent, reducedevent); +DECLARE_SOA_COLUMN(Mass, mass, float); +DECLARE_SOA_COLUMN(Pt, pt, float); +DECLARE_SOA_COLUMN(Eta, eta, float); +DECLARE_SOA_COLUMN(Phi, phi, float); +DECLARE_SOA_COLUMN(Charge, charge, int); +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, [](float pt, float phi) -> float { return pt * std::cos(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, [](float pt, float phi) -> float { return pt * std::sin(phi); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, [](float pt, float eta) -> float { return pt * std::sinh(eta); }); +DECLARE_SOA_DYNAMIC_COLUMN(Pmom, pmom, [](float pt, float eta) -> float { return pt * std::cosh(eta); }); +} // namespace reducedpair + +DECLARE_SOA_TABLE(BarrelTrackCuts, "AOD", "BARRELTRACKCUTS", reducedtrack::IsBarrelSelected); +} // namespace o2::aod + +using MyEvent = soa::Join::iterator; +using MyEventVtxCov = soa::Join::iterator; +using MyBarrelTracks = soa::Join; +using MyBarrelTracksSelected = soa::Join; + +void DefineHistograms(o2::framework::OutputObj histMan, TString histClasses); + +// HACK: In order to be able to deduce which kind of aod object is transmitted to the templated VarManager::Fill functions +// a constexpr static bit map must be defined and sent as template argument +// The user has to include in this bit map all the tables needed in analysis, as defined in VarManager::ObjTypes +// Additionally, one should make sure that the requested tables are actually provided in the process() function, +// otherwise a compile time error will be thrown. +// This is a temporary fix until the arrow/ROOT issues are solved, at which point it will be possible +// to automatically detect the object types transmitted to the VarManager +constexpr static uint32_t fgEventFillMap = VarManager::ObjTypes::ReducedEvent | VarManager::ObjTypes::ReducedEventExtended; +constexpr static uint32_t fgTrackFillMap = VarManager::ObjTypes::ReducedTrack | VarManager::ObjTypes::ReducedTrackBarrel | VarManager::ObjTypes::ReducedTrackBarrelCov | VarManager::ObjTypes::ReducedTrackBarrelPID; + +struct BarrelTrackSelection { + Produces trackSel; + OutputObj fHistMan{"output"}; + AnalysisCompositeCut* fTrackCut; + + float* fValues; // array to be used by the VarManager + + void init(o2::framework::InitContext&) + { + fValues = new float[VarManager::kNVars]; + VarManager::SetDefaultVarNames(); + fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, "TrackBarrel_BeforeCuts;TrackBarrel_AfterCuts;"); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + + DefineCuts(); + } + + void DefineCuts() + { + fTrackCut = new AnalysisCompositeCut(true); // true: use AND + AnalysisCut* cut1 = new AnalysisCut(); + cut1->AddCut(VarManager::kPt, 0.2, 10.0); + cut1->AddCut(VarManager::kEta, -0.8, 0.8); + cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); + cut1->AddCut(VarManager::kITSchi2, 0.0, 5.0); + cut1->AddCut(VarManager::kITSncls, 3.5, 7.5); + cut1->AddCut(VarManager::kTPCncls, 69.5, 159.5); + cut1->AddCut(VarManager::kTPCsignal, 70, 100, false); //exclude = false + fTrackCut->AddCut(cut1); + + // //AnalysisCut* pid_TPChadrej = new AnalysisCut("pid_TPChadrej","PID TPC hadron band rejection"); + // //pid_TPChadrej->AddCut(VarManager::kTPCsignal, 70, 100,false);//exclude = false + // //pid_TPChadrej->AddCut(VarManager::kTPCnSigmaPi,-1e+10,+3.5,true); + // //pid_TPChadrej->AddCut(VarManager::kTPCnSigmaKa, -3.,+3. ,true); + // //pid_TPChadrej->AddCut(VarManager::kTPCnSigmaPr, -3.,+3. ,true); + // + // //AnalysisCut* pid_TOFrec = new AnalysisCut("pid_TOFrec","PID TOF recovery"); + // //pid_TOFrec->AddCut(VarManager::kTPCsignal, 70, 100,false);//exclude = false + // //pid_TOFrec->AddCut(VarManager::kTOFnSigmaPi,-3,+3.,false); + // + // AnalysisCut* pid_TOFrec_pi = new AnalysisCut("pid_TOFrec_pi","PID TOF recovery pion"); + // pid_TOFrec_pi->AddCut(VarManager::kTPCsignal, 70, 100,false);//exclude = false + // pid_TOFrec_pi->AddCut(VarManager::kTOFnSigmaEl,-3,+3.,false,VarManager::kTPCnSigmaPi,-1e+10,+3.5,false); + // + // AnalysisCut* pid_TOFrec_ka = new AnalysisCut("pid_TOFrec_ka","PID TOF recovery Kaon"); + // pid_TOFrec_ka->AddCut(VarManager::kTPCsignal, 70, 100,false);//exclude = false + // pid_TOFrec_ka->AddCut(VarManager::kTOFnSigmaEl,-3,+3.,false,VarManager::kTPCnSigmaKa,-3.,+3.,false); + // + // AnalysisCut* pid_TOFrec_pr = new AnalysisCut("pid_TOFrec_ka","PID TOF recovery Proton"); + // pid_TOFrec_pr->AddCut(VarManager::kTPCsignal, 70, 100,false);//exclude = false + // pid_TOFrec_pr->AddCut(VarManager::kTOFnSigmaEl,-3,+3.,false,VarManager::kTPCnSigmaPr,-3.,+3.,false); + // + // AnalysisCompositeCut *pidcut = new AnalysisCompositeCut(false); // false: use OR + // //pidcut->AddCut(pid_TPChadrej); + // //pidcut->AddCut(pid_TOFrec); + // //pidcut->AddCut(pid_TOFrec_pi); + // pidcut->AddCut(pid_TOFrec_ka); + // pidcut->AddCut(pid_TOFrec_pr); + // fTrackCut->AddCut(pidcut); + // + // //fTrackCut->AddCut(pid_TOFrec_ka); + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + void process(MyEvent event, MyBarrelTracks const& tracks) + { + for (int i = 0; i < VarManager::kNVars; ++i) + fValues[i] = -9999.0f; + // fill event information which might be needed in histograms that combine track and event properties + VarManager::FillEvent(event, fValues); + + for (auto& track : tracks) { + for (int i = VarManager::kNEventWiseVariables; i < VarManager::kNMuonTrackVariables; ++i) + fValues[i] = -9999.0f; + VarManager::FillTrack(track, fValues); + fHistMan->FillHistClass("TrackBarrel_BeforeCuts", fValues); + + if (fTrackCut->IsSelected(fValues)) { + trackSel(1); + fHistMan->FillHistClass("TrackBarrel_AfterCuts", fValues); + } else + trackSel(0); + } + } +}; + +struct DileptonEE { + OutputObj fHistMan{"output"}; + AnalysisCompositeCut* fEventCut; + //NOTE: one could define also a dilepton cut, but for now basic selections can be supported using Partition + + Partition posTracks = aod::reducedtrack::charge > 0 && aod::reducedtrack::isBarrelSelected == 1; + Partition negTracks = aod::reducedtrack::charge < 0 && aod::reducedtrack::isBarrelSelected == 1; + + void init(o2::framework::InitContext&) + { + VarManager::SetDefaultVarNames(); + fHistMan.setObject(new HistogramManager("analysisHistos", "aa", VarManager::kNVars)); + fHistMan->SetUseDefaultVariableNames(kTRUE); + fHistMan->SetDefaultVarNames(VarManager::fgVariableNames, VarManager::fgVariableUnits); + + DefineHistograms(fHistMan, "Event_BeforeCuts;Event_AfterCuts;PairsBarrelULS;PairsBarrelLSpp;PairsBarrelLSnn;"); // define all histograms + VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill + + DefineCuts(); + } + + void DefineCuts() + { + fEventCut = new AnalysisCompositeCut(true); + + AnalysisCut* varCut = new AnalysisCut(); + varCut->AddCut(VarManager::kVtxZ, -10.0, 10.0); + varCut->AddCut(VarManager::kVtxNcontrib, 0.5, 1e+10); + fEventCut->AddCut(varCut); + + VarManager::SetUseVars(AnalysisCut::fgUsedVars); // provide the list of required variables so that VarManager knows what to fill + } + + void process(MyEventVtxCov event, MyBarrelTracksSelected const& tracks) + { + // Reset the VarManager::fgValues array + // The reset can be done selectively, using arguments in the ResetValues() function + VarManager::ResetValues(); + + VarManager::FillEvent(event); + fHistMan->FillHistClass("Event_BeforeCuts", VarManager::fgValues); // automatically fill all the histograms in the class Event + if (!fEventCut->IsSelected(VarManager::fgValues)) + return; + fHistMan->FillHistClass("Event_AfterCuts", VarManager::fgValues); + + // Run the same event pairing for barrel tracks + // TODO: Use combinations() when this will work for Partitions + /* e.g. + * for (auto& [tpos, tneg] : combinations(posTracks, negTracks)) { + VarManager::FillPair(tpos, tneg); + fHistMan->FillHistClass("PairsBarrelULS", VarManager::fgValues); + } + */ + + for (auto tpos : posTracks) { + for (auto tneg : negTracks) { // +- pairs + VarManager::FillPair(tpos, tneg); + fHistMan->FillHistClass("PairsBarrelULS", VarManager::fgValues); + } + for (auto tpos2 = tpos + 1; tpos2 != posTracks.end(); ++tpos2) { // ++ pairs + VarManager::FillPair(tpos, tpos2); + fHistMan->FillHistClass("PairsBarrelLSpp", VarManager::fgValues); + } + } + for (auto tneg : negTracks) { // -- pairs + for (auto tneg2 = tneg + 1; tneg2 != negTracks.end(); ++tneg2) { + VarManager::FillPair(tneg, tneg2); + fHistMan->FillHistClass("PairsBarrelLSnn", VarManager::fgValues); + } + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + return WorkflowSpec{ + adaptAnalysisTask("barrel-track-selection"), + adaptAnalysisTask("dilepton-ee")}; +} + +void DefineHistograms(o2::framework::OutputObj histMan, TString histClasses) +{ + // + // Define here the histograms for all the classes required in analysis. + // The histogram classes are provided in the histClasses string, separated by semicolon ";" + // The histogram classes and their components histograms are defined below depending on the name of the histogram class + // + const int kNRuns = 2; + int runs[kNRuns] = {244918, 244919}; + TString runsStr; + for (int i = 0; i < kNRuns; i++) + runsStr += Form("%d;", runs[i]); + VarManager::SetRunNumbers(kNRuns, runs); + + TObjArray* arr = histClasses.Tokenize(";"); + for (Int_t iclass = 0; iclass < arr->GetEntries(); ++iclass) { + TString classStr = arr->At(iclass)->GetName(); + + if (classStr.Contains("Event")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "VtxZ", "Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "VtxZ_Run", "Vtx Z", true, + kNRuns, 0.5, 0.5 + kNRuns, VarManager::kRunId, 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, runsStr.Data()); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY", "Vtx X vs Vtx Y", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_VtxZ", "vtx x - y - z", false, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 60, -15.0, 15.0, VarManager::kVtxZ); // TH3F histogram + histMan->AddHistogram(classStr.Data(), "NContrib_vs_VtxZ_prof", "Vtx Z vs ncontrib", true, 30, -15.0, 15.0, VarManager::kVtxZ, 10, -1., 1., VarManager::kVtxNcontrib); // TProfile histogram + histMan->AddHistogram(classStr.Data(), "VtxZ_vs_VtxX_VtxY_prof", "Vtx Z vs (x,y)", true, 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 10, -1., 1., VarManager::kVtxZ); // TProfile2D histogram + histMan->AddHistogram(classStr.Data(), "Ncontrib_vs_VtxZ_VtxX_VtxY_prof", "n-contrib vs (x,y,z)", true, + 100, 0.055, 0.08, VarManager::kVtxX, 100, 0.31, 0.35, VarManager::kVtxY, 30, -15., 15., VarManager::kVtxZ, + "", "", "", VarManager::kVtxNcontrib); // TProfile3D + + double vtxXbinLims[10] = {0.055, 0.06, 0.062, 0.064, 0.066, 0.068, 0.070, 0.072, 0.074, 0.08}; + double vtxYbinLims[7] = {0.31, 0.32, 0.325, 0.33, 0.335, 0.34, 0.35}; + double vtxZbinLims[13] = {-15.0, -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 15.0}; + double nContribbinLims[9] = {0.0, 100.0, 200.0, 400.0, 600.0, 1000.0, 1500.0, 2000.0, 4000.0}; + + histMan->AddHistogram(classStr.Data(), "VtxX_VtxY_nonEqualBinning", "Vtx X vs Vtx Y", false, 9, vtxXbinLims, VarManager::kVtxX, 6, vtxYbinLims, VarManager::kVtxY); // THnF histogram with custom non-equal binning + + histMan->AddHistogram(classStr.Data(), "VtxZ_weights", "Vtx Z", false, + 60, -15.0, 15.0, VarManager::kVtxZ, 10, 0., 0., VarManager::kNothing, 10, 0., 0., VarManager::kNothing, + "", "", "", VarManager::kNothing, VarManager::kVtxNcontrib); // TH1F histogram, filled with weights using the vtx n-contributors + + Int_t vars[4] = {VarManager::kVtxX, VarManager::kVtxY, VarManager::kVtxZ, VarManager::kVtxNcontrib}; + TArrayD binLimits[4]; + binLimits[0] = TArrayD(10, vtxXbinLims); + binLimits[1] = TArrayD(7, vtxYbinLims); + binLimits[2] = TArrayD(13, vtxZbinLims); + binLimits[3] = TArrayD(9, nContribbinLims); + histMan->AddHistogram(classStr.Data(), "vtxHisto", "n contrib vs (x,y,z)", 4, vars, binLimits); + + histMan->AddHistogram(classStr.Data(), "CentV0M_vtxZ", "CentV0M vs Vtx Z", false, 60, -15.0, 15.0, VarManager::kVtxZ, 20, 0., 100., VarManager::kCentVZERO); // TH2F histogram + + histMan->AddHistogram(classStr.Data(), "VtxChi2", "Vtx chi2", false, 100, 0.0, 100.0, VarManager::kVtxChi2); // TH1F histogram + + continue; + } // end if(Event) + + if (classStr.Contains("Track")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Pt", "p_{T} distribution", false, 100, 0.0, 10.0, VarManager::kPt); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Eta", "#eta distribution", false, 200, -1.0, 1.0, VarManager::kEta); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Phi_Eta", "#phi vs #eta distribution", false, 200, -1.0, 1.0, VarManager::kEta, 72, 0, TMath::TwoPi(), VarManager::kPhi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "P", "p distribution", false, 200, 0.0, 20.0, VarManager::kP); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "Px", "p_{x} distribution", false, 200, 0.0, 20.0, VarManager::kPx); + histMan->AddHistogram(classStr.Data(), "Py", "p_{y} distribution", false, 200, 0.0, 20.0, VarManager::kPy); + histMan->AddHistogram(classStr.Data(), "Pz", "p_{z} distribution", false, 400, -20.0, 20.0, VarManager::kPz); + + if (classStr.Contains("Barrel")) { + histMan->AddHistogram(classStr.Data(), "TPCncls", "Number of cluster in TPC", false, 160, -0.5, 159.5, VarManager::kTPCncls); // TH1F histogram + histMan->AddHistogram(classStr.Data(), "ITSncls", "Number of cluster in ITS", false, 8, -0.5, 7.5, VarManager::kITSncls); // TH1F histogram + //for TPC PID + histMan->AddHistogram(classStr.Data(), "TPCdedx_pIN", "TPC dE/dx vs pIN", false, 1000, 0.0, 10.0, VarManager::kPin, 200, 0.0, 200., VarManager::kTPCsignal); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_pIN", "TPC dE/dx n#sigma_{e} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaEl_Eta", "TPC dE/dx n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_pIN", "TPC dE/dx n#sigma_{#pi} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPi_Eta", "TPC dE/dx n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_pIN", "TPC dE/dx n#sigma_{K} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaKa_Eta", "TPC dE/dx n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_pIN", "TPC dE/dx n#sigma_{p} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TPCnSigmaPr_Eta", "TPC dE/dx n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTPCnSigmaPr); // TH2F histogram + + //for TOF PID + histMan->AddHistogram(classStr.Data(), "TOFbeta_pIN", "TOF #beta vs pIN", false, 1000, 0.0, 10.0, VarManager::kPin, 120, 0.0, 1.2, VarManager::kTOFbeta); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_pIN", "TOF #beta n#sigma_{e} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaEl_Eta", "TOF #beta n#sigma_{e} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaEl); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_pIN", "TOF #beta n#sigma_{#pi} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPi_Eta", "TOF #beta n#sigma_{#pi} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPi); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_pIN", "TOF #beta n#sigma_{K} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaKa_Eta", "TOF #beta n#sigma_{K} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaKa); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_pIN", "TOF #beta n#sigma_{p} vs pIN", false, 100, 0.0, 10.0, VarManager::kPin, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram + histMan->AddHistogram(classStr.Data(), "TOFnSigmaPr_Eta", "TOF #beta n#sigma_{p} vs #eta", false, 20, -1, +1, VarManager::kEta, 200, -10, +10, VarManager::kTOFnSigmaPr); // TH2F histogram + + histMan->AddHistogram(classStr.Data(), "Cov1Pt_Pt", "cov(1/pt,1/pt) vs p_{T} distribution", false, 100, 0.0, 10.0, VarManager::kPt, 100, 0.0, 1.0, VarManager::kTrackC1Pt21Pt2); // TH2F histogram + } + } + + if (classStr.Contains("Pairs")) { + histMan->AddHistClass(classStr.Data()); + histMan->AddHistogram(classStr.Data(), "Mass_Pt", "", false, 500, 0.0, 5.0, VarManager::kMass, 200, 0.0, 20.0, VarManager::kPt); + } + + } // end loop over histogram classes +} From 153c6e6cb4825bd69d551a6bece821af65a56503 Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Mon, 31 Aug 2020 17:22:30 +0200 Subject: [PATCH 26/76] [ITSCA] Tracker performance tuning Finer grid size gives ~1.4x speedup in the tracker. However, the physics performance is quite stable with efficiency oscillations between two values that differ of ~0.2 per mille. This are currently being investigated. --- .../ITS/tracking/include/ITStracking/Constants.h | 4 ++-- .../include/ITStracking/PrimaryVertexContext.h | 5 +++++ .../tracking/include/ITStracking/TrackerTraits.h | 8 ++++---- .../ITS/tracking/src/PrimaryVertexContext.cxx | 5 +++++ .../ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx | 13 ++++++++----- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h index 87ff6041fde2d..e6353c9cae8af 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Constants.h @@ -66,8 +66,8 @@ GPU_HOST_DEVICE constexpr GPUArray VertexerHistogramVolume() namespace index_table { -constexpr int ZBins{20}; -constexpr int PhiBins{20}; +constexpr int ZBins{256}; +constexpr int PhiBins{128}; constexpr float InversePhiBinSize{constants::index_table::PhiBins / constants::math::TwoPi}; GPU_HOST_DEVICE constexpr GPUArray InverseZBinSize() { diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h index a91aef364af3c..3c363c4d7219f 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/PrimaryVertexContext.h @@ -51,6 +51,9 @@ class PrimaryVertexContext std::array>, constants::its::CellsPerRoad - 1>& getCellsNeighbours(); std::vector& getRoads(); + float getMinR(int layer) { return mMinR[layer]; } + float getMaxR(int layer) { return mMaxR[layer]; } + bool isClusterUsed(int layer, int clusterId) const; void markUsedCluster(int layer, int clusterId); @@ -67,6 +70,8 @@ class PrimaryVertexContext protected: float3 mPrimaryVertex; + std::array mMinR; + std::array mMaxR; std::array, constants::its::LayersNumber> mUnsortedClusters; std::array, constants::its::LayersNumber> mClusters; std::array, constants::its::LayersNumber> mUsedClusters; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index 9a33762586cf1..65500276c3374 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -49,7 +49,7 @@ class TrackerTraits virtual ~TrackerTraits() = default; GPU_HOST_DEVICE static constexpr int4 getEmptyBinsRect() { return int4{0, 0, 0, 0}; } - GPU_DEVICE static const int4 getBinsRect(const Cluster&, const int, const float, float maxdeltaz, float maxdeltaphi); + GPU_DEVICE static const int4 getBinsRect(const Cluster&, const int, const float, const float, float maxdeltaz, float maxdeltaphi); void SetRecoChain(o2::gpu::GPUChainITS* chain, FuncRunITSTrackFit_t&& funcRunITSTrackFit) { @@ -78,11 +78,11 @@ inline void TrackerTraits::UpdateTrackingParameters(const TrackingParameters& tr } inline GPU_DEVICE const int4 TrackerTraits::getBinsRect(const Cluster& currentCluster, const int layerIndex, - const float directionZIntersection, float maxdeltaz, float maxdeltaphi) + const float z1, const float z2, float maxdeltaz, float maxdeltaphi) { - const float zRangeMin = directionZIntersection - 2 * maxdeltaz; + const float zRangeMin = gpu::GPUCommonMath::Min(z1, z2) - maxdeltaz; const float phiRangeMin = currentCluster.phiCoordinate - maxdeltaphi; - const float zRangeMax = directionZIntersection + 2 * maxdeltaz; + const float zRangeMax = gpu::GPUCommonMath::Max(z1, z2) + maxdeltaz; const float phiRangeMax = currentCluster.phiCoordinate + maxdeltaphi; if (zRangeMax < -constants::its::LayersZCoordinate()[layerIndex + 1] || diff --git a/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx b/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx index 87ec5bb5719f3..d4dcbe5f36fc9 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/PrimaryVertexContext.cxx @@ -57,6 +57,9 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st cHelper.clear(); cHelper.resize(clustersNum); + mMinR[iLayer] = 1000.f; + mMaxR[iLayer] = -1.f; + for (int iCluster{0}; iCluster < clustersNum; ++iCluster) { const Cluster& c = currentLayer[iCluster]; ClusterHelper& h = cHelper[iCluster]; @@ -67,6 +70,8 @@ void PrimaryVertexContext::initialise(const MemoryParameters& memParam, const st index_table_utils::getPhiBinIndex(phi)); h.phi = phi; h.r = math_utils::calculateRCoordinate(x, y); + mMinR[iLayer] = gpu::GPUCommonMath::Min(h.r, mMinR[iLayer]); + mMaxR[iLayer] = gpu::GPUCommonMath::Max(h.r, mMaxR[iLayer]); h.bin = bin; h.ind = clsPerBin[bin]++; } diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx index b34bfce0cb928..5925a66c7a204 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraitsCPU.cxx @@ -50,11 +50,14 @@ void TrackerTraitsCPU::computeLayerTracklets() } const float tanLambda{(currentCluster.zCoordinate - primaryVertex.z) / currentCluster.rCoordinate}; - const float directionZIntersection{tanLambda * (constants::its::LayersRCoordinate()[iLayer + 1] - - currentCluster.rCoordinate) + - currentCluster.zCoordinate}; - - const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer, directionZIntersection, + const float zAtRmin{tanLambda * (mPrimaryVertexContext->getMinR(iLayer + 1) - + currentCluster.rCoordinate) + + currentCluster.zCoordinate}; + const float zAtRmax{tanLambda * (mPrimaryVertexContext->getMaxR(iLayer + 1) - + currentCluster.rCoordinate) + + currentCluster.zCoordinate}; + + const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer, zAtRmin, zAtRmax, mTrkParams.TrackletMaxDeltaZ[iLayer], mTrkParams.TrackletMaxDeltaPhi)}; if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { From 321c9738e2e4d51c75568d100676c0e784925258 Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Mon, 31 Aug 2020 19:17:51 +0200 Subject: [PATCH 27/76] Fix CUDA code compilation --- .../include/ITStrackingCUDA/DeviceStoreNV.h | 20 ++++++++++++++++++- .../ITStrackingCUDA/PrimaryVertexContextNV.h | 2 +- .../ITS/tracking/cuda/src/DeviceStoreNV.cu | 6 +++++- .../ITS/tracking/cuda/src/TrackerTraitsNV.cu | 5 +++-- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h index 2b17798c2d0d7..d5e38ff3b6319 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h +++ b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/DeviceStoreNV.h @@ -41,7 +41,9 @@ class DeviceStoreNV final const std::array, constants::its::LayersNumber>&, const std::array, constants::its::TrackletsPerRoad>&, const std::array, constants::its::CellsPerRoad>&, - const std::array, constants::its::CellsPerRoad - 1>&); + const std::array, constants::its::CellsPerRoad - 1>&, + const std::array&, + const std::array&); GPU_DEVICE const float3& getPrimaryVertex(); GPU_HOST_DEVICE Array, constants::its::LayersNumber>& getClusters(); GPU_DEVICE Array, @@ -55,9 +57,14 @@ class DeviceStoreNV final GPU_HOST_DEVICE Array, constants::its::CellsPerRoad - 1>& getCellsPerTrackletTable(); Array, constants::its::CellsPerRoad>& getTempTableArray(); + GPU_HOST_DEVICE float getRmin(int layer); + GPU_HOST_DEVICE float getRmax(int layer); + private: UniquePointer mPrimaryVertex; Array, constants::its::LayersNumber> mClusters; + Array mRmin; + Array mRmax; Array, constants::its::TrackletsPerRoad> mIndexTables; Array, constants::its::TrackletsPerRoad> mTracklets; @@ -112,6 +119,17 @@ GPU_HOST_DEVICE inline Array, constants::its::CellsPerRoad - 1>& { return mCellsPerTrackletTable; } + +GPU_HOST_DEVICE inline float DeviceStoreNV::getRmin(int layer) +{ + return mRmin[layer]; +} + +GPU_HOST_DEVICE inline float DeviceStoreNV::getRmax(int layer) +{ + return mRmax[layer]; +} + } // namespace GPU } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h index 51c30fdb10fa8..d5d3493a52292 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h +++ b/Detectors/ITSMFT/ITS/tracking/cuda/include/ITStrackingCUDA/PrimaryVertexContextNV.h @@ -128,7 +128,7 @@ inline void PrimaryVertexContextNV::initialise(const MemoryParameters& memParam, const std::array& pv, const int iteration) { this->PrimaryVertexContext::initialise(memParam, cl, pv, iteration); - mGPUContextDevicePointer = mGPUContext.initialise(mPrimaryVertex, mClusters, mTracklets, mCells, mCellsLookupTable); + mGPUContextDevicePointer = mGPUContext.initialise(mPrimaryVertex, mClusters, mTracklets, mCells, mCellsLookupTable, mMinR, mMaxR); } } // namespace its diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu index 353804900e5e1..14eb74ff41bde 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu +++ b/Detectors/ITSMFT/ITS/tracking/cuda/src/DeviceStoreNV.cu @@ -124,11 +124,15 @@ UniquePointer DeviceStoreNV::initialise(const float3& primaryVert const std::array, constants::its::LayersNumber>& clusters, const std::array, constants::its::TrackletsPerRoad>& tracklets, const std::array, constants::its::CellsPerRoad>& cells, - const std::array, constants::its::CellsPerRoad - 1>& cellsLookupTable) + const std::array, constants::its::CellsPerRoad - 1>& cellsLookupTable, + const std::array& rmin, + const std::array& rmax) { mPrimaryVertex = UniquePointer{primaryVertex}; for (int iLayer{0}; iLayer < constants::its::LayersNumber; ++iLayer) { + this->mRmin[iLayer] = rmin[iLayer]; + this->mRmax[iLayer] = rmax[iLayer]; this->mClusters[iLayer] = Vector{&clusters[iLayer][0], static_cast(clusters[iLayer].size())}; diff --git a/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu b/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu index de818bfe605ca..6155a94cc5d83 100644 --- a/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu +++ b/Detectors/ITSMFT/ITS/tracking/cuda/src/TrackerTraitsNV.cu @@ -58,9 +58,10 @@ __device__ void computeLayerTracklets(DeviceStoreNV& devStore, const int layerIn }*/ const float tanLambda{(currentCluster.zCoordinate - devStore.getPrimaryVertex().z) / currentCluster.rCoordinate}; - const float directionZIntersection{tanLambda * ((constants::its::LayersRCoordinate())[layerIndex + 1] - currentCluster.rCoordinate) + currentCluster.zCoordinate}; + const float zAtRmin{tanLambda * (devStore.getRmin(layerIndex + 1) - currentCluster.rCoordinate) + currentCluster.zCoordinate}; + const float zAtRmax{tanLambda * (devStore.getRmax(layerIndex + 1) - currentCluster.rCoordinate) + currentCluster.zCoordinate}; - const int4 selectedBinsRect{TrackerTraits::getBinsRect(currentCluster, layerIndex, directionZIntersection, + const int4 selectedBinsRect{TrackerTraits::getBinsRect(currentCluster, layerIndex, zAtRmin, zAtRmax, kTrkPar.TrackletMaxDeltaZ[layerIndex], kTrkPar.TrackletMaxDeltaPhi)}; if (selectedBinsRect.x != 0 || selectedBinsRect.y != 0 || selectedBinsRect.z != 0 || selectedBinsRect.w != 0) { From 790cf1753ad3983912a0ab909d5abd9ffdcb3064 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 8 Sep 2020 00:13:07 +0200 Subject: [PATCH 28/76] TrackPar(Cov) can be invalidated by calling invalidate() method This will set its mX to meaningless value, which can be checked by isValid() method. --- .../Reconstruction/include/ReconstructionDataFormats/Track.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h index 655d4409fe440..e30d2cc090135 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Track.h @@ -200,6 +200,9 @@ class TrackPar void invertParam(); + bool isValid() const { return mX != InvalidX; } + void invalidate() { mX = InvalidX; } + #ifndef GPUCA_ALIGPUCODE void printParam() const; std::string asString() const; @@ -217,6 +220,7 @@ class TrackPar private: // + static constexpr float InvalidX = -99999.; float mX = 0.f; /// X of track evaluation float mAlpha = 0.f; /// track frame angle float mP[kNParams] = {0.f}; /// 5 parameters: Y,Z,sin(phi),tg(lambda),q/pT From 00d407984c868fc01ca1577c215d4df20c97b190 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 8 Sep 2020 00:23:11 +0200 Subject: [PATCH 29/76] Fast DCAFitterN method to get track params at PCA w/o full propagation Only a TrackPar copy will be propagated and returned, in case of propagation failure TrackPar::isValid() will return false. --- .../include/DetectorsVertexing/DCAFitterN.h | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h b/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h index e270062471c0c..d2b2001cfefe1 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/DCAFitterN.h @@ -109,15 +109,12 @@ class DCAFitterN ///< return Chi2 at PCA candidate (no check for its validity) float getChi2AtPCACandidate(int cand = 0) const { return mChi2[mOrder[cand]]; } - ///< track param positions at V0 candidate (no check for the candidate validity) - const Vec3D& getTrackPos(int i, int cand = 0) const { return mTrPos[mOrder[cand]][i]; } - - ///< prapare copies of tracks at the V0 candidate (no check for the candidate validity) + ///< prepare copies of tracks at the V0 candidate (no check for the candidate validity) /// must be called before getTrack(i,cand) query bool propagateTracksToVertex(int cand = 0); - ///< track X-param at V0 candidate (no check for the candidate validity) - float getTrackX(int i, int cand = 0) const { return getTrackPos(i, cand)[0]; } + ///< check if propagation of tracks to candidate vertex was done + bool isPropagateTracksToVertexDone(int cand = 0) const { return mTrPropDone[mOrder[cand]]; } ///< track param propagated to V0 candidate (no check for the candidate validity) /// propagateTracksToVertex must be called in advance @@ -129,6 +126,9 @@ class DCAFitterN return mCandTr[mOrder[cand]][i]; } + ///< calculate on the fly track param (no cov mat) at candidate, check isValid to make sure propagation was successful + o2::track::TrackPar getTrackParamAtPCA(int i, int cand = 0) const; + MatSym3D calcPCACovMatrix(int cand = 0) const; const Track* getOrigTrackPtr(int i) const { return mOrigTrPtr[i]; } @@ -182,6 +182,12 @@ class DCAFitterN bool closerToAlternative() const; static double getAbsMax(const VecND& v); + ///< track param positions at V0 candidate (no check for the candidate validity) + const Vec3D& getTrackPos(int i, int cand = 0) const { return mTrPos[mOrder[cand]][i]; } + + ///< track X-param at V0 candidate (no check for the candidate validity) + float getTrackX(int i, int cand = 0) const { return getTrackPos(i, cand)[0]; } + MatStd3D getTrackRotMatrix(int i) const // generate 3D matrix for track rotation to global frame { MatStd3D mat; @@ -695,6 +701,22 @@ bool DCAFitterN::propagateTracksToVertex(int icand) return true; } +//___________________________________________________________________ +template +inline o2::track::TrackPar DCAFitterN::getTrackParamAtPCA(int i, int icand) const +{ + // propagate tracks param only to current vertex (if not already done) + int ord = mOrder[icand]; + o2::track::TrackPar trc(mCandTr[ord][i]); + if (!mTrPropDone[ord]) { + auto x = mTrAux[i].c * mPCA[ord][0] + mTrAux[i].s * mPCA[ord][1]; // X of PCA in the track frame + if (!trc.propagateParamTo(x, mBz)) { + trc.invalidate(); + } + } + return std::move(trc); +} + //___________________________________________________________________ template inline double DCAFitterN::getAbsMax(const VecND& v) From 180ab2deda5578c4f46120b4d2a0d088bfcfef11 Mon Sep 17 00:00:00 2001 From: Luca Barioglio Date: Tue, 8 Sep 2020 11:21:07 +0200 Subject: [PATCH 30/76] Add task for nuclei (#4301) --- Analysis/Tasks/CMakeLists.txt | 1 + Analysis/Tasks/PWGLF/CMakeLists.txt | 14 ++++++++ Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx | 41 ++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 Analysis/Tasks/PWGLF/CMakeLists.txt create mode 100644 Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx diff --git a/Analysis/Tasks/CMakeLists.txt b/Analysis/Tasks/CMakeLists.txt index d5a267f78032a..751cd40c64c8f 100644 --- a/Analysis/Tasks/CMakeLists.txt +++ b/Analysis/Tasks/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(PWGCF) add_subdirectory(PWGDQ) add_subdirectory(PWGHF) +add_subdirectory(PWGLF) o2_add_dpl_workflow(trackselection SOURCES trackselection.cxx diff --git a/Analysis/Tasks/PWGLF/CMakeLists.txt b/Analysis/Tasks/PWGLF/CMakeLists.txt new file mode 100644 index 0000000000000..a517969a90861 --- /dev/null +++ b/Analysis/Tasks/PWGLF/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# 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. + +o2_add_dpl_workflow(nuclei-spectra + SOURCES NucleiSpectraTask.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2::AnalysisDataModel + COMPONENT_NAME Analysis) diff --git a/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx b/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx new file mode 100644 index 0000000000000..960cc376981b7 --- /dev/null +++ b/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx @@ -0,0 +1,41 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" + +#include "PID/PIDResponse.h" + +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +struct NucleiSpecraTask { + + OutputObj hTPCsignal{TH2F("hTPCsignal", ";#it{p} (GeV/#it{c}); d#it{E}/d#it{X} (a. u.)", 600, 0., 3, 1400, 0, 1400)}; + OutputObj hMomentum{TH1F("hMomentum", ";#it{p} (GeV/#it{c});", 600, 0., 3.)}; + + void process(soa::Join const& tracks) + { + for (auto& track : tracks) { + hTPCsignal->Fill(track.p(), track.tpcSignal()); + hMomentum->Fill(track.p()); + } + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + return WorkflowSpec{ + adaptAnalysisTask("nuclei-spectra")}; +} From 797254724dc7eb6e778d6081c7b9f45325aaa9ea Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 8 Sep 2020 12:10:17 +0200 Subject: [PATCH 31/76] DPL Analysis: drop arrow v0.17 compatibility (#4304) --- Framework/Core/include/Framework/Kernels.h | 145 --------------------- Framework/Core/src/TableTreeHelpers.cxx | 15 --- Framework/Core/test/test_Kernels.cxx | 7 - 3 files changed, 167 deletions(-) diff --git a/Framework/Core/include/Framework/Kernels.h b/Framework/Core/include/Framework/Kernels.h index 2dc39e85619c5..00fac405fc8ed 100644 --- a/Framework/Core/include/Framework/Kernels.h +++ b/Framework/Core/include/Framework/Kernels.h @@ -14,13 +14,6 @@ #include "Framework/BasicOps.h" #include "Framework/TableBuilder.h" -#if __has_include() -#include -#endif -#if __has_include() -#include -#endif - #include #include #include @@ -28,145 +21,8 @@ #include -#if (ARROW_VERSION < 1000000) -namespace arrow -{ -using Datum = compute::Datum; -} -#endif - namespace o2::framework { -#if (ARROW_VERSION < 1000000) -template -struct ARROW_EXPORT GroupByOptions { - std::string columnName; - T size; -}; - -/// Build ranges -template -class ARROW_EXPORT SortedGroupByKernel : public arrow::compute::UnaryKernel -{ - public: - explicit SortedGroupByKernel(GroupByOptions options = {}) : mOptions(options){}; - arrow::Status Call(arrow::compute::FunctionContext*, - arrow::compute::Datum const& table, - arrow::compute::Datum* outputRanges) override - { - using namespace arrow; - if (table.kind() == arrow::compute::Datum::TABLE) { - auto atable = util::get>(table.value); - auto columnIndex = atable->schema()->GetFieldIndex(mOptions.columnName); - auto chunkedArray = atable->column(columnIndex); - return doGrouping(chunkedArray, outputRanges); - }; - return arrow::Status::OK(); - }; -#pragma GCC diagnostic push -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Winconsistent-missing-override" -#endif // __clang__ - std::shared_ptr out_type() const final - { - return mType; - } -#pragma GCC diagnostic pop - - private: - arrow::Status doGrouping(std::shared_ptr chunkedArray, arrow::compute::Datum* outputRanges) - { - o2::framework::TableBuilder builder; - auto writer = builder.persist({"start", "count", "index"}); - auto zeroChunk = std::static_pointer_cast(chunkedArray->chunk(0)); - if (zeroChunk->length() == 0) { - *outputRanges = std::move(builder.finalize()); - return arrow::Status::OK(); - } - T currentIndex = 0; - T currentCount = 0; - T currentOffset = 0; - for (auto ci = 0; ci < chunkedArray->num_chunks(); ++ci) { - auto chunk = chunkedArray->chunk(ci); - T const* data = std::static_pointer_cast(chunk)->raw_values(); - for (auto ai = 0; ai < chunk->length(); ++ai) { - if (currentIndex == data[ai]) { - currentCount++; - } else { - writer(0, currentOffset, currentCount, currentIndex); - currentOffset += currentCount; - while (data[ai] - currentIndex > 1) { - writer(0, currentOffset, 0, ++currentIndex); - } - currentIndex++; - currentCount = 1; - } - } - } - writer(0, currentOffset, currentCount, currentIndex); - while (currentIndex < mOptions.size - 1) { - writer(0, currentOffset, 0, ++currentIndex); - } - *outputRanges = std::move(builder.finalize()); - return arrow::Status::OK(); - } - std::shared_ptr mType; - GroupByOptions mOptions; -}; - -/// Slice a given table is a vector of tables each containing a slice. -/// @a outputSlices the arrow tables in which the original @a inputTable -/// is split into. -/// @a offset the offset in the original table at which the corresponding -/// slice was split. -/// Slice a given table is a vector of tables each containing a slice. -template -arrow::Status sliceByColumn(std::string const& key, - std::shared_ptr const& input, - T size, - std::vector* outputSlices, - std::vector* offsets = nullptr) -{ - arrow::compute::Datum inputTable{input}; - // build all the ranges on the fly. - arrow::compute::Datum outRanges; - auto table = arrow::util::get>(inputTable.value); - o2::framework::SortedGroupByKernel> kernel{GroupByOptions{key, size}}; - - ARROW_RETURN_NOT_OK(kernel.Call(nullptr, inputTable, &outRanges)); - auto ranges = arrow::util::get>(outRanges.value); - outputSlices->reserve(ranges->num_rows()); - if (offsets) { - offsets->reserve(ranges->num_rows()); - } - - auto startChunks = ranges->column(0); - assert(startChunks->num_chunks() == 1); - auto countChunks = ranges->column(1); - assert(countChunks->num_chunks() == 1); - auto startData = std::static_pointer_cast>(startChunks->chunk(0))->raw_values(); - auto countData = std::static_pointer_cast>(countChunks->chunk(0))->raw_values(); - - for (auto ri = 0; ri < ranges->num_rows(); ++ri) { - auto start = startData[ri]; - auto count = countData[ri]; - auto schema = table->schema(); - std::vector> slicedColumns; - slicedColumns.reserve(schema->num_fields()); - // if (count != 0) { - for (auto ci = 0; ci < schema->num_fields(); ++ci) { - slicedColumns.emplace_back(table->column(ci)->Slice(start, count)); - } - // } - outputSlices->emplace_back(arrow::compute::Datum(arrow::Table::Make(table->schema(), slicedColumns))); - if (offsets) { - offsets->emplace_back(start); - } - } - return arrow::Status::OK(); -} - -#else /// Slice a given table in a vector of tables each containing a slice. /// @a slices the arrow tables in which the original @a input /// is split into. @@ -235,7 +91,6 @@ auto sliceByColumn(char const* key, return arrow::Status::OK(); } -#endif } // namespace o2::framework diff --git a/Framework/Core/src/TableTreeHelpers.cxx b/Framework/Core/src/TableTreeHelpers.cxx index 9ea4ac8e5febf..76776141befac 100644 --- a/Framework/Core/src/TableTreeHelpers.cxx +++ b/Framework/Core/src/TableTreeHelpers.cxx @@ -10,13 +10,6 @@ #include "Framework/TableTreeHelpers.h" #include "Framework/Logger.h" -#if __has_include() -#include -#endif -#if __has_include() -#include -#endif - #include "arrow/type_traits.h" namespace o2 @@ -39,19 +32,11 @@ BranchIterator::BranchIterator(TTree* tree, std::shared_ptr mNumberElements = 1; if (mFieldType == arrow::Type::type::FIXED_SIZE_LIST) { -#if (ARROW_VERSION < 1000000) - // element type - if (mField->type()->num_children() <= 0) { - LOGP(FATAL, "Field {} of type {} has no children!", mField->name(), mField->type()->ToString().c_str()); - } - mElementType = mField->type()->child(0)->type()->id(); -#else // element type if (mField->type()->num_fields() <= 0) { LOGP(FATAL, "Field {} of type {} has no children!", mField->name(), mField->type()->ToString().c_str()); } mElementType = mField->type()->field(0)->type()->id(); -#endif // number of elements mNumberElements = static_cast(mField->type().get())->list_size(); mLeaflistString += "[" + std::to_string(mNumberElements) + "]"; diff --git a/Framework/Core/test/test_Kernels.cxx b/Framework/Core/test/test_Kernels.cxx index 46a2087c22b95..b7f48bcc82c9f 100644 --- a/Framework/Core/test/test_Kernels.cxx +++ b/Framework/Core/test/test_Kernels.cxx @@ -21,12 +21,6 @@ using namespace o2::framework; using namespace arrow; using namespace arrow::compute; -#if (ARROW_VERSION < 1000000) -namespace arrow -{ -using Datum = compute::Datum; -} -#else BOOST_AUTO_TEST_CASE(TestSlicing) { TableBuilder builder; @@ -57,7 +51,6 @@ BOOST_AUTO_TEST_CASE(TestSlicing) BOOST_REQUIRE_EQUAL(arr1.Value(i), c[i]); } } -#endif BOOST_AUTO_TEST_CASE(TestSlicingFramework) { From e58031ea872cbf4e3c9011201d653c2c8ffce36c Mon Sep 17 00:00:00 2001 From: Roberto Preghenella Date: Fri, 4 Sep 2020 16:49:20 +0200 Subject: [PATCH 32/76] Workflow for plug-in TOF analyses of compressed data --- Detectors/TOF/compression/CMakeLists.txt | 6 ++ .../src/tof-compressed-analysis.cxx | 43 ++++++++ Detectors/TOF/workflow/CMakeLists.txt | 1 + .../include/TOFWorkflow/CompressedAnalysis.h | 46 +++++++++ .../TOFWorkflow/CompressedAnalysisTask.h | 94 ++++++++++++++++++ .../workflow/src/CompressedAnalysisTask.cxx | 98 +++++++++++++++++++ 6 files changed, 288 insertions(+) create mode 100644 Detectors/TOF/compression/src/tof-compressed-analysis.cxx create mode 100644 Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysis.h create mode 100644 Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysisTask.h create mode 100644 Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx diff --git a/Detectors/TOF/compression/CMakeLists.txt b/Detectors/TOF/compression/CMakeLists.txt index 9dcbfc25f2c94..adef2471c81e4 100644 --- a/Detectors/TOF/compression/CMakeLists.txt +++ b/Detectors/TOF/compression/CMakeLists.txt @@ -27,4 +27,10 @@ o2_add_executable(compressed-inspector PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils ) +o2_add_executable(compressed-analysis + COMPONENT_NAME tof + SOURCES src/tof-compressed-analysis.cxx + PUBLIC_LINK_LIBRARIES O2::TOFWorkflowUtils + ) + diff --git a/Detectors/TOF/compression/src/tof-compressed-analysis.cxx b/Detectors/TOF/compression/src/tof-compressed-analysis.cxx new file mode 100644 index 0000000000000..0e610b60b4e41 --- /dev/null +++ b/Detectors/TOF/compression/src/tof-compressed-analysis.cxx @@ -0,0 +1,43 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 tof-compressor.cxx +/// @author Roberto Preghenella +/// @since 2019-12-18 +/// @brief Basic DPL workflow for TOF raw data compression + +#include "TOFWorkflow/CompressedAnalysisTask.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "FairLogger.h" + +using namespace o2::framework; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ +} + +#include "Framework/runDataProcessing.h" // the main driver + +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + DataProcessorSpec{"compressed-analysis", + select("x:TOF/CRAWDATA"), + Outputs{}, + AlgorithmSpec(adaptFromTask()), + Options{ + {"tof-compressed-analysis-conet-mode", VariantType::Bool, false, {"CONET mode"}}, + {"tof-compressed-analysis-filename", VariantType::String, "", {"Analysis file name"}}, + {"tof-compressed-analysis-function", VariantType::String, "", {"Analysis function call"}}}}}; +} diff --git a/Detectors/TOF/workflow/CMakeLists.txt b/Detectors/TOF/workflow/CMakeLists.txt index 1cda6cfabe976..d75c55259ff79 100644 --- a/Detectors/TOF/workflow/CMakeLists.txt +++ b/Detectors/TOF/workflow/CMakeLists.txt @@ -17,6 +17,7 @@ o2_add_library(TOFWorkflowUtils src/TOFRawWriterSpec.cxx src/CompressedDecodingTask.cxx src/CompressedInspectorTask.cxx + src/CompressedAnalysisTask.cxx src/EntropyEncoderSpec.cxx src/EntropyDecoderSpec.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::TOFBase O2::DataFormatsTOF O2::TOFReconstruction) diff --git a/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysis.h b/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysis.h new file mode 100644 index 0000000000000..32d5a28f63ff9 --- /dev/null +++ b/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysis.h @@ -0,0 +1,46 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 CompressedAnalysisTask.h +/// @author Roberto Preghenella +/// @since 2020-09-04 +/// @brief TOF compressed data analysis base class + +#ifndef O2_TOF_COMPRESSEDANALYSIS +#define O2_TOF_COMPRESSEDANALYSIS + +#include "Headers/RAWDataHeader.h" +#include "DataFormatsTOF/CompressedDataFormat.h" +#include "TOFReconstruction/DecoderBase.h" + +using namespace o2::tof::compressed; + +namespace o2 +{ +namespace tof +{ + +class CompressedAnalysis : public DecoderBaseT +{ + + public: + CompressedAnalysis() = default; + ~CompressedAnalysis() override = default; + + virtual bool initialize() = 0; + virtual bool finalize() = 0; + + private: +}; + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_COMPRESSEDANALYSIS */ diff --git a/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysisTask.h b/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysisTask.h new file mode 100644 index 0000000000000..638030454b38d --- /dev/null +++ b/Detectors/TOF/workflow/include/TOFWorkflow/CompressedAnalysisTask.h @@ -0,0 +1,94 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 CompressedAnalysisTask.h +/// @author Roberto Preghenella +/// @since 2020-09-04 +/// @brief TOF compressed data analysis task + +#ifndef O2_TOF_COMPRESSEDANALYSISTASK +#define O2_TOF_COMPRESSEDANALYSISTASK + +#include "Framework/Task.h" +#include "TOFWorkflow/CompressedAnalysis.h" + +#include "TROOT.h" +#include "TSystem.h" +#include "TGlobal.h" +#include "TFunction.h" +#include +#include + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +class CompressedAnalysisTask : public Task +{ + public: + CompressedAnalysisTask() = default; + ~CompressedAnalysisTask() override = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + + private: + CompressedAnalysis* mAnalysis = nullptr; + bool mStatus = false; + + template + T GetFromMacro(const std::string& file, const std::string& funcname, const std::string& type, const std::string& unique) + { + + /** tweak the string to get the required global function **/ + auto func = funcname; + if (func.empty()) { + auto size = file.size(); + auto firstindex = file.find_last_of("/") + 1; + auto lastindex = file.find_last_of("."); + func = file.substr(firstindex < size ? firstindex : 0, + lastindex < size ? lastindex - firstindex : size - firstindex) + + "()"; + } + auto gfunc = func.substr(0, func.find_first_of('(')); + + /** load macro is global function is not already defined **/ + if (!gROOT->GetGlobalFunction(gfunc.c_str())) { + if (gROOT->LoadMacro(file.c_str()) != 0) { + std::cout << "Cannot find " << file << std::endl; + return nullptr; + } + if (!gROOT->GetGlobalFunction(gfunc.c_str())) { + std::cout << "Global function '" << gfunc << "' not defined" << std::endl; + return nullptr; + } + } + + /** check the return type matches the required one **/ + if (strcmp(gROOT->GetGlobalFunction(gfunc.c_str())->GetReturnTypeName(), type.c_str())) { + std::cout << "Global function '" << gfunc << "' does not return a '" << type << "' type" << std::endl; + return nullptr; + } + + /** process function and retrieve pointer to the returned type **/ + gROOT->ProcessLine(Form("%s __%s__ = %s;", type.c_str(), unique.c_str(), func.c_str())); + auto ptr = (T*)gROOT->GetGlobal(Form("__%s__", unique.c_str()))->GetAddress(); + + /** success **/ + return *ptr; + } +}; + +} // namespace tof +} // namespace o2 + +#endif /* O2_TOF_COMPRESSEDANALYSISTASK */ diff --git a/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx b/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx new file mode 100644 index 0000000000000..4f6037852f186 --- /dev/null +++ b/Detectors/TOF/workflow/src/CompressedAnalysisTask.cxx @@ -0,0 +1,98 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 CompressedAnalysisTask.cxx +/// @author Roberto Preghenella +/// @since 2020-09-04 +/// @brief TOF compressed data analysis task + +#include "TOFWorkflow/CompressedAnalysisTask.h" +#include "Framework/Task.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/CallbackService.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/RawDeviceService.h" +#include "Framework/DeviceSpec.h" +#include + +using namespace o2::framework; + +namespace o2 +{ +namespace tof +{ + +void CompressedAnalysisTask::init(InitContext& ic) +{ + + auto conetmode = ic.options().get("tof-compressed-analysis-conet-mode"); + auto filename = ic.options().get("tof-compressed-analysis-filename"); + auto function = ic.options().get("tof-compressed-analysis-function"); + + if (filename.empty()) { + LOG(ERROR) << "No analysis filename defined"; + mStatus = true; + return; + } + + if (function.empty()) { + LOG(ERROR) << "No analysis function defined"; + mStatus = true; + return; + } + + mAnalysis = GetFromMacro(filename, function, "CompressedAnalysis*", "compressed_analysis"); + if (!mAnalysis) { + LOG(ERROR) << "Could not retrieve analysis from file: " << filename; + mStatus = true; + return; + } + + mAnalysis->setDecoderCONET(conetmode); + mAnalysis->initialize(); + + auto finishFunction = [this]() { + LOG(INFO) << "CompressedBaseTask finish"; + mAnalysis->finalize(); + }; + ic.services().get().set(CallbackService::Id::Stop, finishFunction); +} + +void CompressedAnalysisTask::run(ProcessingContext& pc) +{ + + /** check status **/ + if (mStatus) { + pc.services().get().readyToQuit(QuitRequest::Me); + return; + } + + /** loop over inputs routes **/ + for (auto iit = pc.inputs().begin(), iend = pc.inputs().end(); iit != iend; ++iit) { + if (!iit.isValid()) + continue; + + /** loop over input parts **/ + for (auto const& ref : iit) { + + const auto* headerIn = DataRefUtils::getHeader(ref); + auto payloadIn = ref.payload; + auto payloadInSize = headerIn->payloadSize; + + mAnalysis->setDecoderBuffer(payloadIn); + mAnalysis->setDecoderBufferSize(payloadInSize); + mAnalysis->run(); + } + } +} + +} // namespace tof +} // namespace o2 From 2ec086d69717d7f383ac5dd8504000470c4c50d2 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 8 Sep 2020 13:03:52 +0200 Subject: [PATCH 33/76] DPL: add RawDeviceService::waitFor method (#4303) This avoids exposing FairMQDevice.h to the user in a few more places. Every inclusion of FairMQDevice.h results in 1GB of RAM and 2 seconds of compilations in my naive tests. --- Framework/Core/CMakeLists.txt | 1 + .../Core/include/Framework/RawDeviceService.h | 18 ++++++++------- .../Framework/SimpleRawDeviceService.h | 15 ++++++------ Framework/Core/src/AODReaderHelpers.cxx | 1 - Framework/Core/src/SimpleRawDeviceService.cxx | 23 +++++++++++++++++++ Framework/Core/src/WorkflowHelpers.cxx | 3 +-- .../test_SimpleDataProcessingDevice01.cxx | 3 +-- .../Core/test/test_StaggeringWorkflow.cxx | 6 ++--- 8 files changed, 45 insertions(+), 25 deletions(-) create mode 100644 Framework/Core/src/SimpleRawDeviceService.cxx diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 7c235e03d9b73..8d22c05aec48d 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -97,6 +97,7 @@ o2_add_library(Framework src/ResourcesMonitoringHelper.cxx src/ServiceRegistry.cxx src/SimpleResourceManager.cxx + src/SimpleRawDeviceService.cxx src/StreamOperators.cxx src/TMessageSerializer.cxx src/TableBuilder.cxx diff --git a/Framework/Core/include/Framework/RawDeviceService.h b/Framework/Core/include/Framework/RawDeviceService.h index 360de775adfbc..700df3c9b62a4 100644 --- a/Framework/Core/include/Framework/RawDeviceService.h +++ b/Framework/Core/include/Framework/RawDeviceService.h @@ -7,16 +7,14 @@ // 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 FRAMEWORK_RAWDEVICESERVICE_H -#define FRAMEWORK_RAWDEVICESERVICE_H +#ifndef O2_FRAMEWORK_RAWDEVICESERVICE_H_ +#define O2_FRAMEWORK_RAWDEVICESERVICE_H_ #include "Framework/ServiceHandle.h" class FairMQDevice; -namespace o2 -{ -namespace framework +namespace o2::framework { class DeviceSpec; @@ -33,8 +31,12 @@ class RawDeviceService virtual FairMQDevice* device() = 0; virtual void setDevice(FairMQDevice* device) = 0; virtual DeviceSpec const& spec() = 0; + /// Expose FairMQDevice::WaitFor method to avoid having to include + /// FairMQDevice.h. + /// + /// @a time in millisecond to sleep + virtual void waitFor(unsigned int time) = 0; }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_RAWDEVICESERVICE_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_RAWDEVICESERVICE_H_ diff --git a/Framework/Core/include/Framework/SimpleRawDeviceService.h b/Framework/Core/include/Framework/SimpleRawDeviceService.h index b4b8503e194c2..03e3e75e0c2db 100644 --- a/Framework/Core/include/Framework/SimpleRawDeviceService.h +++ b/Framework/Core/include/Framework/SimpleRawDeviceService.h @@ -7,15 +7,13 @@ // 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 FRAMEWORK_SIMPLERAWDEVICESERVICE_H -#define FRAMEWORK_SIMPLERAWDEVICESERVICE_H +#ifndef O2_FRAMEWORK_SIMPLERAWDEVICESERVICE_H_ +#define O2_FRAMEWORK_SIMPLERAWDEVICESERVICE_H_ #include "Framework/RawDeviceService.h" #include "Framework/DeviceSpec.h" -namespace o2 -{ -namespace framework +namespace o2::framework { /// Fairly unsophisticated service which simply stores and returns the @@ -43,11 +41,12 @@ class SimpleRawDeviceService : public RawDeviceService return mSpec; } + void waitFor(unsigned int ms) final; + private: FairMQDevice* mDevice; DeviceSpec const& mSpec; }; -} // namespace framework -} // namespace o2 -#endif // FRAMEWORK_SIMPLERAWDEVICESERVICE_H +} // namespace o2::framework +#endif // O2_FRAMEWORK_SIMPLERAWDEVICESERVICE_H__ diff --git a/Framework/Core/src/AODReaderHelpers.cxx b/Framework/Core/src/AODReaderHelpers.cxx index 2a614f356a6d5..9e41ec0cd72ba 100644 --- a/Framework/Core/src/AODReaderHelpers.cxx +++ b/Framework/Core/src/AODReaderHelpers.cxx @@ -27,7 +27,6 @@ #include "Framework/ChannelInfo.h" #include "Framework/Logger.h" -#include #include #include #include diff --git a/Framework/Core/src/SimpleRawDeviceService.cxx b/Framework/Core/src/SimpleRawDeviceService.cxx new file mode 100644 index 0000000000000..daf1cb54e0c4d --- /dev/null +++ b/Framework/Core/src/SimpleRawDeviceService.cxx @@ -0,0 +1,23 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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/SimpleRawDeviceService.h" + +#include + +namespace o2::framework +{ + +void SimpleRawDeviceService::waitFor(unsigned int ms) +{ + mDevice->WaitFor(std::chrono::milliseconds(ms)); +} + +} // namespace o2::framework diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 9ffaaf1af00b3..aa9646ef59cc3 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -19,7 +19,6 @@ #include "Framework/RawDeviceService.h" #include "Framework/StringHelpers.h" -#include "fairmq/FairMQDevice.h" #include "Headers/DataHeader.h" #include #include @@ -166,7 +165,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext return [](ProcessingContext& pc) { // this callback is never called since there is no expiring input - pc.services().get().device()->WaitFor(std::chrono::seconds(2)); + pc.services().get().waitFor(2000); }; }}; diff --git a/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx b/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx index a45b048e52757..5b485bb186be4 100644 --- a/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx +++ b/Framework/Core/test/test_SimpleDataProcessingDevice01.cxx @@ -14,7 +14,6 @@ #include "Framework/RawDeviceService.h" #include "Framework/runDataProcessing.h" #include -#include using namespace o2::framework; @@ -40,7 +39,7 @@ std::vector defineDataProcessing(ConfigContext const&) {OutputSpec{"TPC", "CLUSTERS"}, OutputSpec{"ITS", "CLUSTERS"}}, adaptStateless([](DataAllocator& outputs, ControlService& control, RawDeviceService& service) { - service.device()->WaitFor(std::chrono::milliseconds(1000)); + service.waitFor(1000); // Creates a new message of size 1000 which // has "TPC" as data origin and "CLUSTERS" as data description. auto& tpcClusters = outputs.make(Output{"TPC", "CLUSTERS", 0}, 1000); diff --git a/Framework/Core/test/test_StaggeringWorkflow.cxx b/Framework/Core/test/test_StaggeringWorkflow.cxx index 126551647d2d5..f124d099dc4ba 100644 --- a/Framework/Core/test/test_StaggeringWorkflow.cxx +++ b/Framework/Core/test/test_StaggeringWorkflow.cxx @@ -24,8 +24,6 @@ #include "Framework/DispatchPolicy.h" #include "Framework/DeviceSpec.h" #include "Framework/Output.h" -#include -#include #include #include #include @@ -88,9 +86,9 @@ std::vector defineDataProcessing(ConfigContext const&) // because of the CompletionPolicy trigger matcher. This message will be // sent together with the second message. outputs.snapshot(Output{"PROD", "CHANNEL", subspec, Lifetime::Timeframe}, subspec); - device.device()->WaitFor(std::chrono::milliseconds(100)); + device.waitFor(100); outputs.snapshot(Output{"PROD", "TRIGGER", subspec, Lifetime::Timeframe}, subspec); - device.device()->WaitFor(std::chrono::milliseconds(100)); + device.waitFor(100); } control.endOfStream(); control.readyToQuit(QuitRequest::Me); From 985099d9f87094f1de830b402d31bc9f0df17d1d Mon Sep 17 00:00:00 2001 From: Bogdan Vulpescu Date: Mon, 6 Jul 2020 16:07:54 +0200 Subject: [PATCH 34/76] MID: add library MIDWorkflow --- Detectors/MUON/MID/Workflow/CMakeLists.txt | 79 ++++++++++------------ 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/Detectors/MUON/MID/Workflow/CMakeLists.txt b/Detectors/MUON/MID/Workflow/CMakeLists.txt index 487556cd975f8..239e8d98caa8f 100644 --- a/Detectors/MUON/MID/Workflow/CMakeLists.txt +++ b/Detectors/MUON/MID/Workflow/CMakeLists.txt @@ -8,27 +8,42 @@ # granted to it by virtue of its status as an Intergovernmental Organization or # submit itself to any jurisdiction. +o2_add_library(MIDWorkflow + TARGETVARNAME targetName + SOURCES src/RecoWorkflow.cxx + src/ClusterizerMCSpec.cxx + src/DigitReaderSpec.cxx + src/RecoWorkflowMC.cxx + src/TrackerMCSpec.cxx + src/ClusterizerSpec.cxx + src/RecoWorkflow.cxx + src/RawDecoderSpec.cxx + src/RawAggregatorSpec.cxx + src/TrackerSpec.cxx + src/DigitReaderSpec.cxx + src/DigitsToRawWorkflow.cxx + src/RawWriterSpec.cxx + PUBLIC_LINK_LIBRARIES + O2::Framework + O2::SimConfig + ms_gsl::ms_gsl + O2::DetectorsBase + O2::SimulationDataFormat + O2::DataFormatsMID + O2::DPLUtils + O2::MIDSimulation + O2::MIDClustering + O2::MIDTracking + O2::MIDRaw + ) + o2_add_executable( reco-workflow-mc COMPONENT_NAME mid SOURCES src/mid-reco-workflow-mc.cxx - src/ClusterizerMCSpec.cxx - src/DigitReaderSpec.cxx - src/RecoWorkflowMC.cxx - src/TrackerMCSpec.cxx - TARGETVARNAME - exenamerecomc + TARGETVARNAME exenamerecomc PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimConfig - ms_gsl::ms_gsl - O2::DetectorsBase - O2::SimulationDataFormat - O2::DataFormatsMID - O2::DPLUtils - O2::MIDSimulation - O2::MIDClustering - O2::MIDTracking) + O2::MIDWorkflow) target_include_directories( ${exenamerecomc} PRIVATE $) @@ -37,23 +52,9 @@ o2_add_executable( reco-workflow COMPONENT_NAME mid SOURCES src/mid-reco-workflow.cxx - src/ClusterizerSpec.cxx - src/RecoWorkflow.cxx - src/RawDecoderSpec.cxx - src/RawAggregatorSpec.cxx - src/TrackerSpec.cxx - TARGETVARNAME - exenamereco + TARGETVARNAME exenamereco PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimConfig - ms_gsl::ms_gsl - O2::DetectorsBase - O2::DataFormatsMID - O2::DPLUtils - O2::MIDClustering - O2::MIDRaw - O2::MIDTracking) + O2::MIDWorkflow) target_include_directories( ${exenamereco} PRIVATE $) @@ -61,18 +62,10 @@ target_include_directories( o2_add_executable( digits-to-raw-workflow COMPONENT_NAME mid - SOURCES src/mid-digits-to-raw.cxx src/DigitReaderSpec.cxx - src/DigitsToRawWorkflow.cxx src/RawWriterSpec.cxx TARGETVARNAME - exenameraw + SOURCES src/mid-digits-to-raw.cxx + TARGETVARNAME exenameraw PUBLIC_LINK_LIBRARIES - O2::Framework - O2::SimConfig - ms_gsl::ms_gsl - O2::SimulationDataFormat - O2::DataFormatsMID - O2::DPLUtils - O2::MIDSimulation - O2::MIDRaw) + O2::MIDWorkflow) target_include_directories( ${exenameraw} PRIVATE $) From 594ae1d97eea79e892f887f9e98f9cfe8e61cc22 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 8 Sep 2020 14:32:00 +0200 Subject: [PATCH 35/76] Add method to enforce oldest slot finalization/removal --- .../DetectorsCalibration/TimeSlotCalibration.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h index 74373e7137ae3..35ae9e3d7a48d 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h +++ b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h @@ -52,6 +52,7 @@ class TimeSlotCalibration virtual bool process(TFType tf, const gsl::span data); virtual void checkSlotsToFinalize(TFType tf, int maxDelay = 0); + virtual void finalizeOldestSlot(); // Methods to be implemented by the derived user class @@ -136,6 +137,20 @@ void TimeSlotCalibration::checkSlotsToFinalize(TFType tf, int } } +//_________________________________________________ +template +void TimeSlotCalibration::finalizeOldestSlot() +{ + // Enforce finalization and removal of the oldest slot + if (mSlots.empty()) { + LOG(WARNING) << "There are no slots defined"; + return; + } + finalizeSlot(mSlots.front()); + mLastClosedTF = mSlots.front().getTFEnd() + 1; // do not accept any TF below this + mSlots.erase(mSlots.begin()); +} + //________________________________________ template inline TFType TimeSlotCalibration::tf2SlotMin(TFType tf) const From 6ddb56c1c37eed6b89e69abcc0885a974cd1336c Mon Sep 17 00:00:00 2001 From: shahoian Date: Mon, 7 Sep 2020 18:36:57 +0200 Subject: [PATCH 36/76] Init mag.field before initializing generator --- run/O2PrimaryServerDevice.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/run/O2PrimaryServerDevice.h b/run/O2PrimaryServerDevice.h index 9af897b5131a8..07d8507b574ad 100644 --- a/run/O2PrimaryServerDevice.h +++ b/run/O2PrimaryServerDevice.h @@ -27,6 +27,8 @@ #include #include #include +#include "Field/MagneticField.h" +#include #include #include #include @@ -60,6 +62,31 @@ class O2PrimaryServerDevice final : public FairMQDevice TStopwatch timer; timer.Start(); auto& conf = o2::conf::SimConfig::Instance(); + + // init magnetic field as it might be needed by the generator + int fld = conf.getConfigData().mField, fldAbs = std::abs(fld); + float fldCoeff; + o2::field::MagFieldParam::BMap_t fldType; + switch (fldAbs) { + case 5: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeff = fld > 0 ? 1. : -1; + break; + case 0: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeff = 0; + break; + case 2: + fldType = o2::field::MagFieldParam::k2kG; + fldCoeff = fld > 0 ? 1. : -1; + break; + default: + LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0"; + }; + auto field = new o2::field::MagneticField("Maps", "Maps", fldCoeff, fldCoeff, fldType); + TGeoGlobalMagField::Instance()->SetField(field); + TGeoGlobalMagField::Instance()->Lock(); + o2::eventgen::GeneratorFactory::setPrimaryGenerator(conf, &mPrimGen); mPrimGen.SetEvent(&mEventHeader); From 825842c976954c142c17220de6358b53f0604b68 Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 8 Sep 2020 11:42:54 +0200 Subject: [PATCH 37/76] Dedicate field creator method for construction from nominal rounded L3 field value --- Common/Field/include/Field/MagneticField.h | 3 +++ Common/Field/src/MagneticField.cxx | 23 ++++++++++++++++++++++ macro/build_geometry.C | 22 +-------------------- run/O2PrimaryServerDevice.h | 21 +------------------- 4 files changed, 28 insertions(+), 41 deletions(-) diff --git a/Common/Field/include/Field/MagneticField.h b/Common/Field/include/Field/MagneticField.h index 4d19c6800b99b..d4241fe49c498 100644 --- a/Common/Field/include/Field/MagneticField.h +++ b/Common/Field/include/Field/MagneticField.h @@ -68,6 +68,9 @@ class MagneticField : public FairField /// Default destructor ~MagneticField() override = default; + /// create field from rounded value, i.e. +-5 or +-2 kGauss + static MagneticField* createNominalField(int fld); + /// real field creation is here void CreateField(); diff --git a/Common/Field/src/MagneticField.cxx b/Common/Field/src/MagneticField.cxx index 5fb485ee1c3f1..f53ac5a42cfdc 100644 --- a/Common/Field/src/MagneticField.cxx +++ b/Common/Field/src/MagneticField.cxx @@ -148,6 +148,29 @@ MagneticField::MagneticField(const MagFieldParam& param) CreateField(); } +MagneticField* MagneticField::createNominalField(int fld) +{ + float fldCoeff; + o2::field::MagFieldParam::BMap_t fldType; + switch (std::abs(fld)) { + case 5: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeff = fld > 0 ? 1. : -1; + break; + case 0: + fldType = o2::field::MagFieldParam::k5kG; + fldCoeff = 0; + break; + case 2: + fldType = o2::field::MagFieldParam::k2kG; + fldCoeff = fld > 0 ? 1. : -1; + break; + default: + LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0"; + }; + return new o2::field::MagneticField("Maps", "Maps", fldCoeff, fldCoeff, fldType); +} + void MagneticField::CreateField() { /* diff --git a/macro/build_geometry.C b/macro/build_geometry.C index 5628ff0b512fb..60f63e53834ff 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -88,27 +88,7 @@ void build_geometry(FairRunSim* run = nullptr) run->SetMaterials("media.geo"); // Materials // we need a field to properly init the media - int fld = confref.getConfigData().mField, fldAbs = std::abs(fld); - float fldCoeff; - o2::field::MagFieldParam::BMap_t fldType; - switch (fldAbs) { - case 5: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - case 0: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = 0; - break; - case 2: - fldType = o2::field::MagFieldParam::k2kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - default: - LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0"; - }; - - auto field = new o2::field::MagneticField("Maps", "Maps", fldCoeff, fldCoeff, fldType); + auto field = o2::field::MagneticField::createNominalField(confref.getConfigData().mField); run->SetField(field); // Create geometry diff --git a/run/O2PrimaryServerDevice.h b/run/O2PrimaryServerDevice.h index 07d8507b574ad..655b3fae8b815 100644 --- a/run/O2PrimaryServerDevice.h +++ b/run/O2PrimaryServerDevice.h @@ -64,26 +64,7 @@ class O2PrimaryServerDevice final : public FairMQDevice auto& conf = o2::conf::SimConfig::Instance(); // init magnetic field as it might be needed by the generator - int fld = conf.getConfigData().mField, fldAbs = std::abs(fld); - float fldCoeff; - o2::field::MagFieldParam::BMap_t fldType; - switch (fldAbs) { - case 5: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - case 0: - fldType = o2::field::MagFieldParam::k5kG; - fldCoeff = 0; - break; - case 2: - fldType = o2::field::MagFieldParam::k2kG; - fldCoeff = fld > 0 ? 1. : -1; - break; - default: - LOG(FATAL) << "Field option " << fld << " is not supported, use +-2, +-5 or 0"; - }; - auto field = new o2::field::MagneticField("Maps", "Maps", fldCoeff, fldCoeff, fldType); + auto field = o2::field::MagneticField::createNominalField(conf.getConfigData().mField); TGeoGlobalMagField::Instance()->SetField(field); TGeoGlobalMagField::Instance()->Lock(); From 937e1a98cc773b6a1bdb6b124b17327fadc61eac Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 9 Sep 2020 00:24:19 +0200 Subject: [PATCH 38/76] DPL Foundation: use intrinsict for pack element, when available (#4312) --- Framework/Foundation/include/Framework/Pack.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Framework/Foundation/include/Framework/Pack.h b/Framework/Foundation/include/Framework/Pack.h index b8b5f4806a2a0..8e0badcdff474 100644 --- a/Framework/Foundation/include/Framework/Pack.h +++ b/Framework/Foundation/include/Framework/Pack.h @@ -33,6 +33,13 @@ constexpr std::size_t pack_size(pack const&) template struct pack_element; +#ifdef __clang__ +template +struct pack_element> { + using type = __type_pack_element; +}; +#else + // recursive case template struct pack_element> @@ -44,6 +51,7 @@ template struct pack_element<0, pack> { typedef Head type; }; +#endif template using pack_element_t = typename pack_element::type; From 898abc648fa77c527cf3d4f760de84b3907a6d22 Mon Sep 17 00:00:00 2001 From: dsekihat Date: Wed, 9 Sep 2020 17:16:28 +0900 Subject: [PATCH 39/76] update eID (#4314) --- Analysis/Tasks/PWGDQ/dileptonEE.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Analysis/Tasks/PWGDQ/dileptonEE.cxx b/Analysis/Tasks/PWGDQ/dileptonEE.cxx index dcc2afb1dcc2f..9bf806fc14b28 100644 --- a/Analysis/Tasks/PWGDQ/dileptonEE.cxx +++ b/Analysis/Tasks/PWGDQ/dileptonEE.cxx @@ -104,8 +104,13 @@ struct BarrelTrackSelection { cut1->AddCut(VarManager::kTPCchi2, 0.0, 4.0); cut1->AddCut(VarManager::kITSchi2, 0.0, 5.0); cut1->AddCut(VarManager::kITSncls, 3.5, 7.5); - cut1->AddCut(VarManager::kTPCncls, 69.5, 159.5); - cut1->AddCut(VarManager::kTPCsignal, 70, 100, false); //exclude = false + cut1->AddCut(VarManager::kTPCncls, 79.5, 159.5); + cut1->AddCut(VarManager::kTPCsignal, 70, 100, false); //exclude = false + cut1->AddCut(VarManager::kTOFnSigmaEl, -3, +3, false); //exclude = false + + //cut1->AddCut(VarManager::kTPCnSigmaPi, -1e+10, +3.5, true); //exclude = false + //cut1->AddCut(VarManager::kTPCnSigmaKa, -3, +3, true); //exclude = false + //cut1->AddCut(VarManager::kTPCnSigmaPr, -3, +3, true); //exclude = false fTrackCut->AddCut(cut1); // //AnalysisCut* pid_TPChadrej = new AnalysisCut("pid_TPChadrej","PID TPC hadron band rejection"); From 740be0c832f06e9e49ed1a5d628acf0a0c24eefe Mon Sep 17 00:00:00 2001 From: Luca Barioglio Date: Wed, 9 Sep 2020 10:17:18 +0200 Subject: [PATCH 40/76] Add filters to nuclei task (#4311) --- Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx | 26 +++++++++++++++++-- .../include/Framework/AnalysisDataModel.h | 10 ++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx b/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx index 960cc376981b7..902385b40b8dd 100644 --- a/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx +++ b/Analysis/Tasks/PWGLF/NucleiSpectraTask.cxx @@ -22,12 +22,34 @@ using namespace o2::framework::expressions; struct NucleiSpecraTask { - OutputObj hTPCsignal{TH2F("hTPCsignal", ";#it{p} (GeV/#it{c}); d#it{E}/d#it{X} (a. u.)", 600, 0., 3, 1400, 0, 1400)}; + OutputObj hTPCsignal{TH2F("hTPCsignal", ";#it{p} (GeV/#it{c}); d#it{E} / d#it{X} (a. u.)", 600, 0., 3, 1400, 0, 1400)}; OutputObj hMomentum{TH1F("hMomentum", ";#it{p} (GeV/#it{c});", 600, 0., 3.)}; - void process(soa::Join const& tracks) + Configurable absEtaMax{"absEtaMax", 0.8, "pseudo-rapidity edges"}; + Configurable absYmax{"absYmax", 0.5, "rapidity edges"}; + Configurable beamRapidity{"yBeam", 0., "beam rapidity"}; + Configurable chi2TPCperNDF{"chi2TPCperNDF", 4., "chi2 per NDF in TPC"}; + Configurable foundFractionTPC{"foundFractionTPC", 0., "TPC clusters / TPC crossed rows"}; + Configurable recPointsTPC{"recPointsTPC", 0, "clusters in TPC"}; + Configurable signalClustersTPC{"signalClustersTPC", 70, "clusters with PID in TPC"}; + Configurable minEnergyLoss{"minEnergyLoss", 0., "energy loss in TPC"}; + Configurable recPointsITS{"recPointsITS", 2, "number of ITS points"}; + Configurable recPointsITSInnerBarrel{"recPointsITSInnerBarrel", 1, "number of points in ITS Inner Barrel"}; + + Filter etaFilter = aod::track::eta > -1 * absEtaMax&& aod::track::eta < absEtaMax; + Filter chi2Filter = aod::track::tpcChi2NCl < chi2TPCperNDF; + + void process(soa::Filtered> const& tracks) { for (auto& track : tracks) { + // Part not covered by filters + if (track.tpcNClsFound() < recPointsTPC) + continue; + if (track.itsNCls() < recPointsITS) + continue; + if (track.itsNClsInnerBarrel() < recPointsITSInnerBarrel) + continue; + hTPCsignal->Fill(track.p(), track.tpcSignal()); hMomentum->Fill(track.p()); } diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index 8b84781a09d23..e7bb1e6edc148 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -180,6 +180,14 @@ DECLARE_SOA_DYNAMIC_COLUMN(ITSNCls, itsNCls, [](uint8_t itsClusterMap) -> uint8_ itsNcls++; return itsNcls; }); +DECLARE_SOA_DYNAMIC_COLUMN(ITSNClsInnerBarrel, itsNClsInnerBarrel, [](uint8_t itsClusterMap) -> uint8_t { + uint8_t itsNclsInnerBarrel = 0; + constexpr uint8_t bit = 1; + for (int layer = 0; layer < 3; layer++) + if (itsClusterMap & (bit << layer)) + itsNclsInnerBarrel++; + return itsNclsInnerBarrel; +}); DECLARE_SOA_DYNAMIC_COLUMN(TPCCrossedRowsOverFindableCls, tpcCrossedRowsOverFindableCls, [](uint8_t tpcNClsFindable, uint8_t tpcNClsFindableMinusCrossedRows) -> float { @@ -243,7 +251,7 @@ DECLARE_SOA_TABLE(TracksExtra, "AOD", "TRACKEXTRA", track::TPCSignal, track::TRDSignal, track::TOFSignal, track::Length, track::TOFExpMom, track::TPCNClsFound, track::TPCNClsCrossedRows, - track::ITSNCls, + track::ITSNCls, track::ITSNClsInnerBarrel, track::TPCCrossedRowsOverFindableCls, track::TPCFractionSharedCls); From b59767ba9c15b645aecc47246a8eb3359fa0a1fb Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 9 Sep 2020 10:40:24 +0200 Subject: [PATCH 41/76] DPL Analysis: adapt Attach/Extend to new Join (#4307) --- Analysis/Tutorials/src/dynamicColumns.cxx | 4 ++- Analysis/Tutorials/src/extendedColumns.cxx | 4 ++- Framework/Core/include/Framework/ASoA.h | 40 ++++++++++------------ 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Analysis/Tutorials/src/dynamicColumns.cxx b/Analysis/Tutorials/src/dynamicColumns.cxx index e8e2c25eec425..a4c2492d7f443 100644 --- a/Analysis/Tutorials/src/dynamicColumns.cxx +++ b/Analysis/Tutorials/src/dynamicColumns.cxx @@ -28,7 +28,9 @@ struct ATask { auto table_with_extra_dynamic_columns = soa::Attach>(tracks); for (auto& row : table_with_extra_dynamic_columns) { if (row.trackType() != 3) { - LOGF(info, "P^2 = %.3f", row.p2()); + if (row.index() % 100 == 0) { + LOGF(info, "P^2 = %.3f", row.p2()); + } } } } diff --git a/Analysis/Tutorials/src/extendedColumns.cxx b/Analysis/Tutorials/src/extendedColumns.cxx index ad93833eb09d4..7d1ec1185ac41 100644 --- a/Analysis/Tutorials/src/extendedColumns.cxx +++ b/Analysis/Tutorials/src/extendedColumns.cxx @@ -28,7 +28,9 @@ struct ATask { auto table_extension = soa::Extend(tracks); for (auto& row : table_extension) { if (row.trackType() != 3) { - LOGF(info, "P^2 = %.3f", row.p2()); + if (row.index() % 100 == 0) { + LOGF(info, "P^2 = %.3f", row.p2()); + } } } } diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index d4d503fac778e..a059aa12abc21 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -908,10 +908,10 @@ class Table Table(std::shared_ptr table, uint64_t offset = 0) : mTable(table), - mEnd{static_cast(table->num_rows())}, + mEnd{table == nullptr ? 0 : static_cast(table->num_rows())}, mOffset(offset) { - if (mTable->num_rows() == 0) { + if ((mTable == nullptr) or (mTable->num_rows() == 0)) { for (size_t ci = 0; ci < sizeof...(C); ++ci) { mColumnChunks[ci] = nullptr; } @@ -1766,26 +1766,12 @@ auto spawner(framework::pack columns, arrow::Table* atable) chunks[i].emplace_back(v.at(i)); } } - std::array, sizeof...(C)> arrays; + std::vector> arrays; for (auto i = 0u; i < sizeof...(C); ++i) { - arrays[i] = std::make_shared(chunks[i]); + arrays.push_back(std::make_shared(chunks[i])); } - auto new_schema = o2::soa::createSchemaFromColumns(columns); - std::vector> new_columns; - for (auto i = 0u; i < sizeof...(C); ++i) { - new_columns.push_back(arrays[i]); - } - return arrow::Table::Make(new_schema, new_columns); -} - -/// On-the-fly adding of expression columns -template -auto Extend(T const& table) -{ - static_assert((soa::is_type_spawnable_v && ...), "You can only extend a table with expression columns"); - using output_t = JoinBase>; - return output_t{spawner(framework::pack{}, table.asArrowTable().get()), table.offset()}; + return arrow::Table::Make(new_schema, arrays); } /// Template for building an index table to access matching rows from non- @@ -1817,14 +1803,26 @@ struct IndexTable : Table, H, Ts...> { template using is_soa_index_table_t = typename framework::is_base_of_template; +/// On-the-fly adding of expression columns +template +auto Extend(T const& table) +{ + static_assert((soa::is_type_spawnable_v && ...), "You can only extend a table with expression columns"); + using output_t = Join>; + if (table.tableSize() > 0) { + return output_t{{spawner(framework::pack{}, table.asArrowTable().get()), table.asArrowTable()}, 0}; + } + return output_t{{nullptr}, 0}; +} + /// Template function to attach dynamic columns on-the-fly (e.g. inside /// process() function). Dynamic columns need to be compatible with the table. template auto Attach(T const& table) { static_assert((framework::is_base_of_template::value && ...), "You can only attach dynamic columns"); - using output_t = JoinBase>; - return output_t{table.asArrowTable(), table.offset()}; + using output_t = Join>; + return output_t{{table.asArrowTable()}, table.offset()}; } } // namespace o2::soa From e8e149e45eabd346e084c1fa0d82d5b29fd3e8af Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 9 Sep 2020 11:32:14 +0200 Subject: [PATCH 42/76] Add script to merge multiple -ftime-trace outputs. --- scripts/profile-compilation-merge | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 scripts/profile-compilation-merge diff --git a/scripts/profile-compilation-merge b/scripts/profile-compilation-merge new file mode 100755 index 0000000000000..85dadd1cfea4b --- /dev/null +++ b/scripts/profile-compilation-merge @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +"""Combine JSON from multiple -ftime-traces into one. + +scripts/profile-compilation-merge foo.json bar.json. + +results in ./combined.json +""" + +import json +import sys + +if __name__ == '__main__': + start_time = 0 + combined_data = [] + for filename in sys.argv[1:]: + with open(filename, 'r') as f: + file_time = None + for event in json.load(f)['traceEvents']: + # Skip metadata events + # Skip total events + # Filter out shorter events to reduce data size + if event['ph'] == 'M' or \ + event['name'].startswith('Total') or \ + event['dur'] < 5000: + continue + + if event['name'] == 'ExecuteCompiler': + # Find how long this compilation takes + file_time = event['dur'] + # Set the file name in ExecuteCompiler + #event['args']['detail'] = filename + + # Offset start time to make compiles sequential + event['ts'] += start_time + + # Add data to combined + combined_data.append(event) + + # Increase the start time for the next file + # Add 1 to avoid issues with simultaneous events + start_time += file_time + 1 + + with open('combined.json', 'w') as f: + json.dump({'traceEvents': sorted(combined_data, key=lambda k: k['ts'])}, f) From 2b75bf0b061eb1d3d1070de2bf2dd3e43d8a08bf Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 9 Sep 2020 11:33:13 +0200 Subject: [PATCH 43/76] Ignore .clangd folder Cache for Language Server compilations --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6ba91433a67ae..ff8b7c86c8974 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,6 @@ bazel-* # direnv .envrc + +# LSP support on macOS with vim +.clangd From 0712f7ac176ee85e66b9f64697aa848c39d90cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Wed, 9 Sep 2020 12:03:56 +0200 Subject: [PATCH 44/76] Use CCDB headers to get SOR timestamp for run (#4305) - Update timestamp table maker task - Caching requested timestamps for later use - Remove old utilities for Run to Timestamp conversion --- Analysis/Core/CMakeLists.txt | 8 - .../Core/include/Analysis/RunToTimestamp.h | 48 ----- Analysis/Core/src/AnalysisCoreLinkDef.h | 1 - Analysis/Core/src/InsertNewRunToTimestamp.cxx | 103 ----------- Analysis/Core/src/RunToTimestamp.cxx | 60 ------- .../Scripts/insert_Run2_run_to_timestamps.py | 168 ------------------ .../Scripts/inspect_Run2_run_to_timestamps.py | 34 ---- Analysis/Tasks/timestamp.cxx | 68 +++++-- Analysis/Tutorials/src/ccdbaccess.cxx | 1 - 9 files changed, 51 insertions(+), 440 deletions(-) delete mode 100644 Analysis/Core/include/Analysis/RunToTimestamp.h delete mode 100644 Analysis/Core/src/InsertNewRunToTimestamp.cxx delete mode 100644 Analysis/Core/src/RunToTimestamp.cxx delete mode 100755 Analysis/Scripts/insert_Run2_run_to_timestamps.py delete mode 100755 Analysis/Scripts/inspect_Run2_run_to_timestamps.py diff --git a/Analysis/Core/CMakeLists.txt b/Analysis/Core/CMakeLists.txt index 8aeae80d51b5d..03b0393c6029e 100644 --- a/Analysis/Core/CMakeLists.txt +++ b/Analysis/Core/CMakeLists.txt @@ -16,7 +16,6 @@ o2_add_library(AnalysisCore src/HistogramManager.cxx src/AnalysisCut.cxx src/AnalysisCompositeCut.cxx - src/RunToTimestamp.cxx src/TriggerAliases.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel) @@ -28,13 +27,6 @@ o2_target_root_dictionary(AnalysisCore include/Analysis/HistogramManager.h include/Analysis/AnalysisCut.h include/Analysis/AnalysisCompositeCut.h - include/Analysis/RunToTimestamp.h include/Analysis/TriggerAliases.h include/Analysis/MC.h LINKDEF src/AnalysisCoreLinkDef.h) - -o2_add_executable(makerun2timestamp - COMPONENT_NAME AnalysisCore - SOURCES src/InsertNewRunToTimestamp.cxx - PUBLIC_LINK_LIBRARIES O2::AnalysisCore O2::CCDB) - diff --git a/Analysis/Core/include/Analysis/RunToTimestamp.h b/Analysis/Core/include/Analysis/RunToTimestamp.h deleted file mode 100644 index 6dabf861e267e..0000000000000 --- a/Analysis/Core/include/Analysis/RunToTimestamp.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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. - -// -// Class for conversion between run number and timestamp -// -// Author: Nicolo' Jacazio on 2020-06-22 - -#ifndef RunToTimestamp_H -#define RunToTimestamp_H - -#include -#include - -class RunToTimestamp -{ - public: - RunToTimestamp() = default; - ~RunToTimestamp() = default; - - /// Checks if the converter has a particular run - bool Has(unsigned int runNumber) const { return mMap.count(runNumber); } - - /// Inserts a new run with a timestamp in the converter database - bool insert(unsigned int runNumber, long timestamp); - - /// Updates an already present run number with a new timestamp - bool update(unsigned int runNumber, long timestamp); - - /// Gets the timestamp of a run - long getTimestamp(unsigned int runNumber) const; - - /// Prints the content of the converter - void print() const; - - private: - std::map mMap; - ClassDefNV(RunToTimestamp, 1) // converter class between run number and timestamp -}; - -#endif diff --git a/Analysis/Core/src/AnalysisCoreLinkDef.h b/Analysis/Core/src/AnalysisCoreLinkDef.h index b122ef91d96c8..5eac2f6879fa5 100644 --- a/Analysis/Core/src/AnalysisCoreLinkDef.h +++ b/Analysis/Core/src/AnalysisCoreLinkDef.h @@ -18,7 +18,6 @@ #pragma link C++ typedef StepTHnF; #pragma link C++ typedef StepTHnD; -#pragma link C++ class RunToTimestamp+; #pragma link C++ class CorrelationContainer+; #pragma link C++ class TrackSelection+; #pragma link C++ class TriggerAliases+; diff --git a/Analysis/Core/src/InsertNewRunToTimestamp.cxx b/Analysis/Core/src/InsertNewRunToTimestamp.cxx deleted file mode 100644 index ae00495e2d14a..0000000000000 --- a/Analysis/Core/src/InsertNewRunToTimestamp.cxx +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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. - -// -// A simple tool to produce objects for the conversion from run number to timestamp. -// The tool uploads the 'RunNumber -> timestamp' converter to CCDB. -// If no converter object is found in CCDB a new one is created and uploaded. -// -// Author: Nicolo' Jacazio on 2020-06-22 - -#include "Analysis/RunToTimestamp.h" -#include "CCDB/CcdbApi.h" -#include -#include - -namespace bpo = boost::program_options; - -bool initOptionsAndParse(bpo::options_description& options, int argc, char* argv[], bpo::variables_map& vm) -{ - options.add_options()( - "run,r", bpo::value()->required(), "Run number to use")( - "timestamp,t", bpo::value()->required(), "Timestamp to use equivalent to the run number")( - "path,p", bpo::value()->default_value("Analysis/Core/RunToTimestamp"), "Path to the object in the CCDB repository")( - "url,u", bpo::value()->default_value("http://ccdb-test.cern.ch:8080"), "URL of the CCDB database")( - "start,s", bpo::value()->default_value(0), "Start timestamp of object validity")( - "stop,S", bpo::value()->default_value(4108971600000), "Stop timestamp of object validity")( - "update,u", bpo::value()->default_value(0), "Flag to update the object instead of inserting the new timestamp")( - "delete_previous,d", bpo::value()->default_value(0), "Flag to delete previous versions of converter objects in the CCDB before uploading the new one so as to avoid proliferation on CCDB")( - "verbose,v", bpo::value()->default_value(0), "Verbose level 0, 1")( - "help,h", "Produce help message."); - - try { - bpo::store(parse_command_line(argc, argv, options), vm); - - // help - if (vm.count("help")) { - LOG(INFO) << options; - return false; - } - - bpo::notify(vm); - } catch (const bpo::error& e) { - LOG(ERROR) << e.what() << "\n"; - LOG(ERROR) << "Error parsing command line arguments; Available options:"; - LOG(ERROR) << options; - return false; - } - return true; -} - -int main(int argc, char* argv[]) -{ - bpo::options_description options("Allowed options"); - bpo::variables_map vm; - if (!initOptionsAndParse(options, argc, argv, vm)) { - return 1; - } - - o2::ccdb::CcdbApi api; - const std::string url = vm["url"].as(); - api.init(url); - if (!api.isHostReachable()) { - LOG(WARNING) << "CCDB host " << url << " is not reacheable, cannot go forward"; - return 1; - } - - std::string path = vm["path"].as(); - std::map metadata; - std::map* headers; - long start = vm["start"].as(); - long stop = vm["stop"].as(); - - RunToTimestamp* converter = api.retrieveFromTFileAny(path, metadata, -1, headers); - - if (!converter) { - LOG(INFO) << "Did not retrieve run number to timestamp converter, creating a new one!"; - converter = new RunToTimestamp(); - } else { - LOG(INFO) << "Retrieved run number to timestamp converter from ccdb url " << url; - } - if (vm["delete_previous"].as()) { - api.truncate(path); - } - - if (vm["update"].as()) - converter->update(vm["run"].as(), vm["timestamp"].as()); - else - converter->insert(vm["run"].as(), vm["timestamp"].as()); - - if (vm["verbose"].as()) - converter->print(); - - api.storeAsTFileAny(converter, path, metadata, start, stop); - - return 0; -} diff --git a/Analysis/Core/src/RunToTimestamp.cxx b/Analysis/Core/src/RunToTimestamp.cxx deleted file mode 100644 index dffff7b63c04d..0000000000000 --- a/Analysis/Core/src/RunToTimestamp.cxx +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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. - -// -// Class for conversion between run number and timestamp -// -// Author: Nicolo' Jacazio on 2020-06-22 - -#include "Analysis/RunToTimestamp.h" -#include - -ClassImp(RunToTimestamp); - -bool RunToTimestamp::insert(unsigned int runNumber, long timestamp) -{ - std::pair::iterator, bool> check; - check = mMap.insert(std::pair(runNumber, timestamp)); - if (!check.second) { - LOG(FATAL) << "Run number " << runNumber << " already existed with a timestamp of " << check.first->second; - return false; - } - LOG(INFO) << "Add new run " << runNumber << " with timestamp " << timestamp << " to converter"; - return true; -} - -bool RunToTimestamp::update(unsigned int runNumber, long timestamp) -{ - if (!Has(runNumber)) { - LOG(FATAL) << "Run to Timestamp converter does not have run " << runNumber << ", cannot update converter"; - return false; - } - mMap[runNumber] = timestamp; - return true; -} - -long RunToTimestamp::getTimestamp(unsigned int runNumber) const -{ - if (!Has(runNumber)) { - LOG(ERROR) << "Run to Timestamp converter does not have run " << runNumber; - return 0; - } - return mMap.at(runNumber); -} - -void RunToTimestamp::print() const -{ - LOG(INFO) << "Printing run number -> timestamp conversion"; - int counter = 0; - for (auto e : mMap) { - LOG(INFO) << "Entry #" << counter++ << " has run number: " << e.first << " and timestamp: " << e.second; - } - LOG(INFO) << "Total number of runs in converter: " << mMap.size(); -} diff --git a/Analysis/Scripts/insert_Run2_run_to_timestamps.py b/Analysis/Scripts/insert_Run2_run_to_timestamps.py deleted file mode 100755 index 227f047635a75..0000000000000 --- a/Analysis/Scripts/insert_Run2_run_to_timestamps.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# 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. - -""" -Script update the CCDB with run number to timestamp conversion objects. -This is intended to define timestamps for Run2 converted data. -This script works in tandem with `AliRoot/STEER/macros/GetStartAndEndOfRunTimestamp.C`. -The input format is the same as the output of such macro. -Author: Nicolo' Jacazio on 2020-06-30 -""" - -import argparse -import subprocess - - -class run_timestamp: - run = 0 - start = 0 - stop = 0 - - def __init__(self, run, start, stop): - self.run = run - self.start = start - self.stop = stop - self.check() - - def check(self): - """ - Function to check integrity of timestamp - """ - if self.start > self.stop: - raise ValueError("start > stop", self.start, self.stop) - if self.start == 0: - raise ValueError("start is zero") - if self.stop == 0: - raise ValueError("stop is zero") - - def check_if_int(number, name): - """ - Function to check if a timestamp is an integer - """ - if not isinstance(number, int): - raise ValueError( - f"{name} '{number}' is not an integer but a '{type(number)}'") - check_if_int(self.run, "run") - check_if_int(self.start, "start") - check_if_int(self.stop, "stop") - - def check_if_milliseconds(number, name): - """ - Function to check if a timestamp is in milliseconds - """ - if not len(str(number)) == 13: - raise ValueError(f"{name} '{number}' is not in milliseconds") - check_if_milliseconds(self.start, "start") - check_if_milliseconds(self.stop, "stop") - - def __str__(self): - return f"Run {self.run} start {self.start} stop {self.stop}" - - def __eq__(self, other): - return self.run == other.run - - -def main(input_file_name, extra_args, - input_in_seconds=False, delete_previous=True, verbose=False): - """ - Given an input file with line by line runs and start and stop timestamps it updates the dedicated CCDB object. - Extra arguments can be passed to the upload script. - input_in_seconds set to True converts the input from seconds ti milliseconds. - delete_previous deletes previous uploads in the same path so as to avoid proliferation on CCDB - verbose flag can be set to 1, 2 to increase the debug level - URL of ccdb and PATH of objects are passed as default arguments - """ - infile = open(input_file_name) - if verbose: - print(f"Reading run to timestamp from input file '{input_file_name}'") - run_list = [] - for line_no, i in enumerate(infile): - i = i.strip() - if len(i) <= 1: - continue - if verbose >= 2: - print(f"Line number {line_no}: {i}") - i = i.split() - run = i[1] - if not run.isdigit(): - raise ValueError("Read run is not a number", run) - start = i[4] - if not start.isdigit(): - raise ValueError("Read start is not a number", start) - stop = i[8] - if not stop.isdigit(): - raise ValueError("Read stop is not a number", stop) - if input_in_seconds: - if verbose: - print( - f"Converting input timestamps start '{start}' and stop '{stop}' from seconds to milliseconds") - start = f"{start}000" - stop = f"{stop}000" - entry = run_timestamp(int(run), int(start), int(stop)) - if entry not in run_list: - run_list.append(entry) - print("Will set converter for", len(run_list), "runs") - successfull = [] - failed = [] - for i in run_list: - print("Setting run", i) - cmd = "o2-analysiscore-makerun2timestamp" - cmd += f" --run {i.run}" - cmd += f" --timestamp {i.start}" - if delete_previous: - cmd += f" --delete_previous 1" - cmd += f" {extra_args}" - if i == run_list[-1]: - # Printing the status of the converter as a last step - cmd += " -v 1" - if verbose: - print(cmd) - process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - output = output.decode("utf-8") - if verbose: - print(output) - if "[FATAL] " in output: - failed.append(i.run) - else: - successfull.append(i.run) - - def print_status(counter, msg): - if len(counter) > 0: - print(len(counter), msg) - if verbose >= 3: - print("Runs:", counter) - - print_status(successfull, "successfully uploaded new runs") - print_status( - failed, "failed uploads, retry with option '-vvv' for mor info") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description='Uploads run-number-to-timestamp converter to CCDB from input file.') - parser.add_argument('input_file_name', metavar='input_file_name', type=str, - help='Name of the file with the run and corresponding timestamps') - parser.add_argument('--extra_args', metavar='Extra_Arguments', type=str, - default="", - help='Extra arguments for the upload to CCDB. E.g. for the update of the object --extra_args " --update 1"') - parser.add_argument('--input_in_seconds', '-s', action='count', default=0, - help="Use if timestamps taken from input are in seconds") - parser.add_argument('--delete_previous', '-d', action='count', - default=0, help="Deletes previous uploads in the same path so as to avoid proliferation on CCDB") - parser.add_argument('--verbose', '-v', action='count', - default=0, help="Verbose mode 0, 1, 2") - args = parser.parse_args() - main(input_file_name=args.input_file_name, - extra_args=args.extra_args, - input_in_seconds=args.input_in_seconds, - verbose=args.verbose) diff --git a/Analysis/Scripts/inspect_Run2_run_to_timestamps.py b/Analysis/Scripts/inspect_Run2_run_to_timestamps.py deleted file mode 100755 index dbc34abae02ec..0000000000000 --- a/Analysis/Scripts/inspect_Run2_run_to_timestamps.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright CERN and copyright holders of ALICE O2. This software is -# distributed under the terms of the GNU General Public License v3 (GPL -# Version 3), copied verbatim in the file "COPYING". -# -# See http://alice-o2.web.cern.ch/license for full licensing information. -# -# 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. - -""" -Script inspect the CCDB object with run number to timestamp conversion. -Author: Nicolo' Jacazio on 2020-07-08 -""" - -from update_ccdb import get_ccdb_obj -from ROOT import TFile - - -def main(converter_ccdb_path="Analysis/Core/RunToTimestamp", dest="/tmp/", verbose=0): - """ - Given a path in the CCDB downloads the timestamp converte object and inspects it - """ - get_ccdb_obj(converter_ccdb_path, -1, dest=dest, verbose=1) - obj_file = TFile(f"{dest}/{converter_ccdb_path}/snapshot.root", "READ") - obj_file.ls() - obj = obj_file.Get("ccdb_object") - obj.print() - - -if __name__ == "__main__": - main() diff --git a/Analysis/Tasks/timestamp.cxx b/Analysis/Tasks/timestamp.cxx index 496baa443bc1a..83708c8681ddc 100644 --- a/Analysis/Tasks/timestamp.cxx +++ b/Analysis/Tasks/timestamp.cxx @@ -10,55 +10,89 @@ // // A task to fill the timestamp table from run number. -// Uses RunToTimestamp object from CCDB, fails if not available. +// Uses headers from CCDB // // Author: Nicolo' Jacazio on 2020-06-22 #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" -#include "Analysis/RunToTimestamp.h" #include #include "CommonDataFormat/InteractionRecord.h" #include "DetectorsRaw/HBFUtils.h" #include + using namespace o2::framework; using namespace o2::header; using namespace o2; struct TimestampTask { - Produces ts_table; - RunToTimestamp* converter = nullptr; - std::map* mapStartOrbit = nullptr; - Service ccdb; - Configurable path{"ccdb-path", "Analysis/Core/RunToTimestamp", "path to the ccdb object"}; - Configurable timestamp{"ccdb-timestamp", -1, "timestamp of the object"}; + Produces ts_table; /// Table with SOR timestamps produced by the task + Service ccdb; /// Object manager in CCDB + o2::ccdb::CcdbApi api; /// API to access CCDB + std::map* mapStartOrbit = nullptr; /// Map of the starting orbit for the run + std::pair lastCall; /// Last run number processed and its timestamp, needed for caching + std::map mapRunToTimestamp; /// Cache of processed run numbers + + // Configurables + Configurable verbose{"verbose", false, "verbose mode"}; + Configurable path{"ccdb-path", "RCT/RunInformation/", "path to the ccdb object"}; + Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "URL of the CCDB database"}; void init(o2::framework::InitContext&) { LOGF(info, "Initializing TimestampTask"); - converter = ccdb->get(path.value); - if (converter) { - LOGF(info, "Run-number to timestamp converter found!"); - } else { - LOGF(fatal, "Cannot find run-number to timestamp converter in path '%s'.", path.value.data()); - } mapStartOrbit = ccdb->get>("Trigger/StartOrbit"); if (!mapStartOrbit) { LOGF(fatal, "Cannot find map of SOR orbits in CCDB in path Trigger/StartOrbit"); } + api.init(url.value); + if (!api.isHostReachable()) { + LOGF(fatal, "CCDB host %s is not reacheable, cannot go forward", url.value.data()); + } } void process(aod::BC const& bc) { - long timestamp = converter->getTimestamp(bc.runNumber()); + long ts = 0; + if (bc.runNumber() == lastCall.first) { // The run number coincides to the last run processed + LOGF(debug, "Getting timestamp from last call"); + ts = lastCall.second; + } else if (mapRunToTimestamp.count(bc.runNumber())) { // The run number was already requested before: getting it from cache! + LOGF(debug, "Getting timestamp from cache"); + ts = mapRunToTimestamp[bc.runNumber()]; + } else { // The run was not requested before: need to acccess CCDB! + LOGF(debug, "Getting timestamp from CCDB"); + std::map metadata, headers; + const std::string run_path = Form("%s/%i", path.value.data(), bc.runNumber()); + headers = api.retrieveHeaders(run_path, metadata, -1); + if (headers.count("SOR") == 0) { + LOGF(fatal, "Cannot find run-number to timestamp in path '%s'.", run_path.data()); + } + ts = atol(headers["SOR"].c_str()); // timestamp of the SOR in ms + + // Adding the timestamp to the cache map + std::pair::iterator, bool> check; + check = mapRunToTimestamp.insert(std::pair(bc.runNumber(), ts)); + if (!check.second) { + LOGF(fatal, "Run number %i already existed with a timestamp of %llu", bc.runNumber(), check.first->second); + } + LOGF(info, "Add new run %i with timestamp %llu to cache", bc.runNumber(), ts); + } + + // Setting latest run information + lastCall = std::make_pair(bc.runNumber(), ts); + + if (verbose.value) { + LOGF(info, "Run-number to timestamp found! %i %llu ms", bc.runNumber(), ts); + } uint16_t currentBC = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; uint32_t currentOrbit = bc.globalBC() / o2::constants::lhc::LHCMaxBunches; uint16_t initialBC = 0; // exact bc number not relevant due to ms precision of timestamps uint32_t initialOrbit = mapStartOrbit->at(bc.runNumber()); InteractionRecord current(currentBC, currentOrbit); InteractionRecord initial(initialBC, initialOrbit); - timestamp += (current - initial).bc2ns() / 1000000; - ts_table(timestamp); + ts += (current - initial).bc2ns() / 1000000; + ts_table(ts); } }; diff --git a/Analysis/Tutorials/src/ccdbaccess.cxx b/Analysis/Tutorials/src/ccdbaccess.cxx index 5c9036542f3fc..2061a23532a79 100644 --- a/Analysis/Tutorials/src/ccdbaccess.cxx +++ b/Analysis/Tutorials/src/ccdbaccess.cxx @@ -15,7 +15,6 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" -#include "Analysis/RunToTimestamp.h" #include #include "CommonDataFormat/InteractionRecord.h" From f434bc728223f8b91d64332778488634379ef55f Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 9 Sep 2020 01:20:03 +0200 Subject: [PATCH 45/76] Base class for compact index with provenance and flags info --- DataFormats/common/CMakeLists.txt | 3 +- .../include/CommonDataFormat/AbstractRef.h | 82 +++++++++++++++++++ .../common/src/CommonDataFormatLinkDef.h | 2 + 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 DataFormats/common/include/CommonDataFormat/AbstractRef.h diff --git a/DataFormats/common/CMakeLists.txt b/DataFormats/common/CMakeLists.txt index df5fd75cac3fb..1a1e512672fa0 100644 --- a/DataFormats/common/CMakeLists.txt +++ b/DataFormats/common/CMakeLists.txt @@ -18,7 +18,8 @@ o2_target_root_dictionary(CommonDataFormat include/CommonDataFormat/EvIndex.h include/CommonDataFormat/RangeReference.h include/CommonDataFormat/InteractionRecord.h - include/CommonDataFormat/BunchFilling.h) + include/CommonDataFormat/BunchFilling.h + include/CommonDataFormat/AbstractRef.h) o2_add_test(TimeStamp SOURCES test/testTimeStamp.cxx diff --git a/DataFormats/common/include/CommonDataFormat/AbstractRef.h b/DataFormats/common/include/CommonDataFormat/AbstractRef.h new file mode 100644 index 0000000000000..fbfc95d49d213 --- /dev/null +++ b/DataFormats/common/include/CommonDataFormat/AbstractRef.h @@ -0,0 +1,82 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 AbstractRef.h +/// \brief Class to refer to object indicating its Indec, Source and status flags +/// \author ruben.shahoyan@cern.ch + +#ifndef ALICEO2_ABSTRACT_REF_H +#define ALICEO2_ABSTRACT_REF_H + +#include + +namespace o2 +{ +namespace dataformats +{ + +template +class AbstractRef +{ + template + static constexpr auto MVAR() + { + typename std::conditional<(NBIT > 32), uint64_t, typename std::conditional<(NBIT > 16), uint32_t, typename std::conditional<(NBIT > 8), uint16_t, uint8_t>::type>::type>::type tp = 0; + return tp; + } + + public: + using Base_t = decltype(AbstractRef::MVAR()); + using Idx_t = decltype(AbstractRef::MVAR()); + using Src_t = decltype(AbstractRef::MVAR()); + using Flg_t = decltype(AbstractRef::MVAR()); + + static constexpr Base_t BaseMask = Base_t((((0x1U << (NBIdx + NBSrc + NBFlg - 1)) - 1) << 1) + 1); + static constexpr Idx_t IdxMask = Idx_t((((0x1U << (NBIdx - 1)) - 1) << 1) + 1); + static constexpr Src_t SrcMask = Src_t((((0x1U << (NBSrc - 1)) - 1) << 1) + 1); + static constexpr Flg_t FlgMask = Flg_t((((0x1U << (NBFlg - 1)) - 1) << 1) + 1); + static constexpr int NBitsIndex() { return NBIdx; } + static constexpr int NBitsSource() { return NBSrc; } + static constexpr int NBitsFlags() { return NBFlg; } + + AbstractRef() = default; + + AbstractRef(Idx_t idx) { setIndex(idx); } + + AbstractRef(Idx_t idx, Src_t src) { set(idx, src); } + + // + Idx_t getIndex() const { return static_cast(mRef & IdxMask); } + void setIndex(Idx_t idx) { mRef = (mRef & (BaseMask & ~IdxMask)) | (IdxMask & idx); } + + // + Src_t getSource() const { return static_cast((mRef >> NBIdx) & SrcMask); } + void setSource(Src_t src) { mRef = (mRef & (BaseMask & ~(SrcMask << NBIdx))) | ((SrcMask & src) << NBIdx); } + + // + Flg_t getFlags() const { return static_cast((mRef >> (NBIdx + NBSrc)) & FlgMask); } + void setFlags(Flg_t f) { mRef = (mRef & (BaseMask & ~(FlgMask << (NBIdx + NBSrc)))) | ((FlgMask & f) << NBIdx); } + bool testBit(int i) const { return (mRef >> (NBIdx + NBSrc)) & ((0x1U << i) & FlgMask); } + void setBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))) | (((0x1U << i) & FlgMask) << (NBIdx + NBSrc)); } + void resetBit(int i) { mRef = (mRef & (BaseMask & ~(0x1U << (i + NBIdx + NBSrc)))); } + void set(Idx_t idx, Src_t src) { mRef = (mRef & (BaseMask & ~((SrcMask << NBIdx) | (BaseMask & ~IdxMask)))) | ((SrcMask & Src_t(src)) << NBIdx) | (IdxMask & Idx_t(idx)); } + + Base_t getRaw() const { return mRef; } + + protected: + Base_t mRef = 0; // packed reference + + ClassDefNV(AbstractRef, 1); +}; + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/DataFormats/common/src/CommonDataFormatLinkDef.h b/DataFormats/common/src/CommonDataFormatLinkDef.h index 269fb2c5433b2..502697b733e6d 100644 --- a/DataFormats/common/src/CommonDataFormatLinkDef.h +++ b/DataFormats/common/src/CommonDataFormatLinkDef.h @@ -46,4 +46,6 @@ #pragma link C++ class o2::InteractionTimeRecord + ; #pragma link C++ class o2::BunchFilling + ; +#pragma link C++ class o2::dataformats::AbstractRef < 26, 3, 3> + ; + #endif From b7a2f3ea2006e8e4bab716c41a6703866784eb6f Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 9 Sep 2020 01:20:25 +0200 Subject: [PATCH 46/76] Global track index for vertex->track reference --- DataFormats/Reconstruction/CMakeLists.txt | 4 +- .../ReconstructionDataFormats/VtxTrackIndex.h | 51 +++++++++++++++++++ .../src/ReconstructionDataFormatsLinkDef.h | 3 ++ .../Reconstruction/src/VtxTrackIndex.cxx | 39 ++++++++++++++ 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h create mode 100644 DataFormats/Reconstruction/src/VtxTrackIndex.cxx diff --git a/DataFormats/Reconstruction/CMakeLists.txt b/DataFormats/Reconstruction/CMakeLists.txt index 5ba2f75d63cf1..578ceb660a0dd 100644 --- a/DataFormats/Reconstruction/CMakeLists.txt +++ b/DataFormats/Reconstruction/CMakeLists.txt @@ -19,6 +19,7 @@ o2_add_library(ReconstructionDataFormats src/TrackLTIntegral.cxx src/PID.cxx src/DCA.cxx + src/VtxTrackIndex.cxx PUBLIC_LINK_LIBRARIES O2::GPUCommon O2::DetectorsCommonDataFormats O2::CommonDataFormat) @@ -34,7 +35,8 @@ o2_target_root_dictionary( include/ReconstructionDataFormats/MatchInfoTOF.h include/ReconstructionDataFormats/TrackLTIntegral.h include/ReconstructionDataFormats/PID.h - include/ReconstructionDataFormats/DCA.h) + include/ReconstructionDataFormats/DCA.h + include/ReconstructionDataFormats/VtxTrackIndex.h) o2_add_test(Vertex SOURCES test/testVertex.cxx diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h new file mode 100644 index 0000000000000..0088c489e574f --- /dev/null +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h @@ -0,0 +1,51 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 VtxTrackIndex.h +/// \brief Index of track attached to vertx: index in its proper container, container source and flags +/// \author ruben.shahoyan@cern.ch + +#include "CommonDataFormat/AbstractRef.h" +#include +#include + +namespace o2 +{ +namespace dataformats +{ + +class VtxTrackIndex : public AbstractRef<26, 3, 3> +{ + public: + enum Source : uint8_t { // provenance of the track + TPCITS, + ITS, + TPC, + NSources + }; + enum Flags : uint8_t { + Contributor, // flag that it contributes to vertex fit + Attached, // flag that it is attached w/o contributing + Ambiguous, // flag that attachment is ambiguous + NFlags + }; + + using AbstractRef<26, 3, 3>::AbstractRef; + + void print() const; + std::string asString() const; + + ClassDefNV(VtxTrackIndex, 1); +}; + +std::ostream& operator<<(std::ostream& os, const o2::dataformats::VtxTrackIndex& v); + +} // namespace dataformats +} // namespace o2 diff --git a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h index 8016fc3888756..1cf45dcc23905 100644 --- a/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h +++ b/DataFormats/Reconstruction/src/ReconstructionDataFormatsLinkDef.h @@ -41,6 +41,9 @@ #pragma link C++ class std::vector < o2::dataformats::Vertex < o2::dataformats::TimeStampWithError < float, float>>> + ; #pragma link C++ class std::vector < o2::dataformats::PrimaryVertex> + ; +#pragma link C++ class o2::dataformats::VtxTrackIndex + ; +#pragma link C++ class std::vector < o2::dataformats::VtxTrackIndex> + ; + #pragma link C++ class o2::dataformats::DCA + ; #endif diff --git a/DataFormats/Reconstruction/src/VtxTrackIndex.cxx b/DataFormats/Reconstruction/src/VtxTrackIndex.cxx new file mode 100644 index 0000000000000..62d0b39905443 --- /dev/null +++ b/DataFormats/Reconstruction/src/VtxTrackIndex.cxx @@ -0,0 +1,39 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 VtxTrackIndex.h +/// \brief Index of track attached to vertx: index in its proper container, container source and flags +/// \author ruben.shahoyan@cern.ch + +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "Framework/Logger.h" +#include +#include +#include + +using namespace o2::dataformats; + +std::string VtxTrackIndex::asString() const +{ + std::bitset bits{getFlags()}; + return fmt::format("[{:d}/{:d}/{:s}]", getIndex(), getSource(), bits.to_string()); +} + +std::ostream& operator<<(std::ostream& os, const o2::dataformats::VtxTrackIndex& v) +{ + // stream itself + os << v.asString(); + return os; +} + +void VtxTrackIndex::print() const +{ + LOG(INFO) << asString(); +} From 0440ac25534a2f28a2ab560d9cc82f57adb8f3d8 Mon Sep 17 00:00:00 2001 From: Evgeny Kryshen Date: Wed, 9 Sep 2020 20:25:43 +0200 Subject: [PATCH 47/76] Event selection adapted to MC (#4319) --- Analysis/Tasks/eventSelection.cxx | 7 +++++++ Analysis/Tasks/eventSelectionQa.cxx | 4 +++- Analysis/Tasks/timestamp.cxx | 5 +++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Analysis/Tasks/eventSelection.cxx b/Analysis/Tasks/eventSelection.cxx index b48adecd40b24..15ccf4cf87bcb 100644 --- a/Analysis/Tasks/eventSelection.cxx +++ b/Analysis/Tasks/eventSelection.cxx @@ -55,6 +55,8 @@ struct EvSelParameters { struct EventSelectionTask { Produces evsel; Service ccdb; + Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; + EvSelParameters par; aod::Run2V0 getVZero(aod::BC const& bc, aod::Run2V0s const& vzeros) @@ -138,6 +140,11 @@ struct EventSelectionTask { bool bgFDA = timeFDA > par.fFDABGlower && timeFDA < par.fFDABGupper; bool bgFDC = timeFDC > par.fFDCBGlower && timeFDC < par.fFDCBGupper; + if (isMC) { + bbZNA = 1; + bbZNC = 1; + } + // Fill event selection columns evsel(alias, bbV0A, bbV0C, bgV0A, bgV0C, bbZNA, bbZNC, bbFDA, bbFDC, bgFDA, bgFDC); } diff --git a/Analysis/Tasks/eventSelectionQa.cxx b/Analysis/Tasks/eventSelectionQa.cxx index 599a235c6b90f..fdbb8eaef6459 100644 --- a/Analysis/Tasks/eventSelectionQa.cxx +++ b/Analysis/Tasks/eventSelectionQa.cxx @@ -56,9 +56,11 @@ struct EventSelectionTask { OutputObj hTimeFDAacc{TH1F("hTimeFDAacc", "", 1000, -100., 100.)}; OutputObj hTimeFDCacc{TH1F("hTimeFDCacc", "", 1000, -100., 100.)}; + Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; + void process(soa::Join::iterator const& col, aod::BCs const& bcs, aod::Zdcs const& zdcs, aod::Run2V0s const& vzeros, aod::FDDs fdds) { - if (!col.alias()[kINT7]) + if (!isMC && !col.alias()[kINT7]) return; auto vzero = getVZero(col.bc(), vzeros); diff --git a/Analysis/Tasks/timestamp.cxx b/Analysis/Tasks/timestamp.cxx index 83708c8681ddc..79d823ed5e21b 100644 --- a/Analysis/Tasks/timestamp.cxx +++ b/Analysis/Tasks/timestamp.cxx @@ -37,6 +37,7 @@ struct TimestampTask { Configurable verbose{"verbose", false, "verbose mode"}; Configurable path{"ccdb-path", "RCT/RunInformation/", "path to the ccdb object"}; Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "URL of the CCDB database"}; + Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; void init(o2::framework::InitContext&) { @@ -85,10 +86,10 @@ struct TimestampTask { if (verbose.value) { LOGF(info, "Run-number to timestamp found! %i %llu ms", bc.runNumber(), ts); } - uint16_t currentBC = bc.globalBC() % o2::constants::lhc::LHCMaxBunches; - uint32_t currentOrbit = bc.globalBC() / o2::constants::lhc::LHCMaxBunches; uint16_t initialBC = 0; // exact bc number not relevant due to ms precision of timestamps uint32_t initialOrbit = mapStartOrbit->at(bc.runNumber()); + uint16_t currentBC = isMC ? initialBC : bc.globalBC() % o2::constants::lhc::LHCMaxBunches; + uint32_t currentOrbit = isMC ? initialOrbit : bc.globalBC() / o2::constants::lhc::LHCMaxBunches; InteractionRecord current(currentBC, currentOrbit); InteractionRecord initial(initialBC, initialOrbit); ts += (current - initial).bc2ns() / 1000000; From ef09f9f23ffab8606877f937c205be72e4398d43 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 9 Sep 2020 11:26:14 +0200 Subject: [PATCH 48/76] DPL Analysis: move ROOT helpers in a separate file --- .../Core/include/Framework/AnalysisHelpers.h | 19 ----------- .../include/Framework/RootAnalysisHelpers.h | 32 +++++++++++++++++++ Framework/TestWorkflows/src/o2D0Analysis.cxx | 1 + .../src/o2SimpleTracksAnalysis.cxx | 1 + 4 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 Framework/Core/include/Framework/RootAnalysisHelpers.h diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 8d4c3c03b77fd..9a62b86cac9da 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -529,23 +529,4 @@ struct Partition { } // namespace o2::framework -namespace o2 -{ -namespace analysis -{ - -/// Do a single loop on all the entries of the @a input table -ROOT::RDataFrame doSingleLoopOn(std::unique_ptr& input); - -/// Do a double loop on all the entries with the same value for the \a grouping -/// of the @a input table, where the entries for the outer index are prefixed -/// with `_` while the entries for the inner loop are prefixed with -/// `bar_`. -ROOT::RDataFrame doSelfCombinationsWith(std::unique_ptr& input, - std::string name = "p", - std::string grouping = "eventID"); - -} // namespace analysis -} // namespace o2 - #endif // o2_framework_AnalysisHelpers_H_DEFINED diff --git a/Framework/Core/include/Framework/RootAnalysisHelpers.h b/Framework/Core/include/Framework/RootAnalysisHelpers.h new file mode 100644 index 0000000000000..7341d330b736f --- /dev/null +++ b/Framework/Core/include/Framework/RootAnalysisHelpers.h @@ -0,0 +1,32 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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_FRAMEWORK_ROOTANALYSISHELPERS_H_ +#define O2_FRAMEWORK_ROOTANALYSISHELPERS_H_ + +#include "Framework/TableConsumer.h" +#include + +namespace o2::analysis +{ + +/// Do a single loop on all the entries of the @a input table +ROOT::RDataFrame doSingleLoopOn(std::unique_ptr& input); + +/// Do a double loop on all the entries with the same value for the \a grouping +/// of the @a input table, where the entries for the outer index are prefixed +/// with `_` while the entries for the inner loop are prefixed with +/// `bar_`. +ROOT::RDataFrame doSelfCombinationsWith(std::unique_ptr& input, + std::string name = "p", + std::string grouping = "eventID"); + +} // namespace o2::analysis + +#endif // O2_FRAMEWORK_ROOTANALYSISHELPERS_H_ diff --git a/Framework/TestWorkflows/src/o2D0Analysis.cxx b/Framework/TestWorkflows/src/o2D0Analysis.cxx index 393dcc20e7fa7..728f3ca50a35a 100644 --- a/Framework/TestWorkflows/src/o2D0Analysis.cxx +++ b/Framework/TestWorkflows/src/o2D0Analysis.cxx @@ -9,6 +9,7 @@ // or submit itself to any jurisdiction. #include "Framework/runDataProcessing.h" #include "Framework/AnalysisHelpers.h" +#include "Framework/RootAnalysisHelpers.h" #include diff --git a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx index f19c808aa221b..d42924ae64095 100644 --- a/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx +++ b/Framework/TestWorkflows/src/o2SimpleTracksAnalysis.cxx @@ -9,6 +9,7 @@ // or submit itself to any jurisdiction. #include "Framework/runDataProcessing.h" #include "Framework/AnalysisHelpers.h" +#include "Framework/RootAnalysisHelpers.h" #include "Framework/TableBuilder.h" #include "Framework/AnalysisDataModel.h" From c31bffd923a4fd35cd1e92fff5d5a08db9f17e30 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 9 Sep 2020 16:08:48 +0200 Subject: [PATCH 49/76] Fix: protection for processing empty sector --- GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx index 4beb572999aff..8af28459db03c 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.cxx @@ -88,6 +88,9 @@ GPUdii() void GPUTPCCFChargeMapFiller::Thread Date: Thu, 10 Sep 2020 08:21:26 +0200 Subject: [PATCH 50/76] DPL Foundation: speedup has_type_at (#4315) Use multiple inheritance rather than recursion to speedup compilation and hopefully reduce memory usage. --- Framework/Core/include/Framework/ASoA.h | 4 +-- .../Core/include/Framework/AnalysisHelpers.h | 10 +++--- .../Core/include/Framework/AnalysisTask.h | 28 +++++++-------- Framework/Foundation/include/Framework/Pack.h | 36 +++++++++++++++++++ 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index a059aa12abc21..01073b2ed94df 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -629,7 +629,7 @@ struct RowViewCore : public IP, C... { RowViewCore(arrow::ChunkedArray* columnData[sizeof...(C)], IP&& policy) : IP{policy}, - C(columnData[framework::has_type_at(all_columns{})])... + C(columnData[framework::has_type_at_v(all_columns{})])... { bindIterators(persistent_columns_t{}); bindAllDynamicColumns(dynamic_columns_t{}); @@ -862,7 +862,7 @@ class Table auto getId() const { if constexpr (framework::has_type_v, bindings_pack_t>) { - constexpr auto idx = framework::has_type_at>(bindings_pack_t{}); + constexpr auto idx = framework::has_type_at_v>(bindings_pack_t{}); return framework::pack_element_t::getId(); } else if constexpr (std::is_same_v, Parent>) { return this->globalIndex(); diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 9a62b86cac9da..8b1e5ca59026b 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -219,7 +219,7 @@ struct IndexExclusive { int32_t idx = -1; auto setValue = [&](auto& x) -> bool { using type = std::decay_t; - constexpr auto position = framework::has_type_at(rest_it_t{}); + constexpr auto position = framework::has_type_at_v(rest_it_t{}); lowerBound(idx, x); if (x == soa::RowViewSentinel{static_cast(x.mMaxRow)}) { @@ -248,12 +248,12 @@ struct IndexExclusive { auto result = std::apply( [&](auto&... x) { std::array results{setValue(x)...}; - return (results[framework::has_type_at>(rest_it_t{})] && ...); + return (results[framework::has_type_at_v>(rest_it_t{})] && ...); }, iterators); if (result) { - cursor(0, row.globalIndex(), values[framework::has_type_at(tables_t{})]...); + cursor(0, row.globalIndex(), values[framework::has_type_at_v(tables_t{})]...); } } return builder.finalize(); @@ -285,7 +285,7 @@ struct IndexSparse { int32_t idx = -1; auto setValue = [&](auto& x) -> bool { using type = std::decay_t; - constexpr auto position = framework::has_type_at(rest_it_t{}); + constexpr auto position = framework::has_type_at_v(rest_it_t{}); lowerBound(idx, x); if (x == soa::RowViewSentinel{static_cast(x.mMaxRow)}) { @@ -310,7 +310,7 @@ struct IndexSparse { }, iterators); - cursor(0, row.globalIndex(), values[framework::has_type_at(tables_t{})]...); + cursor(0, row.globalIndex(), values[framework::has_type_at_v(tables_t{})]...); } return builder.finalize(); } diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 9c83d8ee38763..762a97c00cb91 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -67,15 +67,15 @@ struct AnalysisDataProcessorBuilder { (doAppendInputWithMetadata(inputs), ...); } - template - static void appendSomethingWithMetadata(std::vector& inputs, std::vector& eInfos) + template + static void appendSomethingWithMetadata(std::vector& inputs, std::vector& eInfos, size_t at) { using dT = std::decay_t; if constexpr (framework::is_specialization::value) { - eInfos.push_back({At, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); + eInfos.push_back({at, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); } else if constexpr (soa::is_soa_iterator_t
::value) { if constexpr (std::is_same_v) { - eInfos.push_back({At, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); + eInfos.push_back({at, o2::soa::createSchemaFromColumns(typename dT::table_t::persistent_columns_t{}), nullptr}); } } doAppendInputWithMetadata(soa::make_originals_from_type
(), inputs); @@ -84,7 +84,7 @@ struct AnalysisDataProcessorBuilder { template static void inputsFromArgs(R (C::*)(Args...), std::vector& inputs, std::vector& eInfos) { - (appendSomethingWithMetadata(pack{})>(inputs, eInfos), ...); + (appendSomethingWithMetadata(inputs, eInfos, o2::framework::has_type_at_v(pack{})), ...); } template @@ -96,7 +96,7 @@ struct AnalysisDataProcessorBuilder { template static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector const& infos) { - return extractSomethingFromRecord(record, infos); + return extractSomethingFromRecord(record, infos, 0); } template @@ -137,20 +137,20 @@ struct AnalysisDataProcessorBuilder { } } - template - static auto extractSomethingFromRecord(InputRecord& record, std::vector const infos) + template + static auto extractSomethingFromRecord(InputRecord& record, std::vector const infos, size_t at) { using decayed = std::decay_t; if constexpr (soa::is_soa_filtered_t::value) { for (auto& info : infos) { - if (info.index == At) + if (info.index == at) return extractFilteredFromRecord(record, info, soa::make_originals_from_type()); } } else if constexpr (soa::is_soa_iterator_t::value) { if constexpr (std::is_same_v) { for (auto& info : infos) { - if (info.index == At) + if (info.index == at) return extractFilteredFromRecord(record, info, soa::make_originals_from_type()); } } else { @@ -165,7 +165,7 @@ struct AnalysisDataProcessorBuilder { template static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector const infos) { - return std::make_tuple(extractSomethingFromRecord(pack{}) + 1u>(record, infos)...); + return std::make_tuple(extractSomethingFromRecord(record, infos, has_type_at_v(pack{}) + 1u)...); } template @@ -236,7 +236,7 @@ struct AnalysisDataProcessorBuilder { /// auto splitter = [&](auto&& x) { using xt = std::decay_t; - constexpr auto index = framework::has_type_at>(associated_pack_t{}); + constexpr auto index = framework::has_type_at_v>(associated_pack_t{}); if (hasIndexTo>(typename xt::persistent_columns_t{})) { auto result = o2::framework::sliceByColumn(indexColumnName.c_str(), x.asArrowTable(), @@ -261,7 +261,7 @@ struct AnalysisDataProcessorBuilder { auto extractor = [&](auto&& x) { using xt = std::decay_t; if constexpr (soa::is_soa_filtered_t::value) { - constexpr auto index = framework::has_type_at>(associated_pack_t{}); + constexpr auto index = framework::has_type_at_v>(associated_pack_t{}); selections[index] = &x.getSelectedRows(); starts[index] = selections[index]->begin(); offsets[index].push_back(std::get(at).tableSize()); @@ -341,7 +341,7 @@ struct AnalysisDataProcessorBuilder { template auto prepareArgument() { - constexpr auto index = framework::has_type_at(associated_pack_t{}); + constexpr auto index = framework::has_type_at_v(associated_pack_t{}); if (hasIndexTo(typename std::decay_t::persistent_columns_t{})) { uint64_t pos; if constexpr (soa::is_soa_filtered_t>::value) { diff --git a/Framework/Foundation/include/Framework/Pack.h b/Framework/Foundation/include/Framework/Pack.h index 8e0badcdff474..0b97e72bd6feb 100644 --- a/Framework/Foundation/include/Framework/Pack.h +++ b/Framework/Foundation/include/Framework/Pack.h @@ -161,6 +161,42 @@ constexpr size_t has_type_at(pack const&) return sizeof...(Ts) + 2; } +namespace +{ +template +struct indexed { + using type = T; + constexpr static std::size_t index = I; +}; + +template +struct indexer; + +template +struct indexer, Ts...> + : indexed... { +}; + +template +indexed select(indexed); + +template +constexpr std::size_t has_type_at_t = decltype(select( + indexer, Ts...>{}))::index; +} // namespace + +template +constexpr std::size_t has_type_at_v(o2::framework::pack<> p) +{ + return -1; +} + +template +constexpr std::size_t has_type_at_v(o2::framework::pack p) +{ + return has_type_at_t; +} + /// Intersect two packs template struct intersect_pack { From 35989058846eae53014a67cec80f215391e6d7e8 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 10 Sep 2020 14:49:37 +0200 Subject: [PATCH 51/76] DPL: hide a few more headers (#4310) --- .../Core/include/Framework/BoostOptionsRetriever.h | 12 ++++++++++-- .../include/Framework/ChannelConfigurationPolicy.h | 2 +- Framework/Core/include/Framework/runDataProcessing.h | 4 ---- Framework/Core/src/BoostOptionsRetriever.cxx | 9 +++++---- Framework/Core/src/DriverInfo.h | 2 ++ 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Framework/Core/include/Framework/BoostOptionsRetriever.h b/Framework/Core/include/Framework/BoostOptionsRetriever.h index 6d33627e8bdc2..148d5c4192b20 100644 --- a/Framework/Core/include/Framework/BoostOptionsRetriever.h +++ b/Framework/Core/include/Framework/BoostOptionsRetriever.h @@ -14,9 +14,17 @@ #include "Framework/ParamRetriever.h" #include -#include +#include #include +namespace boost +{ +namespace program_options +{ +class options_description; +} +} // namespace boost + namespace o2::framework { @@ -32,7 +40,7 @@ class BoostOptionsRetriever : public ParamRetriever boost::property_tree::ptree& provenance) override; private: - boost::program_options::options_description mDescription; + std::unique_ptr mDescription; int mArgc; char** mArgv; bool mIgnoreUnknown; diff --git a/Framework/Core/include/Framework/ChannelConfigurationPolicy.h b/Framework/Core/include/Framework/ChannelConfigurationPolicy.h index 29387ac05cc8e..0fa3be6f1dd86 100644 --- a/Framework/Core/include/Framework/ChannelConfigurationPolicy.h +++ b/Framework/Core/include/Framework/ChannelConfigurationPolicy.h @@ -12,8 +12,8 @@ #include "Framework/ChannelConfigurationPolicyHelpers.h" #include "Framework/ChannelSpec.h" -#include "Framework/DeviceSpec.h" +#include #include namespace o2 diff --git a/Framework/Core/include/Framework/runDataProcessing.h b/Framework/Core/include/Framework/runDataProcessing.h index d4807a782b646..3bed257a41fe4 100644 --- a/Framework/Core/include/Framework/runDataProcessing.h +++ b/Framework/Core/include/Framework/runDataProcessing.h @@ -13,7 +13,6 @@ #include "Framework/ChannelConfigurationPolicy.h" #include "Framework/CompletionPolicy.h" #include "Framework/DispatchPolicy.h" -#include "Framework/ConfigParamsHelper.h" #include "Framework/DataProcessorSpec.h" #include "Framework/WorkflowSpec.h" #include "Framework/ConfigContext.h" @@ -22,9 +21,6 @@ #include "Framework/CommonServices.h" #include "Framework/Logger.h" -#include -#include - #include #include #include diff --git a/Framework/Core/src/BoostOptionsRetriever.cxx b/Framework/Core/src/BoostOptionsRetriever.cxx index e3081aee4b143..892574e3eae11 100644 --- a/Framework/Core/src/BoostOptionsRetriever.cxx +++ b/Framework/Core/src/BoostOptionsRetriever.cxx @@ -14,6 +14,7 @@ #include "PropertyTreeHelpers.h" #include +#include #include #include @@ -28,7 +29,7 @@ namespace o2::framework BoostOptionsRetriever::BoostOptionsRetriever(bool ignoreUnknown, int argc, char** argv) - : mDescription{"ALICE O2 Framework - Available options"}, + : mDescription{std::make_unique("ALICE O2 Framework - Available options")}, mIgnoreUnknown{ignoreUnknown}, mArgc{argc}, mArgv{argv} @@ -39,7 +40,7 @@ void BoostOptionsRetriever::update(std::vector const& specs, boost::property_tree::ptree& store, boost::property_tree::ptree& provenance) { - auto options = mDescription.add_options(); + auto options = mDescription->add_options(); for (auto& spec : specs) { const char* name = spec.name.c_str(); const char* help = spec.help.c_str(); @@ -72,8 +73,8 @@ void BoostOptionsRetriever::update(std::vector const& specs, using namespace bpo::command_line_style; auto style = (allow_short | short_allow_adjacent | short_allow_next | allow_long | long_allow_adjacent | long_allow_next | allow_sticky | allow_dash_for_short); - auto parsed = mIgnoreUnknown ? bpo::command_line_parser(mArgc, mArgv).options(mDescription).style(style).allow_unregistered().run() - : bpo::parse_command_line(mArgc, mArgv, mDescription, style); + auto parsed = mIgnoreUnknown ? bpo::command_line_parser(mArgc, mArgv).options(*mDescription).style(style).allow_unregistered().run() + : bpo::parse_command_line(mArgc, mArgv, *mDescription, style); bpo::variables_map vmap; bpo::store(parsed, vmap); PropertyTreeHelpers::populate(specs, store, vmap, provenance); diff --git a/Framework/Core/src/DriverInfo.h b/Framework/Core/src/DriverInfo.h index 80907e71e9519..494e5604e6f90 100644 --- a/Framework/Core/src/DriverInfo.h +++ b/Framework/Core/src/DriverInfo.h @@ -20,6 +20,8 @@ #include "Framework/ChannelConfigurationPolicy.h" #include "Framework/ConfigParamSpec.h" #include "Framework/TerminationPolicy.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/DispatchPolicy.h" #include "DataProcessorInfo.h" namespace o2::framework From e2c74a2409f76fdf4c4d953a318cdde7a800b8ec Mon Sep 17 00:00:00 2001 From: dstocco Date: Fri, 11 Sep 2020 10:11:35 +0200 Subject: [PATCH 52/76] Use the new raw data decoders in the checks (#4321) Use the new raw data decoders in the checks - Move checkers to a dedicated directory - Use a lighter raw file reader - Improve the raw dumper, allowing to dump the decoded data on demand --- Detectors/MUON/MID/CMakeLists.txt | 1 + Detectors/MUON/MID/QC/CMakeLists.txt | 16 + Detectors/MUON/MID/QC/exe/CMakeLists.txt | 15 + Detectors/MUON/MID/QC/exe/README.md | 46 ++ Detectors/MUON/MID/QC/exe/raw-checker.cxx | 190 +++++++ .../MID/QC/include/MIDQC/GBTRawDataChecker.h | 108 ++++ .../MID/QC/include/MIDQC/RawDataChecker.h | 52 ++ .../MUON/MID/QC/src/GBTRawDataChecker.cxx | 511 ++++++++++++++++++ Detectors/MUON/MID/QC/src/RawDataChecker.cxx | 96 ++++ Detectors/MUON/MID/README.md | 1 + Detectors/MUON/MID/Raw/CMakeLists.txt | 2 - Detectors/MUON/MID/Raw/exe/CMakeLists.txt | 8 +- .../MUON/MID/Raw/exe/CRUBareDataChecker.cxx | 199 ------- .../MUON/MID/Raw/exe/CRUBareDataChecker.h | 56 -- Detectors/MUON/MID/Raw/exe/README.md | 32 +- .../MUON/MID/Raw/exe/mid-raw-checker.cxx | 139 ----- Detectors/MUON/MID/Raw/exe/mid-rawdump.cxx | 95 ---- Detectors/MUON/MID/Raw/exe/rawdump.cxx | 188 +++++++ .../MID/Raw/include/MIDRaw/CRUBareDecoder.h | 68 --- .../MUON/MID/Raw/include/MIDRaw/RawBuffer.h | 72 --- .../MID/Raw/include/MIDRaw/RawFileReader.h | 28 +- .../MUON/MID/Raw/include/MIDRaw/RawUnit.h | 43 -- Detectors/MUON/MID/Raw/src/CRUBareDecoder.cxx | 152 ------ Detectors/MUON/MID/Raw/src/RawBuffer.cxx | 181 ------- Detectors/MUON/MID/Raw/src/RawFileReader.cxx | 104 +--- 25 files changed, 1264 insertions(+), 1139 deletions(-) create mode 100644 Detectors/MUON/MID/QC/CMakeLists.txt create mode 100644 Detectors/MUON/MID/QC/exe/CMakeLists.txt create mode 100644 Detectors/MUON/MID/QC/exe/README.md create mode 100644 Detectors/MUON/MID/QC/exe/raw-checker.cxx create mode 100644 Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h create mode 100644 Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h create mode 100644 Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx create mode 100644 Detectors/MUON/MID/QC/src/RawDataChecker.cxx delete mode 100644 Detectors/MUON/MID/Raw/exe/CRUBareDataChecker.cxx delete mode 100644 Detectors/MUON/MID/Raw/exe/CRUBareDataChecker.h delete mode 100644 Detectors/MUON/MID/Raw/exe/mid-raw-checker.cxx delete mode 100644 Detectors/MUON/MID/Raw/exe/mid-rawdump.cxx create mode 100644 Detectors/MUON/MID/Raw/exe/rawdump.cxx delete mode 100644 Detectors/MUON/MID/Raw/include/MIDRaw/CRUBareDecoder.h delete mode 100644 Detectors/MUON/MID/Raw/include/MIDRaw/RawBuffer.h delete mode 100644 Detectors/MUON/MID/Raw/include/MIDRaw/RawUnit.h delete mode 100644 Detectors/MUON/MID/Raw/src/CRUBareDecoder.cxx delete mode 100644 Detectors/MUON/MID/Raw/src/RawBuffer.cxx diff --git a/Detectors/MUON/MID/CMakeLists.txt b/Detectors/MUON/MID/CMakeLists.txt index 8615904d2a6b8..f36641cb8592d 100644 --- a/Detectors/MUON/MID/CMakeLists.txt +++ b/Detectors/MUON/MID/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(Base) add_subdirectory(Clustering) +add_subdirectory(QC) add_subdirectory(Raw) add_subdirectory(Simulation) add_subdirectory(TestingSimTools) diff --git a/Detectors/MUON/MID/QC/CMakeLists.txt b/Detectors/MUON/MID/QC/CMakeLists.txt new file mode 100644 index 0000000000000..d7440379f2571 --- /dev/null +++ b/Detectors/MUON/MID/QC/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# 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. + +o2_add_library( + MIDQC + SOURCES src/GBTRawDataChecker.cxx src/RawDataChecker.cxx + PUBLIC_LINK_LIBRARIES ms_gsl::ms_gsl O2::MIDRaw) + +add_subdirectory(exe) diff --git a/Detectors/MUON/MID/QC/exe/CMakeLists.txt b/Detectors/MUON/MID/QC/exe/CMakeLists.txt new file mode 100644 index 0000000000000..87be3a2e49bbf --- /dev/null +++ b/Detectors/MUON/MID/QC/exe/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright CERN and copyright holders of ALICE O2. This software is distributed +# under the terms of the GNU General Public License v3 (GPL Version 3), copied +# verbatim in the file "COPYING". +# +# See http://alice-o2.web.cern.ch/license for full licensing information. +# +# 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. + +o2_add_executable( + raw-checker + COMPONENT_NAME mid + SOURCES raw-checker.cxx + PUBLIC_LINK_LIBRARIES O2::MIDQC) diff --git a/Detectors/MUON/MID/QC/exe/README.md b/Detectors/MUON/MID/QC/exe/README.md new file mode 100644 index 0000000000000..05068536f3268 --- /dev/null +++ b/Detectors/MUON/MID/QC/exe/README.md @@ -0,0 +1,46 @@ + + +# Checkers for MID RAW data +This directory contains executable code to verify the raw data. +This is particularly important for testing and debugging the MID read-out. + +## MID raw file checker +This utility allows to test files produced by the CRU w/o using the User Logic. +Basic usage: +```bash +o2-mid-raw-checker --feeId-config-file feeId_filename filename [filename_2 filename_3 ...] +``` +The `feeId_filename` is a file allowing to tell which feeId is readout by the configured GBT. +The file should be in the form explained [here](../../Raw/README.md) + +The output is a file (or a series of files if a list of inputs is provided), named after the input file as `check_filename.txt`, so that it is easy to understand to which input file the output is referring to. +The different e-links are read out and then grouped according to their interaction record. +The output file contains: +- a list of possible problems (if any) for each event processed +- a summary with the number of faulty events + +The list of problems is provided per interaction record. +This should be unique, but it is not always the case, since it can happen that either the decoded local clock information is wrong, or some reset is performed and the same interaction record is repeated. +The data corresponding to one interaction record can be found in different pages. Notice that this also happens for a perfectly good event in case the information does not fit inside the maximum page size. +For debugging purposes, we try to keep track of the page (HB) where the data corresponding to the interaction record were found. +This is rather accurate, although sometimes the data can be found in the preceding page. +We therefore print the interaction records and the corresponding pages (HB), together with the line in the file where the page start. +The line is counted assuming that one reads the file as a series of 4 words of 32 bits each (this is the typical way the binary file is converted into text during the tests). + +For a list of the other available options: +```bash +o2-mid-raw-checker --help +``` +### Performed checks +The decoded information is read HB per HB (multiple pages are read out when needed). +For each HB, the decoded information are gathered according to their interaction. +Notice that, in principle, events belonging to different HBs should have different interaction records, so one could in principle read the full file and then perform the check. +However, in the tests the RDH is not always correctly set, and the orbit number might not increase. That is why we read the HB one by one, and limit the tests to 1 HB at the time. This makes it easier to tag HBs with issues in the RO. +For each interaction record, a number of checks are performed: +- The number of local cards read must be compatible with the number of non-null cards provided by the regional cards. Notice that a mismatch can occur when the local board is busy (but does not correctly signal it) and we therefore get the regional info but not the corresponding local card. An incompatibility can also appear in case of corrupted data reading. +- The word describing the event (SOX, EOX, HC, Calibration, etc.) should be the same for all cards in the interaction record. +- The number of non-zero patterns read must match the information written in the corresponding word that indicates the non-zero detector planes. +- For each card we check that the information is consistent. For example we cannot have SOX and Calibration bits fired at the same time. Also, during an HC, we expect to have no chamber fired for the local boards. Notice that during tests this information is added by hand, so we should not have any issue by design. +- When the overwritten bit is fired, the readout data is actually filled with the masks. In this case we therefore check that the masks are as expected (i.e. they are compatible with the masks that are transmitted at the SOX) diff --git a/Detectors/MUON/MID/QC/exe/raw-checker.cxx b/Detectors/MUON/MID/QC/exe/raw-checker.cxx new file mode 100644 index 0000000000000..575f6a27c9504 --- /dev/null +++ b/Detectors/MUON/MID/QC/exe/raw-checker.cxx @@ -0,0 +1,190 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MID/QC/exe/raw-checker.cxx +/// \brief Raw data checker for MID +/// \author Diego Stocco +/// \date 09 December 2019 + +#include +#include +#include "boost/program_options.hpp" +#include "MIDRaw/FEEIdConfig.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/Decoder.h" +#include "MIDRaw/RawFileReader.h" +#include "MIDQC/RawDataChecker.h" + +namespace po = boost::program_options; + +std::string getOutFilename(const char* inFilename, const char* outDir) +{ + std::string basename(inFilename); + std::string fdir = "./"; + auto pos = basename.find_last_of("/"); + if (pos != std::string::npos) { + basename.erase(0, pos + 1); + fdir = inFilename; + fdir.erase(pos); + } + basename.insert(0, "check_"); + basename += ".txt"; + std::string outputDir(outDir); + if (outputDir.empty()) { + outputDir = fdir; + } + if (outputDir.back() != '/') { + outputDir += "/"; + } + std::string outFilename = outputDir + basename; + return outFilename; +} + +template +int process(po::variables_map& vm) +{ + std::vector inputfiles{vm["input"].as>()}; + + o2::mid::Decoder decoder; + o2::mid::RawDataChecker checker; + if (vm.count("feeId-config-file")) { + o2::mid::FEEIdConfig feeIdConfig(vm["feeId-config-file"].as().c_str()); + decoder.setFeeIdConfig(feeIdConfig); + } + if (vm.count("crate-masks-file")) { + o2::mid::CrateMasks crateMasks(vm["crate-masks-file"].as().c_str()); + decoder.setCrateMasks(crateMasks); + checker.init(crateMasks); + } else { + checker.init(o2::mid::CrateMasks()); + } + decoder.init(true); + + auto nHBs = vm["nHBs"].as(); + auto nMaxErrors = vm["max-errors"].as(); + + for (auto& filename : inputfiles) { + o2::mid::RawFileReader rawFileReader; + if (!rawFileReader.init(filename.c_str())) { + return 2; + } + if (vm.count("custom-memory-size")) { + rawFileReader.setCustomPayloadSize(vm["custom-memory-size"].as()); + } + std::string outFilename = getOutFilename(filename.c_str(), vm["output-dir"].as().c_str()); + std::ofstream outFile(outFilename.c_str()); + if (!outFile.is_open()) { + std::cout << "Error: cannot create " << outFilename << std::endl; + return 2; + } + std::cout << "Writing output to: " << outFilename << " ..." << std::endl; + + std::vector data; + std::vector rofRecords; + std::vector hbRecords; + + checker.clear(); + unsigned long int iHB = 0; + std::stringstream summary; + while (rawFileReader.readHB(vm.count("only-closed-HBs") > 0)) { + decoder.process(rawFileReader.getData()); + rawFileReader.clear(); + size_t offset = data.size(); + data.insert(data.end(), decoder.getData().begin(), decoder.getData().end()); + for (auto& rof : decoder.getROFRecords()) { + rofRecords.emplace_back(rof.interactionRecord, rof.eventType, rof.firstEntry + offset, rof.nEntries); + } + o2::InteractionRecord hb(0, iHB); + hbRecords.emplace_back(hb, o2::mid::EventType::Noise, offset, decoder.getData().size()); + ++iHB; + if ((nHBs > 0 && iHB >= nHBs)) { + break; + } + bool isComplete = true; //(vm.count("bare") && decoder.isComplete()); + // Partial check + if (isComplete) { + // The check assumes that we have all data corresponding to one event. + // However this might not be true since we read one HB at the time. + // So we must test that the event was fully read before running the check. + if (!checker.process(data, rofRecords, hbRecords)) { + outFile << checker.getDebugMessage() << "\n"; + } + data.clear(); + rofRecords.clear(); + hbRecords.clear(); + + if (checker.getNEventsFaulty() >= nMaxErrors) { + summary << "Too many errors found: abort check!\n"; + break; + } + } + } + // Check the remaining data + if (data.size() > 0 && !checker.process(data, rofRecords, hbRecords)) { + outFile << checker.getDebugMessage() << "\n"; + } + summary << "Number of busy raised: " << checker.getNBusyRaised() << "\n"; + summary << "Fraction of faulty events: " << checker.getNEventsFaulty() << " / " << checker.getNEventsProcessed() << " = " << static_cast(checker.getNEventsFaulty()) / ((checker.getNEventsProcessed() > 0) ? static_cast(checker.getNEventsProcessed()) : 1.) << "\n"; + outFile << summary.str(); + std::cout << summary.str(); + + outFile.close(); + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + po::variables_map vm; + po::options_description generic("Generic options"); + + // clang-format off + generic.add_options() + ("help", "produce help message") + ("nHBs", po::value()->default_value(0),"Number of HBs read") + ("only-closed-HBs", po::value()->implicit_value(true),"Return only closed HBs") + ("custom-memory-size", po::value()->implicit_value(0x2000 - 0x100),"Ignore read RDH. Use custom memory size") + ("max-errors", po::value()->default_value(10000),"Maximum number of errors before aborting") + ("feeId-config-file", po::value(),"Filename with crate FEE ID correspondence") + ("crate-masks-file", po::value(),"Filename with crate masks") + ("output-dir", po::value()->default_value(""),"Output directory") + ("bare", po::value()->implicit_value(true),"Use bare decoder"); + + + po::options_description hidden("hidden options"); + hidden.add_options() + ("input", po::value>(),"Input filename"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic).add(hidden); + + po::positional_options_description pos; + pos.add("input", -1); + + po::store(po::command_line_parser(argc, argv).options(cmdline).positional(pos).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << "Usage: " << argv[0] << " [input_raw_filename_1 ...]\n"; + std::cout << generic << std::endl; + return 2; + } + if (vm.count("input") == 0) { + std::cout << "no input file specified" << std::endl; + return 1; + } + + if (vm.count("bare")) { + return process(vm); + } + return process(vm); +} diff --git a/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h b/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h new file mode 100644 index 0000000000000..6e25d85d787f6 --- /dev/null +++ b/Detectors/MUON/MID/QC/include/MIDQC/GBTRawDataChecker.h @@ -0,0 +1,108 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MIDQC/GBTRawDataChecker.h +/// \brief Class to check the raw data from a GBT link +/// \author Diego Stocco +/// \date 28 April 2020 +#ifndef O2_MID_GBTRawDataChecker_H +#define O2_MID_GBTRawDataChecker_H + +#include +#include +#include +#include +#include +#include +#include +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/LocalBoardRO.h" + +namespace o2 +{ +namespace mid +{ +class GBTRawDataChecker +{ + public: + void init(uint16_t feeId, uint8_t mask); + bool process(gsl::span localBoards, gsl::span rofRecords, gsl::span pageRecords); + /// Gets the number of processed events + unsigned int getNEventsProcessed() const { return mStatistics[0]; } + /// Gets the number of faulty events + unsigned int getNEventsFaulty() const { return mStatistics[1]; } + /// Gets the number of busy raised + unsigned int getNBusyRaised() const { return mStatistics[2]; } + /// Gets the + std::string getDebugMessage() const { return mDebugMsg; } + void clear(); + + private: + struct Mask { + std::array patternsBP{}; /// Bending plane mask + std::array patternsNBP{}; /// Non-bending plane mask + }; + + struct GBT { + std::vector regs{}; /// Regional boards + std::vector locs{}; /// Local boards + std::vector pages{}; /// Pages information + }; + + struct BoardInfo { + LocalBoardRO board{}; + o2::InteractionRecord interactionRecord{}; + long int page{-1}; + }; + + void clearChecked(bool isTriggered, bool clearTrigEvents); + bool checkEvent(bool isTriggered, const std::vector& regs, const std::vector& locs); + bool checkEvents(bool isTriggered); + bool checkConsistency(const LocalBoardRO& board); + bool checkConsistency(const std::vector& boards); + bool checkMasks(const std::vector& locs); + bool checkLocalBoardSize(const LocalBoardRO& board); + bool checkLocalBoardSize(const std::vector& boards); + bool checkRegLocConsistency(const std::vector& regs, const std::vector& locs); + uint8_t getElinkId(const LocalBoardRO& board) const; + unsigned int getLastCompleteTrigEvent(); + bool isCompleteSelfTrigEvent(const o2::InteractionRecord& ir) const; + std::string printBoards(const std::vector& boards) const; + void sortEvents(bool isTriggered); + + std::string mEventDebugMsg{}; /// Debug message for the event + std::string mDebugMsg{}; /// Debug message + std::array mStatistics{}; /// Processed events statistics + std::unordered_map mMasks; /// Masks + uint8_t mCrateMask{0xFF}; /// Crate mask + uint16_t mFeeId{0}; /// FeeId + uint16_t mResetVal{0}; /// Reset value + + std::map mTrigEvents{}; ///! Index of triggered events + + std::unordered_map mBusyFlagTrig; /// Busy flag for triggered events + std::unordered_map mBusyFlagSelfTrig; /// Busy flag for self-triggered events + + std::unordered_map> mBoardsTrig{}; ///! Boards with triggered events + std::unordered_map> mBoardsSelfTrig{}; ///! Boards with self-triggered events + + std::map>> mOrderedIndexesTrig{}; ///! Ordered indexes for triggered boards + std::map>> mOrderedIndexesSelfTrig{}; ///! Ordered indexes for self-triggered boards + + std::unordered_map mLastIndexTrig{}; ///! Last checked index for triggered boards + std::unordered_map mLastIndexSelfTrig{}; ///! Last checked index for self-triggered boards + + o2::InteractionRecord mLastCompleteIRTrig{}; ///! Last complete IR for triggered boards + o2::InteractionRecord mLastCompleteIRSelfTrig{}; ///! Last complete IR for self-triggered boards +}; +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_GBTRawDataChecker_H */ diff --git a/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h b/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h new file mode 100644 index 0000000000000..79e86091aecbc --- /dev/null +++ b/Detectors/MUON/MID/QC/include/MIDQC/RawDataChecker.h @@ -0,0 +1,52 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MIDQC/RawDataChecker.h +/// \brief Class to check the raw data +/// \author Diego Stocco +/// \date 9 December 2019 +#ifndef O2_MID_RAWDATACHECKER_H +#define O2_MID_RAWDATACHECKER_H + +#include +#include +#include +#include "DataFormatsMID/ROFRecord.h" +#include "MIDRaw/CrateMasks.h" +#include "MIDRaw/LocalBoardRO.h" +#include "MIDQC/GBTRawDataChecker.h" + +namespace o2 +{ +namespace mid +{ +class RawDataChecker +{ + public: + void init(const CrateMasks& masks); + bool process(gsl::span localBoards, gsl::span rofRecords, gsl::span pageRecords); + /// Gets the number of processed events + unsigned int getNEventsProcessed() const; + /// Gets the number of faulty events + unsigned int getNEventsFaulty() const; + /// Gets the number of busy raised + unsigned int getNBusyRaised() const; + /// Gets the debug message + std::string getDebugMessage() const { return mDebugMsg; } + void clear(); + + private: + std::array mCheckers{}; /// GBT raw data checker + std::string mDebugMsg{}; /// Debug message +}; +} // namespace mid +} // namespace o2 + +#endif /* O2_MID_RAWDATACHECKER_H */ diff --git a/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx b/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx new file mode 100644 index 0000000000000..5aa54a8f25309 --- /dev/null +++ b/Detectors/MUON/MID/QC/src/GBTRawDataChecker.cxx @@ -0,0 +1,511 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MID/QC/src/GBTRawDataChecker.cxx +/// \brief Class to check the raw data from a GBT link +/// \author Diego Stocco +/// \date 28 April 2020 + +#include "MIDQC/GBTRawDataChecker.h" + +#include +#include +#include "MIDRaw/CrateParameters.h" + +namespace o2 +{ +namespace mid +{ + +void GBTRawDataChecker::init(uint16_t feeId, uint8_t mask) +{ + /// Initializer + mFeeId = feeId; + mCrateMask = mask; +} + +bool GBTRawDataChecker::checkLocalBoardSize(const LocalBoardRO& board) +{ + /// Checks that the board has the expected non-null patterns + + // This test only make sense when we have a self-trigger, + // since in this case we expect to have a variable number of non-zero pattern + // as indicated by the corresponding word. + for (int ich = 0; ich < 4; ++ich) { + bool isExpectedNull = (((board.firedChambers >> ich) & 0x1) == 0); + bool isNull = (board.patternsBP[ich] == 0 && board.patternsNBP[ich] == 0); + if (isExpectedNull != isNull) { + std::stringstream ss; + ss << "wrong size for local board:\n"; + ss << board << "\n"; + mEventDebugMsg += ss.str(); + return false; + } + } + return true; +} + +bool GBTRawDataChecker::checkLocalBoardSize(const std::vector& boards) +{ + /// Checks that the boards have the expected non-null patterns + for (auto& board : boards) { + if (!checkLocalBoardSize(board)) { + return false; + } + } + return true; +} + +bool GBTRawDataChecker::checkConsistency(const LocalBoardRO& board) +{ + /// Checks that the event information is consistent + + bool isSoxOrReset = board.triggerWord & (raw::sSOX | raw::sEOX | raw::sRESET); + bool isCalib = raw::isCalibration(board.triggerWord); + bool isPhys = board.triggerWord & raw::sPHY; + + if (isPhys) { + if (isCalib) { + mEventDebugMsg += "inconsistent trigger: calibration and physics trigger cannot be fired together\n"; + return false; + } + if (raw::isLoc(board.statusWord)) { + if (board.firedChambers) { + mEventDebugMsg += "inconsistent trigger: fired chambers should be 0\n"; + return false; + } + } + } + if (isSoxOrReset && (isCalib || isPhys)) { + mEventDebugMsg += "inconsistent trigger: cannot be SOX and calibration\n"; + return false; + } + + return true; +} + +bool GBTRawDataChecker::checkConsistency(const std::vector& boards) +{ + /// Checks that the event information is consistent + for (auto& board : boards) { + if (!checkConsistency(board)) { + std::stringstream ss; + ss << board << "\n"; + mEventDebugMsg += ss.str(); + return false; + } + } + return true; +} + +bool GBTRawDataChecker::checkMasks(const std::vector& locs) +{ + /// Checks the masks + for (auto loc : locs) { + // The board patterns coincide with the masks ("overwritten" mode) + if (loc.statusWord & raw::sOVERWRITTEN) { + auto maskItem = mMasks.find(loc.boardId); + for (int ich = 0; ich < 4; ++ich) { + uint16_t maskBP = 0; + uint16_t maskNBP = 0; + if (maskItem != mMasks.end()) { + maskBP = maskItem->second.patternsBP[ich]; + maskNBP = maskItem->second.patternsNBP[ich]; + } + if (maskBP != loc.patternsBP[ich] || maskNBP != loc.patternsNBP[ich]) { + std::stringstream ss; + ss << "Pattern is not compatible with mask for:\n"; + ss << loc << "\n"; + mEventDebugMsg += ss.str(); + return false; + } + } + } + } + return true; +} + +bool GBTRawDataChecker::checkRegLocConsistency(const std::vector& regs, const std::vector& locs) +{ + /// Checks consistency between local and regional info + uint8_t regFired{0}; + for (auto& reg : regs) { + uint8_t ireg = crateparams::getLocId(reg.boardId) % 2; + auto busyItem = mBusyFlagSelfTrig.find(8 + ireg); + if (reg.triggerWord == 0) { + // Self-triggered event: check the decision + regFired |= (reg.firedChambers << (4 * ireg)); + } else { + // Triggered event: all active boards must answer + regFired |= (mCrateMask & (0xF << (4 * ireg))); + } + } + uint8_t locFired{0}, locBusy{0}; + for (auto& loc : locs) { + auto linkId = getElinkId(loc); + uint8_t mask = (1 << linkId); + if (loc.triggerWord == 0) { + // Self-triggered event: check the decision + if (loc.firedChambers) { + locFired |= mask; + } + } else { + // Triggered event: all active boards must answer + locFired |= mask; + } + } + + // The XOR returns 1 in case of a difference + uint8_t problems = (regFired ^ locFired); + + if (problems) { + // It can be that a busy signal was raised by one of the board in previous events + // If the board is still busy it will not answer. + uint8_t busy{0}; + for (uint8_t iboard = 0; iboard < crateparams::sNELinksPerGBT; ++iboard) { + auto busyItem = mBusyFlagSelfTrig.find(iboard); + if (busyItem != mBusyFlagSelfTrig.end() && busyItem->second) { + busy |= (iboard < crateparams::sMaxNBoardsInLink) ? (1 << iboard) : (0xF << (4 * (iboard % 2))); + } + } + + if (problems & ~busy) { + std::stringstream ss; + ss << fmt::format("loc-reg inconsistency: fired locals ({:08b}) != expected from reg ({:08b});\n", locFired, regFired); + ss << printBoards(regs); + ss << printBoards(locs); + mEventDebugMsg += ss.str(); + return false; + } + } + return true; +} + +std::string GBTRawDataChecker::printBoards(const std::vector& boards) const +{ + /// Prints the boards + std::stringstream ss; + for (auto& board : boards) { + ss << board << "\n"; + } + return ss.str(); +} + +bool GBTRawDataChecker::checkEvent(bool isTriggered, const std::vector& regs, const std::vector& locs) +{ + /// Checks the cards belonging to the same BC + mEventDebugMsg.clear(); + if (!checkRegLocConsistency(regs, locs)) { + return false; + } + + if (!checkConsistency(regs) || !checkConsistency(locs)) { + return false; + } + + if (!isTriggered) { + if (!checkLocalBoardSize(locs)) { + return false; + } + + if (!checkMasks(locs)) { + return false; + } + } + + return true; +} + +uint8_t GBTRawDataChecker::getElinkId(const LocalBoardRO& board) const +{ + /// Returns the e-link ID + if (raw::isLoc(board.statusWord)) { + return board.boardId % 8; + } + return 8 + board.boardId % 8; +} + +void GBTRawDataChecker::clearChecked(bool isTriggered, bool clearTrigEvents) +{ + /// Clears the checked events + + auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig; + auto& lastIndexes = isTriggered ? mLastIndexTrig : mLastIndexSelfTrig; + // Create a new board map with the checked events stripped + std::unordered_map> newBoards{}; + for (auto& lastIdxItem : lastIndexes) { + auto firstIdx = lastIdxItem.second + 1; + auto& boardVec = boards[lastIdxItem.first]; + if (firstIdx < boardVec.size()) { + auto& newVec = newBoards[lastIdxItem.first]; + newVec.insert(newVec.end(), boardVec.begin() + firstIdx, boardVec.end()); + } + } + boards.swap(newBoards); + + if (clearTrigEvents) { + // Clears the map with the processed triggers + auto& lastCompleteTrigIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig; + auto low = mTrigEvents.begin(); + auto up = mTrigEvents.upper_bound(lastCompleteTrigIR); + mTrigEvents.erase(low, up); + } +} + +bool GBTRawDataChecker::isCompleteSelfTrigEvent(const o2::InteractionRecord& ir) const +{ + /// Checks if the self-triggered events are complete + + // The regional board information in self-triggered events is delayed + // compared to triggered events. + // So, we expect information from a previous orbit after having received an orbit trigger. + // Let us check that we have all boards with the same orbit + bool isIncluded = false; + for (uint8_t ireg = 8; ireg < 10; ++ireg) { + auto item = mBoardsSelfTrig.find(ireg); + if (item != mBoardsSelfTrig.end()) { + if (item->second.front().interactionRecord.orbit <= ir.orbit) { + isIncluded = true; + } + if (item->second.back().interactionRecord.orbit <= ir.orbit) { + return false; + } + } + } + return isIncluded; +} + +unsigned int GBTRawDataChecker::getLastCompleteTrigEvent() +{ + /// Checks if we have a triggered event with the information from all active boards + /// The function returns true if it finds a complete event + /// and it returns its interaction record as well. + + // The information for an event comes at different times for different boards, + // depending on the length of the self-triggered event for that board. + // So, before testing the consistency of the event, + // we must wait to have received the information from all boards. + // This can be checked in triggered events, since all boards should be present. + + unsigned int completeMask = 0; + + // Check if we have a triggered event with the information from all active boards + mLastCompleteIRSelfTrig = o2::InteractionRecord(); + uint16_t fullMask = (3 << 8) | mCrateMask; + auto trigEventIt = mTrigEvents.rbegin(); + auto end = mTrigEvents.rend(); + for (; trigEventIt != end; ++trigEventIt) { + if ((trigEventIt->second & fullMask) == fullMask) { + // The trigger events contain the unprocessed events for both triggered and self-triggered events + // These might not be synchronized (typically the latest complete self-triggered events lies behind) + // If the latest IR in memory is more recent than the current complete event found, + // then it means that we need to wait for more HBs. + if (mLastCompleteIRTrig.isDummy() || mLastCompleteIRTrig < trigEventIt->first) { + completeMask |= 1; + mLastCompleteIRTrig = trigEventIt->first; + } + auto trIt = trigEventIt; + while (trIt != end) { + if (isCompleteSelfTrigEvent(trIt->first)) { + completeMask |= (1 << 1); + mLastCompleteIRSelfTrig = trIt->first; + break; + } + ++trIt; + } + return completeMask; + } + } + + return completeMask; +} + +void GBTRawDataChecker::sortEvents(bool isTriggered) +{ + /// Sorts the event in time + auto& orderedIndexes = isTriggered ? mOrderedIndexesTrig : mOrderedIndexesSelfTrig; + auto& lastIndexes = isTriggered ? mLastIndexTrig : mLastIndexSelfTrig; + auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig; + auto& lastCompleteTrigEventIR = isTriggered ? mLastCompleteIRTrig : mLastCompleteIRSelfTrig; + orderedIndexes.clear(); + lastIndexes.clear(); + for (auto& boardItem : boards) { + size_t lastIdx = 0; + for (auto boardIt = boardItem.second.begin(), end = boardItem.second.end(); boardIt != end; ++boardIt) { + if (boardIt->interactionRecord > lastCompleteTrigEventIR) { + break; + } + lastIdx = std::distance(boardItem.second.begin(), boardIt); + orderedIndexes[boardIt->interactionRecord].emplace_back(boardItem.first, lastIdx); + } + lastIndexes[boardItem.first] = lastIdx; + } +} + +bool GBTRawDataChecker::checkEvents(bool isTriggered) +{ + /// Checks the events + bool isOk = true; + auto& boards = isTriggered ? mBoardsTrig : mBoardsSelfTrig; + auto& orderedIndexes = isTriggered ? mOrderedIndexesTrig : mOrderedIndexesSelfTrig; + auto& busyFlag = isTriggered ? mBusyFlagTrig : mBusyFlagSelfTrig; + // Loop on the event indexes + for (auto& evtIdxItem : orderedIndexes) { + // All of these boards have the same timestamp + GBT gbtEvent; + bool busyRaised = false; + for (auto& evtPair : evtIdxItem.second) { + auto& boardInfo = boards[evtPair.first][evtPair.second]; + uint8_t triggerId = boardInfo.board.triggerWord; + auto elinkId = getElinkId(boardInfo.board); + + bool isBusy = ((boardInfo.board.statusWord & raw::sREJECTING) != 0); + busyRaised |= isBusy; + busyFlag[elinkId] = isBusy; + if (isBusy && !isTriggered) { + // This is a special event that just signals a busy. + // Do not add the board to the events to be tested. + // Even because this event can have the same IR and triggerWord (0) of a self-triggered event + continue; + } + if (raw::isLoc(boardInfo.board.statusWord)) { + gbtEvent.locs.push_back(boardInfo.board); + } else { + gbtEvent.regs.push_back(boardInfo.board); + } + if (boardInfo.page >= 0) { + if (std::find(gbtEvent.pages.begin(), gbtEvent.pages.end(), boardInfo.page) == gbtEvent.pages.end()) { + gbtEvent.pages.push_back(boardInfo.page); + } + } + } + if (busyRaised && !isTriggered) { + ++mStatistics[2]; + } + ++mStatistics[0]; + if (!checkEvent(isTriggered, gbtEvent.regs, gbtEvent.locs)) { + std::stringstream ss; + ss << std::hex << std::showbase << evtIdxItem.first; + if (!gbtEvent.pages.empty()) { + ss << " [in"; + for (auto& page : gbtEvent.pages) { + ss << std::dec << " page: " << page << " (line: " << 512 * page + 1 << ") "; + } + ss << "]"; + } + ss << "\n"; + isOk = false; + ss << mEventDebugMsg << "\n"; + mDebugMsg += ss.str(); + ++mStatistics[1]; + } + } + + return isOk; +} + +bool GBTRawDataChecker::process(gsl::span localBoards, gsl::span rofRecords, gsl::span pageRecords) +{ + /// Checks the raw data + mDebugMsg.clear(); + + // Fill board information + for (auto rofIt = rofRecords.begin(); rofIt != rofRecords.end(); ++rofIt) { + for (auto locIt = localBoards.begin() + rofIt->firstEntry; locIt != localBoards.begin() + rofIt->firstEntry + rofIt->nEntries; ++locIt) { + // Find what page this event corresponds to. + // This is useful for debugging. + long int page = -1; + for (auto& rofPage : pageRecords) { + if (rofIt->firstEntry >= rofPage.firstEntry && rofIt->firstEntry < rofPage.firstEntry + rofPage.nEntries) { + page = rofPage.interactionRecord.orbit; + break; + } + } + + // Store the information per local board. + // The information should be already ordered in time + auto id = getElinkId(*locIt); + auto& elinkVec = (locIt->triggerWord == 0) ? mBoardsSelfTrig[id] : mBoardsTrig[id]; + elinkVec.push_back({*locIt, rofIt->interactionRecord, page}); + + if (locIt->triggerWord == 0) { + continue; + } + + // Keep track of the busy + if (locIt->statusWord & raw::sREJECTING) { + auto& selfVec = mBoardsSelfTrig[id]; + auto board = *locIt; + board.triggerWord = 0; + auto ir = rofIt->interactionRecord; + if (id >= crateparams::sMaxNBoardsInLink) { + uint16_t delayRegLocal = 6; + if (rofIt->interactionRecord.bc < delayRegLocal) { + ir -= (constants::lhc::LHCMaxBunches - mResetVal - 1); + } + ir -= delayRegLocal; + } + selfVec.push_back({*locIt, ir, page}); + } + + // Keep track of the orbit triggers + if (locIt->triggerWord & raw::sORB) { + mTrigEvents[rofIt->interactionRecord] |= (1 << id); + mResetVal = rofIt->interactionRecord.bc; + } + + // Compute the masks + if (locIt->triggerWord & raw::sSOX) { + if (raw::isLoc(locIt->statusWord)) { + auto maskItem = mMasks.find(locIt->boardId); + // Check if we have already a mask for this + if (maskItem == mMasks.end()) { + // If not, read the map + auto& mask = mMasks[locIt->boardId]; + for (int ich = 0; ich < 4; ++ich) { + mask.patternsBP[ich] = locIt->patternsBP[ich]; + mask.patternsNBP[ich] = locIt->patternsNBP[ich]; + } + } + } + } + } // loop on local boards + } // loop on ROF records + + auto completeMask = getLastCompleteTrigEvent(); + + bool isOk = true; + + if (completeMask & 0x1) { + sortEvents(true); + isOk &= checkEvents(true); + clearChecked(true, mBoardsSelfTrig.empty()); + } + + if (completeMask & 0x2) { + sortEvents(false); + isOk &= checkEvents(false); + clearChecked(false, true); + } + + return isOk; +} + +void GBTRawDataChecker::clear() +{ + /// Resets the masks and flags + mMasks.clear(); + mBusyFlagTrig.clear(); + mBusyFlagSelfTrig.clear(); + mStatistics.fill(0); +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/QC/src/RawDataChecker.cxx b/Detectors/MUON/MID/QC/src/RawDataChecker.cxx new file mode 100644 index 0000000000000..9f622534d2a1e --- /dev/null +++ b/Detectors/MUON/MID/QC/src/RawDataChecker.cxx @@ -0,0 +1,96 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MID/QC/src/RawDataChecker.cxx +/// \brief Class to check the raw data +/// \author Diego Stocco +/// \date 9 December 2019 + +#include "MIDQC/RawDataChecker.h" + +#include +#include "MIDRaw/CrateParameters.h" + +namespace o2 +{ +namespace mid +{ + +void RawDataChecker::init(const CrateMasks& crateMasks) +{ + /// Initializes the checkers + for (uint16_t igbt = 0; igbt < crateparams::sNGBTs; ++igbt) { + mCheckers[igbt].init(igbt, crateMasks.getMask(igbt)); + } +} + +bool RawDataChecker::process(gsl::span localBoards, gsl::span rofRecords, gsl::span pageRecords) +{ + /// Checks the raw data + + bool isOk = true; + mDebugMsg.clear(); + std::unordered_map> rofs; + for (auto& rof : rofRecords) { + auto& loc = localBoards[rof.firstEntry]; + auto crateId = crateparams::getCrateId(loc.boardId); + auto linkId = crateparams::getGBTIdFromBoardInCrate(crateparams::getLocId(loc.boardId)); + auto feeId = crateparams::makeROId(crateId, linkId); + rofs[feeId].emplace_back(rof); + } + + for (auto& item : rofs) { + isOk &= mCheckers[item.first].process(localBoards, item.second, pageRecords); + mDebugMsg += mCheckers[item.first].getDebugMessage(); + } + + return isOk; +} + +unsigned int RawDataChecker::getNEventsProcessed() const +{ + /// Gets the number of processed events + unsigned int sum = 0; + for (auto& checker : mCheckers) { + sum += checker.getNEventsProcessed(); + } + return sum; +} + +unsigned int RawDataChecker::getNEventsFaulty() const +{ + /// Gets the number of faulty events + unsigned int sum = 0; + for (auto& checker : mCheckers) { + sum += checker.getNEventsFaulty(); + } + return sum; +} + +unsigned int RawDataChecker::getNBusyRaised() const +{ + /// Gets the number of busy raised + unsigned int sum = 0; + for (auto& checker : mCheckers) { + sum += checker.getNBusyRaised(); + } + return sum; +} + +void RawDataChecker::clear() +{ + /// Clears the statistics + for (auto& checker : mCheckers) { + checker.clear(); + } +} + +} // namespace mid +} // namespace o2 diff --git a/Detectors/MUON/MID/README.md b/Detectors/MUON/MID/README.md index 07a0b28aaefa1..1ac569734d269 100644 --- a/Detectors/MUON/MID/README.md +++ b/Detectors/MUON/MID/README.md @@ -8,6 +8,7 @@ This is a top page for the MID detector documentation. # Utilities for MID RAW data -This directory contains two utilities that can be executed to verify the raw data. +This directory contains utilities that can be executed to test the raw data. This is particularly important for testing and debugging the MID Read-out. ## MID raw dumper @@ -20,33 +20,3 @@ For a list of the other available options: ```bash o2-mid-rawdump --help ``` - -## MID raw file checker -This utility allows to test files produced by the CRU w/o using the User Logic. -Basic usage: -```bash -o2-mid-raw-checker filename [filename_2 filename_3 ...] -``` -The output is a file (or a series of files if a list of inputs is provided), named after the input file as `check_filename.txt`, so that it is easy to understand to which input file the output is referring to. -The different e-links are read out and then grouped according to their interaction record. -The output file contains: -- a list of possible problems (if any) for each event processed - -- a summary with the number of faulty events -The list of problems is preceded by the identifier of the processed HB and the corresponding "line" in the file where the HB is. -The line is counted assuming that one reads the file as a series of 4 words of 32 bits each (this is the typical way the binary file is converted into text during the tests). -Notice that one can have more than 1 HB per event, since the data might be split into different pages if the maximum page size is reached. -For a list of the other available options: -```bash -o2-mid-raw-checker --help -``` -### Performed checks -The decoded information is read HB per HB (multiple pages are read out when needed). -For each HB, the decoded information are gathered according to their interaction. -Notice that, in principle, events belonging to different HBs should have different interaction records, so one could in principle read the full file and then perform the check. -However, in the tests the RDH is not always correctly set, and the orbit number might not increase. That is why we read the HB one by one, and limit the tests to 1 HB at the time. This makes it easier to tag HBs with issues in the RO. -For each interaction record, a number of checks are performed: -- The number of local cards read must be 4 times the number of regional cards. Notice that this error often implies that there is a mismatch between the regional and local clocks (so the cards gets split into different interaction records) -- The word describing the event (SOX, EOX, HC, Calibration, etc.) should be the same for all cards in the interaction record. -- The number of non-zero patterns read must match the information written in the corresponding word that indicates the non-zero detector planes. Notice that this might not be true when the patterns represent the masks, since in this case it is fine to transmit a zero pattern. However, for the sake of simplicity, we do not account for this possibility. Of course, this implies that must run the check on tests where all masks are non-zero. -- For each card we check that the information is consistent. For example we cannot have SOX and Calibration bits fired at the same time. Also, during an HC, we expect to have no chamber fired for the local boards. Notice that during tests this information is added by hand, so we should not have any issue by design. \ No newline at end of file diff --git a/Detectors/MUON/MID/Raw/exe/mid-raw-checker.cxx b/Detectors/MUON/MID/Raw/exe/mid-raw-checker.cxx deleted file mode 100644 index 38faa81c0aeac..0000000000000 --- a/Detectors/MUON/MID/Raw/exe/mid-raw-checker.cxx +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 mid-raw-checker.cxx -/// \brief CRU bare data checker for MID -/// \author Diego Stocco -/// \date 09 December 2019 - -#include -#include -#include "boost/program_options.hpp" -#include "MIDRaw/CRUBareDecoder.h" -#include "MIDRaw/RawFileReader.h" -#include "CRUBareDataChecker.h" - -namespace po = boost::program_options; - -o2::header::RAWDataHeader buildCustomRDH() -{ - o2::header::RAWDataHeader rdh; - rdh.word1 |= 0x2000; - rdh.word1 |= ((0x2000 - 0x100)) << 16; - return rdh; -} - -int main(int argc, char* argv[]) -{ - po::variables_map vm; - po::options_description generic("Generic options"); - unsigned long int nHBs = 0; - bool onlyClosedHBs = false; - bool ignoreRDH = true; - - // clang-format off - generic.add_options() - ("help", "produce help message") - ("nHBs", po::value(&nHBs),"Number of HBs read") - ("only-closed-HBs", po::value(&onlyClosedHBs)->implicit_value(true),"Return only closed HBs") - ("ignore-RDH", po::value(&ignoreRDH)->implicit_value(true),"Ignore read RDH. Use custom one instead"); - - - po::options_description hidden("hidden options"); - hidden.add_options() - ("input", po::value>(),"Input filename"); - // clang-format on - - po::options_description cmdline; - cmdline.add(generic).add(hidden); - - po::positional_options_description pos; - pos.add("input", -1); - - po::store(po::command_line_parser(argc, argv).options(cmdline).positional(pos).run(), vm); - po::notify(vm); - - if (vm.count("help")) { - std::cout << "Usage: " << argv[0] << " [input_raw_filename_1 ...]\n"; - std::cout << generic << std::endl; - return 2; - } - if (vm.count("input") == 0) { - std::cout << "no input file specified" << std::endl; - return 1; - } - - std::vector inputfiles{vm["input"].as>()}; - - o2::mid::CRUBareDecoder decoder; - decoder.init(true); - - o2::mid::CRUBareDataChecker checker; - - unsigned long int iHB = 0; - - for (auto& filename : inputfiles) { - o2::mid::RawFileReader rawFileReader; - std::string outFilename = filename; - auto pos = outFilename.find_last_of("/"); - if (pos == std::string::npos) { - pos = 0; - } else { - ++pos; - } - outFilename.insert(pos, "check_"); - outFilename += ".txt"; - std::ofstream outFile(outFilename.c_str()); - if (!rawFileReader.init(filename.c_str())) { - return 2; - } - if (ignoreRDH) { - rawFileReader.setCustomRDH(buildCustomRDH()); - } - std::vector data; - std::vector rofRecords; - std::stringstream ss; - bool isFirst = true; - while (rawFileReader.getState() == 0) { - rawFileReader.readHB(onlyClosedHBs); - decoder.process(rawFileReader.getData()); - rawFileReader.clear(); - size_t offset = data.size(); - std::copy(decoder.getData().begin(), decoder.getData().end(), std::back_inserter(data)); - for (auto& rof : decoder.getROFRecords()) { - rofRecords.emplace_back(rof.interactionRecord, rof.eventType, rof.firstEntry + offset, rof.nEntries); - } - ss << " HB: " << iHB << " (line: " << 512 * iHB + 1 << ")"; - if (decoder.isComplete()) { - // The check assumes that we have all data corresponding to one event. - // However this might not be true since we read one HB at the time. - // So we must test that the event was fully read before running the check. - if (!checker.process(data, rofRecords, isFirst)) { - outFile << ss.str() << "\n"; - outFile << checker.getDebugMessage() << "\n"; - } - isFirst = false; - std::stringstream clean; - ss.swap(clean); - data.clear(); - rofRecords.clear(); - } - ++iHB; - if (nHBs > 0 && iHB >= nHBs) { - break; - } - } - outFile << "Fraction of faulty events: " << checker.getNBCsFaulty() << " / " << checker.getNBCsProcessed() << " = " << static_cast(checker.getNBCsFaulty()) / static_cast(checker.getNBCsProcessed()); - - outFile.close(); - } - - return 0; -} diff --git a/Detectors/MUON/MID/Raw/exe/mid-rawdump.cxx b/Detectors/MUON/MID/Raw/exe/mid-rawdump.cxx deleted file mode 100644 index 47f8519ba00d6..0000000000000 --- a/Detectors/MUON/MID/Raw/exe/mid-rawdump.cxx +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 mid-rawdump.cxx -/// \brief Raw dumper for MID -/// \author Diego Stocco -/// \date 05 December 2019 - -#include -#include "boost/program_options.hpp" -#include "MIDRaw/CRUBareDecoder.h" -#include "MIDRaw/RawFileReader.h" - -namespace po = boost::program_options; - -int main(int argc, char* argv[]) -{ - po::variables_map vm; - po::options_description generic("Generic options"); - std::string outFilename = "mid_raw.txt"; - unsigned long int nHBs = 0; - bool onlyClosedHBs = false; - - // clang-format off - generic.add_options() - ("help", "produce help message") - ("output", po::value(&outFilename),"Output text file") - ("nHBs", po::value(&nHBs),"Number of HBs read") - ("only-closed-HBs", po::value(&onlyClosedHBs)->implicit_value(true),"Return only closed HBs"); - - - po::options_description hidden("hidden options"); - hidden.add_options() - ("input", po::value>(),"Input filename"); - // clang-format on - - po::options_description cmdline; - cmdline.add(generic).add(hidden); - - po::positional_options_description pos; - pos.add("input", -1); - - po::store(po::command_line_parser(argc, argv).options(cmdline).positional(pos).run(), vm); - po::notify(vm); - - if (vm.count("help")) { - std::cout << "Usage: " << argv[0] << " [input_raw_filename_1 ...]\n"; - std::cout << generic << std::endl; - return 2; - } - if (vm.count("input") == 0) { - std::cout << "no input file specified" << std::endl; - return 1; - } - - std::vector inputfiles{vm["input"].as>()}; - - o2::mid::CRUBareDecoder decoder; - - std::ofstream outFile(outFilename); - - unsigned long int iHB = 0; - - for (auto& filename : inputfiles) { - o2::mid::RawFileReader rawFileReader; - if (!rawFileReader.init(filename.c_str())) { - return 2; - } - while (rawFileReader.getState() == 0) { - rawFileReader.readHB(onlyClosedHBs); - decoder.process(rawFileReader.getData()); - rawFileReader.clear(); - for (auto& rof : decoder.getROFRecords()) { - outFile << "Orbit: " << rof.interactionRecord.orbit << " bc: " << rof.interactionRecord.bc << std::endl; - for (auto colIt = decoder.getData().begin() + rof.firstEntry; colIt != decoder.getData().begin() + rof.firstEntry + rof.nEntries; ++colIt) { - outFile << *colIt << std::endl; - } - } - ++iHB; - if (nHBs > 0 && iHB >= nHBs) { - break; - } - } - } - outFile.close(); - - return 0; -} diff --git a/Detectors/MUON/MID/Raw/exe/rawdump.cxx b/Detectors/MUON/MID/Raw/exe/rawdump.cxx new file mode 100644 index 0000000000000..3210b66b6c440 --- /dev/null +++ b/Detectors/MUON/MID/Raw/exe/rawdump.cxx @@ -0,0 +1,188 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 MID/Raw/exe/rawdump.cxx +/// \brief Raw data dumper for MID +/// \author Diego Stocco +/// \date 05 December 2019 + +#include +#include "fmt/format.h" +#include "boost/program_options.hpp" +#include "DPLUtils/RawParser.h" +#include "MIDRaw/FEEIdConfig.h" +#include "MIDRaw/Decoder.h" +#include "MIDRaw/GBTBareDecoder.h" +#include "MIDRaw/GBTUserLogicDecoder.h" +#include "MIDRaw/RawFileReader.h" + +namespace po = boost::program_options; + +std::string getOutFilename(const char* inFilename, const char* outDir) +{ + std::string basename(inFilename); + std::string fdir = "./"; + auto pos = basename.find_last_of("/"); + if (pos != std::string::npos) { + basename.erase(0, pos + 1); + fdir = inFilename; + fdir.erase(pos); + } + basename.insert(0, "dump_"); + basename += ".txt"; + std::string outputDir(outDir); + if (outputDir.empty()) { + outputDir = fdir; + } + if (outputDir.back() != '/') { + outputDir += "/"; + } + std::string outFilename = outputDir + basename; + return outFilename; +} + +template +void decode(o2::mid::Decoder& decoder, gsl::span payload, const RDH& rdh, std::ostream& out) +{ + decoder.clear(); + decoder.process(payload, rdh); + decoder.flush(); + for (auto& rof : decoder.getROFRecords()) { + std::stringstream ss; + ss << std::hex << std::showbase << rof.interactionRecord; + out << ss.str() << std::endl; + for (auto colIt = decoder.getData().begin() + rof.firstEntry; colIt != decoder.getData().begin() + rof.firstEntry + rof.nEntries; ++colIt) { + out << *colIt << std::endl; + } + } +} + +int main(int argc, char* argv[]) +{ + po::variables_map vm; + po::options_description generic("Generic options"); + std::string outFilename = "", feeIdConfigFilename = ""; + unsigned long int nHBs = 0; + unsigned long int firstHB = 0; + + // clang-format off + generic.add_options() + ("help", "produce help message") + ("output", po::value(&outFilename),"Output text file") + ("first", po::value(&firstHB),"First HB to read") + ("nHBs", po::value(&nHBs),"Number of HBs read") + ("rdh-only", po::value()->implicit_value(true),"Only show RDHs") + ("decode", po::value()->implicit_value(true),"Decode output") + ("feeId-config-file", po::value(&feeIdConfigFilename),"Filename with crate FEE ID correspondence") + ("bare", po::value()->implicit_value(true),"Bare decoder"); + + + po::options_description hidden("hidden options"); + hidden.add_options() + ("input", po::value>(),"Input filename"); + // clang-format on + + po::options_description cmdline; + cmdline.add(generic).add(hidden); + + po::positional_options_description pos; + pos.add("input", -1); + + po::store(po::command_line_parser(argc, argv).options(cmdline).positional(pos).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << "Usage: " << argv[0] << " [input_raw_filename_1 ...]\n"; + std::cout << generic << std::endl; + return 2; + } + if (vm.count("input") == 0) { + std::cout << "no input file specified" << std::endl; + return 1; + } + + std::vector inputfiles{vm["input"].as>()}; + + bool isBare = (vm.count("bare") > 0); + bool runDecoder = (vm.count("decode") > 0); + + o2::mid::Decoder ulDecoder; + o2::mid::Decoder bareDecoder; + + if (runDecoder) { + if (!feeIdConfigFilename.empty()) { + o2::mid::FEEIdConfig feeIdConfig(feeIdConfigFilename.c_str()); + bareDecoder.setFeeIdConfig(feeIdConfig); + ulDecoder.setFeeIdConfig(feeIdConfig); + } + bareDecoder.init(true); + ulDecoder.init(true); + } + + std::ofstream outFile; + std::ostream& out = (outFilename.empty()) ? std::cout : (outFile.open(outFilename), outFile); + + unsigned long int iHB = 0; + bool isRdhOnly = vm.count("rdh-only") > 0; + + for (auto& filename : inputfiles) { + // Here we use a custom file reader to be able to read all kind of raw data, + // even those with a malformed structure in terms of number of HBFs per time frame + o2::mid::RawFileReader rawFileReader; + if (!rawFileReader.init(filename.c_str())) { + return 2; + } + while (rawFileReader.readHB()) { + if (iHB >= firstHB) { + o2::framework::RawParser parser(rawFileReader.getData().data(), rawFileReader.getData().size()); + auto it = parser.begin(); // We only have 1 HB + auto const* rdhPtr = reinterpret_cast(it.raw()); + if (!runDecoder) { + o2::raw::RDHUtils::printRDH(rdhPtr); + } + if (it.size() > 0) { + gsl::span payload(it.data(), it.size()); + if (runDecoder) { + if (isBare) { + decode(bareDecoder, payload, *rdhPtr, out); + } else { + decode(ulDecoder, payload, *rdhPtr, out); + } + } else if (!isRdhOnly) { + for (size_t iword = 0; iword < payload.size(); iword += 16) { + auto word = payload.subspan(iword, 16); + for (auto it = word.rbegin(); it != word.rend(); ++it) { + auto ibInWord = word.rend() - it; + if (isBare) { + if (ibInWord == 4 || ibInWord == 9) { + out << " "; + } + if (ibInWord == 5 || ibInWord == 10) { + out << " "; + } + } + out << fmt::format("{:02x}", static_cast(*it)); + } + out << "\n"; + } + } + } + } + rawFileReader.clear(); + ++iHB; + if (nHBs > 0 && iHB >= nHBs + firstHB) { + break; + } + } // loop on HBs + } // loop on files + outFile.close(); + + return 0; +} diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/CRUBareDecoder.h b/Detectors/MUON/MID/Raw/include/MIDRaw/CRUBareDecoder.h deleted file mode 100644 index a041527fc95a9..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/CRUBareDecoder.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 MIDRaw/CRUBareDecoder.h -/// \brief MID CRU core decoder -/// \author Diego Stocco -/// \date 18 November 2019 -#ifndef O2_MID_CRUBAREDECODER_H -#define O2_MID_CRUBAREDECODER_H - -#include -#include -#include -#include "DataFormatsMID/ROFRecord.h" -#include "MIDRaw/CrateMapper.h" -#include "MIDRaw/CrateParameters.h" -#include "MIDRaw/ELinkDecoder.h" -#include "MIDRaw/LocalBoardRO.h" -#include "MIDRaw/RawBuffer.h" - -namespace o2 -{ -namespace mid -{ -class CRUBareDecoder -{ - public: - void init(bool debugMode = false); - void process(gsl::span bytes); - /// Gets the vector of data - const std::vector& getData() const { return mData; } - - /// Gets the vector of data RO frame records - const std::vector& getROFRecords() const { return mROFRecords; } - - bool isComplete() const; - - private: - RawBuffer mBuffer{}; /// Raw buffer handler - std::vector mData{}; /// Vector of output data - std::vector mROFRecords{}; /// List of ROF records - CrateMapper mCrateMapper{}; /// Crate mapper - uint8_t mCrateId{0}; /// Crate ID - std::array mCalibClocks{}; /// Calibration clock - std::array mELinkDecoders{}; /// E-link decoders - std::function mAddReg{[](size_t) {}}; ///! Add regional board - - std::function mCheckBoard{std::bind(&CRUBareDecoder::checkBoard, this, std::placeholders::_1)}; ///! Check board - - bool nextGBTWord(); - void processGBT(size_t offset); - void reset(); - void addBoard(size_t ilink); - bool checkBoard(size_t ilink); - void addLoc(size_t ilink); - uint16_t getPattern(uint16_t pattern, bool invert) const; -}; -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_CRUBAREDECODER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/RawBuffer.h b/Detectors/MUON/MID/Raw/include/MIDRaw/RawBuffer.h deleted file mode 100644 index 6f7e8078d9134..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/RawBuffer.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 MIDRaw/RawBuffer.h -/// \brief Handler of the RAW buffer -/// \author Diego Stocco -/// \date 28 November 2019 -#ifndef O2_MID_RAWBUFFER_H -#define O2_MID_RAWBUFFER_H - -#include -#include -#include -#include "Headers/RAWDataHeader.h" - -namespace o2 -{ -namespace mid -{ -template -class RawBuffer -{ - public: - enum class ResetMode { - all, // Reset buffer and indexes - keepUnconsumed, // Keep the last unconsumed HB - bufferOnly // Do not reset indexes - }; - - void setBuffer(gsl::span bytes, ResetMode resetMode = ResetMode::keepUnconsumed); - - /// Gets the current RDH - const header::RAWDataHeader* getRDH() { return mRDH; } - - unsigned int next(unsigned int nBits); - T next(); - - bool nextHeader(); - - bool hasNext(unsigned int nBytes); - - void skipOverhead(); - - bool isHBClosed(); - - private: - gsl::span mBytes{}; /// gsl span with encoded information - gsl::span mCurrentBuffer{}; /// gsl span with the current encoded information - std::vector mUnconsumed{}; /// Unconsumed buffer - size_t mElementIndex{0}; /// Index of the current element in the buffer - size_t mBitIndex{0}; /// Index of the current bit - size_t mHeaderIndex{0}; /// Index of the current header - size_t mNextHeaderIndex{0}; /// Index of the next header - size_t mEndOfPayloadIndex{0}; /// Index of the end of payload - const unsigned int mElementSizeInBytes{sizeof(T)}; /// Element size in bytes - const unsigned int mElementSizeInBits{mElementSizeInBytes * 8}; /// Element size in bits - const header::RAWDataHeader* mRDH{nullptr}; /// Current header (not owner) - - bool nextPayload(); - void reset(); -}; -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_RAWBUFFER_H */ diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h b/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h index 9f91f830cf254..0df1da74bc6c8 100644 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h +++ b/Detectors/MUON/MID/Raw/include/MIDRaw/RawFileReader.h @@ -15,48 +15,40 @@ #ifndef O2_MID_RAWFILEREADER_H #define O2_MID_RAWFILEREADER_H +#include #include #include -#include -#include "MIDRaw/CrateParameters.h" -#include "MIDRaw/RawBuffer.h" -#include "MIDRaw/RawUnit.h" +#include "Headers/RAWDataHeader.h" namespace o2 { namespace mid { -template class RawFileReader { public: bool init(const char* inFilename, bool readContinuous = false); - bool readAllGBTs(bool reset = true); - bool readHB(bool sendCompleteHBs = true); + bool readHB(bool sendCompleteHBs = false); void clear(); - /// Gets the number of HBs read - unsigned long int getNumberOfHBs(uint16_t feeId) { return mHBCounters.at(feeId); } - /// Gets the state int getState() { return mState; } /// Gets the vector of data - const std::vector& getData() { return mBytes; } + const std::vector& getData() { return mBytes; } void setCustomRDH(const header::RAWDataHeader& rdh) { mCustomRDH = rdh; } + void setCustomPayloadSize(uint16_t memorySize = 0x2000, uint16_t offsetToNext = 0x2000); private: void read(size_t nBytes); - bool hasFullInfo(); bool replaceRDH(size_t headerIndex); - std::ifstream mFile{}; /// Raw file - std::vector mBytes; /// Buffer - RawBuffer mBuffer; /// Raw buffer handler - std::array mHBCounters{}; /// HB counters per GBT - bool mReadContinuous{false}; /// Continuous readout mode - int mState{0}; /// Status flag + std::ifstream mFile{}; /// Raw file + std::vector mBytes; /// Buffer + static constexpr unsigned int sHeaderSize{64}; /// Header size in bytes + bool mReadContinuous{false}; /// Continuous readout mode + int mState{0}; /// Status flag header::RAWDataHeader mCustomRDH{}; /// Custom RDH }; diff --git a/Detectors/MUON/MID/Raw/include/MIDRaw/RawUnit.h b/Detectors/MUON/MID/Raw/include/MIDRaw/RawUnit.h deleted file mode 100644 index 0487a9fa55528..0000000000000 --- a/Detectors/MUON/MID/Raw/include/MIDRaw/RawUnit.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 MIDRaw/RawUnit.h -/// \brief Raw data format MID -/// \author Diego Stocco -/// \date 30 September 2019 -#ifndef O2_MID_RAWUNIT_H -#define O2_MID_RAWUNIT_H - -#include -#include -#include "Headers/RAWDataHeader.h" - -namespace o2 -{ -namespace mid -{ -namespace raw -{ -typedef uint32_t RawUnit; - -// Buffer size -static constexpr size_t sElementSizeInBytes = sizeof(RawUnit); -static constexpr size_t sMaxBufferSize = 8192 / sElementSizeInBytes; -static constexpr size_t sElementSizeInBits = 8 * sElementSizeInBytes; - -// Header size -static constexpr size_t sHeaderSizeInBytes = sizeof(header::RAWDataHeader); -static constexpr size_t sHeaderSizeInElements = sHeaderSizeInBytes / sElementSizeInBytes; - -} // namespace raw -} // namespace mid -} // namespace o2 - -#endif /* O2_MID_RAWUNIT_H */ \ No newline at end of file diff --git a/Detectors/MUON/MID/Raw/src/CRUBareDecoder.cxx b/Detectors/MUON/MID/Raw/src/CRUBareDecoder.cxx deleted file mode 100644 index 3ec0291141401..0000000000000 --- a/Detectors/MUON/MID/Raw/src/CRUBareDecoder.cxx +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 MID/Raw/src/CRUBareDecoder.cxx -/// \brief MID CRU core decoder -/// \author Diego Stocco -/// \date 30 September 2019 - -#include "MIDRaw/CRUBareDecoder.h" - -#include "RawInfo.h" -#include "DetectorsRaw/RDHUtils.h" - -namespace o2 -{ -namespace mid -{ -using RDHUtils = o2::raw::RDHUtils; - -void CRUBareDecoder::reset() -{ - /// Rewind bytes - mData.clear(); - mROFRecords.clear(); -} - -void CRUBareDecoder::init(bool debugMode) -{ - /// Initializes the task - if (debugMode == true) { - mAddReg = std::bind(&CRUBareDecoder::addBoard, this, std::placeholders::_1); - mCheckBoard = [](size_t) { return true; }; - } -} - -void CRUBareDecoder::process(gsl::span bytes) -{ - /// Decodes the buffer - reset(); - - mBuffer.setBuffer(bytes); - - // Each CRU word consists of 128 bits, i.e 16 bytes - while (mBuffer.hasNext(16)) { - processGBT(0); - processGBT(5); - // The GBT word consists of 10 bytes - // but the CRU word is 16 bytes - // So we have 6 empty bytes - for (int iword = 0; iword < 6; ++iword) { - mBuffer.next(); - } - } -} - -void CRUBareDecoder::processGBT(size_t offset) -{ - /// Processes the GBT - - // Regional link - // loc#0 loc#1 loc#2 loc#3 reg - std::array bytes{mBuffer.next(), mBuffer.next(), mBuffer.next(), mBuffer.next(), mBuffer.next()}; - - // Byte corresponding to regional - size_t ibyte = 4; - size_t ilink = offset + ibyte; - - if (mELinkDecoders[ilink].add(bytes[ibyte], 0x80) && mELinkDecoders[ilink].isComplete()) { - // In principle, in the same HB we should have the info of only 1 crate - // So it should be safe to store this information - // and apply it to all subsequent e-links, without checking the clock - mCrateId = mELinkDecoders[ilink].getId(); - mAddReg(ilink); - mELinkDecoders[ilink].reset(); - } - - // local links - for (ibyte = 0; ibyte < 4; ++ibyte) { - ilink = offset + ibyte; - if (mELinkDecoders[ilink].add(bytes[ibyte], 0xc0) && mELinkDecoders[ilink].isComplete()) { - if (mCheckBoard(ilink)) { - addLoc(ilink); - } - mELinkDecoders[ilink].reset(); - } - } -} - -bool CRUBareDecoder::checkBoard(size_t ilink) -{ - /// Performs checks on the board - uint8_t expectedId = ilink - (ilink / 5); - return (expectedId == mELinkDecoders[ilink].getId() % 8); -} - -void CRUBareDecoder::addBoard(size_t ilink) -{ - /// Adds the local or regional board to the output data vector - uint16_t localClock = mELinkDecoders[ilink].getCounter(); - EventType eventType = EventType::Standard; - if (mELinkDecoders[ilink].getTriggerWord() & (1 << 4)) { - mCalibClocks[ilink] = localClock; - eventType = EventType::Noise; - } else if (localClock == mCalibClocks[ilink] + sDelayCalibToFET) { - eventType = EventType::Dead; - } - auto firstEntry = mData.size(); - InteractionRecord intRec(localClock - sDelayBCToLocal, RDHUtils::getTriggerOrbit(*mBuffer.getRDH())); - mData.push_back({mELinkDecoders[ilink].getStatusWord(), mELinkDecoders[ilink].getTriggerWord(), crateparams::makeUniqueLocID(mCrateId, mELinkDecoders[ilink].getId()), mELinkDecoders[ilink].getInputs()}); - mROFRecords.emplace_back(intRec, eventType, firstEntry, 1); -} - -void CRUBareDecoder::addLoc(size_t ilink) -{ - /// Adds the local board to the output data vector - addBoard(ilink); - bool invert = (mROFRecords.back().eventType == EventType::Dead); - for (int ich = 0; ich < 4; ++ich) { - if ((mData.back().firedChambers & (1 << ich))) { - mData.back().patternsBP[ich] = getPattern(mELinkDecoders[ilink].getPattern(0, ich), invert); - mData.back().patternsNBP[ich] = getPattern(mELinkDecoders[ilink].getPattern(1, ich), invert); - } - } - mELinkDecoders[ilink].reset(); -} - -uint16_t CRUBareDecoder::getPattern(uint16_t pattern, bool invert) const -{ - /// Gets the proper pattern - return (invert) ? ~pattern : pattern; -} - -bool CRUBareDecoder::isComplete() const -{ - /// Checks that all links have finished reading - for (auto& elink : mELinkDecoders) { - if (elink.getNBytes() > 0) { - return false; - } - } - return true; -} - -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/RawBuffer.cxx b/Detectors/MUON/MID/Raw/src/RawBuffer.cxx deleted file mode 100644 index 713f0a6a09757..0000000000000 --- a/Detectors/MUON/MID/Raw/src/RawBuffer.cxx +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright CERN and copyright holders of ALICE O2. This software is -// distributed under the terms of the GNU General Public License v3 (GPL -// Version 3), copied verbatim in the file "COPYING". -// -// See http://alice-o2.web.cern.ch/license for full licensing information. -// -// 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 MID/Raw/src/RawBuffer.cxx -/// \brief MID CRU user logic decoder -/// \author Diego Stocco -/// \date 30 September 2019 - -#include "MIDRaw/RawBuffer.h" - -#include "MIDRaw/RawUnit.h" -#include "RawInfo.h" -#include "DetectorsRaw/RDHUtils.h" - -namespace o2 -{ -namespace mid -{ -using RDHUtils = o2::raw::RDHUtils; - -template -unsigned int RawBuffer::next(unsigned int nBits) -{ - /// Reads the next nBits - if (mNextHeaderIndex == 0) { - // This is the first entry - nextPayload(); - } - unsigned int value = 0; - for (int ibit = 0; ibit < nBits; ++ibit) { - if (mBitIndex == mElementSizeInBits) { - mBitIndex = 0; - ++mElementIndex; - nextPayload(); - } - bool isOn = (mBytes[mElementIndex] >> mBitIndex) & 0x1; - if (isOn) { - value |= (1 << ibit); - } - ++mBitIndex; - } - return value; -} - -template -T RawBuffer::next() -{ - /// Reads the next word - nextPayload(); - return mBytes[mElementIndex++]; -} - -template -bool RawBuffer::nextHeader() -{ - /// Goes to next RDH - if (mNextHeaderIndex >= mBytes.size()) { - // This is the end of the buffer - if (mUnconsumed.empty()) { - mElementIndex = mNextHeaderIndex; - mEndOfPayloadIndex = mNextHeaderIndex; - return false; - } - // We were reading the unconsumed part: switch to new buffer - mUnconsumed.clear(); - reset(); - mBytes = mCurrentBuffer; - } - mHeaderIndex = mNextHeaderIndex; - mRDH = reinterpret_cast(&mBytes[mHeaderIndex]); - mEndOfPayloadIndex = mHeaderIndex + (RDHUtils::getMemorySize(*mRDH) / mElementSizeInBytes); - // Go to end of header, i.e. beginning of payload - mElementIndex = mHeaderIndex + (RDHUtils::getHeaderSize(*mRDH) / mElementSizeInBytes); - mNextHeaderIndex = mHeaderIndex + RDHUtils::getOffsetToNext(*mRDH) / mElementSizeInBytes; - mBitIndex = 0; - - return true; -} - -template -bool RawBuffer::nextPayload() -{ - /// Goes to next payload - while (mElementIndex == mEndOfPayloadIndex) { - if (!nextHeader()) { - return false; - } - } - return true; -} - -template -void RawBuffer::reset() -{ - /// Rewind bytes - mElementIndex = 0; - mHeaderIndex = 0; - mNextHeaderIndex = 0; - mEndOfPayloadIndex = 0; - mBitIndex = 0; - mRDH = nullptr; - mUnconsumed.clear(); -} - -template -void RawBuffer::setBuffer(gsl::span bytes, ResetMode resetMode) -{ - /// Sets the buffer and reset the internal indexes - if (resetMode == ResetMode::keepUnconsumed && !mUnconsumed.empty()) { - // There are some unconsumed bytes from the previous buffer - mNextHeaderIndex -= mHeaderIndex; - mEndOfPayloadIndex -= mHeaderIndex; - mElementIndex -= mHeaderIndex; - mHeaderIndex = 0; - mBytes = gsl::span(mUnconsumed); - } else { - mBytes = bytes; - if (resetMode != ResetMode::bufferOnly) { - reset(); - } - } - mCurrentBuffer = bytes; -} - -template -bool RawBuffer::isHBClosed() -{ - /// Tests if the HB is closed - if (!mRDH) { - return false; - } - return RDHUtils::getStop(*mRDH); -} - -template -void RawBuffer::skipOverhead() -{ - /// This function must be called after reading a block of data - /// if the payload is not provided and/or readout in bytes. - /// - /// In this case, indeed, there can be an overhead between the last useful bit and the declared memory size, - /// which is in bytes. - /// Calling this function allows to jump directly to the next header when needed - if (mElementIndex == mEndOfPayloadIndex - 1) { - mElementIndex = mEndOfPayloadIndex; - mBitIndex = 0; - } -} - -template -bool RawBuffer::hasNext(unsigned int nBytes) -{ - /// Tests if the buffer has nBytes left - - // We first need to go to the next payload - // If we do not, we could have a set of empty HBs in front of us - // With lot of memory left in the buffer but no payload - nextPayload(); - bool isOk = mCurrentBuffer.size() + mUnconsumed.size() - mNextHeaderIndex + mEndOfPayloadIndex - mElementIndex >= nBytes / mElementSizeInBytes; - if (!isOk && mElementIndex != mCurrentBuffer.size()) { - // Store the remaining bits for further use - // We need to do it here because the vector of which the mBytes is just a span might not be valid afterwards - // (e.g. when we do the next setBuffer) - // If we do not want to invalidate the mRDH pointer, we need to copy bytes from the last header - mUnconsumed.insert(mUnconsumed.end(), mBytes.begin() + mHeaderIndex, mBytes.end()); - } - return isOk; -} - -template class RawBuffer; -template class RawBuffer; - -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Raw/src/RawFileReader.cxx b/Detectors/MUON/MID/Raw/src/RawFileReader.cxx index 763d37d7adc44..a039749839075 100644 --- a/Detectors/MUON/MID/Raw/src/RawFileReader.cxx +++ b/Detectors/MUON/MID/Raw/src/RawFileReader.cxx @@ -17,16 +17,15 @@ #include #include "Headers/RAWDataHeader.h" +#include "Headers/RDHAny.h" +#include "DPLUtils/RawParser.h" #include "DetectorsRaw/RDHUtils.h" namespace o2 { namespace mid { -using RDHUtils = o2::raw::RDHUtils; - -template -bool RawFileReader::init(const char* inFilename, bool readContinuous) +bool RawFileReader::init(const char* inFilename, bool readContinuous) { /// Initializes the raw file reader mFile.open(inFilename, std::ios::binary); @@ -35,71 +34,41 @@ bool RawFileReader::init(const char* inFilename, bool readContinuous) mState = 2; return false; } - mBytes.reserve(2 * raw::sMaxBufferSize); mReadContinuous = readContinuous; - mHBCounters.fill(0); - return true; } -template -void RawFileReader::read(size_t nBytes) +void RawFileReader::read(size_t nBytes) { /// Reads nBytes of the file size_t currentIndex = mBytes.size(); - mBytes.resize(currentIndex + nBytes / sizeof(T)); + mBytes.resize(currentIndex + nBytes); mFile.read(reinterpret_cast(&(mBytes[currentIndex])), nBytes); } -template -void RawFileReader::clear() +void RawFileReader::clear() { /// Clears the bytes and counters mBytes.clear(); - mBuffer.setBuffer(mBytes, RawBuffer::ResetMode::all); - mHBCounters.fill(0); -} - -template -bool RawFileReader::hasFullInfo() -{ - /// Tests if we have read the same number of HBs for all GBT links - - // We assume here that we read the data of one HV for all of the GBT links - // before moving to the next HB - for (uint16_t feeId = 1; feeId < crateparams::sNGBTs; ++feeId) { - if (mHBCounters[feeId] != mHBCounters[0]) { - return false; - } - } - return mHBCounters[0] != 0; } -template -bool RawFileReader::readAllGBTs(bool reset) +void RawFileReader::setCustomPayloadSize(uint16_t memorySize, uint16_t offsetToNext) { - /// Keeps reading the file until it reads the information of all GBT links - /// It returns the number of HBs read - - if (reset) { - clear(); - } - - while (!hasFullInfo()) { - if (!readHB()) { - return false; - } - } - return true; + /// Sets a custom memory and payload size + /// This is done to be able to correctly read test data + /// that have a wrong RDH + o2::header::RAWDataHeader rdh; + rdh.word1 |= offsetToNext; + rdh.word1 |= (memorySize << 16); + setCustomRDH(rdh); } -template -bool RawFileReader::replaceRDH(size_t headerIndex) +bool RawFileReader::replaceRDH(size_t headerIndex) { /// Replaces the current RDH with a custom one if needed. /// This is done to be able to correctly read test data /// that have a wrong RDH - if (RDHUtils::getOffsetToNext(mCustomRDH) > 0) { + if (o2::raw::RDHUtils::getOffsetToNext(mCustomRDH) > 0) { header::RAWDataHeader* rdh = reinterpret_cast(&mBytes[headerIndex]); *rdh = mCustomRDH; return true; @@ -107,19 +76,17 @@ bool RawFileReader::replaceRDH(size_t headerIndex) return false; } -template -bool RawFileReader::readHB(bool sendCompleteHBs) +bool RawFileReader::readHB(bool sendCompleteHBs) { /// Reads one HB if (mState != 0) { return false; } - auto gbtId = 0; bool isHBClosed = false; while (!isHBClosed) { // Read header size_t headerIndex = mBytes.size(); - read(raw::sHeaderSizeInBytes); + read(sHeaderSize); // The check on the eof needs to be placed here and not at the beginning of the function. // The reason is that the eof flag is set if we try to read after the eof @@ -132,7 +99,7 @@ bool RawFileReader::readHB(bool sendCompleteHBs) if (mReadContinuous) { mFile.clear(); mFile.seekg(0, std::ios::beg); - read(raw::sHeaderSizeInBytes); + read(sHeaderSize); } else { mState = 1; return false; @@ -140,38 +107,23 @@ bool RawFileReader::readHB(bool sendCompleteHBs) } replaceRDH(headerIndex); // We use the buffer only to correctly initialize the RDH - mBuffer.setBuffer(mBytes, RawBuffer::ResetMode::bufferOnly); - mBuffer.nextHeader(); - isHBClosed = mBuffer.isHBClosed(); - gbtId = RDHUtils::getFEEID(*mBuffer.getRDH()); - if (gbtId >= crateparams::sNGBTs) { - // FIXME: this is a problem of the header of some test files - gbtId = 0; + o2::framework::RawParser parser(mBytes.data(), mBytes.size()); + auto lastIt = parser.begin(); + for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { + lastIt = it; } - if (RDHUtils::getOffsetToNext(*mBuffer.getRDH()) > raw::sHeaderSizeInBytes) { - read(RDHUtils::getOffsetToNext(*mBuffer.getRDH()) - raw::sHeaderSizeInBytes); - // CAVEAT: to save memory / CPU time, the RawBuffer does not hold a copy of the buffer, - // but just a span of it. - // If we add bytes to mBytes, the vector can go beyond the capacity - // and the memory is re-allocated. - // If this happens, the span is no longer valid, and we can no longer - // call mBuffer.getRDH() until we pass it mBytes again - // To do so, you need to call: - // mBuffer.setBuffer(mBytes, RawBuffer::ResetMode::bufferOnly); - // mBuffer.nextHeader(); + auto const* rdhPtr = reinterpret_cast(lastIt.raw()); + isHBClosed = o2::raw::RDHUtils::getStop(rdhPtr); + auto offsetNext = o2::raw::RDHUtils::getOffsetToNext(rdhPtr); + if (offsetNext > sHeaderSize) { + read(offsetNext - sHeaderSize); } if (!sendCompleteHBs) { break; } } - - ++mHBCounters[gbtId]; - return true; } -template class RawFileReader; -template class RawFileReader; - } // namespace mid } // namespace o2 From fb9f2d14605723e0d16082c712a63a80ae2f3624 Mon Sep 17 00:00:00 2001 From: mkruegerGitHub Date: Fri, 11 Sep 2020 15:28:24 +0200 Subject: [PATCH 53/76] add some histogram helpers (#4239) --- Analysis/Core/include/Analysis/HistHelpers.h | 274 +++++++++++++++++++ Analysis/Tutorials/CMakeLists.txt | 5 + Analysis/Tutorials/src/histHelpersTest.cxx | 147 ++++++++++ 3 files changed, 426 insertions(+) create mode 100644 Analysis/Core/include/Analysis/HistHelpers.h create mode 100644 Analysis/Tutorials/src/histHelpersTest.cxx diff --git a/Analysis/Core/include/Analysis/HistHelpers.h b/Analysis/Core/include/Analysis/HistHelpers.h new file mode 100644 index 0000000000000..1cbff6e38fa3b --- /dev/null +++ b/Analysis/Core/include/Analysis/HistHelpers.h @@ -0,0 +1,274 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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. + +/// \author Mario Krueger +// +// Some helper templates to simplify working with histograms +// + +#ifndef HistHelpers_H +#define HistHelpers_H + +#include +#include +#include +#include +#include +#include + +#include "Framework/Logger.h" + +namespace o2 +{ +namespace experimental +{ +namespace histhelpers +{ + +template +struct is_shared_ptr : std::false_type { +}; +template +struct is_shared_ptr> : std::true_type { +}; + +//************************************************************************************************** +/** + * Container class for storing and saving root histograms of any type. + * TObjArray inheritance (and concomitant raw pointer gynmnastics) is used to interface with existing O2 file writing functionality. + */ +//************************************************************************************************** +class HistContainer : public TObjArray +{ + public: + HistContainer(const std::string& name) : TObjArray() + { + SetBit(TObject::kSingleKey, false); // not working; seems like WriteObjectAny ignores this... + SetOwner(false); // let container handle object deletion + SetName(name.data()); + } + + using HistType = std::variant, std::shared_ptr, std::shared_ptr, std::shared_ptr, std::shared_ptr>; + + template + void Add(uint8_t histID, T&& hist) + { + if (mHistos.find(histID) != mHistos.end()) { + LOGF(WARNING, "HistContainer %s already holds a histogram at histID = %d. Overriding it now...", GetName(), histID); + TObject* oldPtr = nullptr; + std::visit([&](const auto& sharedPtr) { oldPtr = sharedPtr.get(); }, mHistos[histID]); + TObjArray::Remove(oldPtr); + } + // if shared poiner is provided as argument, object itself is used, otherwise copied + if constexpr (is_shared_ptr::value) + mHistos[histID] = DownCast(hist); + else { + mHistos[histID] = DownCast(std::make_shared(hist)); + } + TObject* rawPtr = nullptr; + std::visit([&](const auto& sharedPtr) { rawPtr = sharedPtr.get(); }, mHistos[histID]); + TObjArray::Add(rawPtr); + } + + // gets the underlying histogram pointer + // unfortunately we cannot automatically infer type here + // so one has to use Get(), Get(), Get(), Get(), Get() + template + std::shared_ptr Get(uint8_t histID) + { + return *std::get_if>(&mHistos[histID]); + } + + template + void Fill(uint8_t histID, Ts&&... position) + { + std::visit([this, &position...](auto&& hist) { GenericFill(hist, std::forward(position)...); }, mHistos[histID]); + } + + private: + std::map mHistos; + + // disallow user to call TObjArray::Add() + using TObjArray::Add; + + template + void GenericFill(std::shared_ptr hist, const Ts&... position) + { + constexpr bool isValidTH3 = (std::is_same_v && sizeof...(Ts) == 3); + constexpr bool isValidTH2 = (std::is_same_v && sizeof...(Ts) == 2); + constexpr bool isValidTH1 = (std::is_same_v && sizeof...(Ts) == 1); + constexpr bool isValidPrimitive = isValidTH1 || isValidTH2 || isValidTH3; + // unfortunately we dont know at compile the dimension of THn(Sparse) + constexpr bool isValidComplex = std::is_base_of::value; + + if constexpr (isValidPrimitive) { + hist->Fill(static_cast(position)...); + } else if constexpr (isValidComplex) { + // savety check for n dimensional histograms (runtime overhead) + // if(hist->GetNdimensions() != sizeof...(position)) return; + double tempArray[] = {static_cast(position)...}; + hist->Fill(tempArray); + } + }; + + template + HistType DownCast(std::shared_ptr hist) + { + // since the variant HistType only knows the interface classes (TH1,TH2,TH3) + // assigning an actual derived type of TH2 and TH3 (e.g. TH2F, TH3I) + // will confuse the compiler since they are both TH2(3) and TH1 at the same time + // it will not know which alternative of HistType to select + // therefore, in these cases we have to explicitly cast to the correct interface type first + if constexpr (std::is_base_of_v) { + return std::static_pointer_cast(hist); + } else if constexpr (std::is_base_of_v) { + return std::static_pointer_cast(hist); + } else { + // all other cases can be left untouched + return hist; + } + } +}; + +//************************************************************************************************** +/** + * Helper class to build all kinds of root histograms with a streamlined user interface. + */ +//************************************************************************************************** + +struct Axis { + std::string name{}; + std::string title{}; + std::vector binEdges{}; + int nBins{}; // 0 when bin edges are specified directly FIXME: make this std::optional +}; + +template +class HistBuilder +{ + public: + HistBuilder() : mAxes{}, mHist{nullptr} {} + HistBuilder(const HistBuilder&) = delete; // non construction-copyable + HistBuilder& operator=(const HistBuilder&) = delete; // non copyable + + void AddAxis(const Axis& axis) { mAxes.push_back(axis); } + void AddAxes(const std::vector& axes) + { + mAxes.insert(mAxes.end(), axes.begin(), axes.end()); + } + void AddAxis(const std::string& name, const std::string& title, const int& nBins, + const double& lowerEdge, const double& upperEdge) + { + mAxes.push_back({name, title, {lowerEdge, upperEdge}, nBins}); + } + void AddAxis(const std::string& name, const std::string& title, + const std::vector& binEdges) + { + mAxes.push_back({name, title, binEdges, 0}); + } + + std::shared_ptr GenerateHist(const std::string& name, bool hasWeights = false) + { + const std::size_t MAX_DIM{10}; + const std::size_t nAxes{mAxes.size()}; + if (nAxes == 0 || nAxes > MAX_DIM) + return nullptr; + + int nBins[MAX_DIM]{0}; + double lowerBounds[MAX_DIM]{0.0}; + double upperBounds[MAX_DIM]{0.0}; + + // first figure out number of bins and dimensions + std::string title = "[ "; + for (std::size_t i = 0; i < nAxes; i++) { + nBins[i] = (mAxes[i].nBins) ? mAxes[i].nBins : mAxes[i].binEdges.size() - 1; + lowerBounds[i] = mAxes[i].binEdges.front(); + upperBounds[i] = mAxes[i].binEdges.back(); + title += mAxes[i].name; + if (i < nAxes - 1) + title += " : "; + else + title += " ]"; + } + + // create histogram + mHist.reset(HistFactory(name, title, nAxes, nBins, lowerBounds, upperBounds)); + + if (!mHist) { + LOGF(WARNING, "ERROR: The number of specified dimensions does not match the type."); + return nullptr; + } + + // set axis properties + for (std::size_t i = 0; i < nAxes; i++) { + TAxis* axis{GetAxis(i)}; + if (axis) { + axis->SetTitle(mAxes[i].title.data()); + if constexpr (std::is_base_of_v) + axis->SetName((std::to_string(i) + "-" + mAxes[i].name).data()); + + // move the bin edges in case a variable binnining was requested + if (!mAxes[i].nBins) { + if (!std::is_sorted(std::begin(mAxes[i].binEdges), std::end(mAxes[i].binEdges))) { + LOGF(WARNING, "ERROR: The bin edges specified for axis %s in histogram %s are not in increasing order!", mAxes[i].name, name); + return nullptr; + } + axis->Set(nBins[i], mAxes[i].binEdges.data()); + } + } + } + if (hasWeights) + mHist->Sumw2(); + mAxes.clear(); // clean up after creating the root histogram + return mHist; + } + + private: + std::vector mAxes; + std::shared_ptr mHist; + + RootHist_t* HistFactory(const std::string& name, const std::string& title, const std::size_t nDim, + const int nBins[], const double lowerBounds[], const double upperBounds[]) + { + if constexpr (std::is_base_of_v) { + return new RootHist_t(name.data(), title.data(), nDim, nBins, lowerBounds, upperBounds); + } else if constexpr (std::is_base_of_v) { + return (nDim != 3) ? nullptr + : new RootHist_t(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1], + nBins[2], lowerBounds[2], upperBounds[2]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 2) ? nullptr + : new RootHist_t(name.data(), title.data(), nBins[0], lowerBounds[0], + upperBounds[0], nBins[1], lowerBounds[1], upperBounds[1]); + } else if constexpr (std::is_base_of_v) { + return (nDim != 1) + ? nullptr + : new RootHist_t(name.data(), title.data(), nBins[0], lowerBounds[0], upperBounds[0]); + } + return nullptr; + } + + TAxis* GetAxis(const int i) + { + if constexpr (std::is_base_of_v) { + return mHist->GetAxis(i); + } else { + return (i == 0) ? mHist->GetXaxis() + : (i == 1) ? mHist->GetYaxis() : (i == 2) ? mHist->GetZaxis() : nullptr; + } + } +}; + +} // namespace histhelpers +} // namespace experimental +} // namespace o2 + +#endif diff --git a/Analysis/Tutorials/CMakeLists.txt b/Analysis/Tutorials/CMakeLists.txt index 84a1ae813f974..c3624626bc491 100644 --- a/Analysis/Tutorials/CMakeLists.txt +++ b/Analysis/Tutorials/CMakeLists.txt @@ -119,3 +119,8 @@ o2_add_dpl_workflow(extended-columns o2_add_dpl_workflow(zdc-vzero-iteration SOURCES src/ZDCVZeroIteration.cxx COMPONENT_NAME AnalysisTutorial) + +o2_add_dpl_workflow(hist-helpers-test + SOURCES src/histHelpersTest.cxx + PUBLIC_LINK_LIBRARIES O2::AnalysisDataModel O2::AnalysisCore + COMPONENT_NAME AnalysisTutorial) diff --git a/Analysis/Tutorials/src/histHelpersTest.cxx b/Analysis/Tutorials/src/histHelpersTest.cxx new file mode 100644 index 0000000000000..ab75b660b8b75 --- /dev/null +++ b/Analysis/Tutorials/src/histHelpersTest.cxx @@ -0,0 +1,147 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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/AnalysisTask.h" +#include "Analysis/HistHelpers.h" + +#include "Framework/AnalysisDataModel.h" +#include "Framework/runDataProcessing.h" +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::experimental::histhelpers; + +struct HistHelpersTest { + + // some unique names for the histograms + enum HistNames : uint8_t { + Hist_pt = 0, + Hist_eta, + Hist_phi, + Hist_nClsTPC, + Hist_nCrossedRowsTPC, + Hist_Chi2PerClTPC, + Hist_nClsITS, + Hist_Chi2PerClITS, + + // for testing + Hist_test_1d_TH1D, + Hist_test_2d_TH2F, + Hist_test_3d_TH3I, + Hist_test_1d_TH1D_Builder, + Hist_test_2d_TH2F_Builder, + + Hist_test_3d_THnI, + Hist_test_5d_THnSparseI, + LAST, + }; + + OutputObj test{HistContainer("Test"), OutputObjHandlingPolicy::QAObject}; + OutputObj kine{HistContainer("Kine"), OutputObjHandlingPolicy::QAObject}; + OutputObj tpc{HistContainer("TPC"), OutputObjHandlingPolicy::QAObject}; + OutputObj its{HistContainer("ITS"), OutputObjHandlingPolicy::QAObject}; + + void init(o2::framework::InitContext&) + { + // add some plain and simple histograms + test->Add(Hist_test_1d_TH1D, TH1D("testHist_TH1", ";x", 100, 0., 50.)); + test->Add(Hist_test_2d_TH2F, TH2F("testHist_TH2", ";x;y", 100, -0.5, 0.5, 100, -0.5, 0.5)); + test->Add(Hist_test_3d_TH3I, TH3I("testHist_TH3", ";x;y;z", 100, 0., 20., 100, 0., 20., 100, 0., 20.)); + + // alternatively use HistBuilder to generate the histogram and add it to container afterwards + HistBuilder sameAsBefore; + sameAsBefore.AddAxis({"x", "x", {0., 50.}, 100}); + test->Add(Hist_test_1d_TH1D_Builder, sameAsBefore.GenerateHist("testHist_TH1_Builder")); + + // the builder enables us to have combinations of flexible + fixed binning in 2d or 3d histograms + // (which are not available via default root constructors) + HistBuilder sameButDifferent; + sameButDifferent.AddAxis({"x", "x", {-0.5, 0.5}, 100}); + sameButDifferent.AddAxis({"y", "y", {-0.5, -0.48, -0.3, 0.4, 0.5}}); // use variable binning for y axsis this time + test->Add(Hist_test_2d_TH2F_Builder, sameButDifferent.GenerateHist("testHist_TH2_Builder")); + + // also for n dimensional histograms things become much simpler: + std::vector ptBins = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, + 1.1, 1.2, 1.3, 1.4, 1.5, 2.0, 5.0, 10.0, 20.0, 50.0}; + std::vector centBins = {0., 30., 60., 90.}; + + // varaiable binning + Axis ptAxis = {"pt", "#it{p}_{T} (GeV/c)", ptBins}; + Axis centAxis = {"cent", "centrality", centBins}; + // equidistant binning + Axis etaAxis = {"eta", "#eta", {-0.8, 0.8}, 5}; + Axis phiAxis = {"phi", "#phi", {0., 2. * M_PI}, 4}; // 36 to see tpc sectors + const int nCuts = 5; + Axis cutAxis = {"cut", "cut setting", {-0.5, nCuts - 0.5}, nCuts}; + + HistBuilder myHistogram; + myHistogram.AddAxis(ptAxis); + myHistogram.AddAxis(etaAxis); + myHistogram.AddAxis("signed1Pt", "q/p_{T}", 200, -8, 8); + test->Add(Hist_test_3d_THnI, myHistogram.GenerateHist("testHist_THn")); + + HistBuilder testSparseHist; + testSparseHist.AddAxis(ptAxis); + testSparseHist.AddAxis(etaAxis); + testSparseHist.AddAxis(phiAxis); + testSparseHist.AddAxis(centAxis); + testSparseHist.AddAxis(cutAxis); + test->Add(Hist_test_5d_THnSparseI, testSparseHist.GenerateHist("testHist_THnSparse")); + + // now add some more useful histograms + + kine->Add(Hist_pt, TH1F("track-pt", "p_{T};p_{T} [GeV/c]", 100, 0., 50.)); + kine->Add(Hist_eta, TH1F("track-eta", "#eta;#eta", 101, -1.0, 1.0)); + kine->Add(Hist_phi, TH1F("track-phi", "#phi;#phi [rad]", 100, 0., 2 * M_PI)); + + tpc->Add(Hist_nCrossedRowsTPC, TH1F("tpc-crossedRows", "number of crossed TPC rows;# crossed rows TPC", 165, -0.5, 164.5)); + tpc->Add(Hist_nClsTPC, TH1F("tpc-foundClusters", "number of found TPC clusters;# clusters TPC", 165, -0.5, 164.5)); + tpc->Add(Hist_Chi2PerClTPC, TH1F("tpc-chi2PerCluster", "chi2 per cluster in TPC;chi2 / cluster TPC", 100, 0, 10)); + + its->Add(Hist_Chi2PerClITS, TH1F("its-chi2PerCluster", "chi2 per ITS cluster;chi2 / cluster ITS", 100, 0, 40)); + } + + void process(soa::Join::iterator const& track) + { + test->Fill(Hist_test_1d_TH1D, 1.); + test->Fill(Hist_test_2d_TH2F, 0.1, 0.3); + test->Fill(Hist_test_3d_TH3I, 10, 10, 15); + + test->Fill(Hist_test_1d_TH1D_Builder, 1.); + test->Fill(Hist_test_2d_TH2F_Builder, 0.1, 0.3); + + test->Fill(Hist_test_3d_THnI, 1., 0., 1.5); + test->Fill(Hist_test_5d_THnSparseI, 1., 0., 1.5, 30, 1); + + // or directly access to the underlying histogram: + test->Get(Hist_test_2d_TH2F)->Fill(0.2, 0.2); + + kine->Fill(Hist_pt, track.pt()); + kine->Fill(Hist_eta, track.eta()); + kine->Fill(Hist_phi, track.phi()); + + tpc->Fill(Hist_nClsTPC, track.tpcNClsFound()); + tpc->Fill(Hist_nCrossedRowsTPC, track.tpcNClsCrossedRows()); + tpc->Fill(Hist_Chi2PerClTPC, track.itsChi2NCl()); + + its->Fill(Hist_Chi2PerClITS, track.tpcChi2NCl()); + } +}; + +//-------------------------------------------------------------------- +// Workflow definition +//-------------------------------------------------------------------- +WorkflowSpec defineDataProcessing(ConfigContext const&) +{ + return WorkflowSpec{ + adaptAnalysisTask("hist-helpers-test")}; +} From 7c508b67fe0fa6c48e9668a6c466887ec58d3601 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Fri, 11 Sep 2020 19:34:00 +0200 Subject: [PATCH 54/76] DPL Analysis: first draft for more generic index binding (#4325) --- Analysis/Tutorials/src/associatedExample.cxx | 31 +++++++------------ Framework/Core/include/Framework/ASoA.h | 23 +++++++++++--- Framework/Foundation/include/Framework/Pack.h | 4 +-- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Analysis/Tutorials/src/associatedExample.cxx b/Analysis/Tutorials/src/associatedExample.cxx index 424c9298b87bc..cbb44589fc32e 100644 --- a/Analysis/Tutorials/src/associatedExample.cxx +++ b/Analysis/Tutorials/src/associatedExample.cxx @@ -15,15 +15,13 @@ namespace o2::aod { namespace etaphi { -DECLARE_SOA_COLUMN(Eta, etas, float); -DECLARE_SOA_COLUMN(Phi, phis, float); -DECLARE_SOA_COLUMN(Pt, pts, float); +DECLARE_SOA_COLUMN(AEta, etas, float); +DECLARE_SOA_COLUMN(APhi, phis, float); +DECLARE_SOA_COLUMN(APt, pts, float); } // namespace etaphi DECLARE_SOA_TABLE(EtaPhi, "AOD", "ETAPHI", - etaphi::Eta, etaphi::Phi); -DECLARE_SOA_TABLE(EtaPhiPt, "AOD", "ETAPHIPT", - etaphi::Eta, etaphi::Phi, etaphi::Pt); + etaphi::AEta, etaphi::APhi); namespace collision { @@ -43,16 +41,13 @@ using namespace o2::framework; // we need GCC 7.4+ for that struct ATask { Produces etaphi; - Produces etaphipt; void process(aod::Tracks const& tracks) { for (auto& track : tracks) { float phi = asin(track.snp()) + track.alpha() + static_cast(M_PI); float eta = log(tan(0.25f * static_cast(M_PI) - 0.5f * atan(track.tgl()))); - float pt = 1.f / track.signed1Pt(); etaphi(eta, phi); - etaphipt(eta, phi, pt); } } }; @@ -72,23 +67,20 @@ struct BTask { LOGF(INFO, "ID: %d", collision.globalIndex()); LOGF(INFO, "Tracks: %d", extTracks.size()); for (auto& track : extTracks) { - LOGF(INFO, "(%f, %f) - (%f, %f)", track.eta(), track.phi(), track.etas(), track.phis()); + LOGF(INFO, "(%f, %f) - (%f, %f)", track.eta(), track.phiraw(), track.etas(), track.phis()); } } }; -struct CTask { - void process(aod::Collision const& collision, soa::Concat const& concatenated) - { - LOGF(INFO, "ID: %d", collision.globalIndex()); - LOGF(INFO, "Tracks: %d", concatenated.size()); - } -}; - struct TTask { + using myCol = soa::Join; void process(soa::Join::iterator const& col, aod::Tracks const& tracks) { - LOGF(INFO, "ID: %d; %d == %d", col.globalIndex(), col.mult(), tracks.size()); + LOGF(INFO, "[direct] ID: %d; %d == %d", col.globalIndex(), col.mult(), tracks.size()); + if (tracks.size() > 0) { + auto track0 = tracks.begin(); + LOGF(INFO, "[index ] ID: %d; %d == %d", track0.collision_as().globalIndex(), track0.collision_as().mult(), tracks.size()); + } } }; @@ -97,7 +89,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) return WorkflowSpec{ adaptAnalysisTask("produce-etaphi"), adaptAnalysisTask("consume-etaphi"), - adaptAnalysisTask("consume-etaphi-twice"), adaptAnalysisTask("produce-mult"), adaptAnalysisTask("consume-mult")}; } diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 01073b2ed94df..d4160f0d33a4c 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1110,6 +1110,13 @@ using JoinBase = decltype(join(std::declval()...)); template using ConcatBase = decltype(concat(std::declval(), std::declval())); +template +constexpr auto is_binding_compatible_v() +{ + return framework::pack_size( + framework::intersected_pack_t, originals_pack_t>{}) > 0; +} + } // namespace o2::soa #define DECLARE_SOA_STORE() \ @@ -1220,24 +1227,30 @@ using ConcatBase = decltype(concat(std::declval(), std::declval())); return *mColumnIterator >= 0; \ } \ \ - binding_t::iterator _Getter_() const \ + template \ + auto _Getter_##_as() const \ { \ assert(mBinding != nullptr); \ - return mBinding->begin() + *mColumnIterator; \ + return static_cast(mBinding)->begin() + *mColumnIterator; \ + } \ + \ + auto _Getter_() const \ + { \ + return _Getter_##_as(); \ } \ \ template \ bool setCurrent(T* current) \ { \ - if constexpr (std::is_same_v) { \ + if constexpr (o2::soa::is_binding_compatible_v()) { \ assert(current != nullptr); \ this->mBinding = current; \ return true; \ } \ return false; \ } \ - binding_t* getCurrent() { return mBinding; } \ - binding_t* mBinding = nullptr; \ + binding_t* getCurrent() { return static_cast(mBinding); } \ + void* mBinding = nullptr; \ }; \ static const o2::framework::expressions::BindingNode _Getter_##Id { _Label_, \ o2::framework::expressions::selectArrowType<_Type_>() } diff --git a/Framework/Foundation/include/Framework/Pack.h b/Framework/Foundation/include/Framework/Pack.h index 0b97e72bd6feb..b357e51af53af 100644 --- a/Framework/Foundation/include/Framework/Pack.h +++ b/Framework/Foundation/include/Framework/Pack.h @@ -186,13 +186,13 @@ constexpr std::size_t has_type_at_t = decltype(select( } // namespace template -constexpr std::size_t has_type_at_v(o2::framework::pack<> p) +constexpr std::size_t has_type_at_v(o2::framework::pack<>) { return -1; } template -constexpr std::size_t has_type_at_v(o2::framework::pack p) +constexpr std::size_t has_type_at_v(o2::framework::pack) { return has_type_at_t; } From e8bd9fe610e7ce3cba6467b5e2a967509b1a788f Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:39:33 +0200 Subject: [PATCH 55/76] Make TPC fwd/bwd time margins float --- .../TPC/include/DataFormatsTPC/TrackTPC.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h index 6cb7b62a36e47..e0e734e552587 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/TrackTPC.h @@ -59,10 +59,10 @@ class TrackTPC : public o2::track::TrackParCov void setHasCSideClusters() { mFlags |= HasCSideClusters; } float getTime0() const { return mTime0; } ///< Reference time of the track, i.e. t-bins of a primary track with eta=0. - short getDeltaTBwd() const { return mDeltaTBwd; } ///< max possible decrement to getTimeVertex - short getDeltaTFwd() const { return mDeltaTFwd; } ///< max possible increment to getTimeVertex - void setDeltaTBwd(short t) { mDeltaTBwd = t; } ///< set max possible decrement to getTimeVertex - void setDeltaTFwd(short t) { mDeltaTFwd = t; } ///< set max possible increment to getTimeVertex + float getDeltaTBwd() const { return mDeltaTBwd; } ///< max possible decrement to getTimeVertex + float getDeltaTFwd() const { return mDeltaTFwd; } ///< max possible increment to getTimeVertex + void setDeltaTBwd(float t) { mDeltaTBwd = t; } ///< set max possible decrement to getTimeVertex + void setDeltaTFwd(float t) { mDeltaTFwd = t; } ///< set max possible increment to getTimeVertex float getChi2() const { return mChi2; } const o2::track::TrackParCov& getOuterParam() const { return mOuterParam; } @@ -112,15 +112,15 @@ class TrackTPC : public o2::track::TrackParCov float mTime0 = 0.f; ///< Reference Z of the track assumed for the vertex, scaled with pseudo ///< VDrift and reference timeframe length, unless it was moved to be on the ///< side of TPC compatible with edge clusters sides. - short mDeltaTFwd = 0; ///< max possible increment to track time - short mDeltaTBwd = 0; ///< max possible decrement to track time + float mDeltaTFwd = 0; ///< max possible increment to track time + float mDeltaTBwd = 0; ///< max possible decrement to track time short mFlags = 0; ///< various flags, see Flags enum float mChi2 = 0.f; // Chi2 of the track o2::track::TrackParCov mOuterParam; // Track parameters at outer end of TPC. dEdxInfo mdEdx; // dEdx Information ClusRef mClustersReference; // reference to externale cluster indices - ClassDefNV(TrackTPC, 3); + ClassDefNV(TrackTPC, 4); }; } // namespace tpc From 98a239e35ba0d69af8dd42ee1538c8b641a5a935 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:41:13 +0200 Subject: [PATCH 56/76] Enforce minimal fwd/bwd delta for CE crossing TPC tracks --- Detectors/TPC/reconstruction/src/GPUCATracking.cxx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx b/Detectors/TPC/reconstruction/src/GPUCATracking.cxx index 2a572c58a2703..e894824d51742 100644 --- a/Detectors/TPC/reconstruction/src/GPUCATracking.cxx +++ b/Detectors/TPC/reconstruction/src/GPUCATracking.cxx @@ -172,6 +172,9 @@ int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* std::atomic_int clusterOffsetCounter; clusterOffsetCounter.store(0); + constexpr float MinDelta = 0.1; + float maxDriftTime = detParam.TPClength * vzbinInv; + #ifdef WITH_OPENMP #pragma omp parallel for if(!outputTracksMCTruth) num_threads(4) #endif @@ -179,7 +182,6 @@ int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* auto& oTrack = (*outputTracks)[iTmp]; const int i = trackSort[iTmp].first; float time0 = 0.f, tFwd = 0.f, tBwd = 0.f; - if (mTrackingCAO2Interface->GetParamContinuous()) { time0 = tracks[i].GetParam().GetTZOffset(); @@ -193,6 +195,9 @@ int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* auto& cl1 = data->clusters->clustersLinear[cacl1.num]; auto& cl2 = data->clusters->clustersLinear[cacl2.num]; delta = fabs(cl1.getTime() - cl2.getTime()) * 0.5f; + if (delta < MinDelta) { + delta = MinDelta; + } break; } } @@ -205,7 +210,7 @@ int GPUCATracking::runTracking(GPUO2InterfaceIOPtrs* data, GPUInterfaceOutputs* float t2 = data->clusters->clustersLinear[c2.num].getTime(); auto times = std::minmax(t1, t2); tFwd = times.first - time0; - tBwd = time0 - (times.second - detParam.TPClength * vzbinInv); + tBwd = time0 - (times.second - maxDriftTime); } } From 24ec3f0bb03929f06ec9753e11958c2020f52a91 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:42:46 +0200 Subject: [PATCH 57/76] Add BunchFilling methods to get 1st and last filled bunch --- .../include/CommonDataFormat/BunchFilling.h | 2 ++ DataFormats/common/src/BunchFilling.cxx | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/DataFormats/common/include/CommonDataFormat/BunchFilling.h b/DataFormats/common/include/CommonDataFormat/BunchFilling.h index 14775e468f9bf..30d50109a6c5c 100644 --- a/DataFormats/common/include/CommonDataFormat/BunchFilling.h +++ b/DataFormats/common/include/CommonDataFormat/BunchFilling.h @@ -29,6 +29,8 @@ class BunchFilling void setBCTrains(int nTrains, int trainSpacingInBC, int nBC, int bcSpacing, int firstBC); void print(int bcPerLine = 100) const; const auto& getPattern() const { return mPattern; } + int getFirstFilledBC() const; + int getLastFilledBC() const; // set BC filling a la TPC TDR, 12 50ns trains of 48 BCs // but instead of uniform train spacing we add 96empty BCs after each train void setDefault() diff --git a/DataFormats/common/src/BunchFilling.cxx b/DataFormats/common/src/BunchFilling.cxx index 328c63ff50707..818be2c9361b0 100644 --- a/DataFormats/common/src/BunchFilling.cxx +++ b/DataFormats/common/src/BunchFilling.cxx @@ -15,6 +15,28 @@ using namespace o2; +//_________________________________________________ +int BunchFilling::getFirstFilledBC() const +{ + for (int bc = 0; bc < o2::constants::lhc::LHCMaxBunches; bc++) { + if (testBC(bc)) { + return bc; + } + } + return -1; +} + +//_________________________________________________ +int BunchFilling::getLastFilledBC() const +{ + for (int bc = o2::constants::lhc::LHCMaxBunches; bc--;) { + if (testBC(bc)) { + return bc; + } + } + return -1; +} + //_________________________________________________ void BunchFilling::setBC(int bcID, bool active) { From 25b438c2389709e86489bd1ab2c1a0c01a66bda1 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:44:00 +0200 Subject: [PATCH 58/76] Add InteractionRecord method to get diff. in ns to other IR --- .../include/CommonDataFormat/InteractionRecord.h | 10 ++++++++++ .../include/FT0Reconstruction/InteractionTag.h | 3 +-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h index b6d34aa5d7605..e68f0260266a6 100644 --- a/DataFormats/common/include/CommonDataFormat/InteractionRecord.h +++ b/DataFormats/common/include/CommonDataFormat/InteractionRecord.h @@ -98,6 +98,16 @@ struct InteractionRecord { return diffBC; } + float differenceInBCns(const InteractionRecord& other) const + { + // return differenc in bunch-crossings + int64_t diffBC = int(bc) - other.bc; + if (orbit != other.orbit) { + diffBC += (int64_t(orbit) - other.orbit) * o2::constants::lhc::LHCMaxBunches; + } + return diffBC; + } + int64_t toLong() const { // return as single long number diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h index ca781e4d02009..21edc29013c30 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/InteractionTag.h @@ -26,7 +26,6 @@ namespace ft0 // These are configurable params for FT0 selection as interaction tag struct InteractionTag : public o2::conf::ConfigurableParamHelper { int minAmplitudeAC = 20; ///< use only FT0 triggers with high enough amplitude - float timeBiasMS = 35.0; ///< relative bias in ns to add bool isSelected(const RecPoints& rp) const { @@ -35,7 +34,7 @@ struct InteractionTag : public o2::conf::ConfigurableParamHelper float getInteractionTimeNS(const RecPoints& rp, const o2::InteractionRecord& refIR) const { - return rp.getInteractionRecord().differenceInBC(refIR) * o2::constants::lhc::LHCBunchSpacingNS + timeBiasMS; // RS FIXME do we want use precise MeanTime? + return rp.getInteractionRecord().differenceInBCns(refIR); // RS FIXME do we want use precise MeanTime? } O2ParamDef(InteractionTag, "ft0tag"); From a3beec26e3aebdb5e094db4609c1edd8b08ddaef Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:53:53 +0200 Subject: [PATCH 59/76] PrimaryVertex min/max IR coverage support --- .../ReconstructionDataFormats/PrimaryVertex.h | 22 ++++++++++++++++--- .../Reconstruction/src/PrimaryVertex.cxx | 10 ++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h index 90d6f8ab74277..8d319333a24da 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertex.h @@ -29,8 +29,12 @@ class PrimaryVertex : public Vertex> PrimaryVertex(const PrimaryVertex&) = default; ~PrimaryVertex() = default; - const InteractionRecord& getIR() const { return mIR; } - void setIR(const InteractionRecord& ir) { mIR = ir; } + const InteractionRecord& getIRMax() const { return mIRMax; } + void setIRMax(const InteractionRecord& ir) { mIRMax = ir; } + const InteractionRecord& getIRMin() const { return mIRMin; } + void setIRMin(const InteractionRecord& ir) { mIRMin = ir; } + void setIR(const InteractionRecord& ir) { mIRMin = mIRMax = ir; } + bool hasUniqueIR() const { return !mIRMin.isDummy() && (mIRMin == mIRMax); } #ifndef ALIGPU_GPUCODE void print() const; @@ -38,7 +42,8 @@ class PrimaryVertex : public Vertex> #endif protected: - InteractionRecord mIR{}; ///< by default not assigned! + InteractionRecord mIRMin{}; ///< by default not assigned! + InteractionRecord mIRMax{}; ///< by default not assigned! ClassDefNV(PrimaryVertex, 1); }; @@ -48,5 +53,16 @@ std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertex& #endif } // namespace dataformats + +/// Defining PrimaryVertex explicitly as messageable +namespace framework +{ +template +struct is_messageable; +template <> +struct is_messageable : std::true_type { +}; +} // namespace framework + } // namespace o2 #endif diff --git a/DataFormats/Reconstruction/src/PrimaryVertex.cxx b/DataFormats/Reconstruction/src/PrimaryVertex.cxx index 387e707d47fe5..f94606c2e203a 100644 --- a/DataFormats/Reconstruction/src/PrimaryVertex.cxx +++ b/DataFormats/Reconstruction/src/PrimaryVertex.cxx @@ -22,9 +22,13 @@ namespace dataformats std::string PrimaryVertex::asString() const { - return o2::utils::concat_string(VertexBase::asString(), - fmt::format("Chi2={:.2f} NCont={:d}: T={:.3f}+-{:.3f} IR=", mChi2, mNContributors, mTimeStamp.getTimeStamp(), mTimeStamp.getTimeStampError()), - mIR.asString()); + auto str = o2::utils::concat_string(VertexBase::asString(), + fmt::format("Chi2={:.2f} NCont={:d}: T={:.3f}+-{:.3f} IR=", mChi2, mNContributors, mTimeStamp.getTimeStamp(), mTimeStamp.getTimeStampError()), + mIRMin.asString()); + if (!hasUniqueIR()) { + str = o2::utils::concat_string(str, " : ", mIRMax.asString()); + } + return str; } std::ostream& operator<<(std::ostream& os, const o2::dataformats::PrimaryVertex& v) From 93f769435babc71a3c6886803394e606d0a4221a Mon Sep 17 00:00:00 2001 From: shahoian Date: Sun, 13 Sep 2020 23:56:45 +0200 Subject: [PATCH 60/76] Validate P.Vertex by bunch filling, set min/max IR --- .../ReconstructionDataFormats/VtxTrackIndex.h | 7 +- .../GlobalTrackingWorkflow/CMakeLists.txt | 1 + .../src/PrimaryVertexingSpec.cxx | 25 ++-- .../include/DetectorsVertexing/PVertexer.h | 18 ++- .../DetectorsVertexing/PVertexerHelpers.h | 2 + .../DetectorsVertexing/PVertexerParams.h | 4 +- Detectors/Vertexing/src/PVertexer.cxx | 110 ++++++++++++++---- 7 files changed, 130 insertions(+), 37 deletions(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h index 0088c489e574f..b001d3f8a73c1 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/VtxTrackIndex.h @@ -12,6 +12,9 @@ /// \brief Index of track attached to vertx: index in its proper container, container source and flags /// \author ruben.shahoyan@cern.ch +#ifndef O2_VERTEX_TRACK_INDEX +#define O2_VERTEX_TRACK_INDEX + #include "CommonDataFormat/AbstractRef.h" #include #include @@ -32,7 +35,7 @@ class VtxTrackIndex : public AbstractRef<26, 3, 3> }; enum Flags : uint8_t { Contributor, // flag that it contributes to vertex fit - Attached, // flag that it is attached w/o contributing + Reserved, // Ambiguous, // flag that attachment is ambiguous NFlags }; @@ -49,3 +52,5 @@ std::ostream& operator<<(std::ostream& os, const o2::dataformats::VtxTrackIndex& } // namespace dataformats } // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt index 2ab0a946f9025..c657d7dd35c97 100644 --- a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt @@ -23,6 +23,7 @@ o2_add_library(GlobalTrackingWorkflow O2::TPCWorkflow O2::FT0Workflow O2::ITSMFTWorkflow + O2::SimulationDataFormat O2::DetectorsVertexing) o2_add_executable(match-workflow diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx index a7a7901dc6d74..27995a0db2962 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx @@ -15,6 +15,8 @@ #include "DetectorsBase/Propagator.h" #include "GlobalTrackingWorkflow/PrimaryVertexingSpec.h" #include "SimulationDataFormat/MCEventLabel.h" +#include "CommonDataFormat/BunchFilling.h" +#include "SimulationDataFormat/DigitizationContext.h" using namespace o2::framework; @@ -30,6 +32,11 @@ void PrimaryVertexingSpec::init(InitContext& ic) mTimer.Stop(); mTimer.Reset(); mVertexer.setValidateWithFT0(mValidateWithFT0); + + // set bunch filling. Eventually, this should come from CCDB + const auto* digctx = o2::steer::DigitizationContext::loadFromFile("collisioncontext.root"); + const auto& bcfill = digctx->getBunchFilling(); + mVertexer.setBunchFilling(bcfill); mVertexer.init(); } @@ -48,7 +55,7 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) lblTPC = pc.inputs().get>("lblTPC"); } std::vector vertices; - std::vector vertexTrackIDs; + std::vector vertexTrackIDs; std::vector v2tRefs; std::vector lblVtx; @@ -57,12 +64,12 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) mVertexer.setStartIR({0, dh->firstTForbit}); mVertexer.process(tracksITSTPC, ft0Data, vertices, vertexTrackIDs, v2tRefs, lblITS, lblTPC, lblVtx); - pc.outputs().snapshot(Output{"GLO", "PVERTEX", 0, Lifetime::Timeframe}, vertices); - pc.outputs().snapshot(Output{"GLO", "PVERTEX_TRIDREFS", 0, Lifetime::Timeframe}, v2tRefs); - pc.outputs().snapshot(Output{"GLO", "PVERTEX_TRID", 0, Lifetime::Timeframe}, vertexTrackIDs); + pc.outputs().snapshot(Output{"GLO", "PVTX", 0, Lifetime::Timeframe}, vertices); + pc.outputs().snapshot(Output{"GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe}, v2tRefs); + pc.outputs().snapshot(Output{"GLO", "PVTX_CONTID", 0, Lifetime::Timeframe}, vertexTrackIDs); if (mUseMC) { - pc.outputs().snapshot(Output{"GLO", "PVERTEX_MCTR", 0, Lifetime::Timeframe}, lblVtx); + pc.outputs().snapshot(Output{"GLO", "PVTX_MCTR", 0, Lifetime::Timeframe}, lblVtx); } mTimer.Stop(); @@ -86,14 +93,14 @@ DataProcessorSpec getPrimaryVertexingSpec(bool validateWithFT0, bool useMC) inputs.emplace_back("fitInfo", "FT0", "RECPOINTS", 0, Lifetime::Timeframe); } - outputs.emplace_back("GLO", "PVERTEX", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVERTEX_TRIDREFS", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVERTEX_TRID", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX_CONTID", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX_CONTIDREFS", 0, Lifetime::Timeframe); if (useMC) { inputs.emplace_back("lblITS", "GLO", "TPCITS_ITSMC", 0, Lifetime::Timeframe); inputs.emplace_back("lblTPC", "GLO", "TPCITS_TPCMC", 0, Lifetime::Timeframe); - outputs.emplace_back("GLO", "PVERTEX_MCTR", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "PVTX_MCTR", 0, Lifetime::Timeframe); } return DataProcessorSpec{ diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h index 39870ec6e2b15..410cc95ab9cd1 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h @@ -16,9 +16,11 @@ #define O2_PVERTEXER_H #include +#include #include "CommonConstants/LHCConstants.h" #include "CommonDataFormat/TimeStamp.h" #include "CommonDataFormat/RangeReference.h" +#include "CommonDataFormat/BunchFilling.h" #include "SimulationDataFormat/MCEventLabel.h" #include "SimulationDataFormat/MCCompLabel.h" #include "MathUtils/Utils.h" @@ -50,12 +52,14 @@ class PVertexer void init(); int process(gsl::span tracksITSTPC, gsl::span ft0Data, - std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs, + std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs, gsl::span lblITS, gsl::span lblTPC, std::vector& lblVtx); + int process(gsl::span tracksITSTPC, gsl::span ft0Data, - std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs); + std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs); + static void createMCLabels(gsl::span lblITS, gsl::span lblTPC, - const std::vector vertices, const std::vector vertexTrackIDs, const std::vector v2tRefs, + const std::vector vertices, const std::vector vertexTrackIDs, const std::vector v2tRefs, std::vector& lblVtx); bool findVertex(const VertexingInput& input, PVertex& vtx); @@ -68,6 +72,9 @@ class PVertexer float getTukey() const; void finalizeVertex(const VertexingInput& input, const PVertex& vtx, std::vector& vertices, std::vector& v2tRefs, std::vector& vertexTrackIDs, SeedHisto& histo); + bool setCompatibleIR(PVertex& vtx); + + void setBunchFilling(const o2::BunchFilling& bf); void setBz(float bz) { mBz = bz; } void setValidateWithFT0(bool v) { mValidateWithFT0 = v; } @@ -105,8 +112,11 @@ class PVertexer void clusterizeTimeBruteForce(float margin = 0.1, float cut = 25); void clusterizeTime(float binSize = 0.1, float maxTDist = 0.6); int findVertices(const VertexingInput& input, std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs); - int getBestFT0Trigger(const PVertex& vtx, gsl::span ft0Data, int& currEntry) const; + std::pair getBestFT0Trigger(const PVertex& vtx, gsl::span ft0Data, int& currEntry) const; + o2::BunchFilling mBunchFilling; + std::array mClosestBunchAbove; // closest filled bunch from above + std::array mClosestBunchBelow; // closest filled bunch from below o2d::VertexBase mMeanVertex{{0., 0., 0.}, {0.1 * 0.1, 0., 0.1 * 0.1, 0., 0., 6. * 6.}}; std::array mXYConstraintInvErr = {1.0f, 0.f, 1.0f}; ///< nominal vertex constraint inverted errors^2 // diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h index 98275a1124595..3d3b322fcff17 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerHelpers.h @@ -18,6 +18,7 @@ #include "gsl/span" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" #include "CommonDataFormat/TimeStamp.h" #include "CommonDataFormat/RangeReference.h" @@ -29,6 +30,7 @@ namespace vertexing using PVertex = o2::dataformats::PrimaryVertex; using TimeEst = o2::dataformats::TimeStampWithError; using V2TRef = o2::dataformats::RangeReference; +using GIndex = o2::dataformats::VtxTrackIndex; ///< weights and scaling params for current vertex struct VertexSeed : public PVertex { diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h index 128c0ca436a6b..42c45afdadbe4 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexerParams.h @@ -41,7 +41,9 @@ struct PVertexerParams : public o2::conf::ConfigurableParamHelper tracksITSTPC, gsl::span ft0Data, - std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs) + std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs) { createTracksPool(tracksITSTPC); @@ -59,37 +59,46 @@ int PVertexer::process(gsl::span tracksITSTPC, gsl::span vertexTrackIDs.clear(); vertices.reserve(verticesLoc.size()); v2tRefs.reserve(v2tRefsLoc.size()); - vertexTrackIDs.resize(vertexTrackIDsLoc.size()); + vertexTrackIDs.reserve(vertexTrackIDsLoc.size()); int trCopied = 0, count = 0, vtimeID = 0; for (auto i : vtTimeSortID) { auto& vtx = verticesLoc[i]; + + bool irSet = setCompatibleIR(vtx); + if (!irSet) { + continue; + } // do we need to validate by FT0 ? if (mValidateWithFT0) { auto bestMatch = getBestFT0Trigger(vtx, ft0Data, vtimeID); - if (bestMatch >= 0) { // RS FIXME eventually, we should assign the IR to vertex? + if (bestMatch.first >= 0) { vtx.setFlags(PVertex::TimeValidated); - vtx.setIR(ft0Data[bestMatch].getInteractionRecord()); - LOG(DEBUG) << "Validated with t0" << bestMatch; + if (bestMatch.second == 1) { + vtx.setIR(ft0Data[bestMatch.first].getInteractionRecord()); + } + LOG(DEBUG) << "Validated with t0 " << bestMatch.first << " with " << bestMatch.second << " candidates"; } else if (vtx.getNContributors() >= mPVParams->minNContributorsForFT0cut) { LOG(DEBUG) << "Discarding " << vtx; continue; // reject } } vertices.push_back(vtx); - memcpy(&vertexTrackIDs[trCopied], &vertexTrackIDsLoc[v2tRefsLoc[i].getFirstEntry()], v2tRefsLoc[i].getEntries() * sizeof(int)); - v2tRefs.emplace_back(trCopied, v2tRefsLoc[i].getEntries()); - trCopied += v2tRefsLoc[i].getEntries(); + int it = v2tRefsLoc[i].getFirstEntry(), itEnd = it + v2tRefsLoc[i].getEntries(), dest0 = vertexTrackIDs.size(); + for (; it < itEnd; it++) { + auto& gid = vertexTrackIDs.emplace_back(vertexTrackIDsLoc[it], GIndex::TPCITS); + gid.setBit(GIndex::Contributor); + } + v2tRefs.emplace_back(dest0, v2tRefsLoc[i].getEntries()); LOG(DEBUG) << "#" << count++ << " " << vertices.back() << " | " << v2tRefs.back().getEntries() << " indices from " << v2tRefs.back().getFirstEntry(); // RS REM } - vertexTrackIDs.resize(trCopied); return vertices.size(); } //___________________________________________________________________ int PVertexer::process(gsl::span tracksITSTPC, gsl::span ft0Data, - std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs, + std::vector& vertices, std::vector& vertexTrackIDs, std::vector& v2tRefs, gsl::span lblITS, gsl::span lblTPC, std::vector& lblVtx) { auto nv = process(tracksITSTPC, ft0Data, vertices, vertexTrackIDs, v2tRefs); @@ -604,7 +613,7 @@ void PVertexer::clusterizeTime(float binSize, float maxTDist) //___________________________________________________________________ void PVertexer::createMCLabels(gsl::span lblITS, gsl::span lblTPC, - const std::vector vertices, const std::vector vertexTrackIDs, const std::vector v2tRefs, + const std::vector vertices, const std::vector vertexTrackIDs, const std::vector v2tRefs, std::vector& lblVtx) { lblVtx.clear(); @@ -636,7 +645,7 @@ void PVertexer::createMCLabels(gsl::span lblITS, gsl::spa labelOccurenceITS.clear(); o2::MCEventLabel winner; // unset at the moment for (; tref < last; tref++) { - int tid = vertexTrackIDs[tref]; + int tid = vertexTrackIDs[tref].getIndex(); const auto& lITS = lblITS[tid]; const auto& lTPC = lblTPC[tid]; if (!lITS.isSet() || !lTPC.isSet()) { @@ -658,23 +667,23 @@ void PVertexer::createMCLabels(gsl::span lblITS, gsl::spa } //___________________________________________________________________ -int PVertexer::getBestFT0Trigger(const PVertex& vtx, gsl::span ft0Data, int& currEntry) const +std::pair PVertexer::getBestFT0Trigger(const PVertex& vtx, gsl::span ft0Data, int& currEntry) const { - // check if the times stamp is compatible with any entry startinge from currEntry in ft0Data vector, return best matching time + // select best matching FT0 recpoint int best = -1, n = ft0Data.size(); - auto t = vtx.getTimeStamp(); - float cut = mPVParams->nSigmaFT0cut * mPVParams->maxTError, bestDf = cut, df = 0; - while (currEntry < n && mFT0Params->getInteractionTimeNS(ft0Data[currEntry], mStartIR) * 1e-3 + cut < t.getTimeStamp()) { + while (currEntry < n && ft0Data[currEntry].getInteractionRecord() < vtx.getIRMin()) { currEntry++; // skip all times which have no chance to be matched } - cut = mPVParams->nSigmaFT0cut * std::min(mPVParams->maxTError, std::max(mPVParams->minTError, t.getTimeStampError())); - int i = currEntry; + int i = currEntry, nCompatible = 0; + float bestDf = 1e12; + auto tVtxNS = (vtx.getTimeStamp().getTimeStamp() + mPVParams->timeBiasMS) * 1e3; // time in ns while (i < n) { - if ((df = mFT0Params->getInteractionTimeNS(ft0Data[i], mStartIR) * 1e-3) > bestDf) { + if (ft0Data[i].getInteractionRecord() > vtx.getIRMax()) { break; } if (mFT0Params->isSelected(ft0Data[i])) { - auto dfa = std::abs(df); + nCompatible++; + auto dfa = std::abs(mFT0Params->getInteractionTimeNS(ft0Data[i], mStartIR) - tVtxNS); if (dfa <= bestDf) { bestDf = dfa; best = i; @@ -682,5 +691,62 @@ int PVertexer::getBestFT0Trigger(const PVertex& vtx, gsl::spannSigmaTimeCut * std::max(mPVParams->minTError, std::min(mPVParams->maxTError, vtxT.getTimeStampError())); + float t = vtxT.getTimeStamp() + mPVParams->timeBiasMS; + if (t > rangeT) { + irMin += o2::InteractionRecord(1.e3 * (t - rangeT)); + } + irMax += o2::InteractionRecord(1.e3 * (t + rangeT)); + irMax++; // to account for rounding + // restrict using bunch filling + int bc = mClosestBunchAbove[irMin.bc]; + if (bc < irMin.bc) { + irMin.orbit++; + } + irMin.bc = bc; + bc = mClosestBunchBelow[irMax.bc]; + if (bc > irMax.bc) { + if (irMax.orbit == 0) { + return false; + } + irMax.orbit--; + } + irMax.bc = bc; + vtx.setIRMin(irMin); + vtx.setIRMax(irMax); + return irMax >= irMin; } From f093899a46d8e980cbb7402026a6a3266318aee3 Mon Sep 17 00:00:00 2001 From: shahoian Date: Mon, 14 Sep 2020 00:08:02 +0200 Subject: [PATCH 61/76] P.Vertex-tracks matching class + related workflows update At the moment the pr.vertex - track matching is done in time only (except vertex fit contributor TPC/ITS tracks), for every vertex list of global indices (VtxTrackIndex) is added, providing the source (global, or ITS or TPC track), ID in the source and bit flags for contributors and ambigous assignment. --- .../GlobalTrackingWorkflow/CMakeLists.txt | 2 + .../PrimaryVertexReaderSpec.h | 10 +- .../PrimaryVertexWriterSpec.h | 2 +- .../VertexTrackMatcherSpec.h | 50 ++++ .../src/PrimaryVertexReaderSpec.cxx | 57 ++-- .../src/PrimaryVertexWriterSpec.cxx | 13 +- .../src/VertexTrackMatcherSpec.cxx | 109 ++++++++ .../src/primary-vertexing-workflow.cxx | 14 +- Detectors/Vertexing/CMakeLists.txt | 5 + .../DetectorsVertexing/VertexTrackMatcher.h | 88 +++++++ .../Vertexing/src/DetectorsVertexingLinkDef.h | 1 + .../Vertexing/src/VertexTrackMatcher.cxx | 246 ++++++++++++++++++ 12 files changed, 571 insertions(+), 26 deletions(-) create mode 100644 Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/VertexTrackMatcherSpec.h create mode 100644 Detectors/GlobalTrackingWorkflow/src/VertexTrackMatcherSpec.cxx create mode 100644 Detectors/Vertexing/include/DetectorsVertexing/VertexTrackMatcher.h create mode 100644 Detectors/Vertexing/src/VertexTrackMatcher.cxx diff --git a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt index c657d7dd35c97..ce3b5df0d4986 100644 --- a/Detectors/GlobalTrackingWorkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/CMakeLists.txt @@ -17,6 +17,7 @@ o2_add_library(GlobalTrackingWorkflow src/PrimaryVertexingSpec.cxx src/PrimaryVertexWriterSpec.cxx src/PrimaryVertexReaderSpec.cxx + src/VertexTrackMatcherSpec.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTracking O2::ITStracking O2::ITSWorkflow @@ -41,5 +42,6 @@ o2_add_executable(vertex-reader-workflow SOURCES src/primary-vertex-reader-workflow.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTrackingWorkflow ) + add_subdirectory(tofworkflow) add_subdirectory(tpcinterpolationworkflow) diff --git a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h index a9b9f5729c0ce..d99b6a0227334 100644 --- a/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h +++ b/Detectors/GlobalTrackingWorkflow/include/GlobalTrackingWorkflow/PrimaryVertexReaderSpec.h @@ -21,6 +21,7 @@ #include "CommonDataFormat/TimeStamp.h" #include "CommonDataFormat/RangeReference.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "SimulationDataFormat/MCEventLabel.h" @@ -35,6 +36,7 @@ class PrimaryVertexReader : public o2::framework::Task using Label = o2::MCEventLabel; using V2TRef = o2::dataformats::RangeReference; using PVertex = o2::dataformats::PrimaryVertex; + using GIndex = o2::dataformats::VtxTrackIndex; public: PrimaryVertexReader(bool useMC) : mUseMC(useMC) {} @@ -43,18 +45,20 @@ class PrimaryVertexReader : public o2::framework::Task void run(o2::framework::ProcessingContext& pc) final; protected: - void connectTree(const std::string& filename); + void connectTree(); + bool mVerbose = false; bool mUseMC = false; std::vector mVertices, *mVerticesPtr = &mVertices; - std::vector mPVTrIdx, *mPVTrIdxPtr = &mPVTrIdx; - std::vector mPV2TrIdx, *mPV2TrIdxPtr = &mPV2TrIdx; std::vector