1#include <catch2/catch_approx.hpp>
2#include <catch2/catch_test_macros.hpp>
3#include <catch2/matchers/catch_matchers.hpp>
6#include "Framework/EventFile.h"
9#include "Framework/RunHeader.h"
15#include "TTreeReader.h"
59 header.setIntParameter(
"Should Be Run Number", header.getRunNumber());
64 int i_event =
event.getEventNumber();
68 std::vector<ldmx::CalorimeterHit> calo_hits;
69 for (
int i = 0; i < i_event; i++) {
70 calo_hits.emplace_back();
71 calo_hits.back().setID(i_event * 10 + i);
74 REQUIRE_NOTHROW(event.add(
"TestCollection", calo_hits));
77 max_pe_hit.
setID(i_event);
83 REQUIRE_NOTHROW(event.add(
"TestObject", res));
87 std::vector<int> event_indices = {i_event, i_event};
88 REQUIRE_NOTHROW(event.add(
"EventIndex", event_indices));
90 float test_float = i_event * 0.1;
91 REQUIRE_NOTHROW(event.add(
"EventTenth", test_float));
110 std::string test_collection_passname_;
111 std::string test_object_passname_;
112 std::string veto_test_object_passname_;
113 std::string tenth_event_passname_;
114 std::string event_index_passname_;
121 test_collection_passname_ =
122 ps.
get<std::string>(
"test_collection_passname",
"");
123 test_object_passname_ = ps.
get<std::string>(
"test_object_passname",
"");
124 veto_test_object_passname_ =
125 ps.
get<std::string>(
"veto_test_object_passname",
"");
126 tenth_event_passname_ = ps.
get<std::string>(
"tenth_event_passname",
"");
127 event_index_passname_ = ps.
get<std::string>(
"event_index_passname",
"");
132 test_hist_ =
new TH1F(
"test_hist_",
"Test Histogram", 101, -50, 50);
137 int i_event =
event.getEventNumber();
139 REQUIRE(i_event > 0);
141 const std::vector<ldmx::CalorimeterHit>& calo_hits =
143 test_collection_passname_);
145 CHECK(calo_hits.size() == i_event);
146 for (
unsigned int i = 0; i < calo_hits.size(); i++) {
147 CHECK(calo_hits.at(i).getID() == i_event * 10 + i);
153 veto_test_object_passname_);
157 CHECK(max_pe_hit.getID() == i_event);
158 CHECK(veto_res.
passesVeto() == (i_event % 2 == 0));
160 const float& tenth_event =
161 event.getObject<
float>(
"EventTenth", tenth_event_passname_);
162 CHECK(tenth_event == Approx(i_event * 0.1));
164 const std::vector<int>& i_event_from_bus =
165 event.getCollection<
int>(
"EventIndex", event_index_passname_);
167 CHECK(i_event_from_bus.size() == 2);
168 CHECK(i_event_from_bus.at(0) == i_event);
169 CHECK(i_event_from_bus.at(1) == i_event);
214 bool match(
const std::string& filename)
const override {
216 TFile* f = TFile::Open(filename.c_str());
217 if (!f)
return false;
218 TDirectory* d = (TDirectory*)f->Get(
"TestAnalyzer");
219 if (!d)
return false;
220 TH1F* h = (TH1F*)d->Get(
"test_hist_");
221 if (!h)
return false;
233 std::ostringstream ss;
234 ss <<
"has the histogram 'TestAnalyzer/test_hist_' with the number of "
280 bool existColl =
true,
bool existObj =
true)
295 bool match(
const std::string& filename)
const override {
296 TFile* f = TFile::Open(filename.c_str());
297 if (!f)
return false;
299 TTreeReader events(
"LDMX_Events", f);
301 if (events.GetEntries(
true) !=
entries_) {
307 TTreeReaderValue<ldmx::EventHeader> header(events,
"EventHeader");
311 TTreeReaderValue<std::vector<ldmx::CalorimeterHit>> collection(
312 events, (
"test_collection_" +
pass_).c_str());
313 while (events.Next()) {
314 if (collection->size() != header->getEventNumber()) {
318 for (
unsigned int i = 0; i < collection->size(); i++)
319 if (collection->at(i).getID() != header->getEventNumber() * 10 + i) {
328 auto t{(TTree*)f->Get(
"LDMX_Events")};
329 if (t and t->GetBranch((
"test_collection_" +
pass_).c_str())) {
337 TTreeReaderValue<ldmx::HcalVetoResult> object(
338 events, (
"test_object_" +
pass_).c_str());
339 while (events.Next()) {
340 if (object->getMaxPEHit().getID() != header->getEventNumber()) {
347 auto t{(TTree*)f->Get(
"LDMX_Events")};
348 if (t and t->GetBranch((
"test_object_" +
pass_).c_str())) {
354 TTreeReader runs(
"LDMX_Run", f);
356 if (runs.GetEntries(
true) !=
runs_) {
361 TTreeReaderValue<ldmx::RunHeader> run_header(runs,
"RunHeader");
363 while (runs.Next()) {
364 if (run_header->getRunNumber() !=
365 run_header->getIntParameter(
"Should Be Run Number")) {
380 std::ostringstream ss;
381 ss <<
"can be opened and has the correct number of entries in the event "
382 "tree and the run tree.";
384 ss <<
" test_collection_" <<
pass_ <<
" was verified to ";
386 ss <<
" be the correct pattern.";
388 ss <<
" not be in the file.";
390 ss <<
" test_object_" <<
pass_ <<
" was verified to ";
392 ss <<
" be the correct pattern.";
394 ss <<
" not be in the file.";
409static bool removeFile(
const std::string& filepath) {
410 return remove(filepath.c_str()) == 0;
419 p = std::make_unique<Process>(parameters);
421 std::cerr <<
"Config Error [" << e.
name() <<
"] : " << e.
message()
423 std::cerr <<
" at " << e.
module() <<
":" << e.
line() <<
" in "
470TEST_CASE(
"Core Framework Functionality",
"[Framework][functionality]") {
473 process.add(
"compressionSetting", 9);
474 process.add(
"maxTriesPerEvent", 1);
475 process.add(
"logFrequency", -1);
476 process.add(
"termLogLevel", 4);
477 process.add(
"fileLogLevel", 4);
478 process.add<std::string>(
"logFileName",
"");
479 process.add<std::string>(
"tree_name",
"LDMX_Events");
482 producer_parameters.
add<std::string>(
"className",
483 "framework::test::TestProducer");
484 producer_parameters.add<std::string>(
"instanceName",
"TestProducer");
487 analyzer_parameters.
add<std::string>(
"className",
488 "framework::test::TestAnalyzer");
489 analyzer_parameters.add<std::string>(
"instanceName",
"TestAnalyzer");
492 std::vector<framework::config::Parameters> sequence;
493 std::vector<std::string> input_files, output_files;
495 SECTION(
"Production Mode") {
498 output_files = {
"test_productionmode_events.root"};
499 process.add<std::string>(
"passName",
"test");
500 process.add(
"outputFiles", output_files);
501 process.add(
"maxEvents", 3);
502 process.add(
"run", 3);
504 producer_parameters.add(
"createRunHeader",
true);
506 sequence = {producer_parameters};
508 SECTION(
"only producers") {
509 process.add(
"sequence", sequence);
510 process.add<std::string>(
"histogramFile",
"");
511 SECTION(
"no drop/keep rules") {
513 REQUIRE(framework::test::runProcess(process));
514 CHECK_THAT(output_files.at(0),
518 SECTION(
"drop TestCollection") {
519 std::vector<std::string> keep = {
"drop .*Collection.*"};
520 process.add(
"keep", keep);
521 REQUIRE(framework::test::runProcess(process));
522 CHECK_THAT(output_files.at(0),
526 SECTION(
"skim for even indexed events") {
527 process.add(
"skimDefaultIsKeep",
false);
528 std::vector<std::string> rules = {
"TestProducer",
""};
529 process.add(
"skimRules", rules);
530 REQUIRE(framework::test::runProcess(process));
531 CHECK_THAT(output_files.at(0),
536 SECTION(
"with Analyses") {
537 std::string hist_file_path =
538 "test_productionmode_withanalyses_hists.root";
540 process.add(
"histogramFile", hist_file_path);
542 sequence.push_back(analyzer_parameters);
543 process.add(
"sequence", sequence);
545 SECTION(
"no drop/keep rules") {
546 REQUIRE(framework::test::runProcess(process));
547 CHECK_THAT(output_files.at(0),
551 SECTION(
"drop TestCollection") {
552 std::vector<std::string> keep = {
"drop .*Collection.*"};
553 process.add(
"keep", keep);
554 REQUIRE(framework::test::runProcess(process));
555 CHECK_THAT(output_files.at(0),
559 SECTION(
"skim for even indexed events") {
560 process.add(
"skimDefaultIsKeep",
false);
561 std::vector<std::string> rules = {
"TestProducer",
""};
562 process.add(
"skimRules", rules);
563 REQUIRE(framework::test::runProcess(process));
564 CHECK_THAT(output_files.at(0),
568 CHECK_THAT(hist_file_path,
570 CHECK(framework::test::removeFile(hist_file_path));
573 CHECK(framework::test::removeFile(output_files.at(0)));
576 SECTION(
"Need Input Files") {
577 input_files = {
"test_needinputfiles_2_events.root",
578 "test_needinputfiles_3_events.root",
579 "test_needinputfiles_4_events.root"};
581 for (
int run{2};
run < 5;
run++) {
582 auto make_inputs = process;
583 make_inputs.add<std::string>(
"passName",
"makeInputs");
584 auto producer = producer_parameters;
585 producer.add(
"createRunHeader",
true);
586 make_inputs.add<std::vector<framework::config::Parameters>>(
"sequence",
588 output_files = {input_files.at(run - 2)};
589 make_inputs.add(
"outputFiles", output_files);
590 make_inputs.add(
"maxEvents", run);
591 make_inputs.add(
"run", run);
592 REQUIRE(framework::test::runProcess(make_inputs));
593 REQUIRE_THAT(input_files.at(run - 2),
596 process.add<std::string>(
"passName",
"test");
598 SECTION(
"Analysis Mode") {
601 sequence = {analyzer_parameters};
602 process.add(
"sequence", sequence);
604 std::string hist_file_path =
"test_analysismode_hists.root";
605 process.add(
"histogramFile", hist_file_path);
607 SECTION(
"one input file") {
608 std::vector<std::string> input_file = {input_files.at(0)};
609 process.add(
"inputFiles", input_file);
610 REQUIRE(framework::test::runProcess(process));
612 CHECK(framework::test::removeFile(hist_file_path));
615 SECTION(
"multiple input files") {
616 process.add(
"inputFiles", input_files);
617 REQUIRE(framework::test::runProcess(process));
619 1 + 2 + 1 + 2 + 3 + 1 + 2 + 3 + 4));
620 CHECK(framework::test::removeFile(hist_file_path));
625 SECTION(
"Merge Mode") {
628 process.add(
"inputFiles", input_files);
630 std::string event_file_path =
"test_mergemode_events.root";
631 output_files = {event_file_path};
632 process.add(
"outputFiles", output_files);
634 SECTION(
"with analyzers") {
635 sequence = {analyzer_parameters};
637 std::string hist_file_path =
"test_mergemode_withanalyzers_hists.root";
639 process.add(
"sequence", sequence);
640 process.add(
"histogramFile", hist_file_path);
642 SECTION(
"no drop/keep rules") {
643 REQUIRE(framework::test::runProcess(process));
645 "makeInputs", 2 + 3 + 4, 3));
648 SECTION(
"drop TestCollection") {
649 std::vector<std::string> keep = {
"drop .*Collection.*"};
650 process.add(
"keep", keep);
651 REQUIRE(framework::test::runProcess(process));
653 "makeInputs", 2 + 3 + 4, 3,
false));
657 1 + 2 + 1 + 2 + 3 + 1 + 2 + 3 + 4));
658 CHECK(framework::test::removeFile(hist_file_path));
661 SECTION(
"with producers") {
662 producer_parameters.add(
"createRunHeader",
false);
663 sequence = {producer_parameters};
665 process.add(
"sequence", sequence);
667 SECTION(
"not listening to storage hints") {
668 REQUIRE(framework::test::runProcess(process));
669 CHECK_THAT(event_file_path,
673 SECTION(
"skim for even indexed events") {
674 process.add(
"skimDefaultIsKeep",
false);
675 std::vector<std::string> rules = {
"TestProducer",
""};
676 process.add(
"skimRules", rules);
677 REQUIRE(framework::test::runProcess(process));
678 CHECK_THAT(event_file_path,
683 CHECK(framework::test::removeFile(event_file_path));
Class that represents a reconstructed hit in a calorimeter cell within the detector.
Base classes for all user event processing components to extend.
#define DECLARE_ANALYZER(CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class that stores Stores reconstructed hit information from the HCAL.
Class used to encapsulate the results obtained from HcalVetoProcessor.
Class which represents the process under execution.
Base class for a module which does not produce a data product.
Analyzer(const std::string &name, Process &process)
Class constructor.
TDirectory * getHistoDirectory()
Access/create a directory in the histogram file for this event processor to create histograms and ana...
void setStorageHint(framework::StorageControl::Hint hint)
Mark the current event as having the given storage control hint from this module_.
Implements an event buffer system for storing event data.
Class which represents the process under execution.
Base class for a module which produces a data product.
Class encapsulating parameters for configuring a processor.
void add(const std::string &name, const T &value)
Add a parameter to the parameter list.
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Standard base exception class with some useful output information.
const std::string & function() const
Get the function name where the exception occurred.
int line() const
Get the source line number where the exception occurred.
const std::string & message() const
Get the message of the exception.
const std::string & name() const
Get the name of the exception.
const std::string & module() const
Get the source filename where the exception occurred.
int entries_
correct number of entries in the event ttree
bool exist_object_
object should exist in file
int runs_
correct number of runs
std::string pass_
pass name to check the collection and/or object for
bool match(const std::string &filename) const override
Actually do the matching.
IsGoodEventFile(const std::string &pass, const int &entries, const int &runs, bool existColl=true, bool existObj=true)
Constructor.
bool exist_collection_
collection should exist in file
virtual std::string describe() const override
Human-readable statement for any match that is true.
IsGoodHistogramFile(int const &n)
Constructor.
bool match(const std::string &filename) const override
Performs the test for this matcher.
virtual std::string describe() const override
Describe this matcher in a helpful, human-readable way.
int correct_get_entries_
Correct number of entries.
Bare analyzer that looks for objects matching what the TestProducer put in.
void configure(framework::config::Parameters &ps) override
Callback for the EventProcessor to configure itself from the given set of parameters.
void analyze(const framework::Event &event) final override
Process the event and make histograms or summaries.
TH1F * test_hist_
test histogram filled with event indices
void onProcessStart() final override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
Bare producer that creates a collection and an object and puts them on the event bus.
int events_
number of events we've gotten to
bool create_run_header_
should we create the run header?
void configure(framework::config::Parameters &p) final override
Callback for the EventProcessor to configure itself from the given set of parameters.
void produce(framework::Event &event) final override
Process the event and put new data products into it.
void beforeNewRun(ldmx::RunHeader &header) final override
Callback for Producers to add parameters to the run header before conditions are initialized.
Represents a reconstructed hit in a calorimeter cell within the detector.
void setID(int id)
Set the detector ID.
Stores reconstructed hit information from the HCAL.
void setVetoResult(const bool &passes_veto=true)
Sets whether the Hcal veto was passed or not.
bool passesVeto() const
Checks if the event passes the Hcal veto.
ldmx::HcalHit getMaxPEHit() const
void setMaxPEHit(const ldmx::HcalHit max_PE_hit)
Set the maximum PE hit.
Parameters run(const std::string &root_object, const std::string &pythonScript, char *args[], int nargs)
run the python script and extract the parameters
All classes in the ldmx-sw project use this namespace.
std::unique_ptr< Process > ProcessHandle
A handle to the current process Used to pass a process from ConfigurePython to fire....