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"
58 header.setIntParameter(
"Should Be Run Number", header.getRunNumber());
63 int i_event =
event.getEventNumber();
67 std::vector<ldmx::CalorimeterHit> caloHits;
68 for (
int i = 0; i < i_event; i++) {
69 caloHits.emplace_back();
70 caloHits.back().setID(i_event * 10 + i);
73 REQUIRE_NOTHROW(event.add(
"TestCollection", caloHits));
76 maxPEHit.
setID(i_event);
82 REQUIRE_NOTHROW(event.add(
"TestObject", res));
86 std::vector<int> event_indices = {i_event, i_event};
87 REQUIRE_NOTHROW(event.add(
"EventIndex", event_indices));
89 float test_float = i_event * 0.1;
90 REQUIRE_NOTHROW(event.add(
"EventTenth", test_float));
114 test_hist_ =
new TH1F(
"test_hist_",
"Test Histogram", 101, -50, 50);
119 int i_event =
event.getEventNumber();
121 REQUIRE(i_event > 0);
123 const std::vector<ldmx::CalorimeterHit>& caloHits =
126 CHECK(caloHits.size() == i_event);
127 for (
unsigned int i = 0; i < caloHits.size(); i++) {
128 CHECK(caloHits.at(i).getID() == i_event * 10 + i);
137 CHECK(maxPEHit.getID() == i_event);
138 CHECK(vetoRes.
passesVeto() == (i_event % 2 == 0));
140 const float& tenth_event =
event.getObject<
float>(
"EventTenth");
141 CHECK(tenth_event == Approx(i_event * 0.1));
143 const std::vector<int>& i_event_from_bus =
144 event.getCollection<
int>(
"EventIndex");
146 CHECK(i_event_from_bus.size() == 2);
147 CHECK(i_event_from_bus.at(0) == i_event);
148 CHECK(i_event_from_bus.at(1) == i_event);
193 bool match(
const std::string& filename)
const override {
195 TFile* f = TFile::Open(filename.c_str());
196 if (!f)
return false;
197 TDirectory* d = (TDirectory*)f->Get(
"TestAnalyzer");
198 if (!d)
return false;
199 TH1F* h = (TH1F*)d->Get(
"test_hist_");
200 if (!h)
return false;
212 std::ostringstream ss;
213 ss <<
"has the histogram 'TestAnalyzer/test_hist_' with the number of "
259 bool existColl =
true,
bool existObj =
true)
274 bool match(
const std::string& filename)
const override {
275 TFile* f = TFile::Open(filename.c_str());
276 if (!f)
return false;
278 TTreeReader events(
"LDMX_Events", f);
280 if (events.GetEntries(
true) !=
entries_) {
286 TTreeReaderValue<ldmx::EventHeader> header(events,
"EventHeader");
290 TTreeReaderValue<std::vector<ldmx::CalorimeterHit>> collection(
291 events, (
"TestCollection_" +
pass_).c_str());
292 while (events.Next()) {
293 if (collection->size() != header->getEventNumber()) {
297 for (
unsigned int i = 0; i < collection->size(); i++)
298 if (collection->at(i).getID() != header->getEventNumber() * 10 + i) {
307 auto t{(TTree*)f->Get(
"LDMX_Events")};
308 if (t and t->GetBranch((
"TestCollection_" +
pass_).c_str())) {
316 TTreeReaderValue<ldmx::HcalVetoResult> object(
317 events, (
"TestObject_" +
pass_).c_str());
318 while (events.Next()) {
319 if (object->getMaxPEHit().getID() != header->getEventNumber()) {
326 auto t{(TTree*)f->Get(
"LDMX_Events")};
327 if (t and t->GetBranch((
"TestObject_" +
pass_).c_str())) {
333 TTreeReader runs(
"LDMX_Run", f);
335 if (runs.GetEntries(
true) !=
runs_) {
340 TTreeReaderValue<ldmx::RunHeader> runHeader(runs,
"RunHeader");
342 while (runs.Next()) {
343 if (runHeader->getRunNumber() !=
344 runHeader->getIntParameter(
"Should Be Run Number")) {
359 std::ostringstream ss;
360 ss <<
"can be opened and has the correct number of entries in the event "
361 "tree and the run tree.";
363 ss <<
" TestCollection_" <<
pass_ <<
" was verified to ";
365 ss <<
" be the correct pattern.";
367 ss <<
" not be in the file.";
369 ss <<
" TestObject_" <<
pass_ <<
" was verified to ";
371 ss <<
" be the correct pattern.";
373 ss <<
" not be in the file.";
388static bool removeFile(
const std::string& filepath) {
389 return remove(filepath.c_str()) == 0;
395static bool runProcess(
const std::map<std::string, std::any>& parameters) {
400 p = std::make_unique<Process>(configuration);
402 std::cerr <<
"Config Error [" << e.
name() <<
"] : " << e.
message()
404 std::cerr <<
" at " << e.
module() <<
":" << e.
line() <<
" in "
451TEST_CASE(
"Core Framework Functionality",
"[Framework][functionality]") {
453 std::map<std::string, std::any> process;
454 process[
"passName"] = std::string(
"test");
455 process[
"compressionSetting"] = 9;
456 process[
"maxTriesPerEvent"] = 1;
457 process[
"logFrequency"] = -1;
458 process[
"termLogLevel"] = 4;
459 process[
"fileLogLevel"] = 4;
460 process[
"logFileName"] = std::string();
461 process[
"tree_name"] = std::string(
"LDMX_Events");
463 process[
"histogramFile"] =
465 process[
"maxEvents"] = -1;
466 process[
"skimDefaultIsKeep"] =
true;
469 std::map<std::string, std::any> producerParameters;
470 producerParameters[
"className"] =
471 std::string(
"framework::test::TestProducer");
472 producerParameters[
"instanceName"] = std::string(
"TestProducer");
473 producerParameters[
"createRunHeader"] =
false;
475 std::map<std::string, std::any> analyzerParameters;
476 analyzerParameters[
"className"] =
477 std::string(
"framework::test::TestAnalyzer");
478 analyzerParameters[
"instanceName"] = std::string(
"TestAnalyzer");
486 std::vector<framework::config::Parameters> sequence;
487 std::vector<std::string> inputFiles, outputFiles;
489 SECTION(
"Production Mode") {
492 outputFiles = {
"test_productionmode_events.root"};
493 process[
"outputFiles"] = outputFiles;
494 process[
"maxEvents"] = 3;
497 producerParameters[
"createRunHeader"] =
true;
500 sequence = {producerConfig};
501 process[
"sequence"] = sequence;
503 SECTION(
"only producers") {
504 SECTION(
"no drop/keep rules") {
506 REQUIRE(framework::test::runProcess(process));
507 CHECK_THAT(outputFiles.at(0),
511 SECTION(
"drop TestCollection") {
512 std::vector<std::string> keep = {
"drop .*Collection.*"};
513 process[
"keep"] = keep;
514 REQUIRE(framework::test::runProcess(process));
515 CHECK_THAT(outputFiles.at(0),
519 SECTION(
"skim for even indexed events") {
520 process[
"skimDefaultIsKeep"] =
false;
521 std::vector<std::string> rules = {
"TestProducer",
""};
522 process[
"skimRules"] = rules;
523 REQUIRE(framework::test::runProcess(process));
524 CHECK_THAT(outputFiles.at(0),
529 SECTION(
"with Analyses") {
530 std::string hist_file_path =
531 "test_productionmode_withanalyses_hists.root";
533 process[
"histogramFile"] = hist_file_path;
535 sequence.push_back(analyzerConfig);
536 process[
"sequence"] = sequence;
538 SECTION(
"no drop/keep rules") {
539 REQUIRE(framework::test::runProcess(process));
540 CHECK_THAT(outputFiles.at(0),
544 SECTION(
"drop TestCollection") {
545 std::vector<std::string> keep = {
"drop .*Collection.*"};
546 process[
"keep"] = keep;
547 REQUIRE(framework::test::runProcess(process));
548 CHECK_THAT(outputFiles.at(0),
552 SECTION(
"skim for even indexed events") {
553 process[
"skimDefaultIsKeep"] =
false;
554 std::vector<std::string> rules = {
"TestProducer",
""};
555 process[
"skimRules"] = rules;
556 REQUIRE(framework::test::runProcess(process));
557 CHECK_THAT(outputFiles.at(0),
561 CHECK_THAT(hist_file_path,
563 CHECK(framework::test::removeFile(hist_file_path));
566 CHECK(framework::test::removeFile(outputFiles.at(0)));
569 SECTION(
"Need Input Files") {
570 inputFiles = {
"test_needinputfiles_2_events.root",
571 "test_needinputfiles_3_events.root",
572 "test_needinputfiles_4_events.root"};
574 producerParameters[
"createRunHeader"] =
true;
577 sequence = {producerConfig};
579 auto makeInputs = process;
580 makeInputs[
"passName"] = std::string(
"makeInputs");
581 makeInputs[
"sequence"] = sequence;
583 outputFiles = {inputFiles.at(0)};
584 makeInputs[
"outputFiles"] = outputFiles;
585 makeInputs[
"maxEvents"] = 2;
586 makeInputs[
"run"] = 2;
588 REQUIRE(framework::test::runProcess(makeInputs));
589 REQUIRE_THAT(inputFiles.at(0),
592 outputFiles = {inputFiles.at(1)};
593 makeInputs[
"outputFiles"] = outputFiles;
594 makeInputs[
"maxEvents"] = 3;
595 makeInputs[
"run"] = 3;
597 REQUIRE(framework::test::runProcess(makeInputs));
598 REQUIRE_THAT(inputFiles.at(1),
601 outputFiles = {inputFiles.at(2)};
602 makeInputs[
"outputFiles"] = outputFiles;
603 makeInputs[
"maxEvents"] = 4;
604 makeInputs[
"run"] = 4;
606 REQUIRE(framework::test::runProcess(makeInputs));
607 REQUIRE_THAT(inputFiles.at(2),
610 SECTION(
"Analysis Mode") {
613 sequence = {analyzerConfig};
614 process[
"sequence"] = sequence;
616 std::string hist_file_path =
"test_analysismode_hists.root";
617 process[
"histogramFile"] = hist_file_path;
619 SECTION(
"one input file") {
620 std::vector<std::string> inputFile = {inputFiles.at(0)};
621 process[
"inputFiles"] = inputFile;
622 REQUIRE(framework::test::runProcess(process));
624 CHECK(framework::test::removeFile(hist_file_path));
627 SECTION(
"multiple input files") {
628 process[
"inputFiles"] = inputFiles;
629 REQUIRE(framework::test::runProcess(process));
631 1 + 2 + 1 + 2 + 3 + 1 + 2 + 3 + 4));
632 CHECK(framework::test::removeFile(hist_file_path));
637 SECTION(
"Merge Mode") {
640 process[
"inputFiles"] = inputFiles;
642 std::string event_file_path =
"test_mergemode_events.root";
643 outputFiles = {event_file_path};
644 process[
"outputFiles"] = outputFiles;
646 SECTION(
"with analyzers") {
647 sequence = {analyzerConfig};
649 std::string hist_file_path =
"test_mergemode_withanalyzers_hists.root";
651 process[
"sequence"] = sequence;
652 process[
"histogramFile"] = hist_file_path;
654 SECTION(
"no drop/keep rules") {
655 REQUIRE(framework::test::runProcess(process));
657 "makeInputs", 2 + 3 + 4, 3));
660 SECTION(
"drop TestCollection") {
661 std::vector<std::string> keep = {
"drop .*Collection.*"};
662 process[
"keep"] = keep;
663 REQUIRE(framework::test::runProcess(process));
665 "makeInputs", 2 + 3 + 4, 3,
false));
669 1 + 2 + 1 + 2 + 3 + 1 + 2 + 3 + 4));
670 CHECK(framework::test::removeFile(hist_file_path));
673 SECTION(
"with producers") {
674 producerParameters[
"createRunHeader"] =
false;
676 sequence = {producerConfig};
678 process[
"sequence"] = sequence;
680 SECTION(
"not listening to storage hints") {
681 REQUIRE(framework::test::runProcess(process));
682 CHECK_THAT(event_file_path,
686 SECTION(
"skim for even indexed events") {
687 process[
"skimDefaultIsKeep"] =
false;
688 std::vector<std::string> rules = {
"TestProducer",
""};
689 process[
"skimRules"] = rules;
690 REQUIRE(framework::test::runProcess(process));
691 CHECK_THAT(event_file_path,
696 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_NS(NS, CLASS)
Macro which allows the framework to construct an analyzer given its name during configuration.
#define DECLARE_PRODUCER_NS(NS, 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.
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 setParameters(std::map< std::string, std::any > parameters)
Set the mapping of parameter names to value.
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.
Bare analyzer that looks for objects matching what the TestProducer put in.
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
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
Handle allowing producers to modify run headers before the run begins.
bool createRunHeader_
should we create the run header?
virtual std::string describe() const override
Human-readable statement for any match that is true.
int runs_
correct number of runs
isGoodEventFile(const std::string &pass, const int &entries, const int &runs, bool existColl=true, bool existObj=true)
Constructor.
bool existCollection_
collection should exist in file
bool existObject_
object should exist in file
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.
int entries_
correct number of entries in the event ttree
Runs a variety of checks to make sure the histogram in the input filename is what we expect it to be.
virtual std::string describe() const override
Describe this matcher in a helpful, human-readable way.
int correctGetEntries_
Correct number of entries.
bool match(const std::string &filename) const override
Performs the test for this matcher.
isGoodHistogramFile(int const &n)
Constructor.
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.
bool passesVeto() const
Checks if the event passes the Hcal veto.
ldmx::HcalHit getMaxPEHit() const
void setVetoResult(const bool &passesVeto=true)
Sets whether the Hcal veto was passed or not.
void setMaxPEHit(const ldmx::HcalHit maxPEHit)
Set the maximum PE hit.
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....