Skip to content

Commit 612fd98

Browse files
authored
Add TS DQM for digi diagnostics, have energy of the hit deducted from PE instead of Sim info (#1825)
1 parent 36dfff6 commit 612fd98

File tree

6 files changed

+179
-25
lines changed

6 files changed

+179
-25
lines changed

.github/validation_samples/target_pn_lyso/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
dqm.TrigScintSimDQM('TargetSimHits','TargetSimHits','target'),
7676
dqm.TrigScintDigiDQM('TargetDigis','TargetDigis','target'),
7777
dqm.TrigScintClusterDQM('TargetClusters','TargetClusters','target'),
78+
dqm.TrigScintDigiVerifierDQM('TrigScintDigiVerifier','TargetSimHits','TargetDigis'),
7879
]
7980

8081

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef DQM_TSDIGIVERIFIER_H
2+
#define DQM_TSDIGIVERIFIER_H
3+
4+
#include <algorithm>
5+
6+
// LDMX Framework
7+
#include "DetDescr/TrigScintID.h"
8+
#include "Framework/Configure/Parameters.h"
9+
#include "Framework/EventProcessor.h"
10+
#include "SimCore/Event/SimCalorimeterHit.h"
11+
#include "TrigScint/Event/TrigScintHit.h"
12+
13+
namespace dqm {
14+
15+
/**
16+
* @class TrigScintDigiVerifier
17+
* @brief Generate histograms to check digi pipeline performance
18+
*/
19+
class TrigScintDigiVerifier : public framework::Analyzer {
20+
public:
21+
/**
22+
* Constructor
23+
*
24+
* Blank Analyzer constructor
25+
*/
26+
TrigScintDigiVerifier(const std::string& name, framework::Process& process)
27+
: framework::Analyzer(name, process) {}
28+
29+
/**
30+
* Input python configuration parameters
31+
*/
32+
virtual void configure(framework::config::Parameters& ps);
33+
34+
/**
35+
* Fills histograms
36+
*/
37+
virtual void analyze(const framework::Event& event);
38+
39+
private:
40+
/// Collection Name for SimHits
41+
std::string ts_simhit_coll_;
42+
43+
/// Pass Name for SimHits
44+
std::string ts_simhit_pass_;
45+
46+
/// Collection Name for digis
47+
std::string ts_digi_coll_;
48+
49+
/// Pass Name for digis
50+
std::string ts_digi_pass_;
51+
};
52+
} // namespace dqm
53+
54+
#endif /* DQM_TSDIGIVERIFIER_H */

DQM/python/dqm.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,24 @@ def __init__(self,name='TrigScintDigiUp',hit_coll='trigScintDigisUp',pad='up') :
904904
self.pad = pad
905905
self.trig_scint_passname = ''
906906

907+
class TrigScintDigiVerifierDQM(ldmxcfg.Analyzer) :
908+
def __init__(self, name = 'TrigScintDigiVerifier', ts_simhit_coll = 'TriggerPadUpSimHits', ts_digi_coll = 'trigScintDigisUp') :
909+
super().__init__(name,'dqm::TrigScintDigiVerifier','DQM')
910+
911+
self.ts_simhit_coll = ts_simhit_coll
912+
self.ts_simhit_pass = ''
913+
self.ts_digi_coll = ts_digi_coll
914+
self.ts_digi_pass = ''
915+
916+
self.build2DHistogram( "sim_edep:rec_amplitude" ,
917+
"Simulated Energy [MeV]" , 1000 , 0. , 50. ,
918+
"Reconstructed Amplitude [MeV]" , 1000 , 0. , 50. )
919+
920+
self.build2DHistogram( "sim_edep:rec_energy" ,
921+
"Simulated Energy [MeV]" , 1000 , 0. , 50. ,
922+
"Reconstructed Energy [MeV]" , 1000 , 0. , 50. )
923+
924+
907925
class TrigScintClusterDQM(ldmxcfg.Analyzer) :
908926
"""Configured TrigScintClusterDQM python object
909927
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include "DQM/TrigScintDigiVerifier.h"
2+
3+
namespace dqm {
4+
5+
void TrigScintDigiVerifier::configure(framework::config::Parameters &ps) {
6+
ts_simhit_coll_ = ps.get<std::string>("ts_simhit_coll");
7+
ts_simhit_pass_ = ps.get<std::string>("ts_simhit_pass");
8+
ts_digi_coll_ = ps.get<std::string>("ts_digi_coll");
9+
ts_digi_pass_ = ps.get<std::string>("ts_digi_pass");
10+
11+
return;
12+
}
13+
14+
void TrigScintDigiVerifier::analyze(const framework::Event &event) {
15+
// get truth information sorted into an ID based map
16+
auto ts_simhits = event.getCollection<ldmx::SimCalorimeterHit>(
17+
ts_simhit_coll_, ts_simhit_pass_);
18+
19+
// sort sim hits by ID
20+
std::sort(ts_simhits.begin(), ts_simhits.end(),
21+
[](const ldmx::SimCalorimeterHit &lhs,
22+
const ldmx::SimCalorimeterHit &rhs) {
23+
return lhs.getID() < rhs.getID();
24+
});
25+
26+
auto ts_digis{
27+
event.getCollection<ldmx::TrigScintHit>(ts_digi_coll_, ts_digi_pass_)};
28+
29+
// sort digi hits by ID
30+
std::sort(ts_digis.begin(), ts_digis.end(),
31+
[](const ldmx::TrigScintHit &lhs, const ldmx::TrigScintHit &rhs) {
32+
return lhs.getID() < rhs.getID();
33+
});
34+
35+
// Loop on the ts rechits
36+
ldmx_log(info) << "There are " << ts_digis.size()
37+
<< " ts digis in this event";
38+
for (const auto &ts_digi : ts_digis) {
39+
// skip anything that digi flagged as noise
40+
if (ts_digi.isNoise()) {
41+
ldmx_log(debug) << "Digi with raw ID " << ts_digi.getID()
42+
<< " and bar ID " << ts_digi.getBarID()
43+
<< " is flagged as noise, skipping";
44+
continue;
45+
}
46+
int raw_id = ts_digi.getID();
47+
ldmx_log(debug) << "Digi with raw ID " << raw_id << " and bar ID "
48+
<< ts_digi.getBarID() << " has energy "
49+
<< ts_digi.getEnergy() << " and amplitude "
50+
<< ts_digi.getAmplitude();
51+
52+
// get information for this hit
53+
54+
double total_sim_energy_dep = 0.;
55+
for (const auto &ts_simhit : ts_simhits) {
56+
if (raw_id == ts_simhit.getID()) {
57+
total_sim_energy_dep += ts_simhit.getEdep();
58+
} else if (raw_id < ts_simhit.getID()) {
59+
// later sim hits - all done
60+
break;
61+
}
62+
}
63+
64+
ldmx_log(info) << " There are " << ts_simhits.size()
65+
<< " sim hits in this event, adding up to a total energy of "
66+
<< total_sim_energy_dep;
67+
68+
histograms_.fill("sim_edep:rec_amplitude", total_sim_energy_dep,
69+
ts_digi.getAmplitude());
70+
histograms_.fill("sim_edep:rec_energy", total_sim_energy_dep,
71+
ts_digi.getEnergy());
72+
} // end of loop on ts digis
73+
74+
return;
75+
}
76+
77+
} // namespace dqm
78+
79+
DECLARE_ANALYZER(dqm::TrigScintDigiVerifier);

TrigScint/python/trigScint.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ def __init__(self,name) :
2727
self.input_collection="TriggerPad3SimHits"
2828
self.input_pass_name="" #take any pass
2929
self.output_collection="trigScintDigisPad3"
30-
import time
31-
self.randomSeed = int(time.time())
32-
self.verbose = False
3330

3431
self.sim_particles_passname = ""
3532

@@ -59,6 +56,8 @@ def target() :
5956
digi = TrigScintDigiProducer( 'TargetDigis' )
6057
digi.input_collection = 'TargetSimHits'
6158
digi.output_collection= 'TargetDigis'
59+
digi.mev_per_mip = 1.
60+
digi.pe_per_mip = 300.
6261
return digi
6362

6463

TrigScint/src/TrigScint/TrigScintDigiProducer.cxx

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,17 @@ TrigScintDigiProducer::TrigScintDigiProducer(const std::string &name,
66
framework::Process &process)
77
: Producer(name, process) {}
88

9-
void TrigScintDigiProducer::configure(
10-
framework::config::Parameters &parameters) {
9+
void TrigScintDigiProducer::configure(framework::config::Parameters &ps) {
1110
// Configure this instance of the producer
12-
strips_per_array_ = parameters.get<int>("number_of_strips");
13-
number_of_arrays_ = parameters.get<int>("number_of_arrays");
14-
mean_noise_ = parameters.get<double>("mean_noise");
15-
mev_per_mip_ = parameters.get<double>("mev_per_mip");
16-
pe_per_mip_ = parameters.get<double>("pe_per_mip");
17-
input_collection_ = parameters.get<std::string>("input_collection");
18-
input_pass_name_ = parameters.get<std::string>("input_pass_name");
19-
output_collection_ = parameters.get<std::string>("output_collection");
20-
sim_particles_passname_ =
21-
parameters.get<std::string>("sim_particles_passname");
11+
strips_per_array_ = ps.get<int>("number_of_strips");
12+
number_of_arrays_ = ps.get<int>("number_of_arrays");
13+
mean_noise_ = ps.get<double>("mean_noise");
14+
mev_per_mip_ = ps.get<double>("mev_per_mip");
15+
pe_per_mip_ = ps.get<double>("pe_per_mip");
16+
input_collection_ = ps.get<std::string>("input_collection");
17+
input_pass_name_ = ps.get<std::string>("input_pass_name");
18+
output_collection_ = ps.get<std::string>("output_collection");
19+
sim_particles_passname_ = ps.get<std::string>("sim_particles_passname");
2220
}
2321

2422
void TrigScintDigiProducer::onNewRun(const ldmx::RunHeader &) {
@@ -46,7 +44,7 @@ ldmx::TrigScintID TrigScintDigiProducer::generateRandomID(int module) {
4644
}
4745

4846
void TrigScintDigiProducer::produce(framework::Event &event) {
49-
std::map<ldmx::TrigScintID, int> cell_p_es, cell_min_p_es;
47+
std::map<ldmx::TrigScintID, int> cell_pes, cell_min_p_es;
5048
std::map<ldmx::TrigScintID, float> xpos, ypos, zpos, edep, time, beam_frac;
5149
std::set<ldmx::TrigScintID> noise_hit_i_ds;
5250

@@ -73,7 +71,7 @@ void TrigScintDigiProducer::produce(framework::Event &event) {
7371
for (int i = 0; i < sim_hit.getNumberOfContribs(); i++) {
7472
auto contrib = sim_hit.getContrib(i);
7573

76-
ldmx_log(trace) << "contrib " << i << " trackID: " << contrib.trackID
74+
ldmx_log(trace) << "Contrib " << i << " trackID: " << contrib.trackID
7775
<< " pdgID: " << contrib.pdgCode
7876
<< " edep: " << contrib.edep;
7977
ldmx_log(trace) << "\t particle id: "
@@ -128,21 +126,26 @@ void TrigScintDigiProducer::produce(framework::Event &event) {
128126
xpos[id] = xpos[id] / edep[id];
129127
ypos[id] = ypos[id] / edep[id];
130128
zpos[id] = zpos[id] / edep[id];
129+
// mean number of photoelectrons produced for the given deposited energy
131130
double mean_pe = dep_energy / mev_per_mip_ * pe_per_mip_;
132131
std::poisson_distribution<int> poisson_dist(mean_pe + mean_noise_);
133-
cell_p_es[id] = poisson_dist(rng_);
132+
cell_pes[id] = poisson_dist(rng_);
133+
// energy corresponding to the number of PEs observed
134+
// the minimum number of PEs is the mean number of PEs minus the noise
135+
double energy_per_pe = mev_per_mip_ / pe_per_mip_;
136+
double cell_energy = energy_per_pe * cell_pes[id];
134137

135138
// If a cell has a PE count above threshold, persit the hit.
136139
// Thresholds are introduced (and configurable) in clustering.
137140
// the cell PE >=1 suppresses artifical noise that is below one light
138141
// quantum in the SiPM and unphysical.
139-
if (cell_p_es[id] >= 1) {
142+
if (cell_pes[id] >= 1) {
140143
ldmx::TrigScintHit hit;
141144
hit.setID(id.raw());
142-
hit.setPE(cell_p_es[id]);
145+
hit.setPE(cell_pes[id]);
143146
hit.setMinPE(cell_min_p_es[id]);
144-
hit.setAmplitude(cell_p_es[id]);
145-
hit.setEnergy(dep_energy);
147+
hit.setAmplitude(cell_pes[id]);
148+
hit.setEnergy(cell_energy);
146149
hit.setTime(time[id]);
147150
hit.setXPos(xpos[id]);
148151
hit.setYPos(ypos[id]);
@@ -155,11 +158,11 @@ void TrigScintDigiProducer::produce(framework::Event &event) {
155158
trig_scint_hits.push_back(hit);
156159
}
157160

158-
ldmx_log(trace) << " ID = " << id.raw() << " Edep: " << edep[id]
159-
<< " numPEs: " << cell_p_es[id] << " time: " << time[id]
161+
ldmx_log(debug) << " ID = " << id.raw() << " Edep: " << edep[id]
162+
<< " numPEs: " << cell_pes[id] << " time: " << time[id]
160163
<< " z: " << zpos[id] << "\t X: " << xpos[id]
161164
<< " Y: " << ypos[id] << " Z: " << zpos[id];
162-
}
165+
} // end of loop over detIDs
163166

164167
// ------------------------------- Noise simulation -----------------------//
165168
// ------------------------------------------------------------------------//

0 commit comments

Comments
 (0)