All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PlotSandbox.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Trigger/Utilities/PlotSandbox.h
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 `icaruscode/PMT/Trigger/Utilities/PlotSandbox.cxx`
7  */
8 
9 #ifndef ICARUSCODE_PMT_TRIGGER_UTILITIES_PLOTSANDBOX_H
10 #define ICARUSCODE_PMT_TRIGGER_UTILITIES_PLOTSANDBOX_H
11 
12 // LArSoft libraries
13 #include "larcorealg/CoreUtils/span.h" // util::make_transformed_span(), ...
14 
15 // framework libraries
16 #include "art_root_io/TFileDirectory.h"
17 #include "cetlib_except/exception.h"
18 
19 // ROOT libraries
20 #include "TDirectory.h"
21 #include "TDirectoryFile.h"
22 #include "TList.h"
23 #include "TKey.h"
24 #include "TClass.h"
25 #include "TObject.h"
26 
27 // C/C++ standard libraries
28 #include <string>
29 #include <map>
30 #include <iterator> // std::prev()
31 #include <utility> // std::pair<>
32 #include <functional> // std::hash<>
33 #include <initializer_list>
34 #include <memory> // std::unique_ptr<>
35 
36 
37 //------------------------------------------------------------------------------
38 // forward declarartions
39 class TGraph;
40 
41 
42 //------------------------------------------------------------------------------
43 namespace icarus::trigger::details {
44 
45  // TODO it seems make_transformed_span() does not support nesting properly;
46  // this should be fixed
47  template <typename Map>
49 
50  static constexpr std::size_t NElement = 1U; // this is the value
51 
52  template <typename T>
53  static constexpr decltype(auto) iterate(T&& coll) noexcept
54  {
55  auto extractor = [](auto&& value) -> decltype(auto)
56  { return *std::get<NElement>(value); };
57  return util::make_transformed_span(coll, extractor);
58  }
59 
60  }; // map_values_impl
61 
62  template <typename Map>
63  decltype(auto) map_dereferenced_values(Map&& map)
64  { return map_dereferenced_values_impl<std::decay_t<Map>>::iterate(std::forward<Map>(map)); }
65 
66 } // namespace util::details
67 
68 
69 //------------------------------------------------------------------------------
70 namespace icarus::trigger { class PlotSandbox; }
71 /**
72  * @brief A helper to manage ROOT objects with consistent naming.
73  *
74  * A sandbox includes a ROOT directory where all the objects are written.
75  * It also provides a name pattern to modify a generic object name in one
76  * specific to this sandbox, e.g. from `"HEnergy"` to `"HMuonNeutrinoEnergy"`.
77  * Object descriptions (usually titles) may also be processed in the same way.
78  *
79  * In addition, the sandbox can point to a parent sandbox, in which case the
80  * names and descriptions are first processed by this sandbox and then passed to
81  * that parent sandbox for further processing.
82  *
83  * The sandbox has two characterizing strings:
84  * * the _name_ is a key used in ROOT object names and it is also by default
85  * the name of the output ROOT directory; for example: `"MuonNeutrino"` or
86  * `"CC"`. This string becoming part of the ROOT object name, it is better to
87  * keep it short and simply alphanumeric.
88  * * the _description_ is a short wording for the content of the sandbox, used
89  * in processing ROOT object titles; for example, `"#nu_{#mu}"` or
90  * `"charged current"`.
91  *
92  * @note By convention the subdirectory names are not processed.
93  *
94  */
96 
97  /*
98  * `art::TFileDirectory` does not give access to the underlying ROOT directory
99  * and to be able to read from it we need the following trick:
100  */
101 
102  /// Contains both a `art::TFileDirectory` and the `TDirectory` it manages.
104  art::TFileDirectory fDir;
105  TDirectory* fROOTdir;
106 
107  TFileDirectoryHelper(art::TFileDirectory dir, TDirectory* ROOTdir)
108  : fDir(dir), fROOTdir(ROOTdir) {}
109 
110  /// Creates a helper managing a subdirectory of `parentDir`.
111  template <typename RootDir = TDirectoryFile>
113  art::TFileDirectory parentDir,
114  std::string const& subdir, std::string const& dirTitle = ""
115  );
116 
117  static TFileDirectoryHelper create(art::TFileDirectory dir);
118 
119  }; // struct TFileDirectoryHelper
120 
121 
122  /// The whole data in a convenient package!
123  struct Data_t {
124 
125  std::string name; ///< The name/key representing this sandbox.
126  std::string desc; ///< The description characterizing the sandbox.
127 
128  PlotSandbox const* parent = nullptr; ///< Optional parent sandbox.
129 
130  /// Contained sand boxes.
131  std::map<std::string, std::unique_ptr<PlotSandbox>> subBoxes;
132 
133  TFileDirectoryHelper outputDir; ///< Output ROOT directory of the sandbox.
134 
135  Data_t() = default;
136  Data_t(Data_t const&) = delete;
137  Data_t(Data_t&&) = default;
138  Data_t& operator= (Data_t const&) = delete;
139  Data_t& operator= (Data_t&&) = default;
140 
141  Data_t
142  (std::string&& name, std::string&& desc, TFileDirectoryHelper outputDir)
143  : name(std::move(name)), desc(std::move(desc))
144  , outputDir(std::move(outputDir))
145  {}
146 
147  void resetSubboxParents(PlotSandbox const* newParent);
148 
149  } fData;
150 
151 
152  /// Helper function for `findSandbox()` implementations.
153  template <typename SandboxType>
154  static auto* findSandbox(SandboxType& sandbox, std::string const& name);
155 
156  /// Helper function for `demandSandbox()` implementations.
157  template <typename SandboxType>
158  static auto& demandSandbox(SandboxType& sandbox, std::string const& name);
159 
160 
161  public:
162 
163  /**
164  * @brief Constructor: specifies all sandbox characteristics.
165  * @param parentDir ROOT directory under which the sandbox is created
166  * @param name the name of the sandbox
167  * @param desc description of the sandbox
168  *
169  * If the `name` is empty, as a special case, the sandbox is unnamed and it is
170  * created directly in `parentDir`. In that case, the title of the output
171  * directory (`parentDir`) is also not changed.
172  * If `name` or `desc` are empty, the pertaining processing is not performed:
173  * if `name` is empty, ROOT object names will be unchanged, and if `desc` is
174  * empty their descriptions/titles will be.
175  *
176  * To create a sandbox with a parent, call `addSubSandbox()` of that parent.
177  */
179  (art::TFileDirectory parentDir, std::string name, std::string desc);
180 
181  PlotSandbox(PlotSandbox const&) = delete;
183 
184  // no assignment supported in `art::TFileDirectory`
185  PlotSandbox& operator=(PlotSandbox const&) = delete;
186  PlotSandbox& operator=(PlotSandbox&& from) = delete;
187 
188 
189  /// Virtual destructor. Default, but C++ wants it.
190  virtual ~PlotSandbox() = default;
191 
192  /// Returns whether we have a non-empty name.
193  bool hasName() const { return !fData.name.empty(); }
194 
195  /// Returns the sandbox name.
196  std::string const& name() const { return fData.name; }
197 
198  /// Returns whether we have a non-empty description.
199  bool hasDescription() const { return !fData.desc.empty(); }
200 
201  /// Returns the sandbox description.
202  std::string const& description() const { return fData.desc; }
203 
204  /// Returns the sandbox description for use at the beginning of a sentence.
205  /// @todo Not implemented yet.
206  virtual std::string const& Description() const { return description(); }
207 
208  /// Returns a string ID for this sandbox.
209  std::string ID() const;
210 
211  /// Processes the specified string as it were a name.
212  virtual std::string processName(std::string const& name) const;
213 
214  /// Processes the specified string as it were a description or title.
215  virtual std::string processTitle(std::string const& title) const;
216 
217 
218  // --- BEGIN -- ROOT object management ---------------------------------------
219  /// @name ROOT object management
220  /// @{
221 
222  /// Returns if the sandbox is empty (neither it nor subboxes hold objects).
223  bool empty() const;
224 
225  /**
226  * @brief Fetches the object with the specified name from the sandbox.
227  * @tparam Obj (default: `TObject`) type of the object to fetch
228  * @param name unprocessed name and path of the object to fetch
229  * @return a constant pointer to the requested object , or `nullptr` if not
230  * available or wrong type
231  * @see `use()`
232  *
233  * The `name` specification may contain a ROOT path. The directory component
234  * of the path, defined by everything preceding a `/` character, is _not_
235  * processed.
236  *
237  * The fetched object is converted to the desired type via `dynamic_cast`.
238  * If conversion fails, a null pointer is returned.
239  */
240  template <typename Obj = TObject>
241  Obj const* get(std::string const& name) const;
242 
243  /**
244  * @brief Fetches an object with the specified name to be modified.
245  * @tparam Obj (default: `TObject`) type of the object to fetch
246  * @param name unprocessed name and path of the object to fetch
247  * @return a pointer to the requested object , or `nullptr` if not
248  * available or wrong type
249  * @see `get()`
250  *
251  * This method is fully equivalent to `get()`, with the difference that the
252  * returned object may be modified.
253  */
254  template <typename Obj = TObject>
255  Obj* use(std::string const& name) const;
256 
257  /**
258  * @brief Fetches an object with the specified name to be modified.
259  * @tparam Obj (default: `TObject`) type of the object to fetch
260  * @param name unprocessed name and path of the object to fetch
261  * @return the requested object
262  * @throw cet::exception (category: `"PlotSandbox"`) if no object with `name`
263  * exists in the box
264  * @see `get()`, `use()`
265  *
266  * This method is equivalent to `use()`, with the difference that the
267  * returned object must exist.
268  */
269  template <typename Obj = TObject>
270  Obj& demand(std::string const& name) const;
271 
272  /**
273  * @brief Fetches the base directory of the sandbox.
274  * @return a pointer to the requested directory, or `nullptr` if wrong type
275  *
276  * The directory is converted to the desired type via `dynamic_cast`.
277  * If conversion fails, a null pointer is returned.
278  */
279  template <typename DirObj = TDirectory>
280  DirObj* getDirectory() const;
281 
282  /**
283  * @brief Fetches the directory with the specified name from the sandbox.
284  * @tparam DirObj (default: `TDirectory`) type of ROOT directory object to get
285  * @param path path of the directory to fetch within this sandbox
286  * @return a constant pointer to the requested directory, or `nullptr` if not
287  * available or wrong type
288  *
289  * The fetched object is converted to the desired type via `dynamic_cast`.
290  * If conversion fails, a null pointer is returned.
291  */
292  template <typename DirObj = TDirectory>
293  DirObj* getDirectory(std::string const& path) const;
294 
295  /**
296  * @brief Creates a new ROOT object with the specified name and title.
297  * @tparam Obj type of ROOT object to be created
298  * @tparam Args types of the argumenst to be forwarded to the constructor
299  * @param name unprocessed name of the new object
300  * @param title unprocessed title of the new object
301  * @param args additional arguments forwarded to the constructor
302  * @return a pointer to the newly created object
303  *
304  * The name and title are processed with `processName()` and `processTitle()`
305  * method respectively, before the object is created.
306  */
307  template <typename Obj, typename... Args>
308  Obj* make(std::string const& name, std::string const& title, Args&&... args);
309 
310 
311  /// @}
312  // --- END -- ROOT object management -----------------------------------------
313 
314 
315  // --- BEGIN -- Contained sandboxes ------------------------------------------
316  /// @name Contained sandboxes
317  /// @{
318 
319  /**
320  * @brief Creates a new sandbox contained in this one.
321  * @tparam SandboxType (default: `PlotSandbox`) type of sandbox to be created
322  * @tparam Args types of the additional arguments for the sandbox constructor
323  * @param name name of the new contained sand box
324  * @param desc description of the new contained sand box
325  * @param args additional arguments for the sandbox constructor
326  * @return a reference to the created sandbox
327  * @throw cet::exception (category: `"PlotSandbox"`) if a sandbox with this
328  * name already exists.
329  *
330  * The arguments of this method are equivalent to the ones of the constructor.
331  *
332  * The new sand box parent is set to point to this sand box.
333  */
334  template <typename SandboxType = PlotSandbox, typename... Args>
335  SandboxType& addSubSandbox(
336  std::string const& name, std::string const& desc,
337  Args&&... args
338  );
339 
340  /// Returns the number of contained sand boxes.
341  std::size_t nSubSandboxes() const { return fData.subBoxes.size(); }
342 
343  // @{
344  /**
345  * @brief Returns the first contained sandbox with the specified name.
346  * @param name unprocessed name of the box to be retrieved
347  * @return the requested contained sandbox, or `nullptr` if not found
348  * @see `demandSandbox()`
349  */
350  PlotSandbox const* findSandbox(std::string const& name) const;
351  PlotSandbox* findSandbox(std::string const& name);
352  // @}
353 
354  // @{
355  /**
356  * @brief Returns the first contained sandbox with the specified name.
357  * @param name unprocessed name of the box to be retrieved
358  * @return the requested contained sandbox
359  * @throw cet::exception (category: `"PlotSandbox"`) if no a sandbox with this
360  * `name` exists
361  * @see `findSandbox()`
362  */
363  PlotSandbox const& demandSandbox(std::string const& name) const;
364  PlotSandbox& demandSandbox(std::string const& name);
365  // @}
366 
367  // @{
368  /// Returns an object proper to iterate through all contained sand boxes.
369  decltype(auto) subSandboxes() const
371  decltype(auto) subSandboxes()
373  // @}
374 
375  /// @brief Deletes the subbox with the specified `name` and its directory.
376  /// @return whether there was a subbox with that `name`
377  bool deleteSubSandbox(std::string const& name);
378 
379  /// @}
380  // --- END -- Contained sandboxes --------------------------------------------
381 
382 
383  /// Dumps the hierarchy of sandboxes into the specified stream.
384  template <typename Stream>
385  void dump(Stream&& out, std::string indent, std::string firstIndent) const;
386 
387  /// Dumps the hierarchy of sandboxes into the specified stream.
388  template <typename Stream>
389  void dump(Stream&& out, std::string indent = "") const
390  { dump(std::forward<Stream>(out), indent, indent); }
391 
392  protected:
393 
394  /**
395  * @brief Constructor: specifies all sandbox characteristics.
396  * @param parent the sandbox used as parent
397  * @param name the name of the sandbox
398  * @param desc description of the sandbox
399  *
400  * Compared to the public constructor, this one picks the parent directory
401  * to be the output directory of the `parent` sandbox, and it registers
402  * that `parent` box as parent.
403  * Note that this constructor does *not* update the list of subboxes of the
404  * parent.
405  */
406  PlotSandbox(PlotSandbox const& parent, std::string name, std::string desc);
407 
408 
409  /// Sets the parent of this box.
410  virtual void setParent(PlotSandbox const* parent) { fData.parent = parent; }
411 
412 
413  /// Applies title processing only at the title part of the string.
414  std::string processPlotTitle(std::string const& title) const;
415 
416 
417  /// Returns a processed version of the name of this sandbox.
418  ///
419  /// This may be used when integrating the sandbox name into the processed
420  /// object names.
421  virtual std::string processedSandboxName() const;
422 
423  /// Returns a processed version of the description of this sandbox.
424  ///
425  /// This may be used when integrating the sandbox description into the
426  /// processed object descriptions.
427  virtual std::string processedSandboxDesc() const;
428 
429  /// Dumps the content of this box (nosubboxes) into `out` stream.
430  template <typename Stream>
431  void dumpContent
432  (Stream&& out, std::string indent, std::string firstIndent) const;
433 
434 
435  // --- BEGIN -- Object creation specializations ------------------------------
436  /**
437  * @name Object creation specializations
438  *
439  * These are implementation details.
440  *
441  * `PlotSandbox` manages the creation of objects to be put into ROOT
442  * directories and acts as an interface between `art::TFileDirectory` and
443  * user code. In particular it takes the responsibility of constructing new
444  * objects to be stored in the directory. There are special arguments to
445  * these objects, that are the name and, to a lesser extent, a title.
446  * `PlotSandbox` manipulates the name of the object to make it unique, and
447  * therefore it has to have full control of everywhere a name is set.
448  * The name is crucial in ROOT because it is the key for searching the object.
449  * So it has a double role of the name of the object (property of the object
450  * itself) and the key of the container that hosts that object.
451  * Some ROOT objects can and must be constructed with a name, and usually a
452  * title too (e.g. `TH1` and `TTree` hierarchies), and their constructor takes
453  * these as the first two arguments. Other object, though, do not follow that
454  * pattern (e.g. `TGraph`), and worse, these object might accept strings as
455  * first constructor arguments, assigning them a different meaning.
456  * For these objects a different initialization pattern is necessary, where
457  * the object is constructed with user-specified arguments first, and then
458  * the name (and, if supported, the title) are set.
459  *
460  * `PlotSandbox` interface attempts to save the user from this hassle,
461  * but because specific actions are needed for specific objects, it needs to
462  * know these needs case by case. This implementation tries to give the
463  * necessary flexibility to easily implement special cases.
464  *
465  * A few basic tools are provided, which support specific _types_ of objects:
466  * * `makeWithNameTitle()` supports the objects which can be constructed
467  * with a name and a title (e.g. `TH1`);
468  * * `makeAndSetNameTitle()`, support objects which are known not to use
469  * name and title as first constructor arguments, but do provide `SetName()`
470  * (safe bet, coming from `TObject`) and `SetTitle()`.
471  *
472  * Building on that, different overloads of `doConstruct()` use one or another
473  * of these utilities, or none, to create the correct type of object.
474  * The overload is entrusted to C++ via the pointer type (which C++ matches
475  * with a pointer to a base class).
476  *
477  * Note that in this strategy it is not possible to use a constructor without
478  * name and title for an object that _also_ supports the construction with
479  * name and title: as long as `PlotSandbox` recognizes an object as falling in
480  * that category, it will always construct it by calling a constructor with
481  * name and title as first arguments.
482  *
483  * Also note that no name decoration happens at this level: all object names
484  * and titles are expected to be final (processing happens e.g. in `make()`).
485  */
486  /// @{
487 
488  /**
489  * @brief Creates, stores and returns a new object.
490  * @tparam Obj type of the new object to create
491  * @tparam Args type of the additional arguments to `Obj` constructor
492  * @param destDir the `art::TFileDirectory` where the object is stored
493  * @param name final name of the object to be created
494  * @param title final title of the object to be created
495  * @param args additional arguments to `Obj` constructor, if any
496  * @return a pointer to the registered object
497  * @see `makeAndSetNameTitle()`
498  *
499  * This method registers a new object into `destDir` via
500  * `art::TFileDirectory::makeAndRegister()`, using the `name` and `title`
501  * as the first arguments of the constructor.
502  */
503  template <typename Obj, typename... Args>
504  Obj* makeWithNameTitle(
505  art::TFileDirectory& destDir,
506  std::string const& name, std::string const& title, Args&&... args
507  ) const;
508 
509  /**
510  * @brief Creates, stores and returns a new object.
511  * @tparam Obj type of the new object to create
512  * @tparam Args type of the additional arguments to `Obj` constructor
513  * @param destDir the `art::TFileDirectory` where the object is stored
514  * @param name final name of the object to be created
515  * @param title final title of the object to be created
516  * @param args additional arguments to `Obj` constructor, if any
517  * @return a pointer to the registered object
518  * @see `makeAndRegister()`
519  *
520  * This method registers a new object into `destDir` via
521  * `art::TFileDirectory::makeAndRegister()`, using only the constructor
522  * arguments specified in `args`. The `name` and `title` are set afterwards
523  * via `SetName()` and `SetTitle()`.
524  */
525  template <typename Obj, typename... Args>
526  Obj* makeAndSetNameTitle(
527  art::TFileDirectory& destDir,
528  std::string const& name, std::string const& title, Args&&... args
529  ) const;
530 
531  /**
532  * @brief General implementation: creates and registers an `Obj`
533  * (name and title used in `Obj` constructor).
534  * @tparam Obj type of the object to construct
535  * @tparam Args type of additional arguments to `Obj` constructor, if any
536  * @param destDir `art::TFileDirectory` where to store the object
537  * @param obj pointer to `Obj`; unused except to direct C++ overloading
538  * @param name final name of the object
539  * @param title final title of the object
540  * @param args additional arguments to `Obj` constructor
541  *
542  * This is the most fundamental method constructing an object, which is used
543  * as fallback for all `TObject`-derived objects if nothing more appropriate
544  * is available. It is also the best option in general, when `Obj` supports
545  * it.
546  * It requires `Obj` to have a constructor whose first two arguments are
547  * name and title of the object.
548  */
549  template <typename Obj, typename... Args>
550  Obj* doConstruct(
551  art::TFileDirectory& destDir,
552  TObject*,
553  std::string const& name, std::string const& title,
554  Args&&... args
555  ) const;
556 
557  /**
558  * @brief Implementation for `TGraph`-derived objects.
559  * @tparam GraphObj type of `TGraph`-derived object to construct
560  * @tparam Args type of arguments to `GraphObj` constructor, if any
561  * @param destDir `art::TFileDirectory` where to store the object
562  * @param graph pointer to `GraphObj`; unused except to direct C++ overloading
563  * @param name final name of the graph object
564  * @param title final title of the graph object
565  * @param args arguments to `GraphObj` constructor
566  *
567  * This method manages the creation of objects derived from `TGraph`.
568  * Note that `TGraph` itself does feature a constructor with two strings as
569  * first arguments, but that is not the standard name/title constructor
570  * (in fact, there is no such standard constructor for `TGraph`, and that
571  * matching one takes a text file path for input and an option string...).
572  *
573  * The name and title of the graph are still set, via `SetName()` and
574  * `SetTitle()` (this action is delegated to
575  * `TFileDirectory::makeAndRegister()`).
576  */
577  template <typename GraphObj, typename... Args>
578  GraphObj* doConstruct(
579  art::TFileDirectory& destDir,
580  TGraph*,
581  std::string const& name, std::string const& title,
582  Args&&... args
583  ) const;
584 
585  // --- END -- Object creation specializations --------------------------------
586 
587 
588  /// Retrieves or, if not present, creates a ROOT subdirectory in the sandbox.
589  /// Returns a pair with the directory and the name part of `path`.
590  /// The directory part may be empty.
591  static std::pair<std::string, std::string> splitPath
592  (std::string const& path, char sep = '/');
593 
594  /// Merges the pieces of path that are not empty into a path.
595  /// One separator at the end of each piece is ignored.
596  static std::string joinPath
597  (std::initializer_list<std::string> pathElements, char sep = '/');
598 
599 }; // icarus::trigger::PlotSandbox
600 
601 
602 //------------------------------------------------------------------------------
603 //--- Standard library support
604 //------------------------------------------------------------------------------
605 namespace std {
606 
607  template <>
608  struct hash<icarus::trigger::PlotSandbox> {
609  auto operator() (icarus::trigger::PlotSandbox const& key) const
610  { return std::hash<std::string>()(key.ID()); }
611  }; // hash<PlotSandbox>
612 
613 } // namespace std
614 
615 
616 //------------------------------------------------------------------------------
617 //--- template implementation
618 //------------------------------------------------------------------------------
619 template <typename RootDir /* = TDirectoryFile */>
621  art::TFileDirectory parentDir,
622  std::string const& subdir, std::string const& dirTitle /* = "" */
623  )
625 {
626  // NOTE: we only support a direct subdirectory of parentDir.
627  // NOTE: if the directory already exists the results are undefined;
628  // we can't figure out if the direct
629 
630  // first we create the directory directly via ROOT,
631  // but starting from the directory stored in `parentDir`
632  TDirectory* pROOTdir
633  = parentDir.make<RootDir>(subdir.c_str(), dirTitle.c_str());
634 
635  // then we create a `art::TFileDirectory` for the same directory;
636  // this is the only way we can create a new `art::TFileDirectory`,
637  // and it actually does not create the ROOT directory because it's lazy,
638  // and it will create it only when it is needed, if not present yet.
639  return { parentDir.mkdir(subdir, dirTitle), pROOTdir };
640 
641 } // icarus::trigger::PlotSandbox::TFileDirectoryHelper::create()
642 
643 
644 //------------------------------------------------------------------------------
645 template <typename Obj /* = TObject */>
646 Obj const* icarus::trigger::PlotSandbox::get(std::string const& name) const
647  { return use<std::add_const_t<Obj>>(name); }
648 
649 
650 //------------------------------------------------------------------------------
651 template <typename Obj /* = TObject */>
652 Obj* icarus::trigger::PlotSandbox::use(std::string const& name) const {
653 
654  auto [ objDir, objName ] = splitPath(name);
655 
656  TDirectory* dir = getDirectory(objDir);
657  if (!dir) return nullptr;
658 
659  std::string const processedName = processName(objName);
660  return dir->Get<Obj>(processedName.c_str());
661 
662 } // icarus::trigger::PlotSandbox::use()
663 
664 
665 //------------------------------------------------------------------------------
666 template <typename Obj /* = TObject */>
667 Obj& icarus::trigger::PlotSandbox::demand(std::string const& name) const {
668 
669  auto* obj = use<Obj>(name);
670  if (obj) return *obj;
671  cet::exception e { "PlotSandbox" };
672  e << "PlotSandbox::demand(): object '" << name
673  << "' not available in the sandbox '" << ID() << "'"
674  << "\nBox content: ";
675  dumpContent(e, "", ""); // no indent
676 
677  throw e << "\n";
678 } // icarus::trigger::PlotSandbox::demand()
679 
680 
681 //------------------------------------------------------------------------------
682 template <typename DirObj /* = TDirectory */>
684  { return dynamic_cast<DirObj*>(fData.outputDir.fROOTdir); }
685 
686 
687 //------------------------------------------------------------------------------
688 template <typename DirObj /* = TDirectory */>
690  (std::string const& path) const
691 {
692  TDirectory* pBaseDir = fData.outputDir.fROOTdir;
693  return dynamic_cast<DirObj*>
694  (path.empty()? pBaseDir: pBaseDir->GetDirectory(path.c_str()));
695 } // icarus::trigger::PlotSandbox::getDirectory()
696 
697 
698 //------------------------------------------------------------------------------
699 template <typename Obj, typename... Args>
701  (std::string const& name, std::string const& title, Args&&... args)
702 {
703  auto [ objDir, objName ] = splitPath(name);
704 
705  std::string const processedName = processName(objName);
706  std::string const processedTitle = processPlotTitle(title);
707 
708  art::TFileDirectory destDir
709  = objDir.empty()? fData.outputDir.fDir: fData.outputDir.fDir.mkdir(objDir);
710 
711  using ObjPtr_t = Obj*;
712  return doConstruct<Obj>(
713  destDir, ObjPtr_t{},
714  processedName, processedTitle, std::forward<Args>(args)...
715  );
716 } // icarus::trigger::PlotSandbox::make()
717 
718 
719 //------------------------------------------------------------------------------
720 template
721  <typename SandboxType /* = icarus::trigger::PlotSandbox */, typename... Args>
723  (std::string const& name, std::string const& desc, Args&&... args)
724 {
725  // we can't use make_unique() because the constructor it needs is protected:
726  auto [ it, bInserted ] = fData.subBoxes.try_emplace
727  (name, new SandboxType(*this, name, desc, std::forward<Args>(args)...));
728  if (!bInserted) {
729  throw cet::exception("PlotSandbox")
730  << "PlotSandbox::addSubSandbox(): a subbox with name '" << name
731  << "' already exists in box '" << ID() << "'.\n";
732  }
733  return *(it->second); // it iterator to the inserted element
734 } // icarus::trigger::PlotSandbox::addSubSandbox()
735 
736 
737 //------------------------------------------------------------------------------
738 template <typename SandboxType>
740  (SandboxType& sandbox, std::string const& name)
741 {
742  auto const it = sandbox.fData.subBoxes.find(name);
743  return (it == sandbox.fData.subBoxes.end())? nullptr: it->second.get();
744 }
745 
746 
747 //------------------------------------------------------------------------------
748 template <typename SandboxType>
750  (SandboxType& sandbox, std::string const& name)
751 {
752  auto* box = findSandbox(sandbox, name);
753  if (box) return *box;
754 
755  cet::exception e { "PlotSandbox" };
756  e << "PlotSandbox::demandSandbox(): box '" << name
757  << "' not available in the sandbox '" << sandbox.ID() << "'";
758  if (sandbox.nSubSandboxes()) {
759  e << "\n" << "Available nested boxes (" << sandbox.nSubSandboxes() << "):";
760  for (auto const& subbox: sandbox.subSandboxes())
761  e << "\n * '" << subbox.ID() << "'";
762  } // if has subboxes
763  else {
764  e << " (no contained box!)";
765  }
766  throw e << "\n";
767 
768 } // icarus::trigger::PlotSandbox::demandSandbox(SandboxType)
769 
770 
771 
772 //------------------------------------------------------------------------------
773 template <typename Obj, typename... Args>
775  art::TFileDirectory& destDir,
776  std::string const& name, std::string const& title, Args&&... args
777 ) const {
778  return destDir.makeAndRegister<Obj>
779  (name, title, name.c_str(), title.c_str(), std::forward<Args>(args)...);
780 } // icarus::trigger::PlotSandbox::makeWithNameTitle()
781 
782 
783 //------------------------------------------------------------------------------
784 template <typename Obj, typename... Args>
786  art::TFileDirectory& destDir,
787  std::string const& name, std::string const& title, Args&&... args
788 ) const {
789  return destDir.makeAndRegister<Obj>(name, title, std::forward<Args>(args)...);
790 } // icarus::trigger::PlotSandbox::justMake()
791 
792 
793 //------------------------------------------------------------------------------
794 template <typename Obj, typename... Args>
796  art::TFileDirectory& destDir,
797  TObject*,
798  std::string const& name, std::string const& title,
799  Args&&... args
800 ) const {
801  return
802  makeWithNameTitle<Obj>(destDir, name, title, std::forward<Args>(args)...);
803 } // icarus::trigger::PlotSandbox::doConstruct()
804 
805 
806 //------------------------------------------------------------------------------
807 template <typename GraphObj, typename... Args>
809  art::TFileDirectory& destDir,
810  TGraph*,
811  std::string const& name, std::string const& title,
812  Args&&... args
813 ) const {
814  return makeAndSetNameTitle<GraphObj>
815  (destDir, name, title, std::forward<Args>(args)...);
816 } // icarus::trigger::PlotSandbox::doConstruct(TGraph)
817 
818 
819 //------------------------------------------------------------------------------
820 template <typename Stream>
822  (Stream&& out, std::string indent, std::string firstIndent) const
823 {
824  out << firstIndent;
825  if (hasName()) out << "Box '" << name() << "'";
826  else out << "Unnamed box";
827  if (hasDescription()) out << " (\"" << description() << "\")";
828  out << " [ID=" << ID() << "] with ";
829  dumpContent(std::forward<Stream>(out), indent, "");
830 
831  if (nSubSandboxes()) {
832  out << "\n" << indent << "Nested boxes (" << nSubSandboxes() << "):";
833  for (auto const& subbox: subSandboxes()) {
834  out << "\n";
835  subbox.dump(std::forward<Stream>(out), indent + " ");
836  }
837  } // if has subboxes
838 } // icarus::trigger::PlotSandbox::dump()
839 
840 
841 //------------------------------------------------------------------------------
842 template <typename Stream>
844  (Stream&& out, std::string indent, std::string firstIndent) const
845 {
846  out << firstIndent;
847 
848  TDirectory const* pDir = fData.outputDir.fROOTdir;
849  if (!pDir) {
850  out << "no content available";
851  return;
852  }
853 
854  TList const* objects = pDir->GetList();
855  TList const* keys = pDir->GetListOfKeys();
856  if (objects && !objects->IsEmpty()) {
857  out << objects->GetSize() << " direct entries:";
858  for (TObject const* obj: *objects) {
859  out << "\n" << indent << " '" << obj->GetName() << "' ["
860  << obj->IsA()->GetName() << "]";
861  } // for objects
862  }
863  else out << "no direct entries;";
864  if (keys) {
865  for (TObject const* keyObj: *keys) {
866  auto key = dynamic_cast<TKey const*>(keyObj);
867  if (!key) continue;
868  if (objects->Contains(key->GetName())) continue; // already in objects
869  out << "\n" << indent
870  << "[KEY] '" << key->GetName() << "' ["
871  << key->GetClassName() << "]"
872  ;
873  } // for
874  } // if has keys
875 
876 } // icarus::trigger::PlotSandbox::dumpContent()
877 
878 
879 //------------------------------------------------------------------------------
880 
881 
882 #endif // ICARUSCODE_PMT_TRIGGER_UTILITIES_PLOTSANDBOX_H
std::string ID() const
Returns a string ID for this sandbox.
Obj * make(std::string const &name, std::string const &title, Args &&...args)
Creates a new ROOT object with the specified name and title.
Definition: PlotSandbox.h:701
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Obj * makeWithNameTitle(art::TFileDirectory &destDir, std::string const &name, std::string const &title, Args &&...args) const
Creates, stores and returns a new object.
Definition: PlotSandbox.h:774
TFileDirectoryHelper outputDir
Output ROOT directory of the sandbox.
Definition: PlotSandbox.h:133
static std::string joinPath(std::initializer_list< std::string > pathElements, char sep= '/')
An object with a begin and end iterator.
The whole data in a convenient package!
Definition: PlotSandbox.h:123
decltype(auto) subSandboxes() const
Returns an object proper to iterate through all contained sand boxes.
Definition: PlotSandbox.h:369
PlotSandbox const * parent
Optional parent sandbox.
Definition: PlotSandbox.h:128
void dump(Stream &&out, std::string indent="") const
Dumps the hierarchy of sandboxes into the specified stream.
Definition: PlotSandbox.h:389
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
virtual void setParent(PlotSandbox const *parent)
Sets the parent of this box.
Definition: PlotSandbox.h:410
static std::pair< std::string, std::string > splitPath(std::string const &path, char sep= '/')
virtual ~PlotSandbox()=default
Virtual destructor. Default, but C++ wants it.
std::string const & name() const
Returns the sandbox name.
Definition: PlotSandbox.h:196
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
std::string name
The name/key representing this sandbox.
Definition: PlotSandbox.h:125
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
std::string desc
The description characterizing the sandbox.
Definition: PlotSandbox.h:126
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).
auto make_transformed_span(BIter begin, EIter end, Op &&op)
Definition: span.h:294
DirObj * getDirectory() const
Fetches the base directory of the sandbox.
Definition: PlotSandbox.h:683
decltype(auto) map_dereferenced_values(Map &&map)
Definition: PlotSandbox.h:63
virtual std::string processedSandboxName() const
std::size_t nSubSandboxes() const
Returns the number of contained sand boxes.
Definition: PlotSandbox.h:341
virtual std::string processedSandboxDesc() const
void dump(Stream &&out, std::string indent, std::string firstIndent) const
Dumps the hierarchy of sandboxes into the specified stream.
Definition: PlotSandbox.h:822
Obj * doConstruct(art::TFileDirectory &destDir, TObject *, std::string const &name, std::string const &title, Args &&...args) const
General implementation: creates and registers an Obj (name and title used in Obj constructor).
Definition: PlotSandbox.h:795
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 const & description() const
Returns the sandbox description.
Definition: PlotSandbox.h:202
virtual std::string const & Description() const
Definition: PlotSandbox.h:206
std::map< std::string, std::unique_ptr< PlotSandbox > > subBoxes
Contained sand boxes.
Definition: PlotSandbox.h:131
Obj const * get(std::string const &name) const
Fetches the object with the specified name from the sandbox.
Definition: PlotSandbox.h:646
std::string processPlotTitle(std::string const &title) const
Applies title processing only at the title part of the string.
SandboxType & addSubSandbox(std::string const &name, std::string const &desc, Args &&...args)
Creates a new sandbox contained in this one.
Definition: PlotSandbox.h:723
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
Obj & demand(std::string const &name) const
Fetches an object with the specified name to be modified.
Definition: PlotSandbox.h:667
temporary value
TFileDirectoryHelper(art::TFileDirectory dir, TDirectory *ROOTdir)
Definition: PlotSandbox.h:107
Data_t & operator=(Data_t const &)=delete
static decltype(auto) constexpr iterate(T &&coll) noexcept
Definition: PlotSandbox.h:53
bool hasDescription() const
Returns whether we have a non-empty description.
Definition: PlotSandbox.h:199
Obj * use(std::string const &name) const
Fetches an object with the specified name to be modified.
Definition: PlotSandbox.h:652
void dumpContent(Stream &&out, std::string indent, std::string firstIndent) const
Dumps the content of this box (nosubboxes) into out stream.
Definition: PlotSandbox.h:844
bnb BNB Stream
Obj * makeAndSetNameTitle(art::TFileDirectory &destDir, std::string const &name, std::string const &title, Args &&...args) const
Creates, stores and returns a new object.
Definition: PlotSandbox.h:785
virtual std::string processTitle(std::string const &title) const
Processes the specified string as it were a description or title.
bool hasName() const
Returns whether we have a non-empty name.
Definition: PlotSandbox.h:193
PlotSandbox & operator=(PlotSandbox const &)=delete
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