LDMX Software
OverlayProducer.cxx
1#include "Recon/OverlayProducer.h"
2
3namespace recon {
4
6 params_ = parameters;
7
8 // name of file containing events to be overlaid, and a list of collections to
9 // overlay
10 overlay_filename_ = parameters.get<std::string>("overlay_filename");
12 parameters.get<std::vector<std::string>>("calo_collections");
14 parameters.get<std::vector<std::string>>("tracker_collections");
16 parameters.get<std::vector<std::string>>("contrib_collections");
17 sim_passname_ = parameters.get<std::string>("sim_passname");
18 overlay_passname_ = parameters.get<std::string>("overlay_passname");
19 out_coll_postfix_ = parameters.get<std::string>("out_coll_postfix");
20 // overlay specifics:
21 poisson_mu_ = parameters.get<double>("poisson_mu");
22 do_poisson_in_time_ = parameters.get<bool>("do_poisson_in_time");
23 do_poisson_out_of_time_ = parameters.get<bool>("do_poisson_out_of_time");
24 time_sigma_ = parameters.get<double>("time_sigma");
25 time_mean_ = parameters.get<double>("time_mean");
26 n_earlier_ = parameters.get<int>("n_earlier");
27 n_later_ = parameters.get<int>("n_later");
28 bunch_spacing_ = parameters.get<double>("bunch_spacing");
29 start_event_min_ = parameters.get<int>("start_event_min");
30 start_event_max_ = parameters.get<int>("start_event_max");
31
33 ldmx_log(debug) << "Got parameters \n \t overlayFileName = "
35 << "\n\t sim pass name = " << sim_passname_
36 << "\n\t overlay pass name = " << overlay_passname_;
37 ldmx_log(debug) << "\n\t overlayCaloHitCollections = ";
38 for (const auto &coll : calo_collections_) {
39 ldmx_log(debug) << coll << "; ";
40 }
41
42 ldmx_log(debug) << "\n\t overlayTrackerHitCollections = ";
43 for (const std::string &coll : tracker_collections_) {
44 ldmx_log(debug) << coll << "; ";
45 }
46
47 ldmx_log(trace) << "\n\t numberOverlaidInteractions = " << poisson_mu_
48 << "\n\t nEarlierBunchesToSample = " << n_earlier_
49 << "\n\t nLaterBunchesToSample = " << n_later_
50 << "\n\t bunchSpacing = " << bunch_spacing_
51 << "\n\t doPoissonIntime = " << do_poisson_in_time_
52 << "\n\t doPoissonOutoftime = " << do_poisson_out_of_time_
53 << "\n\t timeSpread = " << time_sigma_
54 << "\n\t timeMean = " << time_mean_
55 << "\n\t startEventMin = " << start_event_min_
56 << "\n\t startEventMax = " << start_event_max_;
57
58 // given how the contrib collection specification is setup, it's possible for
59 // spelling errors to cause doom here, so we want to flag those
60 for (auto coll_name : contrib_collections_) {
61 if (std::find(calo_collections_.begin(), calo_collections_.end(),
62 coll_name) == calo_collections_.end()) {
63 EXCEPTION_RAISE("CollNameMismatch",
64 "The contrib-using collection " + coll_name +
65 " does not match any SimCalorimeterHit collection in "
66 "'calo_collections_'! Please check your spelling");
67 }
68 }
69
70 return;
71} // end configure()
72
77 rndm_ = std::make_unique<TRandom2>(rnss.getSeed("OverlayProducer::rndm"));
79 std::make_unique<TRandom2>(rnss.getSeed("OverlayProducer::rndmTime"));
80
81 // Pick a random event from the Pileup file
82 int start_event = rndm_->Uniform(start_event_min_, start_event_max_);
83 // EventFile::skipToEvent handles actual number of events in file
84 int ev_number = overlay_file_->skipToEvent(start_event);
85 if (ev_number < 0) {
86 EXCEPTION_RAISE("BadRead", "Couldn't read to starting offset.");
87 }
89 ldmx_log(info) << "Starting overlay process with pileup event number "
90 << ev_number << " (random event number picked was "
91 << start_event << ").";
92} // end onNewRun()
93
95 // using nextEvent to loop, we need to loop over overlay events and in an
96 // inner loop, loop over collections, and store them. after all pileup events
97 // have been added, the vector of collections is iterated over and added to
98 // the event bus.
99 std::map<std::string, std::vector<ldmx::SimCalorimeterHit>>
100 calo_collection_map;
101 std::map<std::string, std::vector<ldmx::SimTrackerHit>>
102 tracker_collection_map;
103 std::map<std::string, std::map<int, ldmx::SimCalorimeterHit>> hit_map;
104
105 // start by copying over all the collections from the sim event
106
107 /* ----------- first do the SimCalorimeterHits ----------- */
108
109 // get the calo hits_ collections that we want to overlay, by looping over
110 // the list of collections passed to the producer : calo_collections_
111 for (const auto &coll_name : calo_collections_) {
112 // search for the collection name in the list of collections that
113 // need contribs to be added, contrib_collections_
114 bool needs_contribs_added{std::find(contrib_collections_.begin(),
116 coll_name) != contrib_collections_.end()
117 ? true
118 : false};
119
120 // start out by just copying the sim hits, unaltered.
121 auto simhits_calo =
122 event.getCollection<ldmx::SimCalorimeterHit>(coll_name, sim_passname_);
123 // but don't copy contrib using hits immediately: for them, wait until
124 // overlay contribs have been added. then add everything through the hit_map
125 if (!needs_contribs_added) {
126 calo_collection_map[coll_name + out_coll_postfix_] = simhits_calo;
127 }
128
129 ldmx_log(debug) << "in loop: start of collection " << coll_name
130 << "in loop: printing current sim event: ";
131 ldmx_log(debug) << "in loop: size of sim hits_ vector " << coll_name
132 << " is " << simhits_calo.size();
133
134 // we don't need to touch the hard process sim hits_, really... but we
135 // might need the simhits in the hit map.
136 if (needs_contribs_added) {
137 ldmx_log(trace) << "Collection " << coll_name << " needs contribs added";
138 for (const ldmx::SimCalorimeterHit &simhit : simhits_calo) {
139 ldmx_log(trace) << simhit;
140 // this copies the hit, its ID and its coordinates directly
141 hit_map[coll_name + out_coll_postfix_][simhit.getID()] = simhit;
142
143 } // over calo simhit collection
144 } // if needContribs
145
146 } // over calo collections for sim event
147
148 /* ----------- then do the same with SimTrackerHits! ----------- */
149
150 // get the SimTrackerHit collections that we want to overlay, by looping
151 // over the list of collections passed to the producer : tracker_collections_
152 for (const auto &coll_name : tracker_collections_) {
153 auto simhits_tracker =
154 event.getCollection<ldmx::SimTrackerHit>(coll_name, sim_passname_);
155 tracker_collection_map[coll_name + out_coll_postfix_] = simhits_tracker;
156
157 // the rest is printouts for debugging
158 ldmx_log(debug) << "in loop: size of sim hits_ vector " << coll_name
159 << " is " << simhits_tracker.size();
160
161 ldmx_log(debug) << "in loop: start of collection " << coll_name
162 << "in loop: printing current sim event: ";
163
164 for (const ldmx::SimTrackerHit &simhit : simhits_tracker) {
165 ldmx_log(trace) << simhit;
166 }
167 } // over tracker collections for sim event
168
169 /* ----------- now do the pileup overlay ----------- */
170
171 // we could shift these by a random number, effectively placing the
172 // sim event at random positions in the interval, preserving the
173 // overall interval length
174 // int simBunch= static_cast<int>(rndm_time_->Uniform(
175 // -(n_earlier_+1) , n_later_+1)); // +1 to get
176 // inclusive interval
177 int start_bunch = -n_earlier_;
178 int end_bunch = n_later_;
179
180 // TODO -- figure out if we should also randomly shift the time of the sim
181 // event (likely only needed if time bias gets picked up by BDT or ML by way
182 // of pulse behaviour)
183 for (int bunch_offset{start_bunch}; bunch_offset <= end_bunch;
184 bunch_offset++) {
185 // sample a poisson distribution, or use mu as fixed number of overlay
186 // events
187 int n_events_overlay = do_poisson_out_of_time_
188 ? rndm_->Poisson(poisson_mu_)
189 : static_cast<int>(poisson_mu_);
190
191 // special case: in-time pileup at bunch 0
192 if (bunch_offset == 0) {
193 if (!do_poisson_in_time_) {
194 // fix it to the average
195 n_events_overlay = static_cast<int>(poisson_mu_);
197 // then we haven't set this yet
198 n_events_overlay = rndm_->Poisson(poisson_mu_);
199 }
200
201 // paticularly useful in the poisson fluctuated case
202 event.getEventHeader().setIntParameter("in_time_pu", n_events_overlay);
203
204 // the total number of events is nPU + 1 (it includes the sim event)
205 // in any case, subtract the sim event from nOverlay
206 n_events_overlay -= 1;
207
208 } // end if bunch_offset == 0
209
210 float bunchtime_offset = bunch_spacing_ * bunch_offset;
211 ldmx_log(debug) << "Will overlay " << n_events_overlay
212 << " events on the simulated one";
213
214 for (int i_ev = 0; i_ev < n_events_overlay; i_ev++) {
221 if (!overlay_file_->nextEvent()) {
222 ldmx_log(error) << "Couldn't read next overlay event!";
223 return;
224 }
225
226 // a pileup event wide time offset to be applied to all its hits_.
227 float time_offset = rndm_time_->Gaus(time_mean_, time_sigma_);
228 time_offset += bunchtime_offset;
229
230 ldmx_log(trace) << "in overlay loop: overlaying event " << "which is "
231 << i_ev + 1 << " out of " << n_events_overlay
232 << "\n\thit time offset is " << time_offset << " ns"
233 << "\n\tbunch position offset is " << bunch_offset
234 << ", leading to a total time offset of "
235 << bunchtime_offset << " ns";
236
237 /* ----------- first do the SimCalorimeterHits overlay ----------- */
238
239 // again get the calo hits_ collections that we want to overlay
240 for (uint i_coll = 0; i_coll < calo_collections_.size(); i_coll++) {
241 // search for the collection name in the list of collections that
242 // need contribs to be added, contrib_collections_
243 bool needs_contribs_added{
244 std::find(contrib_collections_.begin(), contrib_collections_.end(),
246 ? true
247 : false};
248
249 std::vector<ldmx::SimCalorimeterHit> overlay_hits =
252
253 ldmx_log(debug) << "in loop: size of overlay hits_ vector is "
254 << overlay_hits.size();
255
256 std::string out_coll_name =
258
259 ldmx_log(trace) << "in loop: printing overlay event: ";
260
261 for (ldmx::SimCalorimeterHit &overlay_hit : overlay_hits) {
262 ldmx_log(trace) << overlay_hit;
263
264 const float overlay_time = overlay_hit.getTime() + time_offset;
265 overlay_hit.setTime(overlay_time);
266
267 if (needs_contribs_added) { // special treatment for (for now only)
268 // ecal
269 auto &this_coll_hit_map{
270 hit_map[calo_collections_[i_coll] + out_coll_postfix_]};
271 int overlay_hit_id = overlay_hit.getID();
272 if (this_coll_hit_map.find(overlay_hit_id) ==
273 this_coll_hit_map
274 .end()) { // there wasn't already a simhit in this id
275 this_coll_hit_map[overlay_hit_id] = ldmx::SimCalorimeterHit();
276 this_coll_hit_map[overlay_hit_id].setID(overlay_hit_id);
277 std::vector<float> hit_pos = overlay_hit.getPosition();
278 this_coll_hit_map[overlay_hit_id].setPosition(
279 hit_pos[0], hit_pos[1], hit_pos[2]);
280 }
281 // add the overlay hit (as a) contrib
282 // incidentID = -1000, trackID = -1000, pdgCode = 0 <-- these are
283 // set in the header for now but could be parameters
284 this_coll_hit_map[overlay_hit_id].addContrib(
285 overlay_incident_id_, overlay_track_id_, overlay_pdg_code_,
286 overlay_hit.getEdep(), overlay_time);
287 } // if add overlay as contribs
288 else {
289 calo_collection_map[out_coll_name].push_back(overlay_hit);
290
291 ldmx_log(trace) << "Adding non-Ecal overlay hit to outhit vector "
292 << out_coll_name;
293 } // end else !needs_contribs_added
294 } // over overlay calo simhit collection
295
296 if (!needs_contribs_added)
297 ldmx_log(debug) << "Nhits in overlay collection " << out_coll_name
298 << ": " << calo_collection_map[out_coll_name].size();
299
300 } // over calo_collections_
301
302 /* ----------- now do simtracker hits_ overlay ----------- */
303
304 // get the SimTrackerHit collections that we want to overlay
305 for (const auto &coll : tracker_collections_) {
306 auto overlay_tracker_hits{
308 coll, overlay_passname_)};
309
310 ldmx_log(debug) << "in loop: size of overlay hits_ vector is "
311 << overlay_tracker_hits.size();
312
313 std::string out_coll_name_tracker{coll + out_coll_postfix_};
314
315 ldmx_log(trace) << "in loop: printing overlay event: ";
316
317 for (auto &overlay_hit : overlay_tracker_hits) {
318 auto overlay_time{overlay_hit.getTime() + time_offset};
319 overlay_hit.setTime(overlay_time);
320 auto overlay_track_id{overlay_hit.getTrackID()};
321 overlay_hit.setTrackID(overlay_track_id);
322 tracker_collection_map[out_coll_name_tracker].push_back(overlay_hit);
323
324 ldmx_log(trace) << overlay_hit;
325 ldmx_log(trace) << "Adding tracker overlay hit to outhit vector "
326 << out_coll_name_tracker;
327 } // over overlay tracker simhit collection
328
329 ldmx_log(debug) << "Nhits in overlay collection "
330 << out_coll_name_tracker << ": "
331 << tracker_collection_map[out_coll_name_tracker].size();
332
333 } // over tracker_collections_
334
335 } // over overlay events
336 } // over bunches
337
338 // after all events are done, the contrib-using collections' hit_maps are
339 // final and can be written to the event output
340 for (uint i_coll = 0; i_coll < contrib_collections_.size(); i_coll++) {
341 // for each SimCalorimeterHit collection that uses contribs, add overlaid
342 // hits_ as contribs/from hit_map rather than as copied simhits
343 ldmx_log(trace) << "Hits in hit_map after overlay of "
344 << contrib_collections_[i_coll] << "Overlay :";
345
346 for (auto &map_hit :
347 hit_map[contrib_collections_[i_coll] + out_coll_postfix_]) {
348 ldmx_log(trace) << map_hit.second;
349
350 if (calo_collection_map.find(contrib_collections_[i_coll] +
352 calo_collection_map.end()) {
353 ldmx_log(debug) << "Adding first hit from hit map as first outhit "
354 "vector to calo_collection_map";
355 calo_collection_map[contrib_collections_[i_coll] + out_coll_postfix_] =
356 {map_hit.second};
357 } else {
358 calo_collection_map[contrib_collections_[i_coll] + out_coll_postfix_]
359 .push_back(map_hit.second);
360 }
361 } // over hit_map
362 } // second loop over contrib using collections, to collect hits_ from
363 // hit_map
364
365 // done collecting hits_.
366
367 // now we can write the calo collections to the event bus
368 for (auto &[name, coll] : calo_collection_map) {
369 ldmx_log(debug) << "Writing " << name << " to event bus.";
370
371 ldmx_log(trace) << "List of hits_ added: ";
372 for (auto &hit : coll) {
373 ldmx_log(trace) << hit;
374 }
375 event.add(name, coll);
376 }
377
378 // and now for the tracker hits_
379 for (auto &[name, coll] : tracker_collection_map) {
380 ldmx_log(debug) << "Writing " << name << " to event bus.";
381 ldmx_log(trace) << "List of hits_ added: ";
382 for (auto &hit : coll) {
383 ldmx_log(trace) << hit;
384 }
385 event.add(name, coll);
386 }
387
388 return;
389} // end produce()
390
392 // replace by this line once the corresponding tweak to EventFile is ready:
394 std::make_unique<framework::EventFile>(params_, overlay_filename_, true);
395 overlay_file_->setupEvent(&overlay_event_);
396 // we update the iterator at the end of each event. so do this once here to
397 // grab the first event in the processor
398 // ldmx_log(trace) << "Used input file: "
399 // << overlay_file_->getFileName() << " Got event info: " <<
400 // overlay_file_->getEvent()->Print();
401
402 return;
403} // end onProcessStart
404
405} // namespace recon
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
Implements an event buffer system for storing event data.
Definition Event.h:42
ldmx::EventHeader & getEventHeader()
Get the event header.
Definition Event.h:59
const std::vector< ContentType > & getCollection(const std::string &collectionName, const std::string &passName) const
Get a collection (std::vector) of objects from the event bus.
Definition Event.h:400
static const std::string CONDITIONS_OBJECT_NAME
Conditions object name.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
void setEventNumber(int eventNumber)
Set the event number.
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:57
Stores simulated calorimeter hit information.
Represents a simulated tracker hit in the simulation.
Class to overlay in-time pile-up events from an overlay file.
int start_event_max_
Maximum event number to start overlaying from.
std::string overlay_filename_
Pileup overlay events input file name.
std::unique_ptr< framework::EventFile > overlay_file_
Pileup overlay events input file.
bool do_poisson_in_time_
Let the total number of in-time events be poisson distributed, or fix at the chosen value,...
int n_later_
Number of bunches after the sim event to pull pileup events from.
std::string overlay_passname_
Pileup overlay events input pass name.
bool do_poisson_out_of_time_
Let the total number of out-of-time events be poisson distributed, or fix at the chosen value,...
void onNewRun(const ldmx::RunHeader &) override
At the start of the run, the pileup overlay file is set up, and the starting event number is chosen,...
std::vector< std::string > tracker_collections_
List of SimTrackerHit collection(s) to loop over and add hits from, combining sim and pileup.
framework::config::Parameters params_
The parameters used to configure this producer.
std::vector< std::string > contrib_collections_
List of SimCalorimeterHit collections which keep track of hit contribs.
double bunch_spacing_
Spacing in time (in [ns]) between electron bunches.
std::string sim_passname_
To use for finding the sim event bus passengers, mostly a disambiguation.
std::vector< std::string > calo_collections_
List of SimCalorimeterHit collection(s) to loop over and add hits from, combining sim and pileup.
std::unique_ptr< TRandom2 > rndm_time_
Random number generator for pileup event time offset.
std::unique_ptr< TRandom2 > rndm_
Random number generator for number of overlaid events.
void produce(framework::Event &event) override
Based on the list of collections to overlay, and the desired number of events, loop through all relev...
double poisson_mu_
(average) total number of events
void configure(framework::config::Parameters &parameters) override
Configure the processor with input parameters from the python cofig.
std::string out_coll_postfix_
Postfix to add to the collection name of the overlayed collections.
void onProcessStart() override
At the start of processing, the pileup overlay file is set up.
int overlay_incident_id_
For Ecal, overlay hits should be added as contribs.
double time_sigma_
Width of pileup bunch spread in time (in [ns]), specified as a sigma of a Gaussian distribution.
int start_event_min_
Minimum event number to start overlaying from.
framework::Event overlay_event_
The overlay ldmx event bus.
double time_mean_
Average position in time (in [ns]) of pileup bunches, relative to the sim event.
int n_earlier_
Number of bunches before the sim event to pull pileup events from.