ATLAS Offline Software
RootVisualizationService.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
5 
8 
9 #include "GeoModelKernel/throwExcept.h"
10 
11 #include <TCanvas.h>
12 #include <TH2F.h>
13 #include <TROOT.h>
14 #include <TStyle.h>
15 
16 #include <format>
17 #include <thread>
18 #include <filesystem>
19 
20 
21 namespace{
23  std::size_t cleanTrashed(PlotVec_t& toDraw) {
24  toDraw.erase(std::remove_if(toDraw.begin(), toDraw.end(),
25  [](const auto& plot){
26  return plot->trashed();
27  }), toDraw.end());
28  return toDraw.size();
29  }
30 }
31 
32 namespace MuonValR4{
35  gROOT->SetStyle("ATLAS");
36  TStyle* plotStyle = gROOT->GetStyle("ATLAS");
37  plotStyle->SetOptTitle(0);
38  plotStyle->SetHistLineWidth(1.);
39  plotStyle->SetPalette(kViridis);
40 
41  return StatusCode::SUCCESS;
42  }
44  if (token.preFixName.empty()){
45  ATH_MSG_FATAL("Prefix name must not be empty");
46  return StatusCode::FAILURE;
47  }
48  std::unique_lock guard{m_storageMutex};
49  auto insert_itr = m_storage.insert(std::make_pair(token, PlotsPerClient{}));
50  if (!insert_itr.second) {
51  ATH_MSG_FATAL("The token "<<token.preFixName<<" is already registered");
52  return StatusCode::FAILURE;
53  }
54  ATH_MSG_INFO("Registered new client "<<token.preFixName
55  <<", maximum number of plots "<<token.canvasLimit
56  <<", formats: "<<token.fileFormats<<", save single: "
57  <<(token.saveSinglePlots ? "yay" : "nay")
58  <<", save summary: "<<(token.saveSummaryPlot ? "yay" : "nay"));
59  return StatusCode::SUCCESS;
60  }
61 
62  std::shared_ptr<ICanvasObject>
63  RootVisualizationService::prepareCanvas(const EventContext& ctx, const ClientToken& token,
64  const std::string& canvasName){
65  if (canvasName.empty()) {
66  THROW_EXCEPTION("The canvas name must not be empty");
67  }
68  std::unique_lock lock_guard{m_storageMutex};
69  StorageMap_t::iterator store_itr = m_storage.find(token);
70  if (store_itr == m_storage.end()) {
71  THROW_EXCEPTION("The token "<<token.preFixName<<" is unknown.");
72  }
73  PlotsPerClient& dataHolder = store_itr->second;
74  if (!dataHolder.elementsDrawn &&
75  cleanTrashed(dataHolder.toDraw) < store_itr->first.canvasLimit){
76  const std::size_t evt = ctx.eventID().event_number();
77  ATH_MSG_VERBOSE("Provide new canvas "<<canvasName<<" for stream "<<token.preFixName
78  <<" in "<<ctx.eventID());
79  auto newCanvas = dataHolder.toDraw.emplace_back(std::make_shared<detail::DrawCanvasObject>(canvasName, evt));
80  newCanvas->setRangeScale(m_canvasExtraScale, m_quadCanvas);
81  return newCanvas;
82  } else if (!dataHolder.elementsDrawn) {
83  paintObjects(store_itr->first, std::move(dataHolder.toDraw));
84  dataHolder.elementsDrawn = true;
85  }
86  ATH_MSG_VERBOSE("Maximum elements for "<<token.preFixName
87  <<" reached. Don't provide any new canvas");
88  return nullptr;
89  }
90  void RootVisualizationService::paintObjects(const ClientToken& token,
91  PlotVec_t&& toDraw) {
92  if (toDraw.empty()){
93  return;
94  }
96  std::ranges::stable_sort(toDraw, [](const PlotPtr_t& a, const PlotPtr_t& b){
97  return a->event() < b->event();
98  });
99  std::unique_lock guard{m_canvasMutex};
100  std::unique_ptr<TCanvas> summaryCan{};
101  const std::string summaryPdfName = std::format("{:}/All{}.pdf",
102  m_outDir.value(), token.preFixName);
103  if (token.saveSummaryPlot) {
104  ATH_MSG_DEBUG("Open "<<summaryPdfName<<" to dump all canvases in a common file");
105  ensureDirectory(summaryPdfName);
106  summaryCan = std::make_unique<TCanvas>("allCan","allCan", m_canvasWidth, m_canvasHeight);
107  summaryCan->SaveAs(std::format("{:}[", summaryPdfName).c_str());
108  }
109  if (token.fileFormats.count("root") && !m_outFile) {
110  std::string outFile = std::format("{:}/{:}", m_outDir.value(),
111  m_outRootFileName.value());
113  m_outFile.reset(TFile::Open(outFile.c_str(), "RECREATE"));
114  if (!m_outFile || m_outFile->IsZombie()) {
115  THROW_EXCEPTION("Failed to create "<<outFile<<".");
116  }
117  ATH_MSG_DEBUG("Open "<<outFile<<" to save the plots in root format");
118  }
119  std::size_t currEvt{toDraw.back()->event()}, plotCount{0};
120  for (const PlotPtr_t& drawMe : toDraw) {
122  while (!drawMe.unique()) {
123  using namespace std::chrono_literals;
124  ATH_MSG_DEBUG("Wait until "<<drawMe->name()<<" is finished.");
125  std::this_thread::sleep_for(10ms);
126  }
128  if (currEvt != drawMe->event()) {
129  currEvt = drawMe->event();
130  plotCount = 0;
131  }
132  std::string plotName = std::format("{:}/{:}/{:}_{:}_{:}_{:}", m_outDir.value(),
133  token.subDirectory, token.preFixName,
134  drawMe->event(), ++plotCount,
135  removeNonAlphaNum(drawMe->name()));
136 
137  auto singleCan = std::make_unique<TCanvas>("can", "can" , m_canvasWidth, m_canvasHeight);
138  singleCan->cd();
140  using enum ICanvasObject::AxisRanges;
141  ATH_MSG_VERBOSE("Crate new canvas: "<<plotName<<" ["<<drawMe->corner(xLow)<<";"<<drawMe->corner(xHigh)
142  <<"], ["<<drawMe->corner(yLow)<<";"<<drawMe->corner(yHigh)<<"].");
143  auto frameH = std::make_unique<TH2F>("frameH",
144  std::format("frame;{:};{:};{:}", drawMe->xTitle(), drawMe->yTitle(), drawMe->zTitle()).c_str(),
145  1, drawMe->corner(xLow), drawMe->corner(xHigh),
146  1, drawMe->corner(yLow), drawMe->corner(yHigh));
147  frameH->Draw("AXIS");
148  drawMe->add(drawAtlasLabel(0.65, 0.26, m_AtlasLabel));
149  drawMe->add(drawLumiSqrtS(0.65,0.21, m_sqrtSLabel, m_lumiLabel));
151  for (auto& [primitive, opt] : drawMe->primitives()) {
152  primitive->Draw(opt.c_str());
153  }
155  if (token.saveSinglePlots){
156  for (const std::string& fileExt : token.fileFormats) {
157  if (fileExt != "root") {
158  ensureDirectory(plotName);
159  singleCan->SaveAs(std::format("{:}.{:}", plotName, fileExt).c_str());
160  }
161  }
162  }
163  if (token.fileFormats.count("root")) {
164  TDirectory* writeTo = m_outFile.get();
165  if (!token.subDirectory.empty()) {
166  writeTo = m_outFile->GetDirectory(token.subDirectory.c_str());
167  if (!writeTo) {
168  writeTo = m_outFile->mkdir(token.subDirectory.c_str());
169  }
170  }
171  writeTo->WriteObject(singleCan.get(),
172  std::format("{:}_{:}_{:}_{:}",token.preFixName,
173  drawMe->event(), plotCount,
174  removeNonAlphaNum(drawMe->name())).c_str());
175  }
176  if (summaryCan) {
177  singleCan->SaveAs(summaryPdfName.c_str());
178  }
179  }
180  if (summaryCan) {
181  summaryCan->SaveAs(std::format("{:}]", summaryPdfName).c_str());
182  }
183  }
185  ATH_MSG_DEBUG("Finalize the visualization service. Dump all canvases that not have yet been drawn");
186  for (auto& [token, dataHolder] : m_storage) {
187  if (!dataHolder.elementsDrawn) {
188  paintObjects(token, std::move(dataHolder.toDraw));
189  }
190  dataHolder.toDraw.clear();
191  }
192  m_outFile.reset();
193  return StatusCode::SUCCESS;
194  }
195 }
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
MuonValR4::RootVisualizationService::m_outFile
std::unique_ptr< TFile > m_outFile
File into which all Canvases are saved if root is defined as extension.
Definition: RootVisualizationService.h:72
MuonValR4::RootVisualizationService::m_storage
StorageMap_t m_storage
Definition: RootVisualizationService.h:70
MuonValR4::RootVisualizationService::m_canvasHeight
Gaudi::Property< unsigned > m_canvasHeight
Height of all drawn Canvases.
Definition: RootVisualizationService.h:52
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
vtune_athena.format
format
Definition: vtune_athena.py:14
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
MuonValR4::ICanvasObject
RootVisualizationService::ICanvasObject ICanvasObject
Definition: RootVisualizationService.cxx:33
make_coralServer_rep.opt
opt
Definition: make_coralServer_rep.py:19
MuonValR4::RootVisualizationService::m_canvasWidth
Gaudi::Property< unsigned > m_canvasWidth
Width of all drawn Canvases.
Definition: RootVisualizationService.h:50
MuonValR4::RootVisualizationService::m_quadCanvas
Gaudi::Property< bool > m_quadCanvas
Ensure that the canvas has the same interval sizes in x & y.
Definition: RootVisualizationService.h:42
VisualizationHelpers.h
MuonValR4::RootVisualizationService::registerClient
virtual StatusCode registerClient(const ClientToken &token) override final
Definition: RootVisualizationService.cxx:43
MuonValR4::RootVisualizationService::paintObjects
void paintObjects(const ClientToken &token, PlotVec_t &&toDraw)
Definition: RootVisualizationService.cxx:90
MuonValR4::RootVisualizationService::m_storageMutex
std::mutex m_storageMutex
Definition: RootVisualizationService.h:74
MuonValR4::RootVisualizationService::initialize
virtual StatusCode initialize() override final
Definition: RootVisualizationService.cxx:34
MuonValR4::removeNonAlphaNum
std::string removeNonAlphaNum(std::string str)
Removes all non-alpha numerical characters from a string.
Definition: FileHelpers.cxx:10
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
plot
Definition: PhysicsAnalysis/ElectronPhotonID/ElectronPhotonFourMomentumCorrection/python/plot.py:1
DeMoUpdate.newCanvas
bool newCanvas
Definition: DeMoUpdate.py:1115
MuonValR4::RootVisualizationService::m_outRootFileName
Gaudi::Property< std::string > m_outRootFileName
Name of the ROOT file into which the output Canvases are written (needs root to be in the list of out...
Definition: RootVisualizationService.h:57
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
MuonValR4::RootVisualizationService::PlotsPerClient::elementsDrawn
bool elementsDrawn
Flag to indicate whether the plots were already dumped on disk.
Definition: RootVisualizationService.h:66
MuonValR4::RootVisualizationService::m_canvasExtraScale
Gaudi::Property< double > m_canvasExtraScale
Extra safety margin to zoom out from the Canvas.
Definition: RootVisualizationService.h:40
MuonValR4::RootVisualizationService::m_sqrtSLabel
Gaudi::Property< std::string > m_sqrtSLabel
Centre of mass energy label.
Definition: RootVisualizationService.h:46
MuonValR4::RootVisualizationService::PlotsPerClient::toDraw
PlotVec_t toDraw
List of already registered Canvases.
Definition: RootVisualizationService.h:63
MuonValR4::RootVisualizationService::m_canvasMutex
std::mutex m_canvasMutex
Definition: RootVisualizationService.h:75
RootVisualizationService.h
MuonValR4
Lightweight algorithm to read xAOD MDT sim hits and (fast-digitised) drift circles from SG and fill a...
Definition: IPatternVisualizationTool.h:23
DQPostProcessTest.outFile
outFile
Comment Out Those You do not wish to run.
Definition: DQPostProcessTest.py:36
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
THROW_EXCEPTION
#define THROW_EXCEPTION(MESSAGE)
Definition: throwExcept.h:10
MuonValR4::RootVisualizationService::PlotPtr_t
std::shared_ptr< detail::DrawCanvasObject > PlotPtr_t
Definition: RootVisualizationService.h:31
a
TList * a
Definition: liststreamerinfos.cxx:10
MuonValR4::RootVisualizationService::m_outDir
Gaudi::Property< std::string > m_outDir
Directory into which all plots are written to
Definition: RootVisualizationService.h:54
MuonValR4::RootVisualizationService::m_lumiLabel
Gaudi::Property< std::string > m_lumiLabel
Luminosity label.
Definition: RootVisualizationService.h:48
MuonValR4::RootVisualizationService::PlotVec_t
std::vector< PlotPtr_t > PlotVec_t
Definition: RootVisualizationService.h:32
MuonValR4::drawAtlasLabel
std::unique_ptr< TLatex > drawAtlasLabel(const double xPos, const double yPos, const std::string &status="Internal")
Create a ATLAS label.
Definition: VisualizationHelpers.cxx:80
MuonValR4::RootVisualizationService::finalize
virtual StatusCode finalize() override final
Definition: RootVisualizationService.cxx:184
FileHelpers.h
MuonValR4::RootVisualizationService::m_AtlasLabel
Gaudi::Property< std::string > m_AtlasLabel
ATLAS label (Internal / Prelimnary / Simulation)
Definition: RootVisualizationService.h:44
MuonValR4::ensureDirectory
void ensureDirectory(const std::string &path)
Ensures that the subdirectory in the path is created.
Definition: FileHelpers.cxx:17
MuonValR4::RootVisualizationService::prepareCanvas
virtual std::shared_ptr< ICanvasObject > prepareCanvas(const EventContext &ctx, const ClientToken &token, const std::string &canvasName) override final
Definition: RootVisualizationService.cxx:63
MuonValR4::drawLumiSqrtS
std::unique_ptr< TLatex > drawLumiSqrtS(const double xPos, const double yPos, const std::string_view sqrtS="14", const std::string_view lumi="")
Create a luminosity sqrtS label.
Definition: VisualizationHelpers.cxx:84
MuonValR4::RootVisualizationService::PlotsPerClient
Helper struct to group all plots that are belonging to a client of the service.
Definition: RootVisualizationService.h:61
python.SystemOfUnits.ms
float ms
Definition: SystemOfUnits.py:148