All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PlotSandbox.cxx
Go to the documentation of this file.
1 /**
2  * @file useranalysis/Trigger/Design/Utilities/PlotSandbox.cxx
3  * @brief A helper to manage ROOT objects in a `art::TFileDirectory`.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date August 8, 2019
6  * @see `useranalysis/Trigger/Design/Utilities/PlotSandbox.h`
7  */
8 
9 
10 // library header
12 
13 // LArSoft libraries
15 
16 // framework libraries
17 #include "cetlib_except/exception.h"
18 #include "messagefacility/MessageLogger/MessageLogger.h" // MF_XXX() macros
19 
20 // ROOT libraries
21 
22 // C/C++ standard libraries
23 #include <string_view>
24 #include <utility> // std::forward()
25 #include <type_traits> // std::add_const_t<>
26 
27 
28 //------------------------------------------------------------------------------
29 //--- icarus::trigger::PlotSandbox::TFileDirectoryHelper
30 //------------------------------------------------------------------------------
32  (art::TFileDirectory dir) -> TFileDirectoryHelper
33 {
34 
35  /*
36  * Finding the ROOT directory is going to be tricky, since the interface
37  * includes: `mkdir()`, `make()` and `makeAndRegister()`. Woah.
38  *
39  * So the plan is:
40  * 1. have `art::TFileDirectory` `make()` a new ROOT object in its directory;
41  * let that ROOT object be a `TDirectory`
42  * 2. `TDirectory` is placed by default in the current directory (as usual),
43  * and it knows which its parent directory is
44  * 3. after learning which that parent directory is, we delete the directory
45  * we just created; this also updates the mother directory
46  */
47 
48  static constexpr const char* TestDirName = " PlotSandbox invalid name! ";
49 
50  // even if another directory with this name existed, it would not be replaced,
51  // but rather another one would be created with this name:
52  TDirectory* testDir = dir.make<TDirectory>(TestDirName, TestDirName);
53  if (!testDir) {
54  throw cet::exception("PlotSandbox") << "TFileDirectoryHelper::create() "
55  "failed to figure out the ROOT directory!\n";
56  }
57  TDirectory* pROOTdir = testDir->GetMotherDir();
58  MF_LOG_DEBUG("TFileDirectoryHelper")
59  << "icarus::trigger::PlotSandbox::TFileDirectoryHelper::create(): "
60  << "found parent directory: '" << pROOTdir->GetName() << "'";
61  // ... and even if there are multiple directories with the same name, using
62  // the pointer to the object makes this deletion affect only the object itself
63  delete testDir;
64 
65  return { dir, pROOTdir };
66 } // icarus::trigger::PlotSandbox::TFileDirectoryHelper::create()
67 
68 
69 //------------------------------------------------------------------------------
70 //--- icarus::trigger::PlotSandbox
71 //------------------------------------------------------------------------------
73  (PlotSandbox const* newParent)
74 {
75  for (auto& subbox: util::values(subBoxes)) subbox->setParent(newParent);
76 } // icarus::trigger::PlotSandbox::Data_t::resetSubboxParents()
77 
78 
79 //------------------------------------------------------------------------------
81  art::TFileDirectory parentDir,
82  std::string name, std::string desc
83  )
84  : fData(std::move(name), std::move(desc),
85  name.empty()
86  ? TFileDirectoryHelper::create(parentDir)
87  : TFileDirectoryHelper::create(parentDir, name, desc)
88  )
89 {}
90 
91 
92 //------------------------------------------------------------------------------
94  : fData(std::move(from.fData))
95 {
96  fData.resetSubboxParents(this); // adjust the parent pointers of the subboxes
97 } // PlotSandbox::PlotSandbox(PlotSandbox&&)
98 
99 
100 //------------------------------------------------------------------------------
102  { return fData.parent? (fData.parent->ID() + '/' + name()): name(); }
103 
104 
105 //------------------------------------------------------------------------------
107  (std::string const& name) const
108 {
109  std::string const sandboxName = processedSandboxName();
110  return sandboxName.empty()? name: name + '_' + sandboxName;
111 } // icarus::trigger::PlotSandbox::processName()
112 
113 
114 //------------------------------------------------------------------------------
116  (std::string const& title) const
117 {
118  std::string const sandboxDesc = processedSandboxDesc();
119  return sandboxDesc.empty()? title: title + ' ' + sandboxDesc;
120 } // icarus::trigger::PlotSandbox::processTitle()
121 
122 
123 //------------------------------------------------------------------------------
125 
126  std::vector<TDirectory const*> subDirectories; // directories of subboxes
127 
128  // if any of the subboxes is not empty, then this one is not either
129  for (auto& subbox: subSandboxes()) {
130  if (!subbox.empty()) return false;
131  subDirectories.push_back(subbox.getDirectory());
132  } // for
133 
134  auto const isSubDirectory = [b=subDirectories.begin(),e=subDirectories.end()]
135  (TObject const* obj)
136  {
137  auto dir = dynamic_cast<TDirectory const*>(obj);
138  return dir && std::find(b, e, dir) != e;
139  };
140 
141  // if there is any object in memory associated to the directory,
142  // that is not empty (directories from subboxes are exempted)
143  for (TObject const* obj: *(getDirectory()->GetList()))
144  if (!isSubDirectory(obj)) return false;
145 
146  // if there is any key associated to the directory, that is not empty
147  if (getDirectory()->GetListOfKeys()->GetSize()) return false;
148 
149  return true;
150 } // icarus::trigger::PlotSandbox::empty()
151 
152 
153 //------------------------------------------------------------------------------
154 auto icarus::trigger::PlotSandbox::findSandbox(std::string const& name)
155  -> PlotSandbox*
156  { return findSandbox(*this, name); }
157 
158 auto icarus::trigger::PlotSandbox::findSandbox(std::string const& name) const
159  -> PlotSandbox const*
160  { return findSandbox(*this, name); }
161 
162 
163 //------------------------------------------------------------------------------
164 auto icarus::trigger::PlotSandbox::demandSandbox(std::string const& name)
165  -> PlotSandbox&
166  { return demandSandbox(*this, name); }
167 
168 auto icarus::trigger::PlotSandbox::demandSandbox(std::string const& name) const
169  -> PlotSandbox const&
170  { return demandSandbox(*this, name); }
171 
172 
173 //------------------------------------------------------------------------------
174 bool icarus::trigger::PlotSandbox::deleteSubSandbox(std::string const& name) {
175 
176  auto const it = fData.subBoxes.find(name);
177  if (it == fData.subBoxes.end()) return false;
178 
179  if (it->second) {
180  auto&& subbox = std::move(it->second); // will get destroyed at end of scope
181  if (subbox->getDirectory()) delete subbox->getDirectory();
182  if (getDirectory()) getDirectory()->Delete((name + ";*").c_str());
183  }
184 
185  fData.subBoxes.erase(it);
186  return true;
187 } // icarus::trigger::PlotSandbox::deleteSubSandbox()
188 
189 
190 //------------------------------------------------------------------------------
192  (PlotSandbox const& parent, std::string name, std::string desc)
193  : PlotSandbox(parent.fData.outputDir.fDir, std::move(name), std::move(desc))
194 {
195  setParent(&parent);
196 }
197 
198 //------------------------------------------------------------------------------
200  (std::string const& title) const
201 {
202  /*
203  * We want to process the title of the plot, but this "title" string might
204  * contain also axis labels (see e.g. `TH1::SetTitle()`).
205  *
206  * We need to first identify the actual title portion of the "title",
207  * then process it alone and merge it back (one Python line...).
208  *
209  */
210 
211  // eat title until an unescaped ';' is found
212  auto const tbegin = title.begin();
213  auto const tend = title.end();
214  auto atend = tbegin; // actual title end
215  while (atend != tend) {
216  if ((*atend == ';') && ((atend == tbegin) || (*std::prev(atend) != '\\')))
217  break;
218  ++atend;
219  } // while
220 
221  return processTitle({ tbegin, atend }).append(atend, tend);
222 
223 } // icarus::trigger::PlotSandbox::processedPlotTitle()
224 
225 
226 //------------------------------------------------------------------------------
228 {
229  std::string processed;
230 
231  // if there is no name, the processed name is empty (we don't recurse parents)
232  if (!hasName()) return processed;
233 
234  processed = name();
235  if (fData.parent) processed += '_' + fData.parent->processedSandboxName();
236 
237  return processed;
238 } // icarus::trigger::PlotSandbox::processedSandboxName()
239 
240 
241 //------------------------------------------------------------------------------
243 {
244  std::string processed;
245 
246  // if there is no name, the processed name is empty (we don't recurse parents)
247  if (hasDescription()) processed += description();
248 
249  if (fData.parent) processed += ' ' + fData.parent->processedSandboxDesc();
250 
251  return processed;
252 } // icarus::trigger::PlotSandbox::processedSandboxDesc()
253 
254 
255 //------------------------------------------------------------------------------
256 std::pair<std::string, std::string> icarus::trigger::PlotSandbox::splitPath
257  (std::string const& path, char sep /* = '/' */)
258 {
259 
260  auto const iSep = path.rfind(sep);
261  if (iSep == std::string::npos) return { {}, path };
262  else return { path.substr(0U, iSep), path.substr(iSep + 1) };
263 
264 } // icarus::trigger::PlotSandbox::splitPath()
265 
266 
267 //------------------------------------------------------------------------------
269  (std::initializer_list<std::string> pathElements, char sep /* = '/' */)
270 {
271  if (std::empty(pathElements)) return {};
272 
273  auto stripSep = [sep](std::string const& s) -> std::string_view {
274  return {
275  s.data(),
276  ((s.length() > 1) && (s.back() == sep))? s.length() - 1: s.length()
277  };
278  };
279 
280  auto iElem = pathElements.begin();
281  auto const eend = pathElements.end();
282  auto const& first = stripSep(*iElem);
283  std::string s { first.begin(), first.end() };
284  while (++iElem != eend) {
285  auto const& elem = stripSep(*iElem);
286  if (elem.empty()) continue;
287  if (elem.front() != sep) s.push_back(sep);
288  s += elem;
289  } // while
290  return s;
291 } // icarus::trigger::PlotSandbox::joinPath()
292 
293 
294 //------------------------------------------------------------------------------
std::string ID() const
Returns a string ID for this sandbox.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
TFileDirectoryHelper outputDir
Output ROOT directory of the sandbox.
Definition: PlotSandbox.h:133
static std::string joinPath(std::initializer_list< std::string > pathElements, char sep= '/')
static TFileDirectoryHelper create(art::TFileDirectory parentDir, std::string const &subdir, std::string const &dirTitle="")
Creates a helper managing a subdirectory of parentDir.
struct icarus::trigger::PlotSandbox::Data_t fData
static std::pair< std::string, std::string > splitPath(std::string const &path, char sep= '/')
bool deleteSubSandbox(std::string const &name)
Deletes the subbox with the specified name and its directory.
static auto * findSandbox(SandboxType &sandbox, std::string const &name)
Helper function for findSandbox() implementations.
Definition: PlotSandbox.h:740
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
virtual std::string processName(std::string const &name) const
Processes the specified string as it were a name.
bool empty() const
Returns if the sandbox is empty (neither it nor subboxes hold objects).
decltype(auto) values(Coll &&coll)
Range-for loop helper iterating across the values of the specified collection.
virtual std::string processedSandboxName() const
virtual std::string processedSandboxDesc() const
PlotSandbox(art::TFileDirectory parentDir, std::string name, std::string desc)
Constructor: specifies all sandbox characteristics.
Definition: PlotSandbox.cxx:80
tuple dir
Definition: dropbox.py:28
void resetSubboxParents(PlotSandbox const *newParent)
Definition: PlotSandbox.cxx:73
std::string processPlotTitle(std::string const &title) const
Applies title processing only at the title part of the string.
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
do i e
static auto & demandSandbox(SandboxType &sandbox, std::string const &name)
Helper function for demandSandbox() implementations.
Definition: PlotSandbox.h:750
then echo fcl name
Definition of util::values() and util::const_values().
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
A helper to manage ROOT objects in a art::TFileDirectory.
virtual std::string processTitle(std::string const &title) const
Processes the specified string as it were a description or title.
A helper to manage ROOT objects with consistent naming.
Definition: PlotSandbox.h:95
Contains both a art::TFileDirectory and the TDirectory it manages.
Definition: PlotSandbox.h:103