|
23 | 23 | #include <stdexcept> |
24 | 24 | #include <tuple> |
25 | 25 | #include <unordered_map> |
| 26 | +#include <map> |
26 | 27 | #include <variant> |
27 | 28 | #include <vector> |
28 | 29 |
|
@@ -166,18 +167,18 @@ void SimCalorimeterHitProcessor::process(const SimCalorimeterHitProcessor::Input |
166 | 167 | auto [out_hits, out_hit_contribs] = output; |
167 | 168 |
|
168 | 169 | // Map for staging output information. We have 2 levels of structure: |
169 | | - // - top level: (MCParticle, Merged Hit CellID) |
| 170 | + // - top level: (MCParticle, Merged Hit CellID, TimeID) |
170 | 171 | // - second level: (Merged Contributions) |
| 172 | + // We use std::map instead of std::unordered_map to ensure deterministic ordering |
| 173 | + // and reproducible results between single-threaded and multi-threaded execution. |
171 | 174 | // Ideally we would want immediately create our output objects and modify the |
172 | 175 | // contributions when needed. That could reduce the following code to a single loop |
173 | 176 | // (instead of 2 consecutive loops). However, this is not possible as we may have to merge |
174 | 177 | // (hence modify) contributions which is not supported for PodIO VectorMembers. Using |
175 | 178 | // reasonable contribution merging, at least the intermediary structure should be |
176 | 179 | // quite a bit smaller than the original hit collection. |
177 | 180 | using HitIndex = std::tuple<edm4hep::MCParticle, uint64_t /* cellID */, int /* timeID */>; |
178 | | - std::unordered_map<HitIndex, |
179 | | - std::unordered_map<uint64_t /* cellID */, HitContributionAccumulator>> |
180 | | - hit_map; |
| 181 | + std::map<HitIndex, std::map<uint64_t /* cellID */, HitContributionAccumulator>> hit_map; |
181 | 182 |
|
182 | 183 | for (const auto& ih : *in_hits) { |
183 | 184 | // the cell ID of the new superhit we are making |
|
0 commit comments