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