Project
Loading...
Searching...
No Matches
testSimulation.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#define BOOST_TEST_MODULE midSimulation
13#define BOOST_TEST_DYN_LINK
14#include <boost/test/unit_test.hpp>
15
16#include <boost/test/data/test_case.hpp>
17#include <sstream>
18#include "MathUtils/Cartesian.h"
23#include "MIDBase/HitFinder.h"
24#include "MIDBase/Mapping.h"
30#include "MIDSimulation/Hit.h"
36#include "MIDTracking/Tracker.h"
38
39namespace o2
40{
41namespace mid
42{
43
44std::vector<ColumnData> getColumnDataNonMC(const o2::mid::DigitsMerger& dm)
45{
46 std::vector<ColumnData> v;
47 auto ref = dm.getColumnData();
48 v.insert(v.begin(), ref.begin(), ref.end());
49 return v;
50}
51
62
68
69static SimBase simBase;
70
78
79static SimDigitizer simDigitizer;
80
94
95static SimClustering simClustering;
96
102 SimTracking() : tracker(simBase.geoTrans), trackGen(), hitFinder(simBase.geoTrans), trackLabeler()
103 {
104 trackGen.setSeed(123456789);
105 tracker.init(true);
106 }
107};
108
109static SimTracking simTracking;
110
111struct GenTrack {
113 std::vector<Hit> hits;
115 bool isReconstructible() { return nFiredChambers > 2; }
116};
117
118std::vector<Hit> generateHits(size_t nHits, int deId, const Mapping& mapping, const GeometryTransformer geoTrans)
119{
120 std::vector<Hit> hits;
121 std::random_device rd;
122 std::mt19937 mt(rd());
123 std::uniform_real_distribution<double> distX(-127.5, 127.5);
124 std::uniform_real_distribution<double> distY(-40., 40.);
125 while (hits.size() < nHits) {
127 if (!mapping.stripByPosition(point.x(), point.y(), 0, deId, false).isValid()) {
128 continue;
129 }
130 math_utils::Point3D<float> globalPoint = geoTrans.localToGlobal(deId, point);
131 hits.emplace_back(hits.size(), deId, globalPoint, globalPoint);
132 }
133 return hits;
134}
135
136std::vector<size_t> getCompatibleGenTrackIds(size_t igen, const std::vector<GenTrack>& genTracks)
137{
138 // Two generated tracks are indistinguishable in reconstruction if:
139 // - they cross the same strip in all chamber planes
140 // - they cross neighbour strips in all chamber planes
141 // The first case is evident.
142 // The second happens because the digits of the tracks will form a unique cluster.
143 // The maximum strip pitch is 4 cm. So, to simplify,
144 // we consider that the tracks will have digits in the same cluster
145 // if the distance of their hits is smaller than twice the maximum strip pitch.
146 std::vector<size_t> ids;
147 auto& refHits = genTracks[igen].hits;
148 for (auto itr = 0; itr < genTracks.size(); ++itr) {
149 if (itr == igen) {
150 ids.emplace_back(itr);
151 continue;
152 }
153 auto& hits = genTracks[itr].hits;
154 if (hits.size() == refHits.size()) {
155 size_t nSame = 0;
156 for (auto ihit = 0; ihit < refHits.size(); ++ihit) {
157 if (hits[ihit].GetDetectorID() == refHits[ihit].GetDetectorID() && std::abs(hits[ihit].GetX() - refHits[ihit].GetX()) < 8. && std::abs(hits[ihit].GetY() - refHits[ihit].GetY()) < 8.) {
158 ++nSame;
159 } else {
160 break;
161 }
162 }
163 if (nSame == refHits.size()) {
164 ids.emplace_back(itr);
165 }
166 }
167 }
168 return ids;
169}
170
171std::vector<GenTrack> generateTracks(int nTracks)
172{
173 auto tracks = simTracking.trackGen.generate(nTracks);
174 std::vector<GenTrack> genTracks;
175 for (auto trackIt = tracks.begin(), end = tracks.end(); trackIt != end; ++trackIt) {
176 auto trackId = std::distance(tracks.begin(), trackIt);
177 GenTrack genTrack;
178 genTrack.track = *trackIt;
179 for (int ich = 0; ich < 4; ++ich) {
180 auto clusters = simTracking.hitFinder.getLocalPositions(*trackIt, ich);
181 bool isFired = false;
182 for (auto& cl : clusters) {
183 auto stripIndex = simBase.mapping.stripByPosition(cl.xCoor, cl.yCoor, 0, cl.deId, false);
184 if (!stripIndex.isValid()) {
185 continue;
186 }
187 auto pos = simBase.geoTrans.localToGlobal(cl.deId, cl.xCoor, cl.yCoor);
188 genTrack.hits.emplace_back(trackId, cl.deId, pos, pos);
189 isFired = true;
190 }
191 if (isFired) {
192 ++genTrack.nFiredChambers;
193 }
194 }
195 genTracks.emplace_back(genTrack);
196 }
197 return genTracks;
198}
199
200bool checkLabel(const ColumnData& digit, MCLabel& label, std::string& errorMessage)
201{
202 std::stringstream ss;
203 ss << digit << "\n";
204 bool isOk = true;
205 if (label.getDEId() != digit.deId) {
206 isOk = false;
207 ss << "label deId " << label.getDEId() << " != " << digit.deId << "\n";
208 }
209 if (label.getColumnId() != digit.columnId) {
210 isOk = false;
211 ss << "label columnId " << label.getColumnId() << " != " << digit.columnId << "\n";
212 }
213 int firstStrip = label.getFirstStrip();
214 int lastStrip = label.getLastStrip();
215 int cathode = label.getCathode();
216 int nLines = (cathode == 0) ? 4 : 1;
217 for (int iline = 0; iline < nLines; ++iline) {
218 for (int istrip = 0; istrip < 16; ++istrip) {
219 int currStrip = MCLabel::getStrip(istrip, iline);
220 bool isFired = digit.isStripFired(istrip, cathode, iline);
221 if (isFired != (currStrip >= firstStrip && currStrip <= lastStrip)) {
222 isOk = false;
223 ss << "Cathode: " << cathode << " firstStrip: " << firstStrip << " lastStrip: " << lastStrip;
224 ss << " line: " << iline << " strip: " << istrip << " fired: " << isFired << "\n";
225 }
226 }
227 }
228 errorMessage = ss.str();
229 return isOk;
230}
231
232std::vector<PreCluster> getRelatedPreClusters(const Hit& hit, int cathode, const std::vector<PreCluster>& preClusters, const o2::dataformats::MCTruthContainer<MCCompLabel>& labels, const ROFRecord& rofRecord)
233{
234 std::vector<PreCluster> sortedPC;
235 for (size_t ipc = rofRecord.firstEntry; ipc < rofRecord.firstEntry + rofRecord.nEntries; ++ipc) {
236 for (auto& label : labels.getLabels(ipc)) {
237 if (label.getTrackID() == hit.GetTrackID() && preClusters[ipc].cathode == cathode) {
238 sortedPC.emplace_back(preClusters[ipc]);
239 }
240 }
241 }
242 std::sort(sortedPC.begin(), sortedPC.end(), [](const PreCluster& pc1, const PreCluster& pc2) { return (pc1.firstColumn <= pc2.firstColumn); });
243 return sortedPC;
244}
245
246bool isContiguous(const std::vector<PreCluster>& sortedPC)
247{
248 int lastColumn = sortedPC.front().firstColumn;
249 for (auto it = sortedPC.begin() + 1; it != sortedPC.end(); ++it) {
250 if (it->firstColumn - (it - 1)->firstColumn != 1) {
251 return false;
252 }
253 }
254 return true;
255}
256
257bool isInside(double localX, double localY, const std::vector<PreCluster>& sortedPC, std::string& errorMsg)
258{
259 std::stringstream ss;
260 ss << "Point: (" << localX << ", " << localY << ") outside PC:";
261 for (auto& pc : sortedPC) {
262 MpArea area = simClustering.preClusterHelper.getArea(pc);
263 ss << " PC: " << pc;
264 ss << " area: x (" << area.getXmin() << ", " << area.getXmax() << ")";
265 ss << " y (" << area.getYmin() << ", " << area.getYmax() << ")";
266 if (localX >= area.getXmin() && localX <= area.getXmax() &&
267 localY >= area.getYmin() && localY <= area.getYmax()) {
268 return true;
269 }
270 }
271 errorMsg = ss.str();
272 return false;
273}
274
275std::string getDebugInfo(const std::vector<GenTrack>& genTracks, Tracker& tracker, TrackLabeler& trackLabeler, const ROFRecord& rofTrack, const ROFRecord& rofCluster)
276{
277 std::stringstream debug;
278 for (size_t igen = 0; igen < genTracks.size(); ++igen) {
279 debug << "Gen: " << genTracks[igen].track << "\n hits:\n";
280 for (auto& hit : genTracks[igen].hits) {
281 debug << " " << hit << "\n";
282 }
283 debug << " clusters:\n";
284 for (size_t icl = rofCluster.firstEntry; icl < rofCluster.firstEntry + rofCluster.nEntries; ++icl) {
285 bool matches = false;
286 for (auto& label : trackLabeler.getTrackClustersLabels().getLabels(icl)) {
287 if (label.getTrackID() == igen) {
288 matches = true;
289 break;
290 }
291 }
292 if (matches) {
293 debug << " icl: " << icl << " " << tracker.getClusters()[icl] << "\n";
294 }
295 }
296 }
297
298 for (size_t itrack = rofTrack.firstEntry; itrack < rofTrack.firstEntry + rofTrack.nEntries; ++itrack) {
299 debug << "reco: " << tracker.getTracks()[itrack] << " matches: " << trackLabeler.getTracksLabels()[itrack].getTrackID();
300 debug << " clusters:\n";
301 for (int ich = 0; ich < 4; ++ich) {
302 int icl = tracker.getTracks()[itrack].getClusterMatched(ich);
303 debug << " icl: " << icl;
304 if (icl >= 0) {
305 debug << " " << tracker.getClusters()[icl];
306 for (auto& label : trackLabeler.getTrackClustersLabels().getLabels(icl)) {
307 debug << " ID: " << label.getTrackID() << " fires: [" << label.isFiredBP() << ", " << label.isFiredNBP() << "]";
308 }
309 debug << "\n";
310 }
311 }
312 }
313 return debug.str();
314}
315
316std::vector<int> getDEList()
317{
318 // The algorithm should work in the same way on all detection elements.
319 // Let us just sample the detection elements with different shape
320 // (2,6 are long, 3, 5 have a cut geometry and 4 is shorter w.r.t.
321 // the others in the same chamber plane)
322 // in the 4 different chamber planes (different dimensions)
323 std::vector<int> deList = {2, 3, 4, 5, 6, 20, 21, 22, 23, 24, 47, 48, 49, 50, 51, 65, 66, 67, 68, 69};
324 return deList;
325}
326
327BOOST_AUTO_TEST_SUITE(o2_mid_simulation)
328
329BOOST_DATA_TEST_CASE(MID_DigitMerger, boost::unit_test::data::make(getDEList()), deId)
330{
331 // Test the merging of the MC digits
332 size_t nEvents = 20;
333 std::vector<std::vector<ColumnData>> digitsCollection;
334 std::vector<o2::dataformats::MCTruthContainer<MCLabel>> mcContainerCollection;
335 std::vector<ColumnData> digits;
337 std::vector<ROFRecord> rofRecords;
338 for (size_t ievent = 0; ievent < nEvents; ++ievent) {
339 // Generate digits per event. Each event has a different timestamp
340 auto hits = generateHits(1, deId, simBase.mapping, simBase.geoTrans);
341 digitsCollection.push_back({});
342 mcContainerCollection.push_back({});
343 simDigitizer.digitizer.process(hits, digitsCollection.back(), mcContainerCollection.back());
344 rofRecords.emplace_back(o2::constants::lhc::LHCBunchSpacingNS * ievent, EventType::Standard, digits.size(), digitsCollection.back().size());
345 std::copy(digitsCollection.back().begin(), digitsCollection.back().end(), std::back_inserter(digits));
346 mcContainer.mergeAtBack(mcContainerCollection.back());
347 }
348 simDigitizer.digitsMerger.process(digits, mcContainer, rofRecords);
349
350 BOOST_TEST(simDigitizer.digitsMerger.getROFRecords().size() == rofRecords.size());
351 auto rofMCIt = rofRecords.begin();
352 auto rofIt = simDigitizer.digitsMerger.getROFRecords().begin();
353 for (; rofIt != simDigitizer.digitsMerger.getROFRecords().end(); ++rofIt) {
354 // Check that input and output event information are the same
355 BOOST_TEST(rofIt->interactionRecord == rofMCIt->interactionRecord);
356 BOOST_TEST(static_cast<int>(rofIt->eventType) == static_cast<int>(rofMCIt->eventType));
357 // Check that the merged digits are less than the input ones
358 BOOST_TEST(rofIt->nEntries <= rofMCIt->nEntries);
359 ++rofMCIt;
360 }
361}
362
363BOOST_DATA_TEST_CASE(MID_Digitizer, boost::unit_test::data::make(getDEList()), deId)
364{
365 // In this test we generate hits, digitize them and test that the MC labels are correctly assigned
366 auto hits = generateHits(10, deId, simBase.mapping, simBase.geoTrans);
367 std::vector<ColumnData> digitStoreMC;
369 std::vector<ROFRecord> rofRecords;
370 simDigitizer.digitizer.process(hits, digitStoreMC, digitLabelsMC);
371 rofRecords.emplace_back(1, EventType::Standard, 0, digitStoreMC.size());
372 // We check that we have as many sets of labels as digits
373 BOOST_TEST(digitStoreMC.size() == digitLabelsMC.getIndexedSize());
374 for (size_t idig = 0; idig < digitLabelsMC.getIndexedSize(); ++idig) {
375 auto labels = digitLabelsMC.getLabels(idig);
376 auto digit = digitStoreMC[idig];
377 // Then for each label we check that the parameters correctly identify the digit
378 for (auto label : labels) {
379 std::string errorMessage;
380 BOOST_TEST(checkLabel(digit, label, errorMessage), errorMessage.c_str());
381 }
382 }
383
384 // We then test the merging of the hits
385
386 simDigitizer.digitsMerger.process(digitStoreMC, digitLabelsMC, rofRecords);
387 // The number of merged digits should be smaller than the number of input digits
388 BOOST_TEST(simDigitizer.digitsMerger.getColumnData().size() <= digitStoreMC.size());
389 // We check that we have as many sets of labels as digits
390 BOOST_TEST(simDigitizer.digitsMerger.getColumnData().size() == simDigitizer.digitsMerger.getMCContainer().getIndexedSize());
391 // We check that we do not discard any label in the merging
392 BOOST_TEST(simDigitizer.digitsMerger.getMCContainer().getNElements() == digitLabelsMC.getNElements());
393 for (auto digit : digitStoreMC) {
394 bool isMergedDigit = false;
395 for (auto col : simDigitizer.digitsMerger.getColumnData()) {
396 if (digit.deId == col.deId && digit.columnId == col.columnId) {
398 isMergedDigit = true;
399 // Finally we check that all input patterns are contained in the merged ones
400 for (int iline = 0; iline < 4; ++iline) {
401 BOOST_TEST(((digit.getBendPattern(iline) & col.getBendPattern(iline)) == digit.getBendPattern(iline)));
402 }
403 BOOST_TEST(((digit.getNonBendPattern() & col.getNonBendPattern()) == digit.getNonBendPattern()));
404 }
405 }
406 // Check that all digits get merged
407 BOOST_TEST(isMergedDigit);
408 }
409}
410
411BOOST_DATA_TEST_CASE(MID_SingleCluster, boost::unit_test::data::make(getDEList()), deId)
412{
413 // In this test, we generate reconstruct one single hit.
414 // If the hit is in the RPC, the digitizer will return a list of strips,
415 // that are close to each other by construction.
416 // We will therefore have exactly one reconstructed cluster.
417 // It is worth noting, however, that the clustering algorithm is designed to
418 // produce two clusters if the BP and NBP do not overlap.
419 // The digitizer produces superposed BP and NBP strips only if the response parameters
420 // are the same for both.
421 // Otherwise we can have from 1 to 3 clusters produced.
422
423 std::vector<ColumnData> digitStoreMC;
425 std::vector<ROFRecord> rofRecords;
426
427 for (int ievent = 0; ievent < 100; ++ievent) {
428 auto hits = generateHits(1, deId, simBase.mapping, simBase.geoTrans);
429 std::stringstream ss;
430 int nGenClusters = 1, nRecoClusters = 0;
431 simDigitizer.digitizer.process(hits, digitStoreMC, digitLabelsMC);
432 rofRecords.clear();
433 rofRecords.emplace_back(o2::constants::lhc::LHCBunchSpacingNS * ievent, EventType::Standard, 0, digitStoreMC.size());
434 simDigitizer.digitsMerger.process(digitStoreMC, digitLabelsMC, rofRecords);
435 simClustering.preClusterizer.process(getColumnDataNonMC(simDigitizer.digitsMerger), simDigitizer.digitsMerger.getROFRecords());
436 simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords());
437 nRecoClusters = simClustering.clusterizer.getClusters().size();
438 ss << "nRecoClusters: " << nRecoClusters << " nGenClusters: " << nGenClusters << "\n";
439 for (auto& col : simDigitizer.digitsMerger.getColumnData()) {
440 ss << col << "\n";
441 }
442 ss << "\n Clusters:\n";
443 for (auto& cl : simClustering.clusterizer.getClusters()) {
444 ss << cl << "\n";
445 }
446
447 BOOST_TEST(simClustering.clusterizer.getROFRecords().size() == rofRecords.size());
448
449 int nColumns = simDigitizer.digitsMerger.getColumnData().size();
450
451 if (simDigitizer.params.getParB(0, deId) == simDigitizer.params.getParB(1, deId) && nColumns <= 2) {
452 BOOST_TEST((nRecoClusters == nGenClusters), ss.str());
453 } else {
454 BOOST_TEST((nRecoClusters >= nGenClusters && nRecoClusters <= nColumns), ss.str());
455 }
456 }
457}
458
459BOOST_DATA_TEST_CASE(MID_SimClusters, boost::unit_test::data::make(getDEList()), deId)
460{
461 // In this test, we generate few hits, reconstruct the clusters
462 // and verify that the MC labels are correctly assigned to the clusters
463
464 std::vector<ColumnData> digitStoreMC, digitsAccum;
466 std::vector<ROFRecord> digitsROF;
467 std::vector<std::vector<Hit>> hitsCollection;
468
469 for (int ievent = 0; ievent < 100; ++ievent) {
470 auto hits = generateHits(10, deId, simBase.mapping, simBase.geoTrans);
471 hitsCollection.emplace_back(hits);
472 simDigitizer.digitizer.process(hits, digitStoreMC, digitLabelsMC);
473 digitsROF.emplace_back(o2::constants::lhc::LHCBunchSpacingNS * ievent, EventType::Standard, digitsAccum.size(), digitStoreMC.size());
474 std::copy(digitStoreMC.begin(), digitStoreMC.end(), std::back_inserter(digitsAccum));
475 digitLabelsAccum.mergeAtBack(digitLabelsMC);
476 }
477 simDigitizer.digitsMerger.process(digitsAccum, digitLabelsAccum, digitsROF);
478 simClustering.preClusterizer.process(getColumnDataNonMC(simDigitizer.digitsMerger), simDigitizer.digitsMerger.getROFRecords());
479 simClustering.correlation.clear();
480 simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords());
481 simClustering.preClusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simDigitizer.digitsMerger.getMCContainer(), simClustering.preClusterizer.getROFRecords(), simDigitizer.digitsMerger.getROFRecords());
482 // Check that all pre-clusters have a label
483 BOOST_TEST(simClustering.preClusterizer.getPreClusters().size() == simClustering.preClusterLabeler.getContainer().getIndexedSize());
484 // Check that the pre-clusters contain the hits from which they were generated
485 for (size_t ievent = 0; ievent < hitsCollection.size(); ++ievent) {
486 for (auto& hit : hitsCollection[ievent]) {
487 auto pt = simBase.geoTrans.globalToLocal(hit.GetDetectorID(), hit.middlePoint());
488 // Check only the NBP, since in the BP we can have 1 pre-cluster per column
489 auto sortedPC = getRelatedPreClusters(hit, 1, simClustering.preClusterizer.getPreClusters(), simClustering.preClusterLabeler.getContainer(), simClustering.preClusterizer.getROFRecords()[ievent]);
490 // Check that there is only 1 pre-cluster in the NBP
491 // CAVEAT: this is valid as far as we do not have masked strips
492 BOOST_TEST(sortedPC.size() == 1);
493 std::string errorMsg;
494 BOOST_TEST(isInside(pt.x(), pt.y(), sortedPC, errorMsg), errorMsg.c_str());
495 }
496 }
497
498 simClustering.clusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterLabeler.getContainer(), simClustering.clusterizer.getClusters(), simClustering.correlation);
499 // Check that all clusters have a label
500 BOOST_TEST(simClustering.clusterizer.getClusters().size() == simClustering.clusterLabeler.getContainer().getIndexedSize());
501
502 for (auto pair : simClustering.correlation) {
503 // std::string errorMsg;
504 // const auto& cl(clusters[pair.first]);
505 // std::vector<PreCluster> sortedPC{ preClusters[pair.second] };
506 // Test that the cluster is inside the associated pre-cluster
507 // BOOST_TEST(isInside(cl.xCoor, cl.yCoor, sortedPC, errorMsg), errorMsg.c_str());
508 // Test that the cluster has all pre-clusters labels
509 for (auto& pcLabel : simClustering.preClusterLabeler.getContainer().getLabels(pair[1])) {
510 bool isInLabels = false;
511 for (auto& label : simClustering.clusterLabeler.getContainer().getLabels(pair[0])) {
512 if (label.compare(pcLabel) == 1) {
513 isInLabels = true;
514 bool isFired = (simClustering.preClusterizer.getPreClusters()[pair[1]].cathode == 0) ? label.isFiredBP() : label.isFiredNBP();
515 // Test that the fired flag is correctly set
516 BOOST_TEST(isFired);
517 break;
518 }
519 }
520 BOOST_TEST(isInLabels);
521 }
522 }
523}
524
525BOOST_DATA_TEST_CASE(MID_SimTracks, boost::unit_test::data::make({1, 2, 3, 4, 5, 6, 7, 8, 9}), nTracks)
526{
527 // In this test, we generate tracks and we reconstruct them.
528 // It is worth noting that in this case we do not use the default digitizer
529 // But rather a digitizer with a cluster size of 0.
530 // The reason is that, with the current implementation of the digitizer,
531 // which has to be further fine-tuned,
532 // we can have very large clusters, of few local-boards/columns.
533 // In this case the resolution is rather bad, and this impacts the tracking performance,
534 // even when the tracking algorithm has no bugs.
535 // The aim of this test is to check that the algorithms work.
536 // The tracking performance and tuning of the MC will be done in the future via dedicated studies.
537
538 std::vector<ColumnData> digitStoreMC, digitsAccum;
540 std::vector<ROFRecord> digitsROF;
541 std::vector<std::vector<GenTrack>> genTrackCollection;
542
543 // In the tracking algorithm, if we have two tracks that are compatible within uncertainties
544 // we keep only one of the two. This is done to avoid duplicated tracks.
545 // In this test we can have many tracks in the same event.
546 // If two tracks are close, they can give two reconstructed tracks compatible among each others,
547 // within their uncertainties. One of the two is therefore rejected.
548 // However, the track might not be compatible with the (rejected) generated track that has no uncertainty.
549 // To avoid this, compare adding a factor 2 in the sigma cut.
550 float chi2Cut = simTracking.tracker.getSigmaCut() * simTracking.tracker.getSigmaCut();
551
552 unsigned long int nGood = 0, nUntagged = 0, nTaggedNonCompatible = 0, nReconstructible = 0, nFakes = 0;
553
554 for (size_t ievent = 0; ievent < 100; ++ievent) {
555 auto genTracks = generateTracks(nTracks);
556 std::vector<Hit> hits;
557 for (auto& genTrack : genTracks) {
558 std::copy(genTrack.hits.begin(), genTrack.hits.end(), std::back_inserter(hits));
559 if (genTrack.isReconstructible()) {
561 }
562 }
563 genTrackCollection.emplace_back(genTracks);
564
565 simDigitizer.digitizerNoClusterSize.process(hits, digitStoreMC, digitLabelsMC);
566 digitsROF.emplace_back(o2::constants::lhc::LHCBunchSpacingNS * ievent, EventType::Standard, digitsAccum.size(), digitStoreMC.size());
567 std::copy(digitStoreMC.begin(), digitStoreMC.end(), std::back_inserter(digitsAccum));
568 digitLabelsAccum.mergeAtBack(digitLabelsMC);
569 }
570
571 simDigitizer.digitsMerger.process(digitsAccum, digitLabelsAccum, digitsROF);
573 simClustering.correlation.clear();
574 simClustering.clusterizer.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterizer.getROFRecords());
575 simClustering.preClusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simDigitizer.digitsMerger.getMCContainer(), simClustering.preClusterizer.getROFRecords(), simDigitizer.digitsMerger.getROFRecords());
576 simClustering.clusterLabeler.process(simClustering.preClusterizer.getPreClusters(), simClustering.preClusterLabeler.getContainer(), simClustering.clusterizer.getClusters(), simClustering.correlation);
577 simTracking.tracker.process(simClustering.clusterizer.getClusters(), simClustering.clusterizer.getROFRecords());
578 simTracking.trackLabeler.process(simTracking.tracker.getClusters(), simTracking.tracker.getTracks(), simClustering.clusterLabeler.getContainer());
579
580 // For the moment we save all clusters
581 BOOST_TEST(simTracking.tracker.getClusters().size() == simClustering.clusterizer.getClusters().size());
582 BOOST_TEST(simTracking.tracker.getTracks().size() == simTracking.trackLabeler.getTracksLabels().size());
583 BOOST_TEST(simTracking.tracker.getClusters().size() == simTracking.trackLabeler.getTrackClustersLabels().getIndexedSize());
584 BOOST_TEST(simTracking.tracker.getTrackROFRecords().size() == digitsROF.size());
585
586 // Test that all reconstructible tracks are reconstructed
587 for (size_t ievent = 0; ievent < genTrackCollection.size(); ++ievent) {
588 auto firstTrack = simTracking.tracker.getTrackROFRecords()[ievent].firstEntry;
589 auto nTracks = simTracking.tracker.getTrackROFRecords()[ievent].nEntries;
590 std::string debugInfo = "";
591 for (size_t igen = 0; igen < genTrackCollection[ievent].size(); ++igen) {
592 bool isReco = false;
593 auto ids = getCompatibleGenTrackIds(igen, genTrackCollection[ievent]);
594 for (size_t itrack = firstTrack; itrack < firstTrack + nTracks; ++itrack) {
595 auto label = simTracking.trackLabeler.getTracksLabels()[itrack];
596 bool checkReco = false;
597 if (label.isFake()) {
598 checkReco = true;
599 }
600 for (auto& id : ids) {
601 if (label.getTrackID() == id) {
602 checkReco = true;
603 break;
604 }
605 }
606 if (checkReco) {
607 if (simTracking.tracker.getTracks()[itrack].isCompatible(genTrackCollection[ievent][igen].track, chi2Cut)) {
608 isReco = true;
609 break;
610 }
611 }
612 }
613 std::stringstream ss;
614 ss << "Gen ID: " << igen << " isReconstructible: " << genTrackCollection[ievent][igen].isReconstructible() << " != isReco " << isReco;
615 if (debugInfo.empty()) {
616 debugInfo = getDebugInfo(genTrackCollection[ievent], simTracking.tracker, simTracking.trackLabeler, simTracking.tracker.getTrackROFRecords()[ievent], simTracking.tracker.getClusterROFRecords()[ievent]);
617 }
618 ss << "\n"
619 << debugInfo;
620 BOOST_TEST(isReco == genTrackCollection[ievent][igen].isReconstructible(), ss.str().c_str());
621 } // loop on generated tracks
622
623 // Perform some statistics
624 for (size_t itrack = firstTrack; itrack < firstTrack + nTracks; ++itrack) {
625 auto label = simTracking.trackLabeler.getTracksLabels()[itrack];
626 if (label.isEmpty()) {
627 ++nUntagged;
628 continue;
629 }
630 if (label.isFake()) {
631 ++nFakes;
632 continue;
633 }
634 const Track& matchedGenTrack(genTrackCollection[ievent][label.getTrackID()].track);
635 if (simTracking.tracker.getTracks()[itrack].isCompatible(matchedGenTrack, chi2Cut)) {
636 ++nGood;
637 } else {
639 }
640 int nMatched = 0;
641 for (int ich = 0; ich < 4; ++ich) {
642 int trClusIdx = simTracking.tracker.getTracks()[itrack].getClusterMatched(ich);
643 if (trClusIdx < 0) {
644 continue;
645 }
646 for (auto& trClusterLabel : simTracking.trackLabeler.getTrackClustersLabels().getLabels(trClusIdx)) {
647 if (trClusterLabel.getTrackID() == label.getTrackID()) {
648 ++nMatched;
649 }
650 }
651 }
652 BOOST_TEST(nMatched >= 3);
653 } // loop on reconstructed tracks
654 } // loop on event
655 std::stringstream outMsg;
656 outMsg << "Tracks per event: " << nTracks << " fraction of good: " << static_cast<double>(nGood) / static_cast<double>(nReconstructible) << " untagged: " << static_cast<double>(nUntagged) / static_cast<double>(nReconstructible) << " tagged but not compatible: " << static_cast<double>(nTaggedNonCompatible) / static_cast<double>(nReconstructible) << " fake: " << static_cast<double>(nFakes) / static_cast<double>(nReconstructible);
657
658 BOOST_TEST_MESSAGE(outMsg.str().c_str());
659}
660
661BOOST_AUTO_TEST_SUITE_END()
662
663} // namespace mid
664} // namespace o2
Parameters for MID RPC response.
ClusterLabeler for MID.
Strip pattern (aka digits)
Reconstructed MID cluster.
Reconstructed MID track.
Hit for MID.
Digits merger for MID.
Geometry transformer for MID.
Hit finder for MID.
Header to collect LHC related constants.
Mapping for MID.
Cluster reconstruction algorithm for MID.
Digitizer for MID.
Track reconstruction algorithm for MID.
Pre-clusters helper for MID.
PreClusterLabeler for MID.
Pre-cluster reconstruction algorithm for MID.
uint16_t pos
Definition RawData.h:3
uint32_t col
Definition RawData.h:4
Fast track generator for MID.
Tracks labeler for MID.
std::ostringstream debug
int GetTrackID() const
Definition BaseHits.h:30
A container to hold and manage MC truth information/labels.
gsl::span< TruthElement > getLabels(uint32_t dataindex)
void mergeAtBack(MCTruthContainer< TruthElement > const &other)
double getParB(int cathode, int deId) const
void process(gsl::span< const PreCluster > preClusters, const o2::dataformats::MCTruthContainer< MCCompLabel > &inMCContainer, gsl::span< const Cluster > clusters, gsl::span< const std::array< size_t, 2 > > correlations)
const o2::dataformats::MCTruthContainer< MCClusterLabel > & getContainer()
Clusterizing algorithm for MID.
Definition Clusterizer.h:38
const std::vector< Cluster > & getClusters()
Gets the vector of reconstructed clusters.
Definition Clusterizer.h:55
const std::vector< ROFRecord > & getROFRecords()
Gets the vector of clusters RO frame records.
Definition Clusterizer.h:58
bool init(std::function< void(size_t, size_t)> func=[](size_t, size_t) {})
void process(gsl::span< const PreCluster > preClusters, bool accumulate=false)
void process(const std::vector< Hit > &hits, std::vector< ColumnData > &digitStore, o2::dataformats::MCTruthContainer< MCLabel > &mcContainer)
const std::vector< ColumnData > & getColumnData() const
Gets the merged column data.
void process(const std::vector< ColumnData > &inDigitStore, const o2::dataformats::MCTruthContainer< MCLabel > &inMCContainer, const std::vector< ROFRecord > &inROFRecords, bool mergeInBunchPileup=true)
Merges the MC digits that are provided per hit into the format that we expect from data.
const o2::dataformats::MCTruthContainer< MCLabel > & getMCContainer() const
Gets the merged MC labels.
const std::vector< ROFRecord > & getROFRecords() const
Gets the merged RO frame records.
math_utils::Point3D< T > localToGlobal(int deId, const math_utils::Point3D< T > &position) const
math_utils::Point3D< T > globalToLocal(int deId, const math_utils::Point3D< T > &position) const
Class to find the impact point of a track on the chamber.
Definition HitFinder.h:31
std::vector< Cluster > getLocalPositions(const Track &track, int chamber, bool withUncertainties=false) const
static int getStrip(int strip, int line)
Gets the strip.
Definition MCLabel.h:81
MpStripIndex stripByPosition(double xPos, double yPos, int cathode, int deId, bool warn=true) const
Definition Mapping.cxx:592
MpArea getArea(const PreCluster &pc) const
const o2::dataformats::MCTruthContainer< MCCompLabel > & getContainer()
void process(gsl::span< const PreCluster > preClusters, const o2::dataformats::MCTruthContainer< MCLabel > &inMCContainer, gsl::span< const ROFRecord > rofRecordsPC, gsl::span< const ROFRecord > rofRecordsData)
Pre-clustering algorithm for MID.
const std::vector< ROFRecord > & getROFRecords()
Gets the vector of pre-clusters RO frame records.
void process(gsl::span< const ColumnData > stripPatterns, bool accumulate=false)
const std::vector< PreCluster > & getPreClusters()
Gets the vector of reconstructed pre-clusters.
Class to generate tracks for MID.
std::vector< Track > generate()
void setSeed(unsigned int seed)
Sets the seed.
const o2::dataformats::MCTruthContainer< MCClusterLabel > & getTrackClustersLabels()
Returns the cluster labels.
void process(gsl::span< const Cluster > clusters, gsl::span< const Track > tracks, const o2::dataformats::MCTruthContainer< MCClusterLabel > &inMCContainer)
const std::vector< MCCompLabel > & getTracksLabels()
Returns the tracks labels.
This class defines the MID track.
Definition Track.h:30
Tracking algorithm for MID.
Definition Tracker.h:34
const std::vector< ROFRecord > & getClusterROFRecords()
Gets the vector of cluster RO frame records.
Definition Tracker.h:57
bool init(bool keepAll=false)
Definition Tracker.cxx:38
void process(gsl::span< const Cluster > clusters, bool accumulate=false)
Definition Tracker.cxx:109
const std::vector< Cluster > & getClusters()
Gets the array of associated clusters.
Definition Tracker.h:51
float getSigmaCut() const
Gets number of sigmas for cuts.
Definition Tracker.h:41
const std::vector< Track > & getTracks()
Gets the array of reconstructes tracks.
Definition Tracker.h:48
const std::vector< ROFRecord > & getTrackROFRecords()
Gets the vector of tracks RO frame records.
Definition Tracker.h:54
GLuint GLuint end
Definition glcorearb.h:469
GLuint * ids
Definition glcorearb.h:647
const GLdouble * v
Definition glcorearb.h:832
GLenum const GLfloat * params
Definition glcorearb.h:272
GLboolean * data
Definition glcorearb.h:298
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
constexpr double LHCBunchSpacingNS
o2::track::TrackParCov Track
std::unique_ptr< const o2::dataformats::MCTruthContainer< MCLabel > > getLabels(framework::ProcessingContext &pc, std::string_view dataBind)
BOOST_TEST_MESSAGE("Fraction of fake tracks: "<<(double) nTotFakes/(double) nTotReconstructible)
std::vector< int > getDEList()
std::vector< std::vector< GenTrack > > genTrackCollection
unsigned long int nReconstructible
std::vector< ROFRecord > digitsROF
ChamberResponseParams createDefaultChamberResponseParams()
o2::dataformats::MCTruthContainer< MCLabel > digitLabelsAccum
bool checkLabel(const ColumnData &digit, MCLabel &label, std::string &errorMessage)
Digitizer createDefaultDigitizer()
ChamberEfficiencyResponse createDefaultChamberEfficiencyResponse()
std::vector< ColumnData > getColumnDataNonMC(const o2::mid::DigitsMerger &dm)
BOOST_DATA_TEST_CASE(MID_DigitMerger, boost::unit_test::data::make(getDEList()), deId)
std::string getDebugInfo(const std::vector< GenTrack > &genTracks, Tracker &tracker, TrackLabeler &trackLabeler, const ROFRecord &rofTrack, const ROFRecord &rofCluster)
std::vector< size_t > getCompatibleGenTrackIds(size_t igen, const std::vector< GenTrack > &genTracks)
bool isInside(double localX, double localY, const std::vector< PreCluster > &sortedPC, std::string &errorMsg)
ChamberHV createDefaultChamberHV()
Creates the default chamber voltages.
Definition ChamberHV.cxx:65
std::mt19937 mt(rd())
std::vector< Hit > generateHits(size_t nHits, int deId, const Mapping &mapping, const GeometryTransformer geoTrans)
std::uniform_real_distribution< float > distX(-127.5, 127.5)
o2::dataformats::MCTruthContainer< MCLabel > digitLabelsMC
unsigned long int nGood
unsigned long int nUntagged
std::uniform_real_distribution< float > distY(-68., 68.)
Digitizer createDigitizerNoClusterSize()
std::vector< GenTrack > generateTracks(int nTracks)
BOOST_TEST(clusters.size()==clusterizer.getClusters().size())
GeometryTransformer createDefaultTransformer()
std::vector< Cluster > clusters
bool isContiguous(const std::vector< PreCluster > &sortedPC)
unsigned long int nFakes
gsl::span< const PreCluster > preClusters(preClusterizer.getPreClusters().data(), preClusterizer.getPreClusters().size())
unsigned long int nTaggedNonCompatible
std::stringstream outMsg
std::vector< PreCluster > getRelatedPreClusters(const Hit &hit, int cathode, const std::vector< PreCluster > &preClusters, const o2::dataformats::MCTruthContainer< MCCompLabel > &labels, const ROFRecord &rofRecord)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Column data structure for MID.
Definition ColumnData.h:29
uint8_t columnId
Column in DE.
Definition ColumnData.h:31
bool isStripFired(int istrip, int cathode, int line) const
uint8_t deId
Index of the detection element.
Definition ColumnData.h:30
std::vector< Hit > hits
bool isValid()
Check if Strip is Valid.
Definition Mapping.h:36
GeometryTransformer geoTrans
PreClusterHelper preClusterHelper
std::vector< std::array< size_t, 2 > > correlation
PreClusterLabeler preClusterLabeler
PreClusterizer preClusterizer
ClusterLabeler clusterLabeler
ChamberResponseParams params
TrackGenerator trackGen
const int nEvents
Definition test_Fifo.cxx:27
std::random_device rd
std::vector< Digit > digits