1#include <catch2/catch_approx.hpp>
2#include <catch2/catch_test_macros.hpp>
3#include <catch2/matchers/catch_matchers.hpp>
6#include "Ecal/Event/EcalHit.h"
7#include "Framework/Configure/Python.h"
11#include "Recon/Event/HgcrocTrigDigi.h"
23static const double MIP_SI_ENERGY = 0.130;
32static const double MEV_PER_FC = MIP_SI_ENERGY / (37 * 0.1602);
43static const double MAX_ENERGY_PERCENT_ERROR_DAQ = 0.025;
54static const double MAX_ENERGY_PERCENT_ERROR_TP = 0.15;
65static const double MAX_ENERGY_ERROR_DAQ = MIP_SI_ENERGY / 2;
76static const double MAX_ENERGY_ERROR_TP = 2 * MIP_SI_ENERGY;
88static const int NUM_TEST_SIM_HITS = 2000;
113 double const& rel_diff)
125 bool match(
const double& daq_energy)
const override {
134 std::ostringstream ss;
192 min_energy_ = ps.get<
double>(
"min_energy", MIP_SI_ENERGY);
193 max_energy_ = ps.get<
double>(
"max_energy", 10000. * MEV_PER_FC);
196 min_time_ = ps.get<
double>(
"min_time", 1.);
197 max_time_ = ps.get<
double>(
"max_time", 1.);
199 int n_steps = ps.get<
int>(
"n_steps", NUM_TEST_SIM_HITS);
209 header.setDetectorName(
"ldmx-det-v15-8gev");
214 std::vector<ldmx::SimCalorimeterHit> pretend_sim_hits(1);
217 pretend_sim_hits[0].setID(
id.raw());
221 pretend_sim_hits[0].setPosition(0., 0., 299.);
224 REQUIRE_NOTHROW(event.add(
"EcalSimHits", pretend_sim_hits));
246 std::string ecal_simhits_passname_;
247 std::string ecal_digis_passname_;
248 std::string ecal_rechits_passname_;
249 std::string ecal_trig_digis_passname_;
250 bool check_trig_prim_;
260 check_trig_prim_ = parameters.get<
bool>(
"check_trig_prim",
true);
261 ecal_simhits_passname_ =
262 parameters.get<std::string>(
"ecal_simhits_passname",
"");
263 ecal_digis_passname_ =
264 parameters.get<std::string>(
"ecal_digis_passname",
"");
265 ecal_rechits_passname_ =
266 parameters.get<std::string>(
"ecal_rechits_passname",
"");
267 ecal_trig_digis_passname_ =
268 parameters.get<std::string>(
"ecal_trig_digis_passname",
"");
288 "EcalSimHits", ecal_simhits_passname_);
290 REQUIRE(sim_hits.size() == 1);
292 float truth_energy = sim_hits.at(0).getEdep();
296 "EcalDigis", ecal_digis_passname_)};
298 if (daq_digis.getNumDigis() == 1) {
299 auto daq_digi = daq_digis.getDigi(0);
301 bool is_in_adc_mode = daq_digi.isADC();
308 INFO(
"sim hit arrival time = " << sim_hits.at(0).getContrib(0).time_
310 INFO(
"digi is " << (is_in_adc_mode ?
"ADC" :
"TOT") <<
" mode");
313 "EcalRecHits", ecal_rechits_passname_);
314 CHECK(rec_hits.size() == 1);
317 if (rec_hits.size() != 1)
return;
319 auto hit = rec_hits.at(0);
321 CHECK_FALSE(hit.isNoise());
322 CHECK(
id.raw() == sim_hits.at(0).getID());
324 double daq_energy{hit.getAmplitude()};
325 CHECK_THAT(daq_energy,
IsCloseEnough(truth_energy, MAX_ENERGY_ERROR_DAQ,
326 MAX_ENERGY_PERCENT_ERROR_DAQ));
329 if (not check_trig_prim_)
return;
331 const auto trig_digis{
event.getObject<ldmx::HgcrocTrigDigiCollection>(
332 "ecalTrigDigis", ecal_trig_digis_passname_)};
333 CHECK(trig_digis.size() == 1);
335 auto trig_digi = trig_digis.at(0);
337 8 * trig_digi.linearPrimitive() * 320. / 1024 * MEV_PER_FC;
339 CHECK_THAT(tp_energy,
IsCloseEnough(truth_energy, MAX_ENERGY_ERROR_TP,
340 MAX_ENERGY_PERCENT_ERROR_TP));
342 ntuple_.
setVar<
int>(
"TrigPrimDigiEncoded", trig_digi.getPrimitive());
343 ntuple_.
setVar<
int>(
"TrigPrimDigiLinear", trig_digi.linearPrimitive());
369TEST_CASE(
"Ecal Digi Pipeline test",
"[Ecal][functionality]") {
370 const std::string config_file{
"ecal_digi_pipeline_test_config.py"};
371 char** args{
nullptr};
375 auto p{std::make_unique<framework::Process>(cfg)};
390TEST_CASE(
"Ecal Digi Pipeline out-of-time test",
"[Ecal][functionality]") {
391 const std::string config_file{
"ecal_digi_out_of_time_test_config.py"};
392 char** args{
nullptr};
396 auto p{std::make_unique<framework::Process>(cfg)};
Class that defines an ECal detector ID with a cell number.
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 represents a digitized hit in a calorimeter cell readout by an HGCROC.
Class which represents the process under execution.
Class which stores simulated calorimeter hit information.
void onProcessStart() final override
Callback for the EventProcessor to take any necessary action when the processing of events starts,...
void configure(framework::config::Parameters ¶meters) final 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.
double curr_time_
current arrival time of the sim hit we are on
double max_time_
last arrival time of the sim hit to make [ns]
void beforeNewRun(ldmx::RunHeader &header) final override
Callback for Producers to add parameters to the run header before conditions are initialized.
void produce(framework::Event &event) final override
Process the event and put new data products into it.
double curr_energy_
current energy of the sim hit we are on
void configure(framework::config::Parameters &ps) final override
Callback for the EventProcessor to configure itself from the given set of parameters.
double max_energy_
Maximum energy to make a simulated hit for [MeV].
double min_time_
first arrival time of the sim hit to make [ns]
double min_energy_
Minimum energy to make a sim hit for [MeV] Needs to be above readout threshold (after internal EcalDi...
double energy_step_
The step between energies (times) is calculated depending on the min, max energy (time) and the numbe...
Our custom energy checker which makes sure that the input energy is "close enough" to the truth energ...
IsCloseEnough(double const &truth, double const &abs_diff, double const &rel_diff)
Constructor.
virtual std::string describe() const override
Describes matcher for printing to terminal.
bool match(const double &daq_energy) const override
Performs the test for this matcher.
const double MAX_ABSOLUTE_DIFF
maximum absolute energy difference [MeV]
const double MAX_RELATIVE_DIFF
maximum relative energy difference
double truth_
correct (sim-level) energy [MeV]
Base class for a module which does not produce a data product.
NtupleManager & ntuple_
Manager for any ntuples.
TDirectory * getHistoDirectory()
Access/create a directory in the histogram file for this event processor to create histograms and ana...
Implements an event buffer system for storing event data.
void addVar(const std::string &tname, const std::string &vname)
Add a variable of type VarType to the ROOT tree with name 'tname'.
void create(const std::string &tname)
Create a ROOT tree to hold the ntuple variables (ROOT leaves).
void setVar(const std::string &vname, const T &value)
Set the value of the variable named 'vname'.
Class which represents the process under execution.
Base class for a module which produces a data product.
Producer(const std::string &name, Process &process)
Class constructor.
Class encapsulating parameters for configuring a processor.
Stores reconstructed hit information from the ECAL.
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Represents a collection of the digi hits readout by an HGCROC.
Stores simulated calorimeter hit information.
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.