RawDataDrawer.cxx
Go to the documentation of this file.
1 /**
2  * @file RawDataDrawer.cxx
3  * @brief Class to aid in the rendering of RawData objects
4  * @author messier@indiana.edu
5  *
6  * This class prepares the rendering of the raw digits content for the 2D view
7  * of the display. In particular, it fills the 2D view of detected charge
8  * vs. time and wire number for a single TPC.
9  * The code is not ready to support an arbitrary TPC from the detector;
10  * it can be fixed to support that, but a good deal of the calling code also
11  * has to change.
12  *
13  * Notes from Gianluca Petrillo (petrillo@fnal.gov) on August 19, 2015
14  * --------------------------------------------------------------------
15  *
16  * As of August 2015, this class performs some preprocessing for the data to
17  * be displayed.
18  * The main argument here is that the display assigns to each plane a space
19  * of 600x250 pixels, while the amound of data is typically 500x5000 elements.
20  * These numbers vary wildly: while the first number is close to the current
21  * default size for a new window, that window can be resized and windows many
22  * times larger can be obtained; for the data content, a MicroBooNE plane
23  * contains 2400x9600 elements (that's roughly 25 millions, and there is three
24  * of them), each of the two LArIAT planes contains 240x3200 (less than 1
25  * million), and a single TPC of DUNE's 35t prototype about 350x4800 (but it
26  * is larger when extended readout window modes are used).
27  * The code produces TBox'es to be rendered by the nuevdb event display
28  * infrastructure. The code before August 2015 would produce one box for each
29  * of the aggregated charge; charge could be aggregated in time by FHiCL
30  * configuration to merge TDC ticks. This typically bloats rendering time,
31  * since rendering of all boxes is attempted.
32  * The new code performs dynamic aggregation after discovering the actual size
33  * of the graphical viewport, and it submits at most one TBox per pixel.
34  * Additional improvement is caching of the uncompressed raw data, so that
35  * following zooming is faster, and especially a way to bypass the decompression
36  * when the original data is not compressed in the first place, that saves
37  * a bit of time and quite some memory.
38  *
39  * @todo There are probably a number of glitches and shortcuts in the current
40  * preprocessing implementation. If they become a problem, they can probably be
41  * fixed on demand. Examples include:
42  * - no alignment of the boxes with the wire and tick numbers
43  * - possible border effects
44  * - the fact that only the maximum charge is displayed on each box , and no
45  * dynamic charge range detection is in place
46  * - the first drawing is performed with a grid that is not the final one
47  * (because for some reason the frame starts larger than it should and is
48  * resized later)
49  * - the drawing honours the zoom region the user selected, even if the viewport
50  * ends up being larger (that is, if upstream decides that the zoom region is
51  * too small and a larger area will be drawn, the additional area will be
52  * blank)
53  */
54 #include <algorithm> // std::fill(), std::find_if(), ...
55 #include <cmath> // std::abs(), ...
56 #include <cstddef> // std::ptrdiff_t
57 #include <limits> // std::numeric_limits<>
58 #include <memory> // std::unique_ptr()
59 #include <tuple>
60 #include <type_traits> // std::add_const_t<>, ...
61 #include <typeinfo> // to use typeid()
62 #include <utility> // std::move()
63 
64 #include "TBox.h"
65 #include "TFrame.h"
66 #include "TH1F.h"
67 #include "TVirtualPad.h"
68 
71 #include "lardataalg/Utilities/StatCollector.h" // lar::util::MinMaxCollector<>
73 #include "lardataobj/RawData/raw.h"
74 #include "lareventdisplay/EventDisplay/ChangeTrackers.h" // util::PlaneDataChangeTracker_t
82 #include "nuevdb/EventDisplayBase/View2D.h"
83 
90 #include "cetlib_except/demangle.h"
92 
93 namespace {
94  template <typename Stream, typename T>
95  void
96  PrintRange(Stream&& out, std::string header, lar::util::MinMaxCollector<T> const& range)
97  {
98  out << header << ": " << range.min() << " -- " << range.max() << " ("
99  << (range.has_data() ? "valid" : "invalid") << ")";
100  } // PrintRange()
101 } // local namespace
102 
103 // internal use classes declaration;
104 // it can't live in the header because it uses C++11/14
105 namespace details {
106  /// @todo Document this code and make it into a library
107  template <typename T>
109  public:
110  using value_type = T;
111  using const_value_type = std::add_const_t<value_type>;
112  using reference = std::add_lvalue_reference_t<value_type>;
113  using const_reference = std::add_lvalue_reference_t<const_value_type>;
114  using pointer = std::add_pointer_t<value_type>;
115  using const_pointer = std::add_pointer_t<const_value_type>;
116 
117  /// Destructor: gets rid of the owned data
119 
120  /// @name Dereferencing
121  /// @{
122  const_reference operator*() const { return *pData; }
123  reference operator*() { return *pData; }
124 
125  const_pointer operator->() const { return pData; }
126  pointer operator->() { return pData; }
127  /// @}
128 
129  /// Returns whether we point to something
130  operator bool() const { return hasData(); }
131 
132  /// Returns whether we point to nothing
133  bool operator!() const { return !hasData(); }
134 
135  /// Returns whether we have data
136  bool
137  hasData() const
138  {
139  return bool(pData);
140  }
141 
142  /// Returns whether we have data and we own it
143  bool
144  owned() const
145  {
146  return bOwned && hasData();
147  }
148 
149  /// Sets the data and the ownership
150  void
152  {
153  Clear();
154  bOwned = owned;
155  pData = data;
156  }
157  /// Acquire ownership of the specified data
158  void
160  {
161  SetData(data, true);
162  }
163  /// Point to the specified data, not acquiring ownership
164  void
166  {
167  SetData(data, false);
168  }
169  /// Point to the specified data, not acquiring ownership
170  void
172  {
173  SetData(&data, false);
174  }
175  /// Move data from the specified object, and own it
176  void
177  StealData(std::remove_const_t<T>&& data)
178  {
179  AcquireData(new T(std::move(data)));
180  }
181  /// Create a owned copy of the specified object
182  void
183  NewData(T const& data)
184  {
185  AcquireData(new T(data));
186  }
187  /// Stop pointing to the data; if owned, delete it
188  void
190  {
191  if (bOwned) delete pData;
192  pData = nullptr;
193  bOwned = false;
194  } // Clear()
195 
196  protected:
197  bool bOwned = false; ///< whether we own our data
198  pointer pData = nullptr; ///< pointer to data
199  }; // class PointerToData_t<>
200 }
201 
202 namespace evd {
203  namespace details {
204 
205  /// Information about a RawDigit; may contain uncompressed duplicate of data
207  public:
208  /// Returns an art pointer to the actual digit
210  DigitPtr() const
211  {
212  return digit;
213  }
214 
215  /// Returns an art pointer to the actual digit
216  raw::RawDigit const&
217  Digit() const
218  {
219  return *digit;
220  }
221 
222  /// Returns the channel of this digit (for convenience)
224  Channel() const
225  {
226  return digit ? digit->Channel() : raw::InvalidChannelID;
227  }
228 
229  /// minimum charge
230  short
231  MinCharge() const
232  {
233  return SampleInfo().min_charge;
234  }
235 
236  /// maximum charge
237  short
238  MaxCharge() const
239  {
240  return SampleInfo().max_charge;
241  }
242 
243  /// average charge
244  // short AverageCharge() const { return SampleInfo().average_charge; }
245 
246  /// Returns the uncompressed data
247  raw::RawDigit::ADCvector_t const& Data() const;
248 
249  /// Parses the specified digit
250  void Fill(art::Ptr<raw::RawDigit> const& src);
251 
252  /// Deletes the data
253  void Clear();
254 
255  /// Dumps the content of the digit info
256  template <typename Stream>
257  void Dump(Stream&& out) const;
258 
259  private:
260  typedef struct {
261  short min_charge = std::numeric_limits<short>::max(); ///< minimum charge
262  short max_charge = std::numeric_limits<short>::max(); ///< maximum charge
263  // float average_charge = 0.; ///< average charge
264  } SampleInfo_t; // SampleInfo_t
265 
266  art::Ptr<raw::RawDigit> digit; ///< a pointer to the actual digit
267 
268  /// Uncompressed data
269  mutable ::details::PointerToData_t<raw::RawDigit::ADCvector_t const> data;
270 
271  /// Information collected from the uncompressed data
272  mutable std::unique_ptr<SampleInfo_t> sample_info;
273 
274  /// Fills the uncompressed data cache
275  void UncompressData() const;
276 
277  /// Fills the sample info cache
278  void CollectSampleInfo() const;
279 
280  /// Returns the uncompressed data
281  SampleInfo_t const& SampleInfo() const;
282 
283  }; // class RawDigitInfo_t
284 
285  /// Cached set of RawDigitInfo_t
287  public:
288  /// Returns the list of digit info
289  std::vector<RawDigitInfo_t> const&
290  Digits() const
291  {
292  return digits;
293  }
294 
295  /// Returns a pointer to the digit info of given channel, nullptr if none
296  RawDigitInfo_t const* FindChannel(raw::ChannelID_t channel) const;
297 
298  /// Returns the largest number of samples in the unpacked raw digits
299  size_t
300  MaxSamples() const
301  {
302  return max_samples;
303  }
304 
305  /// Returns whether the cache is empty() (STL-like interface)
306  bool
307  empty() const
308  {
309  return digits.empty();
310  }
311 
312  /// Empties the cache
313  void Clear();
314 
315  /// Fills the cache from the specified raw digits product handle
316  void Refill(art::Handle<std::vector<raw::RawDigit>>& rdcol);
317 
318  /// Clears the cache and marks it as invalid (use Update() to fill it)
319  void Invalidate();
320 
321  /// Updates the cache for new_timestamp using the specified event
322  /// @return true if it needed to update (that might have failed)
323  bool Update(art::Event const& evt, CacheID_t const& new_timestamp);
324 
325  /// Dump the content of the cache
326  template <typename Stream>
327  void Dump(Stream&& out) const;
328 
329  private:
331 
332  bool bUpToDate = false;
333  std::vector<raw::RawDigit> const* digits = nullptr;
334 
335  BoolWithUpToDateMetadata() = default;
336  BoolWithUpToDateMetadata(bool uptodate, std::vector<raw::RawDigit> const* newdigits)
337  : bUpToDate(uptodate), digits(newdigits)
338  {}
339 
340  operator bool() const { return bUpToDate; }
341  }; // struct BoolWithUpToDateMetadata
342 
343  std::vector<RawDigitInfo_t> digits; ///< vector of raw digit information
344 
345  CacheID_t timestamp; ///< object expressing validity range of cached data
346 
347  size_t max_samples = 0; ///< the largest number of ticks in any digit
348 
349  /// Checks whether an update is needed; can load digits in the process
350  BoolWithUpToDateMetadata CheckUpToDate(CacheID_t const& ts,
351  art::Event const* evt = nullptr) const;
352 
353  static std::vector<raw::RawDigit> const* ReadProduct(art::Event const& evt,
355 
356  }; // struct RawDigitCacheDataClass
357 
360  {
361  return cache.Digits().cbegin();
362  }
365  {
366  return cache.Digits().cend();
367  }
368 
369  /// Manages a cell-like division of a coordinate
371  public:
372  /// Default constructor: an invalid range
373  GridAxisClass() { Init(0, 0., 0.); }
374 
375  /// Constructor: sets the limits and the number of cells
376  GridAxisClass(size_t nDiv, float new_min, float new_max) { Init(nDiv, new_min, new_max); }
377 
378  //@{
379  /// Returns the index of the specified cell
380  std::ptrdiff_t GetCell(float coord) const;
381  std::ptrdiff_t
382  operator()(float coord) const
383  {
384  return GetCell(coord);
385  }
386  //@}
387 
388  /// Returns whether the cell is present or not
389  bool
390  hasCell(std::ptrdiff_t iCell) const
391  {
392  return (iCell >= 0) && ((size_t)iCell < NCells());
393  }
394 
395  /// Returns whether the coordinate is included in the range or not
396  bool
397  hasCoord(float coord) const
398  {
399  return (coord >= Min()) && (coord < Max());
400  }
401 
402  //@{
403  /// Returns the extremes of the axis
404  float
405  Min() const
406  {
407  return min;
408  }
409  float
410  Max() const
411  {
412  return max;
413  }
414  //@}
415 
416  /// Returns the length of the axis
417  float
418  Length() const
419  {
420  return max - min;
421  }
422 
423  /// Returns the length of the axis
424  size_t
425  NCells() const
426  {
427  return n_cells;
428  }
429 
430  /// Returns whether minimum and maximum match
431  bool
432  isEmpty() const
433  {
434  return max == min;
435  }
436 
437  /// Returns the cell size
438  float
439  CellSize() const
440  {
441  return cell_size;
442  }
443 
444  /// Returns the lower edge of the cell
445  float
446  LowerEdge(std::ptrdiff_t iCell) const
447  {
448  return Min() + CellSize() * iCell;
449  }
450 
451  /// Returns the upper edge of the cell
452  float
453  UpperEdge(std::ptrdiff_t iCell) const
454  {
455  return LowerEdge(iCell + 1);
456  }
457 
458  /// Initialize the axis, returns whether cell size is finite
459  bool Init(size_t nDiv, float new_min, float new_max);
460 
461  /// Initialize the axis limits, returns whether cell size is finite
462  bool SetLimits(float new_min, float new_max);
463 
464  /// Expands the cell (at fixed range) to meet minimum cell size
465  /// @return Whether the cell size was changed
466  bool SetMinCellSize(float min_size);
467 
468  /// Expands the cell (at fixed range) to meet maximum cell size
469  /// @return Whether the cell size was changed
470  bool SetMaxCellSize(float max_size);
471 
472  /// Expands the cell (at fixed range) to meet maximum cell size
473  /// @return Whether the cell size was changed
474  bool
475  SetCellSizeBoundary(float min_size, float max_size)
476  {
477  return SetMinCellSize(min_size) || SetMaxCellSize(max_size);
478  }
479 
480  template <typename Stream>
481  void Dump(Stream&& out) const;
482 
483  private:
484  size_t n_cells; ///< number of cells in the axis
485  float min, max; ///< extremes of the axis
486 
487  float cell_size; ///< size of each cell
488 
489  }; // GridAxisClass
490 
491  /// Manages a grid-like division of 2D space
493  public:
494  /// Default constructor: invalid ranges
495  CellGridClass() : wire_axis(), tdc_axis() {}
496 
497  /// Constructor: sets the extremes and assumes one cell for each element
498  CellGridClass(unsigned int nWires, unsigned int nTDC);
499 
500  /// Constructor: sets the wire and TDC ranges in detail
501  CellGridClass(float min_wire,
502  float max_wire,
503  unsigned int nWires,
504  float min_tdc,
505  float max_tdc,
506  unsigned int nTDC);
507 
508  /// Returns the total number of cells in the grid
509  size_t
510  NCells() const
511  {
512  return wire_axis.NCells() * tdc_axis.NCells();
513  }
514 
515  /// Return the information about the wires
516  GridAxisClass const&
517  WireAxis() const
518  {
519  return wire_axis;
520  }
521 
522  /// Return the information about the TDCs
523  GridAxisClass const&
524  TDCAxis() const
525  {
526  return tdc_axis;
527  }
528 
529  /// Returns the index of specified cell, or -1 if out of range
530  std::ptrdiff_t GetCell(float wire, float tick) const;
531 
532  /// Returns the coordinates { w1, t1, w2, t2 } of specified cell
533  std::tuple<float, float, float, float> GetCellBox(std::ptrdiff_t iCell) const;
534 
535  //@{
536  /// Returns whether the range includes the specified wire
537  bool
538  hasWire(float wire) const
539  {
540  return wire_axis.hasCoord(wire);
541  }
542  bool
543  hasWire(int wire) const
544  {
545  return hasWire((float)wire);
546  }
547  //@}
548 
549  //@{
550  /// Returns whether the range includes the specified wire
551  bool
552  hasTick(float tick) const
553  {
554  return tdc_axis.hasCoord(tick);
555  }
556  bool
557  hasTick(int tick) const
558  {
559  return hasTick((float)tick);
560  }
561  //@}
562 
563  /// Increments the specified cell of cont with the value v
564  /// @return whether there was such a cell
565  template <typename CONT>
566  bool
567  Add(CONT& cont, float wire, float tick, typename CONT::value_type v)
568  {
569  std::ptrdiff_t cell = GetCell(wire, tick);
570  if (cell < 0) return false;
571  cont[(size_t)cell] += v;
572  return true;
573  } // Add()
574 
575  /// @name Setters
576  /// @{
577  /// Sets a simple wire range: all the wires, one cell per wire
578  void
579  SetWireRange(unsigned int nWires)
580  {
581  SetWireRange(0., (float)nWires, nWires);
582  }
583 
584  /// Sets the wire range, leaving the number of wire cells unchanged
585  void
586  SetWireRange(float min_wire, float max_wire)
587  {
588  wire_axis.SetLimits(min_wire, max_wire);
589  }
590 
591  /// Sets the complete wire range
592  void
593  SetWireRange(float min_wire, float max_wire, unsigned int nWires)
594  {
595  wire_axis.Init(nWires, min_wire, max_wire);
596  }
597 
598  /// Sets the complete wire range, with minimum cell size
599  void
600  SetWireRange(float min_wire, float max_wire, unsigned int nWires, float min_size)
601  {
602  wire_axis.Init(nWires, min_wire, max_wire);
603  wire_axis.SetMinCellSize(min_size);
604  }
605 
606  /// Sets a simple TDC range: all the ticks, one cell per tick
607  void
608  SetTDCRange(unsigned int nTDC)
609  {
610  SetTDCRange(0., (float)nTDC, nTDC);
611  }
612 
613  /// Sets the complete TDC range
614  void
615  SetTDCRange(float min_tdc, float max_tdc, unsigned int nTDC)
616  {
617  tdc_axis.Init(nTDC, min_tdc, max_tdc);
618  }
619 
620  /// Sets the TDC range, leaving the number of ticks unchanged
621  void
622  SetTDCRange(float min_tdc, float max_tdc)
623  {
624  tdc_axis.SetLimits(min_tdc, max_tdc);
625  }
626 
627  /// Sets the complete TDC range, with minimum cell size
628  void
629  SetTDCRange(float min_tdc, float max_tdc, unsigned int nTDC, float min_size)
630  {
631  tdc_axis.Init(nTDC, min_tdc, max_tdc);
632  tdc_axis.SetMinCellSize(min_size);
633  }
634 
635  /// @}
636 
637  /// Sets the minimum size for wire cells
638  bool
639  SetMinWireCellSize(float min_size)
640  {
641  return wire_axis.SetMinCellSize(min_size);
642  }
643 
644  /// Sets the minimum size for TDC cells
645  bool
646  SetMinTDCCellSize(float min_size)
647  {
648  return tdc_axis.SetMinCellSize(min_size);
649  }
650 
651  /// Prints the current axes on the specified stream
652  template <typename Stream>
653  void Dump(Stream&& out) const;
654 
655  private:
658  }; // CellGridClass
659 
660  //--------------------------------------------------------------------------
661  /// Applies Birks correction
663  public:
665  : detProp{dp}
666  , wirePitch{art::ServiceHandle<geo::Geometry const>()->WirePitch(pid)}
667  , electronsToADC{dp.ElectronsToADC()}
668  {}
669 
670  /// Applies Birks correction to the specified pedestal-subtracted charge
671  double
672  operator()(float adc) const
673  {
674  if (adc < 0.) return 0.;
675  double const dQdX = adc / wirePitch / electronsToADC;
676  return detProp.BirksCorrection(dQdX);
677  }
678 
679  private:
681  double wirePitch; ///< wire pitch
682  double electronsToADC; ///< conversion constant
683 
684  }; // ADCCorrectorClass
685  //--------------------------------------------------------------------------
686  } // namespace details
687 } // namespace evd
688 
689 namespace evd {
690 
691  // empty vector
692  std::vector<raw::RawDigit> const RawDataDrawer::EmptyRawDigits;
693 
694  //......................................................................
695  RawDataDrawer::RawDataDrawer()
696  : digit_cache(new details::RawDigitCacheDataClass)
697  , fStartTick(0)
698  , fTicks(2048)
699  , fCacheID(new details::CacheID_t)
700  , fDrawingRange(new details::CellGridClass)
701  {
703 
705  geo::TPCID tpcid(rawopt->fCryostat, rawopt->fTPC);
706 
707  fStartTick = rawopt->fStartTick;
708  fTicks = rawopt->fTicks;
709 
710  // set the list of bad channels in this detector
711  unsigned int nplanes = geo->Nplanes(tpcid);
712  fWireMin.resize(nplanes, -1);
713  fWireMax.resize(nplanes, -1);
714  fTimeMin.resize(nplanes, -1);
715  fTimeMax.resize(nplanes, -1);
716  fRawCharge.resize(nplanes, 0);
717  fConvertedCharge.resize(nplanes, 0);
718  }
719 
720  //......................................................................
722  {
723  delete digit_cache;
724  delete fDrawingRange;
725  delete fCacheID;
726  }
727 
728  //......................................................................
729  void
730  RawDataDrawer::SetDrawingLimits(float low_wire, float high_wire, float low_tdc, float high_tdc)
731  {
732  MF_LOG_DEBUG("RawDataDrawer") << __func__ << "() setting drawing range as wires ( " << low_wire
733  << " - " << high_wire << " ), ticks ( " << low_tdc << " - "
734  << high_tdc << " )";
735 
736  // we need to set the minimum cell size to 1, otherwise some cell will not
737  // cover any wire/tick and they will be always empty
738  if (PadResolution) {
739  // TODO implement support for swapping axes here
740  unsigned int wire_pixels = PadResolution.width;
741  unsigned int tdc_pixels = PadResolution.height;
742  fDrawingRange->SetWireRange(low_wire, high_wire, wire_pixels, 1.F);
743  fDrawingRange->SetTDCRange(low_tdc, high_tdc, tdc_pixels, 1.F);
744  }
745  else {
746  MF_LOG_DEBUG("RawDataDrawer") << "Pad size not available -- using existing cell size";
747  fDrawingRange->SetWireRange(low_wire, high_wire);
749  fDrawingRange->SetTDCRange(low_tdc, high_tdc);
751  }
752 
753  } // RawDataDrawer::SetDrawingLimits()
754 
755  void
757  {
758  SetDrawingLimits(fWireMin[plane], fWireMax[plane], fTimeMin[plane], fTimeMax[plane]);
759  } // RawDataDrawer::SetDrawingLimitsFromRoI()
760 
761  void
762  RawDataDrawer::ExtractRange(TVirtualPad* pPad, std::vector<double> const* zoom /* = nullptr */)
763  {
764  mf::LogDebug log("RawDataDrawer");
765  log << "ExtractRange() on pad '" << pPad->GetName() << "'";
766 
767  TFrame const* pFrame = pPad->GetFrame();
768  if (pFrame) {
769  // these coordinates are used to find the actual extent of pad in pixels
770  double low_wire = pFrame->GetX1(), high_wire = pFrame->GetX2();
771  double low_tdc = pFrame->GetY1(), high_tdc = pFrame->GetY2();
772  double const wire_pixels = pPad->XtoAbsPixel(high_wire) - pPad->XtoAbsPixel(low_wire);
773  double const tdc_pixels = -(pPad->YtoAbsPixel(high_tdc) - pPad->YtoAbsPixel(low_tdc));
774 
775  PadResolution.width = (unsigned int)wire_pixels;
776  PadResolution.height = (unsigned int)tdc_pixels;
777 
778  log << "\n frame window is " << PadResolution.width << "x" << PadResolution.height
779  << " pixel big and";
780  // those coordinates also are a (unreliable) estimation of the zoom;
781  // if we have a better one, let's use it
782  // (this does not change the size of the window in terms of pixels)
783  if (zoom) {
784  log << ", from external source,";
785  low_wire = (*zoom)[0];
786  high_wire = (*zoom)[1];
787  low_tdc = (*zoom)[2];
788  high_tdc = (*zoom)[3];
789  }
790 
791  log << " spans wires " << low_wire << "-" << high_wire << " and TDC " << low_tdc << "-"
792  << high_tdc;
793 
794  // TODO support swapping axes here:
795  // if (rawopt.fAxisOrientation < 1) { normal ; } else { swapped; }
796 
797  fDrawingRange->SetWireRange(low_wire, high_wire, (unsigned int)wire_pixels, 1.0);
798  fDrawingRange->SetTDCRange(low_tdc, high_tdc, (unsigned int)tdc_pixels, 1.0);
799  }
800  else {
801  // keep the old frame (if any)
802  log << "\n no frame!";
803  }
804 
805  } // RawDataDrawer::ExtractRange()
806 
807  //......................................................................
809  public:
810  OperationBaseClass(geo::PlaneID const& pid, RawDataDrawer* data_drawer = nullptr)
811  : pRawDataDrawer(data_drawer), planeID(pid)
812  {}
813 
814  virtual ~OperationBaseClass() = default;
815 
816  virtual bool
818  {
819  return true;
820  }
821 
822  virtual bool
824  {
825  return true;
826  }
827  virtual bool ProcessTick(size_t) { return true; }
828 
829  virtual bool Operate(geo::WireID const& wireID, size_t tick, float adc) = 0;
830 
831  virtual bool
833  {
834  return true;
835  }
836 
837  virtual std::string
838  Name() const
839  {
840  return cet::demangle_symbol(typeid(*this).name());
841  }
842 
843  bool
844  operator()(geo::WireID const& wireID, size_t tick, float adc)
845  {
846  return Operate(wireID, tick, adc);
847  }
848 
849  geo::PlaneID const&
850  PlaneID() const
851  {
852  return planeID;
853  }
856  {
857  return pRawDataDrawer;
858  }
859 
860  protected:
861  RawDataDrawer* pRawDataDrawer = nullptr;
862 
863  private:
865  }; // class RawDataDrawer::OperationBaseClass
866 
867  //......................................................................
869  std::vector<std::unique_ptr<RawDataDrawer::OperationBaseClass>> operations;
870 
871  public:
872  ManyOperations(geo::PlaneID const& pid, RawDataDrawer* data_drawer = nullptr)
873  : OperationBaseClass(pid, data_drawer)
874  {}
875 
876  bool
877  Initialize() override
878  {
879  bool bAllOk = true;
880  for (std::unique_ptr<OperationBaseClass> const& op : operations)
881  if (!op->Initialize()) bAllOk = false;
882  return bAllOk;
883  }
884 
885  bool
886  ProcessWire(geo::WireID const& wireID) override
887  {
888  for (std::unique_ptr<OperationBaseClass> const& op : operations)
889  if (op->ProcessWire(wireID)) return true;
890  return false;
891  }
892  bool
893  ProcessTick(size_t tick) override
894  {
895  for (std::unique_ptr<OperationBaseClass> const& op : operations)
896  if (op->ProcessTick(tick)) return true;
897  return false;
898  }
899 
900  bool
901  Operate(geo::WireID const& wireID, size_t tick, float adc) override
902  {
903  for (std::unique_ptr<OperationBaseClass> const& op : operations)
904  if (!op->Operate(wireID, tick, adc)) return false;
905  return true;
906  }
907 
908  bool
909  Finish() override
910  {
911  bool bAllOk = true;
912  for (std::unique_ptr<OperationBaseClass> const& op : operations)
913  if (!op->Finish()) bAllOk = false;
914  return bAllOk;
915  }
916 
918  Name() const override
919  {
920  std::string msg = cet::demangle_symbol(typeid(*this).name());
921  msg += (" [running " + std::to_string(operations.size()) + " operations:");
922  for (auto const& op : operations) { // it's unique_ptr<OperationBaseClass>
923  if (op)
924  msg += " " + op->Name();
925  else
926  msg += " <invalid>";
927  }
928  return msg + " ]";
929  }
930 
932  Operator(size_t iOp)
933  {
934  return operations.at(iOp).get();
935  }
936  OperationBaseClass const*
937  Operator(size_t iOp) const
938  {
939  return operations.at(iOp).get();
940  }
941 
942  void
943  AddOperation(std::unique_ptr<OperationBaseClass> new_op)
944  {
945  if (!new_op) return;
946  if (PlaneID() != new_op->PlaneID()) {
948  << "RawDataDrawer::ManyOperations(): trying to run operations on "
949  << std::string(PlaneID()) << " and " << std::string(new_op->PlaneID())
950  << " at the same time";
951  }
952  if (RawDataDrawerPtr() && (RawDataDrawerPtr() != new_op->RawDataDrawerPtr())) {
954  << "RawDataDrawer::ManyOperations(): "
955  "trying to run operations on different RawDataDrawer"; // possible, but very unlikely
956  }
957  operations.emplace_back(std::move(new_op));
958  }
959 
960  }; // class RawDataDrawer::ManyOperations
961 
962  //......................................................................
963  bool
965  {
966  geo::PlaneID const& pid = operation->PlaneID();
968 
969  if (digit_cache->empty()) return true;
970 
971  MF_LOG_DEBUG("RawDataDrawer") << "RawDataDrawer::RunOperation() running " << operation->Name();
972 
973  // if we have an initialization failure, return false immediately;
974  // but it's way better if the failure throws an exception
975  if (!operation->Initialize()) return false;
976 
977  lariov::ChannelStatusProvider const& channelStatus =
979 
980  //get pedestal conditions
981  const lariov::DetPedestalProvider& pedestalRetrievalAlg =
982  *(lar::providerFrom<lariov::DetPedestalService>());
983 
984  geo::GeometryCore const& geom = *(lar::providerFrom<geo::Geometry>());
985 
986  // loop over all the channels/raw digits
987  for (evd::details::RawDigitInfo_t const& digit_info : *digit_cache) {
988  raw::RawDigit const& hit = digit_info.Digit();
989  raw::ChannelID_t const channel = hit.Channel();
990 
991  // skip the bad channels
992  if (!channelStatus.IsPresent(channel)) continue;
993  // The following test is meant to be temporary until the "correct" solution is implemented
994  if (!ProcessChannelWithStatus(channelStatus.Status(channel))) continue;
995 
996  // we have a list of all channels, but we are drawing only on one plane;
997  // most of the channels will not contribute to this plane,
998  // and before we start querying databases, unpacking data etc.
999  // we want to know it's for something
1000 
1001  std::vector<geo::WireID> WireIDs = geom.ChannelToWire(channel);
1002 
1003  bool bDrawChannel = false;
1004  for (geo::WireID const& wireID : WireIDs) {
1005  if (wireID.planeID() != pid) continue; // not us!
1006  bDrawChannel = true;
1007  break;
1008  } // for wires
1009  if (!bDrawChannel) continue;
1010 
1011  // collect bad channels
1012  bool const bGood = rawopt->fSeeBadChannels || !channelStatus.IsBad(channel);
1013 
1014  // nothing else to be done if the channel is not good:
1015  // cells are marked bad by default and if any good channel falls in any of
1016  // them, they become good
1017  if (!bGood) continue;
1018 
1019  // at this point we know we have to process this channel
1020  raw::RawDigit::ADCvector_t const& uncompressed = digit_info.Data();
1021 
1022  // recover the pedestal
1023  float pedestal = 0;
1024  if (rawopt->fPedestalOption == 0) { pedestal = pedestalRetrievalAlg.PedMean(channel); }
1025  else if (rawopt->fPedestalOption == 1) {
1026  pedestal = hit.GetPedestal();
1027  }
1028  else if (rawopt->fPedestalOption == 2) {
1029  pedestal = 0;
1030  }
1031  else {
1032  mf::LogWarning("RawDataDrawer")
1033  << " PedestalOption is not understood: " << rawopt->fPedestalOption
1034  << ". Pedestals not subtracted.";
1035  }
1036 
1037  // loop over all the wires that are covered by this channel;
1038  // without knowing better, we have to draw into all of them
1039  for (geo::WireID const& wireID : WireIDs) {
1040  // check that the plane and tpc are the correct ones to draw
1041  if (wireID.planeID() != pid) continue; // not us!
1042 
1043  // do we have anything to do with this wire?
1044  if (!operation->ProcessWire(wireID)) continue;
1045 
1046  // get an iterator over the adc values
1047  // accumulate all the data of this wire in our "cells"
1048  size_t const max_tick = std::min({uncompressed.size(), size_t(fStartTick + fTicks)});
1049 
1050  for (size_t iTick = fStartTick; iTick < max_tick; ++iTick) {
1051 
1052  // do we have anything to do with this wire?
1053  if (!operation->ProcessTick(iTick)) continue;
1054 
1055  float const adc = uncompressed[iTick] - pedestal;
1056  //std::cout << "adc, pedestal: " << adc << " " << pedestal << std::endl;
1057 
1058  if (!operation->Operate(wireID, iTick, adc)) return false;
1059 
1060  } // if good
1061  } // for wires
1062  } // for channels
1063 
1064  return operation->Finish();
1065  } // ChannelLooper()
1066 
1067  //......................................................................
1069  public:
1071  geo::PlaneID const& pid,
1072  RawDataDrawer* dataDrawer,
1073  evdb::View2D* new_view)
1074  : OperationBaseClass(pid, dataDrawer)
1075  , view(new_view)
1076  , rawCharge(0.)
1077  , convertedCharge(0.)
1078  , drawingRange(*(dataDrawer->fDrawingRange))
1079  , ADCCorrector(detProp, PlaneID())
1080  {}
1081 
1082  bool
1083  Initialize() override
1084  {
1086 
1087  // set up the size of the grid to be visualized;
1088  // the information on the size has to be already there:
1089  // caller should have user ExtractRange(), or similar, first.
1090  // set the minimum cell in ticks to at least match fTicksPerPoint
1091  drawingRange.SetMinTDCCellSize((float)rawopt->fTicksPerPoint);
1092  // also set the minimum wire cell size to 1,
1093  // otherwise there will be cells represented by no wire.
1094  drawingRange.SetMinWireCellSize(1.F);
1095  boxInfo.clear();
1096  boxInfo.resize(drawingRange.NCells());
1097  return true;
1098  }
1099 
1100  bool
1101  ProcessWire(geo::WireID const& wire) override
1102  {
1103  return drawingRange.hasWire((int)wire.Wire);
1104  }
1105 
1106  bool
1107  ProcessTick(size_t tick) override
1108  {
1109  return drawingRange.hasTick((float)tick);
1110  }
1111 
1112  bool
1113  Operate(geo::WireID const& wireID, size_t tick, float adc) override
1114  {
1115  geo::WireID::WireID_t const wire = wireID.Wire;
1116  std::ptrdiff_t cell = drawingRange.GetCell(wire, tick);
1117  if (cell < 0) return true;
1118 
1119  BoxInfo_t& info = boxInfo[cell];
1120  info.good = true; // if in range, we mark this cell as good
1121 
1122  rawCharge += adc;
1123  convertedCharge += ADCCorrector(adc);
1124 
1125  // draw maximum digit in the cell
1126  if (std::abs(info.adc) <= std::abs(adc)) info.adc = adc;
1127 
1128  return true;
1129  }
1130 
1131  bool
1132  Finish() override
1133  {
1134  // write the information back
1135  geo::PlaneID::PlaneID_t const plane = PlaneID().Plane;
1136  RawDataDrawerPtr()->fRawCharge[plane] = rawCharge;
1137  RawDataDrawerPtr()->fConvertedCharge[plane] = convertedCharge;
1138 
1139  // the cell size might have changed because of minimum size settings
1140  // from configuration (see Initialize())
1141  *(RawDataDrawerPtr()->fDrawingRange) = drawingRange;
1142 
1143  // complete the drawing
1144  RawDataDrawerPtr()->QueueDrawingBoxes(view, PlaneID(), boxInfo);
1145 
1146  return true;
1147  }
1148 
1149  private:
1150  evdb::View2D* view;
1151 
1152  double rawCharge = 0., convertedCharge = 0.;
1154  std::vector<BoxInfo_t> boxInfo;
1156  }; // class RawDataDrawer::BoxDrawer
1157 
1158  void
1160  geo::PlaneID const& pid,
1161  std::vector<BoxInfo_t> const& BoxInfo)
1162  {
1163  //
1164  // All the information is now collected in BoxInfo.
1165  // Make boxes out of it.
1166  //
1168 
1169  MF_LOG_DEBUG("RawDataDrawer") << "Filling " << BoxInfo.size() << " boxes to be rendered";
1170 
1171  // drawing options:
1172  float const MinSignal = rawopt.fMinSignal;
1173  bool const bScaleDigitsByCharge = rawopt.fScaleDigitsByCharge;
1174 
1176 
1178  geo::SigType_t const sigType = geom.SignalType(pid);
1179  evdb::ColorScale const& ColorSet = cst->RawQ(sigType);
1180  size_t const nBoxes = BoxInfo.size();
1181  unsigned int nDrawnBoxes = 0;
1182  for (size_t iBox = 0; iBox < nBoxes; ++iBox) {
1183  BoxInfo_t const& info = BoxInfo[iBox];
1184 
1185  // too little signal, don't bother drawing
1186  if (info.good && (std::abs(info.adc) < MinSignal)) continue;
1187 
1188  // skip the bad cells
1189  if (!info.good) continue;
1190 
1191  // box color, proportional to the ADC count
1192  int const color = ColorSet.GetColor(info.adc);
1193 
1194  // scale factor, proportional to ADC count (optional)
1195  constexpr float q0 = 1000.;
1196  float const sf = bScaleDigitsByCharge ? std::min(std::sqrt((float)info.adc / q0), 1.0F) : 1.;
1197 
1198  // coordinates of the cell box
1199  float min_wire, max_wire, min_tick, max_tick;
1200  std::tie(min_wire, min_tick, max_wire, max_tick) = fDrawingRange->GetCellBox(iBox);
1201  /*
1202  MF_LOG_TRACE("RawDataDrawer")
1203  << "Wires ( " << min_wire << " - " << max_wire << " ) ticks ("
1204  << min_tick << " - " << max_tick << " ) for cell " << iBox;
1205  */
1206  if (sf != 1.) { // need to shrink the box
1207  float const nsf = 1. - sf; // negation of scale factor
1208  float const half_box_wires = (max_wire - min_wire) / 2.,
1209  half_box_ticks = (max_tick - min_tick) / 2.;
1210 
1211  // shrink the box:
1212  min_wire += nsf * half_box_wires;
1213  max_wire -= nsf * half_box_wires;
1214  min_tick += nsf * half_box_ticks;
1215  max_tick -= nsf * half_box_ticks;
1216  } // if scaling
1217 
1218  // allocate the box on the view;
1219  // the order of the coordinates depends on the orientation
1220  TBox* pBox;
1221  if (rawopt.fAxisOrientation < 1)
1222  pBox = &(view->AddBox(min_wire, min_tick, max_wire, max_tick));
1223  else
1224  pBox = &(view->AddBox(min_tick, min_wire, max_tick, max_wire));
1225 
1226  pBox->SetFillStyle(1001);
1227  pBox->SetFillColor(color);
1228  pBox->SetBit(kCannotPick);
1229 
1230  ++nDrawnBoxes;
1231  } // for (iBox)
1232 
1233  MF_LOG_DEBUG("RawDataDrawer") << "Sent " << nDrawnBoxes << "/" << BoxInfo.size()
1234  << " boxes to be rendered";
1235  } // RawDataDrawer::QueueDrawingBoxes()
1236 
1237  void
1239  detinfo::DetectorPropertiesData const& detProp,
1240  evdb::View2D* view,
1241  unsigned int plane)
1242  {
1243 
1244  // Check if we're supposed to draw raw hits at all
1246  if (rawopt->fDrawRawDataOrCalibWires == 1) return;
1247 
1248  geo::PlaneID const pid(rawopt->CurrentTPC(), plane);
1249  BoxDrawer drawer(detProp, pid, this, view);
1250  if (!RunOperation(evt, &drawer)) {
1251  throw art::Exception(art::errors::Unknown) << "RawDataDrawer::RunDrawOperation(): "
1252  "somewhere something went somehow wrong";
1253  }
1254 
1255  } // RawDataDrawer::RunDrawOperation()
1256 
1257  //......................................................................
1259  public:
1260  float const RoIthreshold;
1261 
1263  : OperationBaseClass(pid, data_drawer)
1264  , RoIthreshold(art::ServiceHandle<evd::RawDrawingOptions const>()->RoIthreshold(PlaneID()))
1265  {}
1266 
1267  bool
1268  Operate(geo::WireID const& wireID, size_t tick, float adc) override
1269  {
1270  if (std::abs(adc) < RoIthreshold) return true;
1271  WireRange.add(wireID.Wire);
1272  TDCrange.add(tick);
1273  return true;
1274  } // Operate()
1275 
1276  bool
1277  Finish() override
1278  {
1279  geo::PlaneID::PlaneID_t const plane = PlaneID().Plane;
1280  int& WireMin = pRawDataDrawer->fWireMin[plane];
1281  int& WireMax = pRawDataDrawer->fWireMax[plane];
1282  int& TimeMin = pRawDataDrawer->fTimeMin[plane];
1283  int& TimeMax = pRawDataDrawer->fTimeMax[plane];
1284 
1285  if ((WireMin == WireMax) && WireRange.has_data()) {
1287  mf::LogInfo("RawDataDrawer")
1288  << "Region of interest for " << std::string(PlaneID()) << " detected to be within wires "
1289  << WireRange.min() << " to " << WireRange.max() << " (plane has "
1290  << geom.Nwires(PlaneID()) << " wires)";
1291  WireMax = WireRange.max() + 1;
1292  WireMin = WireRange.min();
1293  }
1294  if ((TimeMin == TimeMax) && TDCrange.has_data()) {
1295  mf::LogInfo("RawDataDrawer")
1296  << "Region of interest for " << std::string(PlaneID()) << " detected to be within ticks "
1297  << TDCrange.min() << " to " << TDCrange.max();
1298  TimeMax = TDCrange.max() + 1;
1299  TimeMin = TDCrange.min();
1300  }
1301  return true;
1302  } // Finish()
1303 
1304  private:
1306  }; // class RawDataDrawer::RoIextractorClass
1307 
1308  void
1309  RawDataDrawer::RunRoIextractor(art::Event const& evt, unsigned int plane)
1310  {
1312  geo::PlaneID const pid(rawopt->CurrentTPC(), plane);
1313 
1314  // if we have no region of interest, prepare to extract it
1315  bool const bExtractRoI = !hasRegionOfInterest(plane);
1316  MF_LOG_TRACE("RawDataDrawer") << "Region of interest for " << pid
1317  << (bExtractRoI ? " extracted" : " not extracted")
1318  << " on this draw";
1319 
1320  if (!bExtractRoI) return;
1321 
1322  RoIextractorClass Extractor(pid, this);
1323  if (!RunOperation(evt, &Extractor)) {
1324  throw std::runtime_error(
1325  "RawDataDrawer::RunRoIextractor(): somewhere something went somehow wrong");
1326  }
1327 
1328  } // RawDataDrawer::RunRoIextractor()
1329 
1330  //......................................................................
1331 
1332  void
1334  detinfo::DetectorPropertiesData const& detProp,
1335  evdb::View2D* view,
1336  unsigned int plane,
1337  bool bZoomToRoI /* = false */
1338  )
1339  {
1341  geo::PlaneID const pid(rawopt->CurrentTPC(), plane);
1342 
1343  bool const bDraw = (rawopt->fDrawRawDataOrCalibWires != 1);
1344  // if we don't need to draw, don't bother doing anything;
1345  // if the region of interest is required, RunRoIextractor() should be called
1346  // (ok, now it's private, but it could be exposed)
1347  if (!bDraw) return;
1348 
1350 
1351  // Need to loop over the labels, but we don't want to zap existing cached RawDigits that are valid
1352  // So... do the painful search to make sure the RawDigits we recover at those we are searching for.
1353  bool theDroidIAmLookingFor = false;
1354 
1355  // Loop over labels
1356  for (const auto& rawDataLabel : rawopt->fRawDataLabels) {
1357  // make sure we reset what needs to be reset
1358  // before the operations are initialized;
1359  // we call for reading raw digits; they will be cached, so it's not a waste
1360  details::CacheID_t NewCacheID(evt, rawDataLabel, pid);
1361  GetRawDigits(evt, NewCacheID);
1362 
1363  // Painful check to see if these RawDigits contain the droids we are looking for
1364  for (const auto& rawDigit : digit_cache->Digits()) {
1365  std::vector<geo::WireID> WireIDs = geom->ChannelToWire(rawDigit.Channel());
1366 
1367  for (geo::WireID const& wireID : WireIDs) {
1368  if (wireID.planeID() != pid) continue; // not us!
1369  theDroidIAmLookingFor = true;
1370  break;
1371  } // for wires
1372 
1373  if (theDroidIAmLookingFor) break;
1374  }
1375 
1376  if (theDroidIAmLookingFor) break;
1377  }
1378 
1379  if (!theDroidIAmLookingFor) return;
1380 
1381  bool const hasRoI = hasRegionOfInterest(plane);
1382 
1383  // - if we don't have a RoI yet, we want to get it while we draw
1384  // * if we are zooming into it now, we have to extract it first, then draw
1385  // * if we are not zooming, we can do both at the same time
1386  // - if we have a RoI, we don't want to extract it again
1387  if (!bZoomToRoI) { // we are not required to zoom to the RoI
1388 
1389  std::unique_ptr<OperationBaseClass> operation;
1390 
1391  // we will do the drawing in one pass
1392  MF_LOG_DEBUG("RawDataDrawer") << __func__ << "() setting up one-pass drawing";
1393  operation.reset(new BoxDrawer(detProp, pid, this, view));
1394 
1395  if (!hasRoI) { // we don't have any RoI; since it's cheap, let's get it
1396  MF_LOG_DEBUG("RawDataDrawer") << __func__ << "() adding RoI extraction";
1397 
1398  // swap cards: operation becomes a multiple operation:
1399  // - prepare the two operations (one is there already, somehow)
1400  std::unique_ptr<OperationBaseClass> drawer(std::move(operation));
1401  std::unique_ptr<OperationBaseClass> extractor(new RoIextractorClass(pid, this));
1402  // - create a new composite operation and give it the sub-ops
1403  operation.reset(new ManyOperations(pid, this));
1404  ManyOperations* pManyOps = static_cast<ManyOperations*>(operation.get());
1405  pManyOps->AddOperation(std::move(drawer));
1406  pManyOps->AddOperation(std::move(extractor));
1407  }
1408 
1409  if (!RunOperation(evt, operation.get())) {
1410  throw art::Exception(art::errors::Unknown) << "RawDataDrawer::RunDrawOperation(): "
1411  "somewhere something went somehow wrong";
1412  }
1413  }
1414  else { // we are zooming to RoI
1415  // first, we want the RoI extracted; the extractor will update this object
1416  if (!hasRoI) {
1417  MF_LOG_DEBUG("RawDataDrawer") << __func__ << "() setting up RoI extraction for " << pid;
1418  RoIextractorClass extractor(pid, this);
1419  if (!RunOperation(evt, &extractor)) {
1421  << "RawDataDrawer::RunDrawOperation():"
1422  " something went somehow wrong while extracting RoI";
1423  }
1424  }
1425  else {
1426  MF_LOG_DEBUG("RawDataDrawer")
1427  << __func__ << "() using existing RoI for " << pid << ": wires ( " << fWireMin[plane]
1428  << " - " << fWireMax[plane] << " ), ticks ( " << fTimeMin[plane] << " - "
1429  << fTimeMax[plane] << " )";
1430  }
1431 
1432  // adopt the drawing limits information from the wire/time limits
1434 
1435  // then we draw
1436  MF_LOG_DEBUG("RawDataDrawer") << __func__ << "() setting up drawing";
1437  BoxDrawer drawer(detProp, pid, this, view);
1438  if (!RunOperation(evt, &drawer)) {
1439  throw art::Exception(art::errors::Unknown) << "RawDataDrawer::RunDrawOperation():"
1440  " something went somehow wrong while drawing";
1441  }
1442  }
1443  } // RawDataDrawer::RawDigit2D()
1444 
1445  //........................................................................
1446  int
1447  RawDataDrawer::GetRegionOfInterest(int plane, int& minw, int& maxw, int& mint, int& maxt)
1448  {
1450 
1451  if ((unsigned int)plane >= fWireMin.size()) {
1452  mf::LogWarning("RawDataDrawer")
1453  << " Requested plane " << plane << " is larger than those available " << std::endl;
1454  return -1;
1455  }
1456 
1457  minw = fWireMin[plane];
1458  maxw = fWireMax[plane];
1459  mint = fTimeMin[plane];
1460  maxt = fTimeMax[plane];
1461 
1462  if ((minw == maxw) || (mint == maxt)) return 1;
1463 
1464  //make values a bit larger, but make sure they don't go out of bounds
1465  minw = (minw - 30 < 0) ? 0 : minw - 30;
1466  mint = (mint - 10 < 0) ? 0 : mint - 10;
1467 
1468  maxw = (maxw + 10 > (int)geo->Nwires(plane)) ? geo->Nwires(plane) : maxw + 10;
1469  maxt = (maxt + 10 > TotalClockTicks()) ? TotalClockTicks() : maxt + 10;
1470 
1471  return 0;
1472  }
1473 
1474  //......................................................................
1475  void
1476  RawDataDrawer::GetChargeSum(int plane, double& charge, double& convcharge)
1477  {
1478  charge = fRawCharge[plane];
1479  convcharge = fConvertedCharge[plane];
1480  }
1481 
1482  //......................................................................
1483  void
1484  RawDataDrawer::FillQHisto(const art::Event& evt, unsigned int plane, TH1F* histo)
1485  {
1486 
1487  // Check if we're supposed to draw raw hits at all
1489  if (rawopt->fDrawRawDataOrCalibWires == 1) return;
1490 
1492 
1493  geo::PlaneID const pid(rawopt->CurrentTPC(), plane);
1494 
1495  for (const auto& rawDataLabel : rawopt->fRawDataLabels) {
1496  details::CacheID_t NewCacheID(evt, rawDataLabel, pid);
1497  GetRawDigits(evt, NewCacheID);
1498 
1499  lariov::ChannelStatusProvider const& channelStatus =
1501 
1502  //get pedestal conditions
1503  const lariov::DetPedestalProvider& pedestalRetrievalAlg =
1505 
1506  for (evd::details::RawDigitInfo_t const& digit_info : *digit_cache) {
1507  raw::RawDigit const& hit = digit_info.Digit();
1508  raw::ChannelID_t const channel = hit.Channel();
1509 
1510  if (!channelStatus.IsPresent(channel)) continue;
1511 
1512  // The following test is meant to be temporary until the "correct" solution is implemented
1513  if (!ProcessChannelWithStatus(channelStatus.Status(channel))) continue;
1514 
1515  // to be explicit: we don't cound bad channels in
1516  if (!rawopt->fSeeBadChannels && channelStatus.IsBad(channel)) continue;
1517 
1518  std::vector<geo::WireID> wireids = geo->ChannelToWire(channel);
1519  for (auto const& wid : wireids) {
1520  // check that the plane and tpc are the correct ones to draw
1521  if (wid.planeID() != pid) continue;
1522 
1523  raw::RawDigit::ADCvector_t const& uncompressed = digit_info.Data();
1524 
1525  //float const pedestal = pedestalRetrievalAlg.PedMean(channel);
1526  // recover the pedestal
1527  float pedestal = 0;
1528  if (rawopt->fPedestalOption == 0) { pedestal = pedestalRetrievalAlg.PedMean(channel); }
1529  else if (rawopt->fPedestalOption == 1) {
1530  pedestal = hit.GetPedestal();
1531  }
1532  else if (rawopt->fPedestalOption == 2) {
1533  pedestal = 0;
1534  }
1535  else {
1536  mf::LogWarning("RawDataDrawer")
1537  << " PedestalOption is not understood: " << rawopt->fPedestalOption
1538  << ". Pedestals not subtracted.";
1539  }
1540 
1541  for (short d : uncompressed)
1542  histo->Fill(float(d) - pedestal); //pedestals[plane]); //hit.GetPedestal());
1543 
1544  // this channel is on the correct plane, don't double count the raw signal
1545  // if there are more than one wids for the channel
1546  break;
1547  } // end loop over wids
1548  } //end loop over raw hits
1549  } //end loop over labels
1550  }
1551 
1552  //......................................................................
1553  void
1555  unsigned int plane,
1556  unsigned int wire,
1557  TH1F* histo)
1558  {
1559 
1560  // Check if we're supposed to draw raw hits at all
1562  if (rawopt->fDrawRawDataOrCalibWires == 1) return;
1563 
1564  // make sure we have the raw digits cached
1565  geo::PlaneID const pid(rawopt->CurrentTPC(), plane);
1566 
1567  // loop over labels
1568  for (const auto& rawDataLabel : rawopt->fRawDataLabels) {
1569  details::CacheID_t NewCacheID(evt, rawDataLabel, pid);
1570  GetRawDigits(evt, NewCacheID);
1571 
1572  if (digit_cache->empty()) return;
1573 
1574  geo::WireID const wireid(pid, wire);
1575 
1576  // find the channel
1578  raw::ChannelID_t const channel = geom->PlaneWireToChannel(wireid);
1579  if (!raw::isValidChannelID(channel)) { // no channel, empty histogram
1580  mf::LogError("RawDataDrawer")
1581  << __func__ << ": no channel associated to " << std::string(wireid);
1582  return;
1583  } // if no channel
1584 
1585  // check the channel status; bad channels are still ok.
1586  lariov::ChannelStatusProvider const& channelStatus =
1588 
1589  if (!channelStatus.IsPresent(channel)) return;
1590 
1591  // The following test is meant to be temporary until the "correct" solution is implemented
1592  if (!ProcessChannelWithStatus(channelStatus.Status(channel))) return;
1593 
1594  // we accept to see the content of a bad channel, so this is commented out:
1595  if (!rawopt->fSeeBadChannels && channelStatus.IsBad(channel)) return;
1596 
1597  //get pedestal conditions
1598  const lariov::DetPedestalProvider& pedestalRetrievalAlg =
1600 
1601  // find the raw digit
1602  // (iDigit is an iterator to a evd::details::RawDigitInfo_t)
1603  evd::details::RawDigitInfo_t const* pDigit = digit_cache->FindChannel(channel);
1604 
1605  if (
1606  !pDigit) { // this is weird... actually no, this can happen if the RawDigits are per TPC (or something)
1607  // mf::LogWarning("RawDataDrawer") << __func__
1608  // << ": can't find raw digit for channel #" << channel
1609  // << " (" << std::string(wireid) << ")";
1610  continue;
1611  }
1612 
1613  raw::RawDigit::ADCvector_t const& uncompressed = pDigit->Data();
1614 
1615  // recover the pedestal
1616  float pedestal = 0;
1617  if (rawopt->fPedestalOption == 0) { pedestal = pedestalRetrievalAlg.PedMean(channel); }
1618  else if (rawopt->fPedestalOption == 1) {
1619  pedestal = pDigit->DigitPtr()->GetPedestal();
1620  }
1621  else if (rawopt->fPedestalOption == 2) {
1622  pedestal = 0;
1623  }
1624  else {
1625  mf::LogWarning("RawDataDrawer")
1626  << " PedestalOption is not understood: " << rawopt->fPedestalOption
1627  << ". Pedestals not subtracted.";
1628  }
1629 
1630  for (size_t j = 0; j < uncompressed.size(); ++j)
1631  histo->Fill(float(j),
1632  float(uncompressed[j]) - pedestal); //pedestals[plane]); //hit.GetPedestal());
1633  }
1634 
1635  } // RawDataDrawer::FillTQHisto()
1636 
1637  //......................................................................
1638 
1639  // void RawDataDrawer::RawDigit3D(const art::Event& evt,
1640  // evdb::View3D* view)
1641  // {
1642  // // Check if we're supposed to draw raw hits at all
1643  // art::ServiceHandle<evd::RawDrawingOptions const> rawopt;
1644  // if (rawopt->fDrawRawOrCalibHits!=0) return;
1645 
1646  // art::ServiceHandle<geo::Geometry const> geom;
1647 
1648  // HitTower tower;
1649  // tower.fQscale = 0.01;
1650 
1651  // for (unsigned int imod=0; imod<rawopt->fRawDigitModules.size(); ++imod) {
1652  // const char* which = rawopt->fRawDigitModules[imod].c_str();
1653 
1654  // std::vector<raw::RawDigit> rawhits;
1655  // GetRawDigits(evt, which, rawhits);
1656 
1657  // for (unsigned int i=0; i<rawhits.size(); ++i) {
1658  // double t = 0;
1659  // double q = 0;
1660  // t = rawhits[i]->fTDC[0];
1661  // for (unsigned int j=0; j<rawhits[i]->NADC(); ++j) {
1662  // q += rawhits[i]->ADC(j);
1663  // }
1664  // // Hack for now...
1665  // if (q<=0.0) q = 1+i%10;
1666 
1667  // // Get the cell geometry for the hit
1668  // int iplane = cmap->GetPlane(rawhits[i].get());
1669  // int icell = cmap->GetCell(rawhits[i].get());
1670  // double xyz[3];
1671  // double dpos[3];
1672  // geo::View_t v;
1673  // geom->CellInfo(iplane, icell, &v, xyz, dpos);
1674 
1675  // switch (rawopt->fRawDigit3DStyle) {
1676  // case 1:
1677  // //
1678  // // Render digits as towers
1679  // //
1680  // if (v==geo::kX) {
1681  // tower.AddHit(v, iplane, icell, xyz[0], xyz[2], q, t);
1682  // }
1683  // else if (v==geo::kY) {
1684  // tower.AddHit(v, iplane, icell, xyz[1], xyz[2], q, t);
1685  // }
1686  // else abort();
1687  // break;
1688  // default:
1689  // //
1690  // // Render Digits as boxes
1691  // //
1692  // TPolyLine3D& p = view->AddPolyLine3D(5,kGreen+1,1,2);
1693  // double sf = std::sqrt(0.01*q);
1694  // if (v==geo::kX) {
1695  // double x1 = xyz[0] - sf*dpos[0];
1696  // double x2 = xyz[0] + sf*dpos[0];
1697  // double z1 = xyz[2] - sf*dpos[2];
1698  // double z2 = xyz[2] + sf*dpos[2];
1699  // p.SetPoint(0, x1, geom->DetHalfHeight(), z1);
1700  // p.SetPoint(1, x2, geom->DetHalfHeight(), z1);
1701  // p.SetPoint(2, x2, geom->DetHalfHeight(), z2);
1702  // p.SetPoint(3, x1, geom->DetHalfHeight(), z2);
1703  // p.SetPoint(4, x1, geom->DetHalfHeight(), z1);
1704  // }
1705  // else if (v==geo::kY) {
1706  // double y1 = xyz[1] - sf*dpos[1];
1707  // double y2 = xyz[1] + sf*dpos[1];
1708  // double z1 = xyz[2] - sf*dpos[2];
1709  // double z2 = xyz[2] + sf*dpos[2];
1710  // p.SetPoint(0, geom->DetHalfWidth(), y1, z1);
1711  // p.SetPoint(1, geom->DetHalfWidth(), y2, z1);
1712  // p.SetPoint(2, geom->DetHalfWidth(), y2, z2);
1713  // p.SetPoint(3, geom->DetHalfWidth(), y1, z2);
1714  // p.SetPoint(4, geom->DetHalfWidth(), y1, z1);
1715  // }
1716  // else abort();
1717  // break;
1718  // } // switch fRawDigit3DStyle
1719  // }//end loop over raw digits
1720  // }// end loop over RawDigit modules
1721 
1722  // // Render the towers for that style choice
1723  // if (rawopt->fRawDigit3DStyle==1) tower.Draw(view);
1724  // }
1725 
1726  //......................................................................
1727  bool
1729  {
1730 
1731  return (fWireMax[plane] != -1) && (fTimeMax[plane] != -1);
1732 
1733  } // RawDataDrawer::hasRegionOfInterest()
1734 
1735  //......................................................................
1736  void
1738  {
1739 
1740  MF_LOG_DEBUG("RawDataDrawer") << "RawDataDrawer[" << ((void*)this)
1741  << "]: resetting the region of interest";
1742 
1743  std::fill(fWireMin.begin(), fWireMin.end(), -1);
1744  std::fill(fWireMax.begin(), fWireMax.end(), -1);
1745  std::fill(fTimeMin.begin(), fTimeMin.end(), -1);
1746  std::fill(fTimeMax.begin(), fTimeMax.end(), -1);
1747 
1748  } // RawDataDrawer::ResetRegionOfInterest()
1749 
1750  //......................................................................
1751 
1752  void
1754  {
1755  MF_LOG_DEBUG("RawDataDrawer") << "GetRawDigits() for " << new_timestamp
1756  << " (last for: " << *fCacheID << ")";
1757 
1758  // update cache
1759  digit_cache->Update(evt, new_timestamp);
1760 
1761  // if time stamp is changing, we want to reconsider which region is
1762  // interesting
1763  if (!fCacheID->sameTPC(new_timestamp)) ResetRegionOfInterest();
1764 
1765  // all the caches have been properly updated or invalidated;
1766  // we are now on a new cache state
1767  *fCacheID = new_timestamp;
1768 
1769  } // RawDataDrawer::GetRawDigits()
1770 
1771  //......................................................................
1772  bool
1774  lariov::ChannelStatusProvider::Status_t channel_status) const
1775  {
1776  // if we don't have a valid status, we can't reject the channel
1777  if (!lariov::ChannelStatusProvider::IsValidStatus(channel_status)) return true;
1778 
1779  // is the status "too bad"?
1781  if (channel_status > drawopt->fMaxChannelStatus) return false;
1782  if (channel_status < drawopt->fMinChannelStatus) return false;
1783 
1784  // no reason to reject it...
1785  return true;
1786  } // RawDataDrawer::ProcessChannel()
1787 
1788  //----------------------------------------------------------------------------
1789  namespace details {
1790 
1791  //--------------------------------------------------------------------------
1792  //--- RawDigitInfo_t
1793  //---
1796  {
1797  if (!data.hasData()) UncompressData();
1798  return *data;
1799  } // RawDigitInfo_t::Data()
1800 
1801  void
1802  RawDigitInfo_t::Fill(art::Ptr<raw::RawDigit> const& src)
1803  {
1804  data.Clear();
1805  digit = src;
1806  } // RawDigitInfo_t::Fill()
1807 
1808  void
1809  RawDigitInfo_t::Clear()
1810  {
1811  data.Clear();
1812  sample_info.reset();
1813  }
1814 
1815  void
1816  RawDigitInfo_t::UncompressData() const
1817  {
1818  data.Clear();
1819 
1820  if (!digit) return; // no original data, can't do anything
1821 
1823 
1824  if (digit->Compression() == kNone) {
1825  // no compression, we can refer to the original data directly
1826  data.PointToData(digit->ADCs());
1827  }
1828  else {
1829  // data is compressed, need to do the real work
1830  if (drawopt->fUncompressWithPed) { //Use pedestal in uncompression
1831  int pedestal = (int)digit->GetPedestal();
1833  samples.resize(digit->Samples());
1834  Uncompress(digit->ADCs(), samples, pedestal, digit->Compression());
1835  data.StealData(std::move(samples));
1836  }
1837  else {
1839  samples.resize(digit->Samples());
1840  Uncompress(digit->ADCs(), samples, digit->Compression());
1841  data.StealData(std::move(samples));
1842  }
1843  }
1844  } // RawDigitInfo_t::UncompressData()
1845 
1846  void
1847  RawDigitInfo_t::CollectSampleInfo() const
1848  {
1849  raw::RawDigit::ADCvector_t const& samples = Data();
1850 
1851  // lar::util::StatCollector<double> stat;
1852  // stat.add(samples.begin(), samples.end());
1853 
1855  samples.end());
1856 
1857  sample_info.reset(new SampleInfo_t);
1858  sample_info->min_charge = stat.min();
1859  sample_info->max_charge = stat.max();
1860  // sample_info->average_charge = stat.Average();
1861 
1862  } // RawDigitInfo_t::CollectSampleInfo()
1863 
1865  RawDigitInfo_t::SampleInfo() const
1866  {
1867  if (!sample_info) CollectSampleInfo();
1868  return *sample_info;
1869  } // SampleInfo()
1870 
1871  template <typename Stream>
1872  void
1873  RawDigitInfo_t::Dump(Stream&& out) const
1874  {
1875  out << " digit at " << ((void*)digit.get()) << " on channel #" << digit->Channel()
1876  << " with " << digit->NADC();
1877  if (digit->Compression() == kNone)
1878  out << " uncompressed data";
1879  else
1880  out << " data items compressed with <" << digit->Compression() << ">";
1881  if (data.hasData())
1882  out << " with data (" << data->size() << " samples)";
1883  else
1884  out << " without data";
1885  } // RawDigitInfo_t::Dump()
1886 
1887  //--------------------------------------------------------------------------
1888  //--- RawDigitCacheDataClass
1889  //---
1890 
1891  RawDigitInfo_t const*
1892  RawDigitCacheDataClass::FindChannel(raw::ChannelID_t channel) const
1893  {
1894  auto iDigit = std::find_if(
1895  digits.cbegin(), digits.cend(), [channel](evd::details::RawDigitInfo_t const& digit) {
1896  return digit.Channel() == channel;
1897  });
1898  return (iDigit == digits.cend()) ? nullptr : &*iDigit;
1899  } // RawDigitCacheDataClass::FindChannel()
1900 
1901  std::vector<raw::RawDigit> const*
1902  RawDigitCacheDataClass::ReadProduct(art::Event const& evt, art::InputTag label)
1903  {
1905  if (!evt.getByLabel(label, rdcol)) return nullptr;
1906  return &*rdcol;
1907  } // RawDigitCacheDataClass::ReadProduct()
1908 
1909  void
1910  RawDigitCacheDataClass::Refill(art::Handle<std::vector<raw::RawDigit>>& rdcol)
1911  {
1912  digits.resize(rdcol->size());
1913  for (size_t iDigit = 0; iDigit < rdcol->size(); ++iDigit) {
1914  art::Ptr<raw::RawDigit> pDigit(rdcol, iDigit);
1915  digits[iDigit].Fill(pDigit);
1916  size_t samples = pDigit->Samples();
1917  if (samples > max_samples) max_samples = samples;
1918  } // for
1919  } // RawDigitCacheDataClass::Refill()
1920 
1921  void
1922  RawDigitCacheDataClass::Invalidate()
1923  {
1924  timestamp.clear();
1925  } // RawDigitCacheDataClass::Invalidate()
1926 
1927  void
1928  RawDigitCacheDataClass::Clear()
1929  {
1930  Invalidate();
1931  digits.clear();
1932  max_samples = 0;
1933  } // RawDigitCacheDataClass::Clear()
1934 
1936  RawDigitCacheDataClass::CheckUpToDate(CacheID_t const& ts,
1937  art::Event const* evt /* = nullptr */) const
1938  {
1939  BoolWithUpToDateMetadata res{false, nullptr};
1940 
1941  // normally only if either the event or the product label have changed,
1942  // cache becomes invalid:
1943  if (!ts.sameProduct(timestamp)) return res; // outdated cache
1944 
1945  // But: our cache stores pointers to the original data, and on a new TPC
1946  // the event display may reload the event anew, removing the "old" data
1947  // from memory.
1948  // Since TPC can change with or without the data being invalidated,
1949  // a more accurate verification is needed.
1950 
1951  // if the cache is empty, well, it does not make much difference;
1952  // we invalidate it to be sure
1953  if (empty()) return res; // outdated cache
1954 
1955  if (!evt) return res; // outdated, since we can't know better without the event
1956 
1957  // here we force reading of the product
1958  res.digits = ReadProduct(*evt, ts.inputLabel());
1959  if (!res.digits) return res; // outdated cache; this is actually an error
1960 
1961  if (res.digits->empty())
1962  return res; // outdated; no digits (strange!), invalidate just in case
1963 
1964  // use the first digit as test
1965  raw::ChannelID_t channel = res.digits->front().Channel();
1966  RawDigitInfo_t const* pInfo = FindChannel(channel);
1967  if (!pInfo) return res; // outdated: we don't even have this channel in cache!
1968 
1969  if (&(pInfo->Digit()) != &(res.digits->front()))
1970  return res; // outdated: different memory address for data
1971 
1972  res.bUpToDate = true;
1973  return res; // cache still valid
1974  } // RawDigitCacheDataClass::CheckUpToDate()
1975 
1976  bool
1978  {
1979  BoolWithUpToDateMetadata update_info = CheckUpToDate(new_timestamp, &evt);
1980 
1981  if (update_info) return false; // already up to date: move on!
1982 
1983  MF_LOG_DEBUG("RawDataDrawer") << "Refilling raw digit cache RawDigitCacheDataClass["
1984  << ((void*)this) << "] for " << new_timestamp;
1985 
1986  Clear();
1987 
1989  if (!evt.getByLabel(new_timestamp.inputLabel(), rdcol)) {
1990  mf::LogWarning("RawDataDrawer")
1991  << "no RawDigit collection '" << new_timestamp.inputLabel() << "' found";
1992  return true;
1993  }
1994 
1995  Refill(rdcol);
1996 
1997  timestamp = new_timestamp;
1998  return true;
1999  } // RawDigitCacheDataClass::Update()
2000 
2001  template <typename Stream>
2002  void
2003  RawDigitCacheDataClass::Dump(Stream&& out) const
2004  {
2005  out << "Cache at " << ((void*)this) << " with time stamp " << std::string(timestamp)
2006  << " and " << digits.size() << " entries (maximum sample: " << max_samples << ");"
2007  << " data at " << ((void*)digits.data());
2008  for (RawDigitInfo_t const& digitInfo : digits) {
2009  out << "\n ";
2010  digitInfo.Dump(out);
2011  } // for
2012  out << "\n";
2013  } // RawDigitCacheDataClass::Dump()
2014 
2015  //--------------------------------------------------------------------------
2016  //--- GridAxisClass
2017  //---
2018  std::ptrdiff_t
2019  GridAxisClass::GetCell(float coord) const
2020  {
2021  return std::ptrdiff_t((coord - min) / cell_size); // truncate
2022  } // GridAxisClass::GetCell()
2023 
2024  //--------------------------------------------------------------------------
2025  bool
2026  GridAxisClass::Init(size_t nDiv, float new_min, float new_max)
2027  {
2028 
2029  n_cells = std::max(nDiv, size_t(1));
2030  return SetLimits(new_min, new_max);
2031 
2032  } // GridAxisClass::Init()
2033 
2034  //--------------------------------------------------------------------------
2035  bool
2036  GridAxisClass::SetLimits(float new_min, float new_max)
2037  {
2038  min = new_min;
2039  max = new_max;
2040  cell_size = Length() / float(n_cells);
2041 
2042  return std::isnormal(cell_size);
2043  } // GridAxisClass::SetLimits()
2044 
2045  //--------------------------------------------------------------------------
2046  bool
2047  GridAxisClass::SetMinCellSize(float min_size)
2048  {
2049  if (cell_size >= min_size) return false;
2050 
2051  // n_cells gets truncated
2052  n_cells = (size_t)std::max(std::floor(Length() / min_size), 1.0F);
2053 
2054  // reevaluate cell size, that might be different than min_size
2055  // because of n_cells truncation or minimum value
2056  cell_size = Length() / float(n_cells);
2057  return true;
2058  } // GridAxisClass::SetMinCellSize()
2059 
2060  //--------------------------------------------------------------------------
2061  bool
2062  GridAxisClass::SetMaxCellSize(float max_size)
2063  {
2064  if (cell_size <= max_size) return false;
2065 
2066  // n_cells gets rounded up
2067  n_cells = (size_t)std::max(std::ceil(Length() / max_size), 1.0F);
2068 
2069  // reevaluate cell size, that might be different than max_size
2070  // because of n_cells rounding or minimum value
2071  cell_size = Length() / float(n_cells);
2072  return true;
2073  } // GridAxisClass::SetMaxCellSize()
2074 
2075  //--------------------------------------------------------------------------
2076  template <typename Stream>
2077  void
2078  GridAxisClass::Dump(Stream&& out) const
2079  {
2080  out << NCells() << " cells from " << Min() << " to " << Max() << " (length: " << Length()
2081  << ")";
2082  } // GridAxisClass::Dump()
2083 
2084  //--------------------------------------------------------------------------
2085  //--- CellGridClass
2086  //---
2087  CellGridClass::CellGridClass(unsigned int nWires, unsigned int nTDC)
2088  : wire_axis((size_t)nWires, 0., float(nWires)), tdc_axis((size_t)nTDC, 0., float(nTDC))
2089  {} // CellGridClass::CellGridClass(int, int)
2090 
2091  //--------------------------------------------------------------------------
2093  float max_wire,
2094  unsigned int nWires,
2095  float min_tdc,
2096  float max_tdc,
2097  unsigned int nTDC)
2098  : wire_axis((size_t)nWires, min_wire, max_wire), tdc_axis((size_t)nTDC, min_tdc, max_tdc)
2099  {} // CellGridClass::CellGridClass({ float, float, int } x 2)
2100 
2101  //--------------------------------------------------------------------------
2102  std::ptrdiff_t
2103  CellGridClass::GetCell(float wire, float tick) const
2104  {
2105  std::ptrdiff_t iWireCell = wire_axis.GetCell(wire);
2106  if (!wire_axis.hasCell(iWireCell)) return std::ptrdiff_t(-1);
2107  std::ptrdiff_t iTDCCell = tdc_axis.GetCell(tick);
2108  if (!tdc_axis.hasCell(iTDCCell)) return std::ptrdiff_t(-1);
2109  return iWireCell * TDCAxis().NCells() + iTDCCell;
2110  } // CellGridClass::GetCell()
2111 
2112  //--------------------------------------------------------------------------
2113  std::tuple<float, float, float, float>
2114  CellGridClass::GetCellBox(std::ptrdiff_t iCell) const
2115  {
2116  // { w1, t1, w2, t2 }
2117  size_t const nTDCCells = TDCAxis().NCells();
2118  std::ptrdiff_t iWireCell = (std::ptrdiff_t)(iCell / nTDCCells),
2119  iTDCCell = (std::ptrdiff_t)(iCell % nTDCCells);
2120 
2121  return std::tuple<float, float, float, float>(WireAxis().LowerEdge(iWireCell),
2122  TDCAxis().LowerEdge(iTDCCell),
2123  WireAxis().UpperEdge(iWireCell),
2124  TDCAxis().UpperEdge(iTDCCell));
2125  } // CellGridClass::GetCellBox()
2126 
2127  //--------------------------------------------------------------------------
2128  template <typename Stream>
2129  void
2130  CellGridClass::Dump(Stream&& out) const
2131  {
2132  out << "Wire axis: ";
2133  WireAxis().Dump(out);
2134  out << "; time axis: ";
2135  TDCAxis().Dump(out);
2136  } // CellGridClass::Dump()
2137 
2138  //--------------------------------------------------------------------------
2139 
2140  } // details
2141 
2142 } // namespace evd
2143 
2144 ////////////////////////////////////////////////////////////////////////
virtual bool IsBad(raw::ChannelID_t channel) const =0
Returns whether the specified channel is bad in the current run.
int GetRegionOfInterest(int plane, int &minw, int &maxw, int &mint, int &maxt)
float GetPedestal() const
Definition: RawDigit.h:214
Data_t max() const
Returns the accumulated maximum, or a very small number if no values.
const_pointer operator->() const
bool Operate(geo::WireID const &wireID, size_t tick, float adc) override
details::CellGridClass drawingRange
float Length(const PFPStruct &pfp)
Definition: PFPUtils.cxx:3303
short MaxCharge() const
maximum charge
bool has_data() const
Returns whether at least one datum has been added.
~PointerToData_t()
Destructor: gets rid of the owned data.
int fScaleDigitsByCharge
scale the size of the digit by the charge
bool Update(art::Event const &evt, CacheID_t const &new_timestamp)
BoxDrawer(detinfo::DetectorPropertiesData const &detProp, geo::PlaneID const &pid, RawDataDrawer *dataDrawer, evdb::View2D *new_view)
bool sameProduct(PlaneDataChangeTracker_t const &as) const
Returns whether we are in the same event (the rest could differ)
BoolWithUpToDateMetadata(bool uptodate, std::vector< raw::RawDigit > const *newdigits)
bool SetCellSizeBoundary(float min_size, float max_size)
ULong64_t Samples() const
Number of samples in the uncompressed ADC data.
Definition: RawDigit.h:213
bool ProcessTick(size_t tick) override
unsigned int fTPC
TPC number to draw, typically set by TWQProjectionView.
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
void SetWireRange(float min_wire, float max_wire)
Sets the wire range, leaving the number of wire cells unchanged.
void FillTQHisto(const art::Event &evt, unsigned int plane, unsigned int wire, TH1F *histo)
int adc
total ADC count in this box
raw::RawDigit const & Digit() const
Returns an art pointer to the actual digit.
void SetTDCRange(float min_tdc, float max_tdc, unsigned int nTDC, float min_size)
Sets the complete TDC range, with minimum cell size.
void SetWireRange(float min_wire, float max_wire, unsigned int nWires, float min_size)
Sets the complete wire range, with minimum cell size.
void msg(const char *fmt,...)
Definition: message.cpp:107
bool Operate(geo::WireID const &wireID, size_t tick, float adc) override
OperationBaseClass(geo::PlaneID const &pid, RawDataDrawer *data_drawer=nullptr)
void RunDrawOperation(art::Event const &evt, detinfo::DetectorPropertiesData const &detProp, evdb::View2D *view, unsigned int plane)
void SetWireRange(unsigned int nWires)
Display parameters for the raw data.
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
float Min() const
Returns the extremes of the axis.
int fDrawRawDataOrCalibWires
0 for raw
const_reference operator*() const
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
void Dump(Stream &&out) const
Prints the current axes on the specified stream.
void SetDrawingLimitsFromRoI(geo::PlaneID::PlaneID_t plane)
double fStartTick
low tick
unsigned int PlaneID_t
Type for the ID number.
Definition: geo_types.h:473
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
details::CacheID_t * fCacheID
information about the last processed plane
GridAxisClass const & WireAxis() const
Return the information about the wires.
std::unique_ptr< SampleInfo_t > sample_info
Information collected from the uncompressed data.
CacheID_t timestamp
object expressing validity range of cached data
ChannelID_t Channel() const
DAQ channel this raw data was read from.
Definition: RawDigit.h:212
std::vector< std::unique_ptr< RawDataDrawer::OperationBaseClass > > operations
float cell_size
size of each cell
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
Definition: RawDigit.h:73
bool SetMinTDCCellSize(float min_size)
Sets the minimum size for TDC cells.
std::ptrdiff_t GetCell(float wire, float tick) const
Returns the index of specified cell, or -1 if out of range.
GridAxisClass()
Default constructor: an invalid range.
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
void SetTDCRange(float min_tdc, float max_tdc)
Sets the TDC range, leaving the number of ticks unchanged.
int16_t adc
Definition: CRTFragment.hh:202
std::vector< BoxInfo_t > boxInfo
void RawDigit2D(art::Event const &evt, detinfo::DetectorPropertiesData const &detProp, evdb::View2D *view, unsigned int plane, bool bZoomToRoI=false)
Draws raw digit content in 2D wire plane representation.
bool hasTick(int tick) const
bool operator!() const
Returns whether we point to nothing.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
intermediate_table::const_iterator const_iterator
ManyOperations(geo::PlaneID const &pid, RawDataDrawer *data_drawer=nullptr)
bool hasTick(float tick) const
Returns whether the range includes the specified wire.
uint8_t channel
Definition: CRTFragment.hh:201
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
void PointToData(pointer data)
Point to the specified data, not acquiring ownership.
raw::ChannelID_t Channel() const
Returns the channel of this digit (for convenience)
lar::util::MinMaxCollector< float > WireRange
bool ProcessChannelWithStatus(lariov::ChannelStatusProvider::Status_t channel_status) const
Returns whether a channel with the specified status should be processed.
Classes gathering simple statistics.
std::vector< double > fRawCharge
Sum of Raw Charge.
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
std::vector< int > fWireMin
lowest wire in interesting region for each plane
art framework interface to geometry description
double electronsToADC
conversion constant
Manages a cell-like division of a coordinate.
std::add_pointer_t< value_type > pointer
void SetDrawingLimits(float low_wire, float high_wire, float low_tdc, float high_tdc)
Fills the viewport borders from the specified extremes.
size_t n_cells
number of cells in the axis
friend class RoIextractorClass
def update_info(flist, md)
details::ADCCorrectorClass ADCCorrector
unsigned short Status_t
type representing channel status
std::vector< int > fTimeMax
highest time in interesting region for each plane
Keeps track of the minimum and maximum value we observed.
Information about a RawDigit; may contain uncompressed duplicate of data.
art::InputTag const & inputLabel() const
T abs(T value)
OperationBaseClass const * Operator(size_t iOp) const
std::add_lvalue_reference_t< value_type > reference
Data_t min() const
Returns the accumulated minimum, or a very large number if no values.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
constexpr ChannelID_t InvalidChannelID
ID of an invalid channel.
Definition: RawTypes.h:32
detinfo::DetectorPropertiesData const & detProp
float Length() const
Returns the length of the axis.
double fTicks
number of ticks of the clock
mutable::details::PointerToData_t< raw::RawDigit::ADCvector_t const > data
Uncompressed data.
bool ProcessWire(geo::WireID const &wire) override
LArSoft includes.
Definition: InfoTransfer.h:33
void AcquireData(pointer data)
Acquire ownership of the specified data.
PadResolution_t PadResolution
stored pad resolution
short MinCharge() const
minimum charge
raw::RawDigit::ADCvector_t const & Data() const
average charge
bool SetMinWireCellSize(float min_size)
Sets the minimum size for wire cells.
double operator()(float adc) const
Applies Birks correction to the specified pedestal-subtracted charge.
bool Add(CONT &cont, float wire, float tick, typename CONT::value_type v)
const evdb::ColorScale & RawQ(geo::SigType_t st) const
unsigned int fCryostat
Cryostat number to draw, typically set by TWQProjectionView.
enum geo::_plane_sigtype SigType_t
std::string Name() const override
bool hasWire(int wire) const
std::ptrdiff_t operator()(float coord) const
ADCCorrectorClass(detinfo::DetectorPropertiesData const &dp, geo::PlaneID const &pid)
unsigned int fMaxChannelStatus
Display channels with this status and below.
def move(depos, offset)
Definition: depos.py:107
Cached set of RawDigitInfo_t.
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
float UpperEdge(std::ptrdiff_t iCell) const
Returns the upper edge of the cell.
float LowerEdge(std::ptrdiff_t iCell) const
Returns the lower edge of the cell.
void FillQHisto(const art::Event &evt, unsigned int plane, TH1F *histo)
void GetChargeSum(int plane, double &charge, double &convcharge)
double fMinSignal
minimum ADC count to display a time bin
#define MF_LOG_TRACE(id)
void RunRoIextractor(art::Event const &evt, unsigned int plane)
std::vector< int > fWireMax
highest wire in interesting region for each plane
double fTicks
number of TDC ticks to display, ie # fTicks past fStartTick
std::add_lvalue_reference_t< const_value_type > const_reference
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
constexpr bool isValidChannelID(raw::ChannelID_t channel)
Definition: RawTypes.h:37
void GetRawDigits(art::Event const &evt)
Reads raw::RawDigits; also triggers Reset()
virtual Status_t Status(raw::ChannelID_t channel) const
Returns a status integer with arbitrary meaning.
geo::TPCID CurrentTPC() const
Returns the current TPC as a TPCID.
bool hasCell(std::ptrdiff_t iCell) const
Returns whether the cell is present or not.
double TotalClockTicks() const
Definition: RawDataDrawer.h:82
Class providing information about the quality of channels.
static int max(int a, int b)
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
Description of geometry of one entire detector.
virtual bool Operate(geo::WireID const &wireID, size_t tick, float adc)=0
bool operator()(geo::WireID const &wireID, size_t tick, float adc)
void Init(void)
Definition: gXSecComp.cxx:138
no compression
Definition: RawTypes.h:16
bool isEmpty() const
Returns whether minimum and maximum match.
bool bOwned
whether we own our data
Detector simulation of raw signals on wires.
void SetTDCRange(float min_tdc, float max_tdc, unsigned int nTDC)
Sets the complete TDC range.
float CellSize() const
Returns the cell size.
Detects the presence of a new event, data product or wire plane.
std::vector< RawDigitInfo_t > const & Digits() const
Returns the list of digit info.
CellGridClass()
Default constructor: invalid ranges.
bool empty() const
Returns whether the cache is empty() (STL-like interface)
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
geo::PlaneID const & PlaneID() const
std::size_t color(std::string const &procname)
Fw2dFFT::Data Data
void NewData(T const &data)
Create a owned copy of the specified object.
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
RawDigitInfo_t const * FindChannel(raw::ChannelID_t channel) const
Returns a pointer to the digit info of given channel, nullptr if none.
int fTicksPerPoint
number of ticks to include in one point
virtual bool IsPresent(raw::ChannelID_t channel) const =0
Returns whether the specified channel is physical and connected to wire.
virtual bool ProcessWire(geo::WireID const &)
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
def fill(s)
Definition: translator.py:93
bool fSeeBadChannels
Allow "bad" channels to be viewed.
bool hasCoord(float coord) const
Returns whether the coordinate is included in the range or not.
bool hasRegionOfInterest(geo::PlaneID::PlaneID_t plane) const
friend class BoxDrawer
void SetWireRange(float min_wire, float max_wire, unsigned int nWires)
Sets the complete wire range.
void PointToData(reference data)
Point to the specified data, not acquiring ownership.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
#define MF_LOG_DEBUG(id)
pointer pData
pointer to data
bool hasWire(float wire) const
Returns whether the range includes the specified wire.
size_t NCells() const
Returns the length of the axis.
void QueueDrawingBoxes(evdb::View2D *view, geo::PlaneID const &pid, std::vector< BoxInfo_t > const &BoxInfo)
int fAxisOrientation
0 = TDC values on y-axis, wire number on x-axis, 1 = swapped
void Clear()
Stop pointing to the data; if owned, delete it.
std::vector< art::InputTag > fRawDataLabels
module label that made the raw digits, default is daq
Aid in the rendering of RawData objects.
Definition: RawDataDrawer.h:40
Interface for experiment-specific channel quality info provider.
art::Ptr< raw::RawDigit > digit
a pointer to the actual digit
virtual float PedMean(raw::ChannelID_t ch) const =0
Retrieve pedestal information.
GridAxisClass(size_t nDiv, float new_min, float new_max)
Constructor: sets the limits and the number of cells.
bool ProcessTick(size_t tick) override
double fStartTick
Starting tick for the display.
bool good
whether the channel is not bad
void Dump(Stream &&out) const
unsigned int WireID_t
Type for the ID number.
Definition: geo_types.h:561
bool owned() const
Returns whether we have data and we own it.
detail::Node< FrameID, bool > PlaneID
Definition: CRTID.h:125
RawDataDrawer * RawDataDrawerPtr() const
size_t MaxSamples() const
Returns the largest number of samples in the unpacked raw digits.
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
RoIextractorClass(geo::PlaneID const &pid, RawDataDrawer *data_drawer)
void ResetRegionOfInterest()
Forgets about the current region of interest.
details::CellGridClass * fDrawingRange
information about the viewport
std::vector< int > fTimeMin
lowest time in interesting region for each plane
void Uncompress(const gar::raw::ADCvector_t &adc, gar::raw::ADCvector_t &uncompressed, gar::raw::Compress_t compress)
Uncompresses a raw data buffer.
Definition: raw.cxx:183
::util::PlaneDataChangeTracker_t CacheID_t
Definition: RawDataDrawer.h:35
std::add_const_t< value_type > const_value_type
Manages a grid-like division of 2D space.
TCEvent evt
Definition: DataStructs.cxx:7
bool ProcessWire(geo::WireID const &wireID) override
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
Applies Birks correction.
Interface for experiment-specific service for channel quality info.
OperationBaseClass * Operator(size_t iOp)
virtual std::string Name() const
evd::details::RawDigitCacheDataClass * digit_cache
Cache of raw digits.
int fPedestalOption
0: use DetPedestalService; 1: Use pedestal in raw::RawDigt; 2: no ped subtraction ...
void SetTDCRange(unsigned int nTDC)
Sets a simple TDC range: all the ticks, one cell per tick.
void StealData(std::remove_const_t< T > &&data)
Move data from the specified object, and own it.
LArSoft geometry interface.
Definition: ChannelGeo.h:16
std::vector< RawDigitInfo_t > digits
vector of raw digit information
GridAxisClass const & TDCAxis() const
Return the information about the TDCs.
int bool
Definition: qglobal.h:345
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
bool hasData() const
Returns whether we have data.
art::Ptr< raw::RawDigit > DigitPtr() const
Returns an art pointer to the actual digit.
bool RunOperation(art::Event const &evt, OperationBaseClass *operation)
std::tuple< float, float, float, float > GetCellBox(std::ptrdiff_t iCell) const
Returns the coordinates { w1, t1, w2, t2 } of specified cell.
size_t NCells() const
Returns the total number of cells in the grid.
void SetData(pointer data, bool owned)
Sets the data and the ownership.
bool Operate(geo::WireID const &wireID, size_t tick, float adc) override
bool Update(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, PFPStruct &pfp, bool prt)
Definition: PFPUtils.cxx:1056
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
QTextStream & endl(QTextStream &s)
bool fUncompressWithPed
Option to uncompress with pedestal. Turned off by default.
std::add_pointer_t< const_value_type > const_pointer
static bool IsValidStatus(Status_t status)
Returns whether the specified status is a valid one.
std::ptrdiff_t GetCell(float coord) const
Returns the index of the specified cell.
void AddOperation(std::unique_ptr< OperationBaseClass > new_op)
std::vector< double > fConvertedCharge
Sum of Charge Converted using Birks&#39; formula.
void ExtractRange(TVirtualPad *pPad, std::vector< double > const *zoom=nullptr)
Fills the viewport information from the specified pad.