artdaq  v3_01_00
genToArt.cc
1 // genToArt
3 //
4 // This application is intended to invoke a configurable set of fragment
5 // generators, and funnel the result to an invocation of art. This is
6 // not an MPI application (see caveat below), so is not intended for
7 // high performance production DAQ scenarios -- for that, see the pmt
8 // application driver and its associated applcations boardreader and
9 // eventbuilder.
11 
12 #define TRACE_NAME "genToArt"
13 
14 #include "art/Framework/Art/artapp.h"
15 #include "canvas/Utilities/Exception.h"
16 #include "artdaq-core/Generators/FragmentGenerator.hh"
17 #include "artdaq-core/Data/Fragment.hh"
18 #include "artdaq/DAQdata/GenericFragmentSimulator.hh"
19 #include "artdaq/Application/CommandableFragmentGenerator.hh"
20 #include "artdaq/DAQrate/SharedMemoryEventManager.hh"
21 #include "artdaq-core/Generators/makeFragmentGenerator.hh"
22 #include "artdaq-core/Core/SimpleMemoryReader.hh"
23 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
24 #include "cetlib/container_algorithms.h"
25 #include "fhiclcpp/ParameterSet.h"
26 #include "fhiclcpp/make_ParameterSet.h"
27 
28 #include <boost/program_options.hpp>
29 
30 #include <deque>
31 #include <iostream>
32 #include <map>
33 #include <memory>
34 #include <string>
35 #include <utility>
36 
37 namespace bpo = boost::program_options;
38 
39 namespace
40 {
48  int process_cmd_line(int argc, char** argv,
49  bpo::variables_map& vm)
50  {
51  std::ostringstream descstr;
52  descstr << argv[0]
53  << " <-c <config-file>> <other-options> [<source-file>]+";
54  bpo::options_description desc(descstr.str());
55  desc.add_options()
56  ("config,c", bpo::value<std::string>(), "Configuration file.")
57  ("help,h", "produce help message");
58  try
59  {
60  bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
61  bpo::notify(vm);
62  }
63  catch (bpo::error const& e)
64  {
65  TLOG(TLVL_ERROR) << "Exception from command line processing in " << argv[0]
66  << ": " << e.what();
67  return -1;
68  }
69  if (vm.count("help"))
70  {
71  std::cout << desc << std::endl;
72  return 1;
73  }
74  if (!vm.count("config"))
75  {
76  TLOG(TLVL_ERROR) << "Exception from command line processing in " << argv[0]
77  << ": no configuration file given.\n"
78  << "For usage and an options list, please do '"
79  << argv[0] << " --help"
80  << "'.";
81  return 2;
82  }
83  return 0;
84  }
85 
91  {
92  public:
98  ThrottledGenerator(std::string const& generator,
99  fhicl::ParameterSet const& ps);
100 
106  bool getNext(artdaq::FragmentPtrs& newFrags);
107 
112  size_t numFragIDs() const;
113 
120  void start(int run, uint64_t timeout, uint64_t timestamp) const
121  {
122  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
123  if (gen_ptr != nullptr) gen_ptr->StartCmd(run, timeout, timestamp);
124  }
130  void stop(uint64_t timeout, uint64_t timestamp) const
131  {
132  auto gen_ptr = dynamic_cast<artdaq::CommandableFragmentGenerator*>(generator_.get());
133  if (gen_ptr != nullptr) gen_ptr->StopCmd(timeout, timestamp);
134  }
135 
136  private:
137  bool generateFragments_();
138 
139  std::unique_ptr<artdaq::FragmentGenerator> generator_;
140  size_t const numFragIDs_;
141  std::map<artdaq::Fragment::fragment_id_t,
142  std::deque<artdaq::FragmentPtr>> frags_;
143  };
144 
145  ThrottledGenerator::
146  ThrottledGenerator(std::string const& generator,
147  fhicl::ParameterSet const& ps)
148  :
149  generator_(artdaq::makeFragmentGenerator(generator, ps))
150  , numFragIDs_(generator_->fragmentIDs().size())
151  , frags_()
152  {
153  assert(generator_);
154  }
155 
156  bool
158  getNext(artdaq::FragmentPtrs& newFrags)
159  {
160  if (frags_.size() && frags_.begin()->second.size())
161  { // Something stored.
162  for (auto& fQp : frags_)
163  {
164  assert(fQp.second.size());
165  newFrags.emplace_back(std::move(fQp.second.front()));
166  fQp.second.pop_front();
167  }
168  }
169  else
170  { // Need fresh fragments.
171  return generateFragments_() && getNext(newFrags);
172  }
173  return true;
174  }
175 
176  bool
177  ThrottledGenerator::
178  generateFragments_()
179  {
180  artdaq::FragmentPtrs incomingFrags;
181  bool result{ false };
182  while ((result = generator_->getNext(incomingFrags)) &&
183  incomingFrags.empty()) {
184  }
185  for (auto&& frag : incomingFrags)
186  {
187  frags_[frag->fragmentID()].emplace_back(std::move(frag));
188  }
189  return result;
190  }
191 
192  size_t
194  numFragIDs() const
195  {
196  return numFragIDs_;
197  }
198 
199  // artdaq::FragmentGenerator &
200  // ThrottledGenerator::
201  // generator() const
202  // {
203  // return *generator_;
204  // }
205 
223  int process_data(fhicl::ParameterSet const& pset)
224  {
225  auto const gta_pset = pset.get<fhicl::ParameterSet>("genToArt");
226 
227  // Make the generators based on the configuration.
228  std::vector<ThrottledGenerator> generators;
229 
230  auto const fr_pset = gta_pset.get<std::vector<fhicl::ParameterSet>>("fragment_receivers");
231  for (auto const& gen_ps : fr_pset)
232  {
233  generators.emplace_back(gen_ps.get<std::string>("generator"),
234  gen_ps);
235  }
236 
237  artdaq::FragmentPtrs frags;
238  auto eb_pset = gta_pset.get<fhicl::ParameterSet>("event_builder", {});
239  size_t expected_frags_per_event = 0;
240  for (auto& gen : generators)
241  {
242  gen.start(1000, 0, 0);
243  expected_frags_per_event += gen.numFragIDs();
244  }
245  eb_pset.put_or_replace<size_t>("expected_fragments_per_event", expected_frags_per_event);
246 
247  artdaq::SharedMemoryEventManager store(eb_pset, pset);
248  store.startRun(gta_pset.get<int>("run_number", 1000));
249 
250  auto const events_to_generate =
251  gta_pset.get<artdaq::Fragment::sequence_id_t>("events_to_generate", -1);
252  auto const reset_sequenceID = pset.get<bool>("reset_sequenceID", true);
253  bool done = false;
254  for (artdaq::Fragment::sequence_id_t event_count = 1;
255  (events_to_generate == static_cast<decltype(events_to_generate)>(-1)
256  || event_count <= events_to_generate) && (!done);
257  ++event_count)
258  {
259  for (auto& gen : generators)
260  {
261  done |= !gen.getNext(frags);
262  }
263  TLOG(TLVL_TRACE) << "There are " << std::to_string(frags.size()) << " Fragments in event " << std::to_string(event_count) << "." ;
264  artdaq::Fragment::sequence_id_t current_sequence_id = -1;
265  for (auto& val : frags)
266  {
267  if (reset_sequenceID)
268  {
269  TLOG(TLVL_DEBUG) << "Setting fragment sequence id to " << std::to_string(event_count) ;
270  val->setSequenceID(event_count);
271  }
272  if (current_sequence_id ==
273  static_cast<artdaq::Fragment::sequence_id_t>(-1))
274  {
275  current_sequence_id = val->sequenceID();
276  }
277  else if (val->sequenceID() != current_sequence_id)
278  {
279  throw art::Exception(art::errors::DataCorruption)
280  << "Data corruption: apparently related fragments have "
281  << " different sequence IDs: "
282  << val->sequenceID()
283  << " and "
284  << current_sequence_id
285  << ".\n";
286  }
287  artdaq::FragmentPtr tempFrag;
288  auto sts = store.AddFragment(std::move(val), 1000000, tempFrag);
289  if (!sts)
290  {
291  TLOG(TLVL_ERROR) << "Fragment was not added after 1s. Check art thread status!" ;
292  store.endOfData();
293  exit(1);
294  }
295  }
296  frags.clear();
297  TLOG(TLVL_TRACE) << "Event " << std::to_string(event_count) << " END" ;
298  }
299  for (auto& gen : generators)
300  {
301  gen.stop(0, 0);
302  }
303 
304  bool endSucceeded = store.endOfData();
305  if (endSucceeded)
306  {
307  return 0;
308  }
309  else
310  {
311  return 15;
312  }
313  }
314 }
315 
316 int main(int argc, char* argv[]) try
317 {
318  artdaq::configureMessageFacility("genToArt");
319  // Command line handling.
320  bpo::variables_map vm;
321  auto result = process_cmd_line(argc, argv, vm);
322  if (result != 0)
323  {
324  return (result);
325  }
326  // Read FHiCL configuration file.
327  fhicl::ParameterSet pset;
328  if (getenv("FHICL_FILE_PATH") == nullptr)
329  {
330  TLOG(TLVL_ERROR)
331  << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
332  setenv("FHICL_FILE_PATH", ".", 0);
333  }
334  artdaq::SimpleLookupPolicy lookup_policy("FHICL_FILE_PATH");
335  make_ParameterSet(vm["config"].as<std::string>(), lookup_policy, pset);
336  return process_data(pset);
337 }
338 catch (std::string& x)
339 {
340  TLOG(TLVL_ERROR) << "Exception (type string) caught in genToArt: " << x << '\n';
341  return 1;
342 }
343 catch (char const* m)
344 {
345  TLOG(TLVL_ERROR) << "Exception (type char const*) caught in genToArt: ";
346  if (m)
347  {
348  TLOG(TLVL_ERROR) << m;
349  }
350  else
351  {
352  TLOG(TLVL_ERROR) << "[the value was a null pointer, so no message is available]";
353  }
354 }
void start(int run, uint64_t timeout, uint64_t timestamp) const
Send start signal to FragmentGenerator, if it&#39;s a CommandableFragmentGenerator.
Definition: genToArt.cc:120
The SharedMemoryEventManager is a SharedMemoryManger which tracks events as they are built...
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
int process_cmd_line(int argc, char **argv, bpo::variables_map &vm)
Process the command line.
Definition: genToArt.cc:48
bool getNext(artdaq::FragmentPtrs &newFrags)
Get the next fragment from the generator.
Definition: genToArt.cc:158
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
int process_data(fhicl::ParameterSet const &pset)
Run the test, instantiating configured generators and an EventStore.
Definition: genToArt.cc:223
void stop(uint64_t timeout, uint64_t timestamp) const
Send stop signal to FragmentGenerator, if it&#39;s a CommandableFragmentGenerator.
Definition: genToArt.cc:130
size_t numFragIDs() const
Get the number of Fragment IDs handled by this generator.
Definition: genToArt.cc:194
ThrottledGenerator: ensure that we only get one fragment per type at a time from the generator...
Definition: genToArt.cc:90