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) {
126 math_utils::Point3D<float> point(distX(mt), distY(mt), 0.);
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.
std::ostringstream debug
Geometry transformer for MID.
Hit finder for MID.
std::vector< o2::MCCompLabel > labels
std::vector< o2::its::TrackITS > tracks
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.
int GetTrackID() const
Definition BaseHits.h:30
A container to hold and manage MC truth information/labels.
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
GLint ref
Definition glcorearb.h:291
o2::track::TrackParCov Track
std::unique_ptr< const o2::dataformats::MCTruthContainer< MCLabel > > getLabels(framework::ProcessingContext &pc, std::string_view dataBind, EventType eventType=EventType::Standard)
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
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