diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index 475e65bf9212b..27dad43480913 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -22,14 +22,20 @@ #include "Framework/DataOutputDirector.h" #include "Framework/TableTreeHelpers.h" #include "Framework/Monitoring.h" +#include "Framework/Signpost.h" #include +#include #include #include #include #include #include #include +#include +#include + +O2_DECLARE_DYNAMIC_LOG(histogram_registry); namespace o2::framework::writers { @@ -46,6 +52,7 @@ struct InputObjectRoute { struct InputObject { TClass* kind = nullptr; void* obj = nullptr; + std::string container; std::string name; int count = -1; }; @@ -273,24 +280,30 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) callbacks.set(endofdatacb); return [inputObjects, objmap, tskmap](ProcessingContext& pc) mutable -> void { auto mergePart = [&inputObjects, &objmap, &tskmap, &pc](DataRef const& ref) { + O2_SIGNPOST_ID_GENERATE(hid, histogram_registry); + O2_SIGNPOST_START(histogram_registry, hid, "mergePart", "Merging histogram"); if (!ref.header) { - LOG(error) << "Header not found"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Header not found."); return; } auto datah = o2::header::get(ref.header); if (!datah) { - LOG(error) << "No data header in stack"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No data header in stack"); return; } if (!ref.payload) { - LOGP(error, "Payload not found for {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Payload not found for %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } auto objh = o2::header::get(ref.header); if (!objh) { - LOGP(error, "No output object header in stack of {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No output object header in stack of %{public}s/%{public}s/%d.", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } @@ -300,48 +313,73 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) obj.kind = tm.ReadClass(); tm.SetBufferOffset(0); tm.ResetMap(); + O2_SIGNPOST_ID_GENERATE(did, histogram_registry); + O2_SIGNPOST_START(histogram_registry, did, "initialising root", "Starting deserialization of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); if (obj.kind == nullptr) { - LOGP(error, "Cannot read class info from buffer of {}/{}/{}", datah->dataOrigin.as(), datah->dataDescription.as(), datah->subSpecification); + O2_SIGNPOST_END(histogram_registry, did, "initialising root", "Failed to deserialise"); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "Cannot read class info from buffer of %{public}s/%{public}s/%d.", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); return; } + O2_SIGNPOST_END(histogram_registry, did, "initialising root", "Done init."); auto policy = objh->mPolicy; auto sourceType = objh->mSourceType; auto hash = objh->mTaskHash; + O2_SIGNPOST_START(histogram_registry, did, "deserialization", "Starting deserialization of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); obj.obj = tm.ReadObjectAny(obj.kind); auto* named = static_cast(obj.obj); obj.name = named->GetName(); + O2_SIGNPOST_END(histogram_registry, did, "deserialization", "Done deserialization."); + // If we have a folder, we assume the first element of the path + // to be the name of the registry. + if (sourceType == HistogramRegistrySource) { + obj.container = objh->containerName; + } else { + obj.container = obj.name; + } auto hpos = std::find_if(tskmap.begin(), tskmap.end(), [&](auto&& x) { return x.id == hash; }); if (hpos == tskmap.end()) { - LOG(error) << "No task found for hash " << hash; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No task found for hash %d.", hash); return; } auto taskname = hpos->name; auto opos = std::find_if(objmap.begin(), objmap.end(), [&](auto&& x) { return x.id == hash; }); if (opos == objmap.end()) { - LOG(error) << "No object list found for task " << taskname << " (hash=" << hash << ")"; + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No object list found for task %{public}s (hash=%d).", + taskname.c_str(), hash); return; } auto objects = opos->bindings; - if (std::find(objects.begin(), objects.end(), obj.name) == objects.end()) { - LOG(error) << "No object " << obj.name << " in map for task " << taskname; + if (std::find(objects.begin(), objects.end(), obj.container) == objects.end()) { + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "mergePart", "No container %{public}s in map for task %{public}s.", + obj.container.c_str(), taskname.c_str()); return; } auto nameHash = runtime_hash(obj.name.c_str()); InputObjectRoute key{obj.name, nameHash, taskname, hash, policy, sourceType}; auto existing = std::find_if(inputObjects->begin(), inputObjects->end(), [&](auto&& x) { return (x.first.uniqueId == nameHash) && (x.first.taskHash == hash); }); // If it's the first one, we just add it to the list. + O2_SIGNPOST_START(histogram_registry, did, "merging", "Starting merging of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); if (existing == inputObjects->end()) { obj.count = objh->mPipelineSize; - inputObjects->push_back(std::make_pair(key, obj)); + inputObjects->emplace_back(key, obj); existing = inputObjects->end() - 1; } else { obj.count = existing->second.count; // Otherwise, we merge it with the existing one. auto merger = existing->second.kind->GetMerge(); if (!merger) { - LOG(error) << "Already one unmergeable object found for " << obj.name; + O2_SIGNPOST_END(histogram_registry, did, "merging", "Unabled to merge"); + O2_SIGNPOST_END_WITH_ERROR(histogram_registry, hid, "merging", "Already one unmergeable object found for %{public}s", obj.name.c_str()); return; } TList coll; @@ -353,15 +391,22 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) existing->second.count -= 1; if (existing->second.count != 0) { + O2_SIGNPOST_END(histogram_registry, did, "merging", "Done partial merging."); + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Pipeline lanes still missing."); return; } + O2_SIGNPOST_END(histogram_registry, did, "merging", "Done merging."); // Write the object here. auto route = existing->first; auto entry = existing->second; auto file = ROOTfileNames.find(route.policy); if (file == ROOTfileNames.end()) { + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Not matching any file."); return; } + O2_SIGNPOST_START(histogram_registry, did, "writing", "Starting writing of %{public}s/%{public}s/%d", + datah->dataOrigin.as().c_str(), datah->dataDescription.as().c_str(), + datah->subSpecification); auto filename = file->second; if (f[route.policy] == nullptr) { f[route.policy] = TFile::Open(filename.c_str(), "RECREATE"); @@ -375,53 +420,53 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) currentFile = filename; } - // translate the list-structure created by the registry into a directory structure within the file - std::function writeListToFile; - writeListToFile = [&](TList* list, TDirectory* parentDir) { - TIter next(list); - TObject* object = nullptr; - while ((object = next())) { - if (object->InheritsFrom(TList::Class())) { - writeListToFile(static_cast(object), parentDir->mkdir(object->GetName(), object->GetName(), true)); + // FIXME: handle folders + f[route.policy]->cd("/"); + auto* currentDir = f[route.policy]->GetDirectory(currentDirectory.c_str()); + // The name contains a path... + int objSize = 0; + if (sourceType == HistogramRegistrySource) { + TDirectory* currentFolder = currentDir; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Toplevel folder is %{public}s.", + currentDir->GetName()); + std::string objName = entry.name; + auto lastSlash = entry.name.rfind('/'); + + if (lastSlash != std::string::npos) { + auto dirname = entry.name.substr(0, lastSlash); + objName = entry.name.substr(lastSlash + 1); + currentFolder = currentDir->GetDirectory(dirname.c_str()); + if (!currentFolder) { + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Creating folder %{public}s", + dirname.c_str()); + currentFolder = currentDir->mkdir(dirname.c_str(), "", kTRUE); } else { - int objSize = parentDir->WriteObjectAny(object, object->Class(), object->GetName()); - static int maxSizeWritten = 0; - if (objSize > maxSizeWritten) { - auto& monitoring = pc.services().get(); - maxSizeWritten = objSize; - monitoring.send(Metric{fmt::format("{}/{}:{}", object->ClassName(), object->GetName(), objSize), "aod-largest-object-written"}.addTag(tags::Key::Subsystem, tags::Value::DPL)); - } - auto* written = list->Remove(object); - delete written; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Folder %{public}s already there.", + currentFolder->GetName()); } } - }; - - TDirectory* currentDir = f[route.policy]->GetDirectory(currentDirectory.c_str()); - if (route.sourceType == OutputObjSourceType::HistogramRegistrySource) { - auto* outputList = static_cast(entry.obj); - outputList->SetOwner(false); - - // if registry should live in dedicated folder a TNamed object is appended to the list - if (outputList->Last() && outputList->Last()->IsA() == TNamed::Class()) { - delete outputList->Last(); - outputList->RemoveLast(); - currentDir = currentDir->mkdir(outputList->GetName(), outputList->GetName(), true); - } - - writeListToFile(outputList, currentDir); - outputList->SetOwner(); - delete outputList; + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Writing %{public}s of kind %{public}s in %{public}s", + entry.name.c_str(), entry.kind->GetName(), currentDir->GetName()); + objSize = currentFolder->WriteObjectAny(entry.obj, entry.kind, objName.c_str()); + O2_SIGNPOST_END(histogram_registry, did, "writing", "End writing %{public}s", entry.name.c_str()); + delete (TObject*)entry.obj; entry.obj = nullptr; } else { - currentDir->WriteObjectAny(entry.obj, entry.kind, entry.name.c_str()); + O2_SIGNPOST_EVENT_EMIT(histogram_registry, hid, "mergePart", "Writing %{public}s of kind %{public}s in %{public}s", + entry.name.c_str(), entry.kind->GetName(), currentDir->GetName()); + objSize = currentDir->WriteObjectAny(entry.obj, entry.kind, entry.name.c_str()); + O2_SIGNPOST_END(histogram_registry, did, "writing", "End writing %{public}s", entry.name.c_str()); delete (TObject*)entry.obj; entry.obj = nullptr; } + O2_SIGNPOST_END(histogram_registry, hid, "mergePart", "Done merging object of %d bytes.", objSize); }; + O2_SIGNPOST_ID_GENERATE(rid, histogram_registry); + O2_SIGNPOST_START(histogram_registry, rid, "processParts", "Start merging %zu parts received together.", pc.inputs().getNofParts(0)); for (int pi = 0; pi < pc.inputs().getNofParts(0); ++pi) { mergePart(pc.inputs().get("x", pi)); } + O2_SIGNPOST_END(histogram_registry, rid, "processParts", "Done histograms in multipart message."); }; }}; } diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 6c43bf3eebebb..596f3da6a557a 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -11,6 +11,7 @@ #ifndef FRAMEWORK_ANALYSISMANAGERS_H #define FRAMEWORK_ANALYSISMANAGERS_H +#include "DataAllocator.h" #include "Framework/AnalysisHelpers.h" #include "Framework/DataSpecUtils.h" #include "Framework/GroupedCombinations.h" @@ -247,7 +248,10 @@ template bool postRunOutput(EndOfStreamContext& context, T& hr) { auto& deviceSpec = context.services().get(); - context.outputs().snapshot(hr.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *(hr.getListOfHistograms())); + auto sendHistos = [deviceSpec, &context](HistogramRegistry const& self, TNamed* obj) mutable { + context.outputs().snapshot(self.ref(deviceSpec.inputTimesliceId, deviceSpec.maxInputTimeslices), *obj); + }; + hr.apply(sendHistos); hr.clean(); return true; } diff --git a/Framework/Core/include/Framework/HistogramRegistry.h b/Framework/Core/include/Framework/HistogramRegistry.h index 6db4bd0a2d0e2..49ef006f84a79 100644 --- a/Framework/Core/include/Framework/HistogramRegistry.h +++ b/Framework/Core/include/Framework/HistogramRegistry.h @@ -173,16 +173,15 @@ class HistogramRegistry template std::shared_ptr operator()(const HistName& histName); + // Apply @a callback on every single entry in the registry + void apply(std::function callback) const; // return the OutputSpec associated to the HistogramRegistry OutputSpec const spec(); - OutputRef ref(uint16_t idx, uint16_t pipelineSize); + OutputRef ref(uint16_t idx, uint16_t pipelineSize) const; void setHash(uint32_t hash); - /// returns the list of histograms, properly sorted for writing. - TList* getListOfHistograms(); - /// deletes all the histograms from the registry void clean(); @@ -220,16 +219,13 @@ class HistogramRegistry // helper function to find the histogram position in the registry template - uint32_t getHistIndex(const T& histName); + uint32_t getHistIndex(const T& histName) const; constexpr uint32_t imask(uint32_t i) const { return i & REGISTRY_BITMASK; } - // helper function to create resp. find the subList defined by path - TList* getSubList(TList* list, std::deque& path); - // helper function to split user defined path/to/hist/name string std::deque splitPath(const std::string& pathAndNameUser); @@ -431,7 +427,7 @@ std::shared_ptr HistogramRegistry::operator()(const HistName& histName) } template -uint32_t HistogramRegistry::getHistIndex(const T& histName) +uint32_t HistogramRegistry::getHistIndex(const T& histName) const { if (O2_BUILTIN_LIKELY(histName.hash == mRegistryKey[histName.idx])) { return histName.idx; diff --git a/Framework/Core/include/Framework/OutputObjHeader.h b/Framework/Core/include/Framework/OutputObjHeader.h index 6e665bb697572..f1c284d564f15 100644 --- a/Framework/Core/include/Framework/OutputObjHeader.h +++ b/Framework/Core/include/Framework/OutputObjHeader.h @@ -44,6 +44,8 @@ struct OutputObjHeader : public BaseHeader { uint32_t mTaskHash; uint16_t mPipelineIndex = 0; uint16_t mPipelineSize = 1; + // Name of the actual container for the object, e.g. the HistogramRegistry name + char containerName[64] = {0}; constexpr OutputObjHeader() : BaseHeader(sizeof(OutputObjHeader), sHeaderType, sSerializationMethod, sVersion), diff --git a/Framework/Core/src/HistogramRegistry.cxx b/Framework/Core/src/HistogramRegistry.cxx index 0a0cc1fc3a690..5e39fbe7181e7 100644 --- a/Framework/Core/src/HistogramRegistry.cxx +++ b/Framework/Core/src/HistogramRegistry.cxx @@ -51,9 +51,12 @@ OutputSpec const HistogramRegistry::spec() return OutputSpec{OutputLabel{mName}, "ATSK", desc, 0, Lifetime::QA}; } -OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize) +OutputRef HistogramRegistry::ref(uint16_t pipelineIndex, uint16_t pipelineSize) const { - return OutputRef{std::string{mName}, 0, o2::header::Stack{OutputObjHeader{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize}}}; + OutputObjHeader header{mPolicy, OutputObjSourceType::HistogramRegistrySource, mTaskHash, pipelineIndex, pipelineSize}; + // Copy the name of the registry to the haeder. + strncpy(header.containerName, mName.data(), 64); + return OutputRef{std::string{mName}, 0, o2::header::Stack{header}}; } void HistogramRegistry::setHash(uint32_t hash) @@ -282,87 +285,26 @@ void HistogramRegistry::print(bool showAxisDetails) LOGF(info, ""); } -// create output structure will be propagated to file-sink -TList* HistogramRegistry::getListOfHistograms() +void HistogramRegistry::apply(std::function callback) const { - TList* list = new TList(); - list->SetName(mName.data()); - + // Keep the list sorted as originally done to avoid hidden dependency on the order, for now , for now. + auto finalList = mRegisteredNames; + auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) { + return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), + [](char c1, char c2) { return std::tolower(static_cast(c1)) < std::tolower(static_cast(c2)); }); + }; if (mSortHistos) { - auto caseInsensitiveCompare = [](const std::string& s1, const std::string& s2) { - return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), - [](char c1, char c2) { return std::tolower(static_cast(c1)) < std::tolower(static_cast(c2)); }); - }; - std::sort(mRegisteredNames.begin(), mRegisteredNames.end(), caseInsensitiveCompare); + std::sort(finalList.begin(), finalList.end(), caseInsensitiveCompare); } - - for (auto& curHistName : mRegisteredNames) { + for (auto& curHistName : finalList) { TNamed* rawPtr = nullptr; std::visit([&](const auto& sharedPtr) { rawPtr = (TNamed*)sharedPtr.get(); }, mRegistryValue[getHistIndex(HistName{curHistName.data()})]); - if (rawPtr) { - std::deque path = splitPath(rawPtr->GetName()); - std::string name = path.back(); - path.pop_back(); - TList* targetList{getSubList(list, path)}; - if (targetList) { - rawPtr->SetName(name.data()); - targetList->Add(rawPtr); - } else { - LOGF(fatal, "Specified subfolder could not be created."); - } - } - } - - // place lists always at the top - std::function moveListsToTop; - moveListsToTop = [&](TList* list) { - TIter next(list); - TNamed* subList = nullptr; - std::vector subLists; - while ((subList = (TNamed*)next())) { - if (subList->InheritsFrom(TList::Class())) { - subLists.push_back(subList); - moveListsToTop((TList*)subList); - } - } - std::reverse(subLists.begin(), subLists.end()); - for (auto curList : subLists) { - list->Remove(curList); - list->AddFirst(curList); - } - }; - moveListsToTop(list); - - // create dedicated directory containing all of the registrys histograms - if (mCreateRegistryDir) { - // propagate this to the writer by adding a 'flag' to the output list - list->AddLast(new TNamed("createFolder", "")); - } - return list; -} - -// helper function to create resp. find the subList defined by path -TList* HistogramRegistry::getSubList(TList* list, std::deque& path) -{ - if (path.empty()) { - return list; - } - TList* targetList{nullptr}; - std::string nextList = path[0]; - path.pop_front(); - if (auto subList = (TList*)list->FindObject(nextList.data())) { - if (subList->InheritsFrom(TList::Class())) { - targetList = getSubList((TList*)subList, path); - } else { - return nullptr; + if (!rawPtr) { + // Skipping empty histograms + continue; } - } else { - subList = new TList(); - subList->SetName(nextList.data()); - list->Add(subList); - targetList = getSubList(subList, path); + callback(*this, rawPtr); } - return targetList; } // helper function to split user defined path/to/hist/name string diff --git a/Framework/Foundation/include/Framework/Signpost.h b/Framework/Foundation/include/Framework/Signpost.h index 7ed544c529303..51d1b0433b0de 100644 --- a/Framework/Foundation/include/Framework/Signpost.h +++ b/Framework/Foundation/include/Framework/Signpost.h @@ -611,6 +611,16 @@ void o2_debug_log_set_stacktrace(_o2_log_t* log, int stacktrace) } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ _o2_signpost_interval_end(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } +// Print out a message at error level in any case even if the signpost is not enable. +// If it is enabled, behaves like O2_SIGNPOST_END. +#define O2_SIGNPOST_END_WITH_ERROR(log, id, name, format, ...) \ + if (O2_BUILTIN_UNLIKELY(O2_SIGNPOST_ENABLED_MAC(log))) { \ + O2_SIGNPOST_END_MAC(log, id, name, format, ##__VA_ARGS__); \ + } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ + _o2_signpost_interval_end(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ + } else { \ + O2_LOG_MACRO_RAW(error, remove_engineering_type(format).data(), ##__VA_ARGS__); \ + } #else // This is the release implementation, it does nothing. #define O2_DECLARE_DYNAMIC_LOG(x) #define O2_DECLARE_DYNAMIC_STACKTRACE_LOG(x) diff --git a/Framework/TestWorkflows/src/o2TestHistograms.cxx b/Framework/TestWorkflows/src/o2TestHistograms.cxx index 61710e1f63d5f..ae3610ca01e67 100644 --- a/Framework/TestWorkflows/src/o2TestHistograms.cxx +++ b/Framework/TestWorkflows/src/o2TestHistograms.cxx @@ -43,6 +43,16 @@ struct EtaAndClsHistogramsSimple { Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + void init(InitContext&) { if (!trackFilterString->empty()) { @@ -56,6 +66,11 @@ struct EtaAndClsHistogramsSimple { for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.pt()); skimEx(track.pt(), track.eta()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } }; @@ -66,6 +81,16 @@ struct EtaAndClsHistogramsIUSimple { Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + void init(InitContext&) { if (!trackFilterString->empty()) { @@ -79,12 +104,28 @@ struct EtaAndClsHistogramsIUSimple { for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.pt()); skimEx(track.pt(), track.eta()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } }; struct EtaAndClsHistogramsFull { OutputObj etaClsH{TH3F("eta_vs_cls_vs_sigmapT", "#eta vs N_{cls} vs sigma_{1/pT}", 102, -2.01, 2.01, 160, -0.5, 159.5, 100, 0, 10)}; + + HistogramRegistry registry{ + "registry", + { + {"a/b/eta", "#Eta", {HistType::kTH1F, {{100, -2.0, 2.0}}}}, // + {"a/phi", "#Phi", {HistType::kTH1D, {{102, 0, 2 * M_PI}}}}, // + {"c/pt", "p_{T}", {HistType::kTH1D, {{1002, -0.01, 50.1}}}}, // + {"ptToPt", "#ptToPt", {HistType::kTH2F, {{100, -0.01, 10.01}, {100, -0.01, 10.01}}}} // + } // + }; + Configurable trackFilterString{"track-filter", "o2::aod::track::pt < 10.f", "Track filter string"}; Filter trackFilter = o2::aod::track::pt < 10.f; @@ -100,6 +141,11 @@ struct EtaAndClsHistogramsFull { LOGP(info, "Invoking the run 3 one"); for (auto& track : tracks) { etaClsH->Fill(track.eta(), track.tpcNClsFindable(), track.sigma1Pt()); + + registry.fill(HIST("a/b/eta"), track.eta()); + registry.fill(HIST("a/phi"), track.phi()); + registry.fill(HIST("c/pt"), track.pt()); + registry.fill(HIST("ptToPt"), track.pt(), track.signed1Pt()); } } };