MixFilterTestETS_module.cc
Go to the documentation of this file.
2 
14 #include "cetlib/map_vector.h"
16 
17 #include "boost/noncopyable.hpp"
18 
19 #include <algorithm>
20 #include <iterator>
21 #include <memory>
22 #include <unordered_set>
23 
24 namespace arttest {
25  class MixFilterTestDetail;
26 #if ART_TEST_EVENTS_TO_SKIP_CONST
27 #define ART_MFT MixFilterTestETSc
28 #define ART_TEST_EVENTS_TO_SKIP_CONST_TXT const
29 #elif defined ART_TEST_EVENTS_TO_SKIP_CONST
30 #define ART_MFT MixFilterTestETS
31 #define ART_TEST_EVENTS_TO_SKIP_CONST_TXT
32 #elif defined ART_TEST_OLD_STARTEVENT
33 #define ART_MT MixFilterTestOldStartEvent
34 #elif defined ART_TEST_NO_STARTEVENT
35 #define ART_MT MixFilterTestNoStartEvent
36 #else
37 // Normal case
38 #define ART_MFT MixFilterTest
39 #endif
41 }
42 
43 namespace {
44  class SecondaryFileNameProvider {
45  public:
46  SecondaryFileNameProvider(std::vector<std::string>&& fileNames)
47  : fileNames_(std::move(fileNames)), fileNameIter_(fileNames_.cbegin())
48  {}
49  SecondaryFileNameProvider(SecondaryFileNameProvider&&) = default;
50 
51  SecondaryFileNameProvider& operator=(SecondaryFileNameProvider&&) = default;
52 
53  SecondaryFileNameProvider(SecondaryFileNameProvider const& other)
54  : fileNames_(other.fileNames_)
55  , fileNameIter_(fileNames_.cbegin() +
56  (other.fileNameIter_ - other.fileNames_.cbegin()))
57  {}
58 
59  SecondaryFileNameProvider&
60  operator=(SecondaryFileNameProvider const& other)
61  {
62  SecondaryFileNameProvider tmp(other);
63  std::swap(tmp, *this);
64  return *this;
65  }
66 
67  ~SecondaryFileNameProvider() noexcept = default;
68 
70  operator()()
71  {
72  if (fileNameIter_ == fileNames_.end()) {
73  return std::string();
74  } else {
75  return *(fileNameIter_++);
76  }
77  }
78 
79  private:
80  std::vector<std::string> fileNames_;
81  decltype(fileNames_.cbegin()) fileNameIter_;
82  };
83 } // namespace
84 
86 public:
88  using mvv_t = typename mv_t::value_type;
89  using mvm_t = typename mv_t::mapped_type;
90 
91  // Constructor is responsible for registering mix operations with
92  // MixHelper::declareMixOp() and bookkeeping products with
93  // MixHelperproduces().
95 
98 
100 
101 #ifdef ART_TEST_OLD_STARTEVENT
102  // Old startEvent signature -- check it still works
103  void startEvent();
104 #elif !defined ART_TEST_NO_STARTEVENT
105  // Optional startEvent(Event const &): initialize state for each event,
106  void startEvent(art::Event const&);
107 #endif
108 
109  // Return the number of secondaries to read this time. Declare const
110  // if you don't plan to change your class' state.
111  size_t nSecondaries() const;
112 
113  // Optional eventsToSkip(): number of events to skip at the start of
114  // the file.
115 #ifdef ART_TEST_EVENTS_TO_SKIP_CONST
116  size_t
117  eventsToSkip() ART_TEST_EVENTS_TO_SKIP_CONST_TXT
118  {
119  return 7;
120  }
121 #endif
122 
123  // Optional processEventIDs(): after the generation of the event
124  // sequence, this function will be called if it exists to provide the
125  // sequence of EventIDs.
126  void processEventIDs(art::EventIDSequence const& seq);
127 
128  // Optional.finalizeEvent(): (eg) put bookkeping products in event. Do
129  // *not* place mix products into the event: this will already have
130  // been done for you.
131  void finalizeEvent(art::Event& t);
132 
133  // Optional respondToXXXfunctions, called at the right time if they
134  // exist.
135  void respondToOpenInputFile(art::FileBlock const& fb);
136  void respondToCloseInputFile(art::FileBlock const& fb);
139 
140  // Mixing functions. Note that they do not *have* to be member
141  // functions of this detail class: they may be member functions of a
142  // completely unrelated class; free functions or function objects
143  // provided they (or the function object's operator()) have the
144  // expected signature.
145  template <typename T>
146  bool mixByAddition(std::vector<T const*> const&, T&, art::PtrRemapper const&);
147 
149  std::vector<std::vector<double> const*> const& in,
150  std::vector<double>& out,
151  art::PtrRemapper const&);
152 
153  bool aggregate_map_vector(std::vector<mv_t const*> const& in,
154  mv_t& out,
155  art::PtrRemapper const&);
156 
157  bool mixPtrs(std::vector<std::vector<art::Ptr<double>> const*> const& in,
159  art::PtrRemapper const& remap);
160 
161 #ifndef ART_NO_MIX_PTRVECTOR
162  bool mixPtrVectors(std::vector<art::PtrVector<double> const*> const& in,
164  art::PtrRemapper const& remap);
165 #endif
166 
167  bool mixProductWithPtrs(
168  std::vector<arttest::ProductWithPtrs const*> const& in,
170  art::PtrRemapper const& remap);
171 
172  bool mixmap_vectorPtrs(
176  art::PtrRemapper const& remap);
177 
178  template <typename COLL>
179  void verifyInSize(COLL const& in) const;
180 
181 private:
182  size_t const nSecondaries_;
183  bool const testRemapper_;
184  std::vector<size_t> doubleVectorOffsets_, map_vectorOffsets_;
185  std::unique_ptr<art::EventIDSequence> eIDs_;
186  bool startEvent_called_;
188  int currentEvent_;
189  bool const testZeroSecondaries_;
190  bool const testPtrFailure_;
191  bool const testEventOrdering_;
192  bool const testNoLimEventDupes_;
193  bool const compactMissingProducts_;
195 
196  size_t respondFunctionsSeen_;
197 
198  // For testing no_replace mode only:
199  std::vector<int> allEvents_;
200  std::unordered_set<int> uniqueEvents_;
201 };
202 
203 template <typename COLL>
204 inline void
205 arttest::MixFilterTestDetail::verifyInSize(COLL const& in) const
206 {
207  BOOST_REQUIRE_EQUAL(
208  in.size(),
210 }
211 
213  art::MixHelper& helper)
214  : nSecondaries_(p.get<size_t>("numSecondaries", 1))
215  , testRemapper_(p.get<bool>("testRemapper", true))
218  , eIDs_()
219  , startEvent_called_(false)
220  , processEventIDs_called_(false)
221  , currentEvent_(-1)
222  , testZeroSecondaries_(p.get<bool>("testZeroSecondaries", false))
223  , testPtrFailure_(p.get<bool>("testPtrFailure", false))
224  , testEventOrdering_(p.get<bool>("testEventOrdering", false))
225  , testNoLimEventDupes_(p.get<bool>("testNoLimEventDupes", false))
226  , compactMissingProducts_(p.get<bool>("compactMissingProducts", false))
227  , readMode_(helper.readMode())
229  , allEvents_()
230  , uniqueEvents_()
231 {
232  std::vector<std::string> fnToProvide;
233  if (p.get_if_present("fileNamesToProvide", fnToProvide)) {
234  std::cerr << "Calling registerSecondaryFileNameProvider.\n";
235  std::copy(fnToProvide.cbegin(),
236  fnToProvide.cend(),
237  std::ostream_iterator<std::string>(std::cerr, ", "));
238  std::cerr << "\n";
240  SecondaryFileNameProvider(std::move(fnToProvide)));
241  }
242 
243  std::string mixProducerLabel(
244  p.get<std::string>("mixProducerLabel", "mixProducer"));
245  helper.produces<std::string>(); // "Bookkeeping"
246  helper.produces<art::EventIDSequence>(); // "Bookkeeping"
247  helper.declareMixOp(art::InputTag(mixProducerLabel, "doubleLabel"),
248  &MixFilterTestDetail::mixByAddition<double>,
249  *this);
250  helper.declareMixOp(art::InputTag(mixProducerLabel, "IntProductLabel"),
251  &MixFilterTestDetail::mixByAddition<arttest::IntProduct>,
252  *this);
253  helper.declareMixOp(art::InputTag(mixProducerLabel, "stringLabel", "SWRITE"),
254  &MixFilterTestDetail::mixByAddition<std::string>,
255  *this);
256  helper.declareMixOp(art::InputTag(mixProducerLabel, "doubleCollectionLabel"),
258  *this);
259  helper.declareMixOp(art::InputTag(mixProducerLabel, "doubleVectorPtrLabel"),
261  *this);
262 #ifndef ART_NO_MIX_PTRVECTOR
263  helper.declareMixOp(art::InputTag(mixProducerLabel, "doublePtrVectorLabel"),
265  *this);
266 #endif
267  helper.declareMixOp(art::InputTag(mixProducerLabel, "ProductWithPtrsLabel"),
269  *this);
270  helper.declareMixOp(art::InputTag(mixProducerLabel, "mapVectorLabel"),
272  *this);
273  helper.declareMixOp(art::InputTag(mixProducerLabel, "intVectorPtrLabel"),
275  *this);
276  std::function<bool(std::vector<IntProduct const*> const&,
277  IntProduct&,
278  art::PtrRemapper const&)>
279  mixfunc([this](std::vector<IntProduct const*> const& in,
280  IntProduct,
281  art::PtrRemapper const&) -> bool {
282  auto const sz = in.size();
283  auto expected = nSecondaries_;
285  expected -= std::count_if(
286  eIDs_->begin(), eIDs_->end(), [](art::EventID const& eID) {
287  return (eID.event() % 100) == 0;
288  });
289  }
290  for (auto i = 0ul; i < sz; ++i) {
291  if (!compactMissingProducts_ && ((*eIDs_)[i].event() % 100) == 0) {
292  // Product missing
293  BOOST_REQUIRE(in[i] == nullptr);
294  } else {
295  BOOST_REQUIRE(in[i] != nullptr);
296  }
297  }
298  BOOST_REQUIRE_EQUAL(
299  sz, (currentEvent_ == 2 && testZeroSecondaries_) ? 0ul : expected);
300  return false;
301  });
302  helper.declareMixOp(
303  art::InputTag(mixProducerLabel, "SpottyProductLabel"), mixfunc, false);
304 }
305 
307 {
309  testNoLimEventDupes_ == false) {
310  // Require dupes across the job.
311  BOOST_CHECK_GT(allEvents_.size(), uniqueEvents_.size());
313  // Require no dupes across the job.
314  BOOST_CHECK_EQUAL(allEvents_.size(), uniqueEvents_.size());
315  }
316  BOOST_CHECK_EQUAL(respondFunctionsSeen_, 4ul);
317 }
318 
319 #ifndef ART_TEST_NO_STARTEVENT
320 void
322 #ifdef ART_TEST_OLD_STARTEVENT
323  startEvent()
324 #else
325  // Normal case
327 #endif
328 {
329  startEvent_called_ = true;
330  eIDs_.reset();
331  ++currentEvent_;
332 }
333 #endif
334 
335 size_t
337 {
338  return (currentEvent_ == 2 && testZeroSecondaries_) ? 0 : nSecondaries_;
339 }
340 
341 void
343 {
344 #ifdef ART_TEST_NO_STARTEVENT
345  // Need to deal with this here
346  ++currentEvent_;
347 #endif
349  eIDs_.reset(new art::EventIDSequence(seq));
350  if (!testEventOrdering_) {
351  return;
352  }
353  switch (readMode_) {
355  auto count(1);
356  for (auto const& eid : seq) {
357  BOOST_REQUIRE_EQUAL(eid.event(),
358  currentEvent_ * nSecondaries() + count++);
359  }
360  } break;
362  // We should have a duplicate within the secondaries.
363  std::unordered_set<int> s;
364  std::transform(seq.cbegin(),
365  seq.cend(),
366  std::inserter(s, s.begin()),
367  [](art::EventID const& eid) { return eid.event(); });
368  BOOST_CHECK_GT(seq.size(), s.size());
369  } break;
371  if (testNoLimEventDupes_) {
372  // We should have no duplicate within the secondaries.
373  std::unordered_set<int> s;
374  std::transform(seq.cbegin(),
375  seq.cend(),
376  std::inserter(s, s.begin()),
377  [](art::EventID const& eid) { return eid.event(); });
378  BOOST_CHECK_EQUAL(seq.size(), s.size());
379  } else { // Require dupes over 2 events.
380  auto checkpoint(allEvents_.size());
381  std::transform(seq.cbegin(),
382  seq.cend(),
383  std::back_inserter(allEvents_),
384  [](art::EventID const& eid) { return eid.event(); });
385  uniqueEvents_.insert(allEvents_.cbegin() + checkpoint,
386  allEvents_.cend());
387  // Test at end job for duplicates.
388  }
389  break;
391  auto checkpoint(allEvents_.size());
392  std::transform(seq.cbegin(),
393  seq.cend(),
394  std::back_inserter(allEvents_),
395  [](art::EventID const& eid) { return eid.event(); });
396  uniqueEvents_.insert(allEvents_.cbegin() + checkpoint, allEvents_.cend());
397  // Test at end job for no duplicates.
398  } break;
399  default:;
400  }
401 }
402 
403 void
405 {
406  e.put(std::unique_ptr<std::string>(new std::string("BlahBlahBlah")));
407  e.put(std::move(eIDs_));
408 #ifndef ART_TEST_NO_STARTEVENT
410  startEvent_called_ = false;
411 #endif
413  processEventIDs_called_ = false;
414 }
415 
416 void
418 {
420 }
421 
422 void
424 {
426 }
427 
428 void
430 {
432 }
433 
434 void
436 {
438 }
439 
440 template <typename T>
441 bool
442 arttest::MixFilterTestDetail::mixByAddition(std::vector<T const*> const& in,
443  T& out,
444  art::PtrRemapper const&)
445 {
446  verifyInSize(in);
447  for (auto const* prod : in) {
448  if (prod != nullptr) {
449  out += *prod;
450  }
451  }
452  return true; // Always want product in event.
453 }
454 
455 bool
457  std::vector<std::vector<double> const*> const& in,
458  std::vector<double>& out,
459  art::PtrRemapper const&)
460 {
461  verifyInSize(in);
463  return true; // Always want product in event.
464 }
465 
466 bool
468  std::vector<mv_t const*> const& in,
469  mv_t& out,
470  art::PtrRemapper const&)
471 {
472  verifyInSize(in);
474  return true; // Always want product in event.
475 }
476 
477 bool
479  std::vector<std::vector<art::Ptr<double>> const*> const& in,
481  art::PtrRemapper const& remap)
482 {
483  verifyInSize(in);
484  remap(in, std::back_inserter(out), doubleVectorOffsets_);
485  if (testPtrFailure_) {
486  BOOST_REQUIRE_THROW(*out.front(), art::Exception);
487  }
488  return true; // Always want product in event.
489 }
490 
491 #ifndef ART_NO_MIX_PTRVECTOR
492 bool
494  std::vector<art::PtrVector<double> const*> const& in,
496  art::PtrRemapper const& remap)
497 {
498  verifyInSize(in);
499  remap(in, std::back_inserter(out), doubleVectorOffsets_);
500  return true; // Always want product in event.
501 }
502 #endif
503 
504 bool
506  std::vector<arttest::ProductWithPtrs const*> const& in,
508  art::PtrRemapper const& remap)
509 {
510  verifyInSize(in);
511 #ifndef ART_NO_MIX_PTRVECTOR
512  remap(in,
513  std::back_inserter(out.ptrVectorDouble()),
516 #endif
517  remap(in,
518  std::back_inserter(out.vectorPtrDouble()),
521  // Throw-away object to test non-standard remap interface.
523  remap(in,
524  std::back_inserter(tmp.vectorPtrDouble()),
527  return true; // Always want product in event.
528 }
529 
530 bool
535  art::PtrRemapper const& remap)
536 {
537  verifyInSize(in);
538  remap(in, std::back_inserter(out), map_vectorOffsets_);
539  return true; // Always want product in event.
540 }
541 
542 namespace arttest {
544 }
void startEvent(art::Event const &)
void registerSecondaryFileNameProvider(ProviderFunc_ func)
Definition: MixHelper.cc:146
void respondToCloseInputFile(art::FileBlock const &fb)
std::vector< EventID > EventIDSequence
Definition: MixTypes.h:22
art::PtrVector< double > const & ptrVectorDouble() const
std::vector< art::Ptr< double > > const & vectorPtrDouble() const
bool mixPtrs(std::vector< std::vector< art::Ptr< double >> const * > const &in, std::vector< art::Ptr< double >> &out, art::PtrRemapper const &remap)
const char expected[]
Definition: Exception_t.cc:22
void respondToCloseOutputFiles(art::FileBlock const &fb)
std::string string
Definition: nybbler.cc:12
bool mixByAddition(std::vector< PROD const * > const &, OPROD &, art::PtrRemapper const &)
std::pair< key_type, mapped_type > value_type
Definition: map_vector.h:89
MixFilterTestDetail(Parameters const &p, art::MixHelper &helper)
bool mixPtrVectors(std::vector< art::PtrVector< double > const * > const &in, art::PtrVector< double > &out, art::PtrRemapper const &remap)
bool mixmap_vectorPtrs(std::vector< std::vector< art::Ptr< cet::map_vector< unsigned int >::value_type >> const * > const &in, std::vector< art::Ptr< cet::map_vector< unsigned int >::value_type >> &out, art::PtrRemapper const &remap)
void produces(std::string const &instanceName={})
Definition: MixHelper.h:455
bool aggregateDoubleCollection(std::vector< std::vector< double > const * > const &in, std::vector< double > &out, art::PtrRemapper const &)
Value mapped_type
Definition: map_vector.h:88
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
void flattenCollections(std::vector< COLLECTION const * > const &in, COLLECTION &out)
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:68
void declareMixOp(InputTag const &inputTag, MixFunc< PROD, OPROD > mixFunc, bool outputProduct=true)
Definition: MixHelper.h:471
void swap(Handle< T > &a, Handle< T > &b)
void verifyInSize(COLL const &in) const
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< size_t > map_vectorOffsets_
bool get_if_present(std::string const &key, T &value) const
Definition: ParameterSet.h:208
art::MixFilter< MixFilterTestDetail > ART_MFT
value_type const & front() const
Definition: map_vector.h:343
art::MixHelper::Mode const readMode_
MixFilterTestDetail & operator=(MixFilterTestDetail const &)=delete
BOOST_REQUIRE(inFile)
std::unique_ptr< art::EventIDSequence > eIDs_
std::vector< art::Ptr< double > > vpd_
std::unordered_set< int > uniqueEvents_
p
Definition: test.py:228
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
bool aggregate_map_vector(std::vector< mv_t const * > const &in, mv_t &out, art::PtrRemapper const &)
void respondToOpenInputFile(art::FileBlock const &fb)
std::vector< size_t > doubleVectorOffsets_
T copy(T const &v)
void respondToOpenOutputFiles(art::FileBlock const &fb)
EventNumber_t event() const
Definition: EventID.h:117
static const double s
Definition: Units.h:99
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
bool mixProductWithPtrs(std::vector< arttest::ProductWithPtrs const * > const &in, arttest::ProductWithPtrs &out, art::PtrRemapper const &remap)
ProductID put(std::unique_ptr< PROD > &&edp, FullSemantic< Level::Run > const semantic)
Definition: DataViewImpl.h:692
void processEventIDs(art::EventIDSequence const &seq)