otsdaq_mu2e  v2_04_02
WFViewer_module.cc
1 #include "art/Framework/Core/EDAnalyzer.h"
2 #include "art/Framework/Core/ModuleMacros.h"
3 #include "art/Framework/Principal/Event.h"
4 #include "art/Framework/Principal/Handle.h"
5 #include "art/Framework/Principal/Run.h"
6 #include "canvas/Utilities/InputTag.h"
7 
8 #include "artdaq-core/Data/Fragments.hh"
9 
10 #include "otsdaq-demo/Overlays/DataGenFragment.hh"
11 #include "otsdaq-demo/Overlays/FragmentType.hh"
12 
13 #include "cetlib/exception.h"
14 
15 #include "TAxis.h"
16 #include "TCanvas.h"
17 #include "TFile.h"
18 #include "TGraph.h"
19 #include "TH1D.h"
20 #include "TRootCanvas.h"
21 #include "TStyle.h"
22 
23 #include "otsdaq/Macros/CoutMacros.h"
24 #include "otsdaq/MessageFacility/MessageFacility.h"
25 
26 #include <algorithm>
27 #include <functional>
28 #include <initializer_list>
29 #include <iostream>
30 #include <limits>
31 #include <numeric>
32 #include <sstream>
33 #include <vector>
34 
35 namespace ots
36 {
37 class WFViewer : public art::EDAnalyzer
38 {
39  public:
40  explicit WFViewer(fhicl::ParameterSet const& p);
41  virtual ~WFViewer() = default;
42 
43  void analyze(art::Event const& e) override;
44  void beginRun(art::Run const&) override;
45  double calcmean(const float*);
46 
47  private:
48  std::unique_ptr<TCanvas> canvas_[2];
49  std::vector<Double_t> x_;
50  int prescale_;
51  art::RunNumber_t current_run_;
52 
53  std::size_t num_x_plots_;
54  std::size_t num_y_plots_;
55 
56  std::vector<std::string> fragment_type_labels_;
57  std::vector<artdaq::Fragment::fragment_id_t> fragment_ids_;
58 
59  std::vector<std::unique_ptr<TGraph>> graphs_;
60  std::vector<std::unique_ptr<TH1D>> histograms_;
61 
62  std::map<artdaq::Fragment::fragment_id_t, std::size_t> id_to_index_;
63  std::string outputFileName_;
64  TFile* fFile_;
65  bool writeOutput_;
66 };
67 
68 } // namespace ots
69 
70 ots::WFViewer::WFViewer(fhicl::ParameterSet const& ps)
71  : art::EDAnalyzer(ps)
72  , prescale_(ps.get<int>("prescale"))
73  , current_run_(0)
74  , num_x_plots_(
75  ps.get<std::size_t>("num_x_plots", std::numeric_limits<std::size_t>::max()))
76  , num_y_plots_(
77  ps.get<std::size_t>("num_y_plots", std::numeric_limits<std::size_t>::max()))
78  , fragment_type_labels_(ps.get<std::vector<std::string>>("fragment_type_labels"))
79  , fragment_ids_(ps.get<std::vector<artdaq::Fragment::fragment_id_t>>("fragment_ids"))
80  , graphs_(fragment_ids_.size())
81  , histograms_(fragment_ids_.size())
82  , outputFileName_(ps.get<std::string>("fileName", "otsdaqdemo_onmon.root"))
83  , writeOutput_(ps.get<bool>("write_to_file", false))
84 {
85  __COUT__ << "WFViewer CONSTRUCTOR BEGIN!!!!" << std::endl;
86  prescale_ = 1;
87  if(num_x_plots_ == std::numeric_limits<std::size_t>::max() ||
88  num_y_plots_ == std::numeric_limits<std::size_t>::max())
89  {
90  switch(fragment_ids_.size())
91  {
92  case 1:
93  num_x_plots_ = num_y_plots_ = 1;
94  break;
95  case 2:
96  num_x_plots_ = 2;
97  num_y_plots_ = 1;
98  break;
99  case 3:
100  case 4:
101  num_x_plots_ = 2;
102  num_y_plots_ = 2;
103  break;
104  case 5:
105  case 6:
106  num_x_plots_ = 3;
107  num_y_plots_ = 2;
108  break;
109  case 7:
110  case 8:
111  num_x_plots_ = 4;
112  num_y_plots_ = 2;
113  break;
114  default:
115  num_x_plots_ = num_y_plots_ =
116  static_cast<std::size_t>(ceil(sqrt(fragment_type_labels_.size())));
117  }
118  }
119 
120  // id_to_index_ will translate between a fragment's ID and where in
121  // the vector of graphs and histograms it's located
122 
123  for(std::size_t i_f = 0; i_f < fragment_ids_.size(); ++i_f)
124  {
125  id_to_index_[fragment_ids_[i_f]] = i_f;
126  }
127 
128  // Throw out any duplicate fragment_type_labels_ ; in this context we only
129  // care about the different types that we plan to encounter, not how
130  // many of each there are
131 
132  sort(fragment_type_labels_.begin(), fragment_type_labels_.end());
133  fragment_type_labels_.erase(
134  unique(fragment_type_labels_.begin(), fragment_type_labels_.end()),
135  fragment_type_labels_.end());
136 
137  gStyle->SetOptStat("irm");
138  gStyle->SetMarkerStyle(22);
139  gStyle->SetMarkerColor(4);
140 
141  std::cout << __COUT_HDR_FL__ << "WFViewer CONSTRUCTOR END" << std::endl;
142 }
143 
144 double ots::WFViewer::calcmean(const float* data)
145 {
146  int ii;
147  double mean = 0;
148  // uint32_t *lp;
149  // lp = (uint32_t *)data;
150  for(ii = 0; ii < 10; ii++)
151  {
152  // std::cout << __COUT_HDR_FL__ << " DJN+ " << data[ii] << std::endl;
153  mean += data[ii];
154  }
155  mean /= 10;
156  std::cout << "WFViewer mean is " << mean << " data[0] is " << data[0]
157  << " data[1] is " << data[1] << " 2=" << data[2] << " 3=" << data[3]
158  << std::endl
159  << std::endl;
160  std::cout << "WFViewer mean is " << mean << " data[15997] is " << data[15997]
161  << " data[15998] is " << data[15998] << " 2=" << data[15999]
162  << " 3=" << data[15999] << std::endl
163  << std::endl;
164  //"Hex[0]:" << std::hex << lp[0] << " [1]:" << std::hex << lp[1] << " [2]:" <<
165  // std::hex << lp[2] << " [3]:" << std::hex << lp[3] << " [4]:" << std::hex <<
166  // lp[4] << std::endl << std::endl << std::endl;
167  return mean;
168 }
169 
170 void ots::WFViewer::analyze(art::Event const& e)
171 {
172  std::cout << __COUT_HDR_FL__ << "WFViewer Analyzing event " << e.event() << std::endl;
173  static std::size_t evt_cntr = -1;
174  evt_cntr++;
175 
176  // John F., 1/22/14 -- there's probably a more elegant way of
177  // collecting fragments of various types using ART interface code;
178  // will investigate. Right now, we're actually re-creating the
179  // fragments locally
180 
181  artdaq::Fragments fragments;
182 
183  for(auto label : fragment_type_labels_)
184  {
185  art::Handle<artdaq::Fragments> fragments_with_label;
186 
187  e.getByLabel("daq", label, fragments_with_label);
188 
189  // for (int i_l = 0; i_l <
190  // static_cast<int>(fragments_with_label->size()); ++i_l) {
191  // fragments.emplace_back( (*fragments_with_label)[i_l] );
192  // }
193 
194  // std::cout << __COUT_HDR_FL__ << "WFViewer: There are " <<
195  // (*fragments_with_label).size() << " fragments in this event" << std::endl;
196 
197  for(auto frag : *fragments_with_label)
198  {
199  fragments.emplace_back(frag);
200  }
201  }
202 
203  // John F., 1/5/14
204 
205  // Here, we loop over the fragments passed to the analyze
206  // function. A warning is flashed if either (A) the fragments aren't
207  // all from the same event, or (B) there's an unexpected number of
208  // fragments given the number of boardreaders and the number of
209  // fragments per board
210 
211  // For every Nth event, where N is the "prescale" setting, plot the
212  // distribution of ADC counts from each board_id / fragment_id
213  // combo. Also, if "digital_sum_only" is set to false in the FHiCL
214  // string, then plot, for the Nth event, a graph of the ADC values
215  // across all channels in each board_id / fragment_id combo
216 
217  artdaq::Fragment::sequence_id_t expected_sequence_id =
218  std::numeric_limits<artdaq::Fragment::sequence_id_t>::max();
219 
220  // for (std::size_t i = 0; i < fragments.size(); ++i) {
221  for(const auto& frag : fragments)
222  {
223  // Pointers to the types of fragment overlays WFViewer can handle;
224  // only one will be used per fragment, of course
225 
226  std::unique_ptr<DataGenFragment> drPtr;
227 
228  // const auto& frag( fragments[i] ); // Basically a shorthand
229 
230  // if (i == 0)
231  if(expected_sequence_id ==
232  std::numeric_limits<artdaq::Fragment::sequence_id_t>::max())
233  {
234  expected_sequence_id = frag.sequenceID();
235  }
236 
237  if(expected_sequence_id != frag.sequenceID())
238  {
239  mf::LogWarning("WFViewer")
240  << "Warning in WFViewer: expected fragment with sequence ID "
241  << expected_sequence_id << ", received one with sequence ID "
242  << frag.sequenceID();
243  }
244 
245  FragmentType fragtype = static_cast<FragmentType>(frag.type());
246  // std::cout << __COUT_HDR_FL__ << "WFViewer: Fragment type is " << fragtype
247  // << " (DataGen=" << FragmentType::DataGen << ")" << std::endl;
248  // John F., 1/22/14 -- this should definitely be improved; I'm
249  // just using the max # of bits per ADC value for a given fragment
250  // type as is currently defined for the V172x fragments (as
251  // opposed to the Toy fragment, which have this value in their
252  // metadata). Since it's not using external variables for this
253  // quantity, this would need to be edited should these values
254  // change.
255 
256  switch(fragtype)
257  {
258  case FragmentType::DataGen:
259  drPtr.reset(new DataGenFragment(frag));
260  break;
261  default:
262  throw cet::exception("Error in WFViewer: unknown fragment type supplied: " +
263  fragmentTypeToString(fragtype));
264  }
265 
266  artdaq::Fragment::fragment_id_t fragment_id = frag.fragmentID();
267  std::size_t ind = id_to_index_[fragment_id];
268 
269  // If a histogram doesn't exist for this board_id / fragment_id combo,
270  // create it
271 
272  if(!histograms_[ind])
273  {
274  histograms_[ind] = std::unique_ptr<TH1D>(
275  new TH1D(Form("Fragment_%d_hist", fragment_id),
276  "Title Dennis",
277  300,
278  (Double_t)0.0,
279  (Double_t)std::numeric_limits<uint8_t>::max()));
280 
281  histograms_[ind]->SetTitle(Form(
282  "Frag %d, Type %s", fragment_id, fragmentTypeToString(fragtype).c_str()));
283  histograms_[ind]->GetXaxis()->SetTitle("Vector Mean");
284  }
285 
286  // For every event, fill the histogram (prescale is ignored here)
287 
288  // Is there some way to templatize an ART module? If not, we're
289  // stuck with this switch code...
290 
291  switch(fragtype)
292  {
293  case FragmentType::DataGen:
294  // for (auto val = drPtr->dataBegin(); val <= drPtr->dataEnd(); ++val )
295  {
296  auto val = drPtr->dataBegin();
297  double the_mean = calcmean(val->data);
298  std::cout << __COUT_HDR_FL__ << "DJN WFViewer: Putting datapoint "
299  << the_mean << " into histogram" << std::endl;
300  mf::LogInfo("WFViewer")
301  << "Putting datapoint " << the_mean << " into histogram";
302  // histograms_[ind]->Fill( static_cast<uint8_t>(val->data[0]) );
303  histograms_[ind]->Fill(the_mean);
304  }
305  break;
306 
307  default:
308  throw cet::exception("Error in WFViewer: unknown fragment type supplied: " +
309  fragmentTypeToString(fragtype));
310  }
311 
312  if(evt_cntr % prescale_ - 1 && prescale_ > 1)
313  {
314  continue;
315  }
316 
317  // Draw the histogram
318 
319  canvas_[0]->cd(ind + 1);
320  histograms_[ind]->Draw();
321 
322  canvas_[0]->Modified();
323  canvas_[0]->Update();
324 
325  if(writeOutput_)
326  {
327  canvas_[0]->Write("wf0", TObject::kOverwrite);
328  fFile_->Write();
329  }
330  }
331 }
332 
333 void ots::WFViewer::beginRun(art::Run const& e)
334 {
335  if(e.run() == current_run_)
336  return;
337  current_run_ = e.run();
338 
339  if(writeOutput_)
340  {
341  fFile_ = new TFile(outputFileName_.c_str(), "RECREATE");
342  fFile_->cd();
343  }
344 
345  for(int i = 0; i < 2; i++)
346  canvas_[i] = 0;
347  for(auto& x : graphs_)
348  x = 0;
349  for(auto& x : histograms_)
350  x = 0;
351 
352  for(int i = 0; i < 1; i++)
353  {
354  canvas_[i] = std::unique_ptr<TCanvas>(new TCanvas(Form("wf%d", i)));
355  canvas_[i]->Divide(num_x_plots_, num_y_plots_);
356  canvas_[i]->Update();
357  ((TRootCanvas*)canvas_[i]->GetCanvasImp())->DontCallClose();
358  }
359 
360  canvas_[0]->SetTitle("ADC Value Distribution");
361 
362  if(writeOutput_)
363  {
364  canvas_[0]->Write();
365  }
366 }
367 
368 DEFINE_ART_MODULE(ots::WFViewer)