Project
Loading...
Searching...
No Matches
AlignableDetectorITS.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
16
20#include "Align/Controller.h"
21#include "Align/AlignConfig.h"
27#include "ITStracking/IOUtils.h"
28#include <TMath.h>
29#include <cstdio>
30
31using namespace TMath;
32using namespace o2::align::utils;
33
34namespace o2
35{
36namespace align
37{
38
39//____________________________________________
46
47/*
48//____________________________________________
49void AlignableDetectorITS::initGeom()
50{
51 if (getInitGeomDone()) {
52 return;
53 }
54 defineVolumes();
55 AlignableDetector::initGeom();
56}
57*/
58//____________________________________________
60{
61 // define ITS volumes
62 //
64
65 AlignableVolume *volITS = nullptr, *volLr = nullptr, *volHB = nullptr, *volSt = nullptr, *volHSt = nullptr, *volMod = nullptr;
66 AlignableSensorITS* sens = nullptr;
67 //
68 std::unordered_map<std::string, AlignableVolume*> sym2vol;
69 addVolume(volITS = new AlignableVolume(geom->composeSymNameITS(), getDetLabel(), mController));
70 sym2vol[volITS->getSymName()] = volITS;
71 //
72 int nonSensCnt = 0;
73 for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) {
74 for (int ihb = 0; ihb < geom->getNumberOfHalfBarrels(); ihb++) {
75 addVolume(volLr = new AlignableVolume(geom->composeSymNameHalfBarrel(ilr, ihb), getNonSensLabel(nonSensCnt++), mController));
76 sym2vol[volLr->getSymName()] = volLr;
77 volLr->setParent(volITS);
78 int nstavesHB = geom->getNumberOfStaves(ilr) / 2;
79 for (int ist = 0; ist < nstavesHB; ist++) {
80 addVolume(volSt = new AlignableVolume(geom->composeSymNameStave(ilr, ihb, ist), getNonSensLabel(nonSensCnt++), mController));
81 sym2vol[volSt->getSymName()] = volSt;
82 volSt->setParent(volLr);
83 for (int ihst = 0; ihst < geom->getNumberOfHalfStaves(ilr); ihst++) {
84 addVolume(volHSt = new AlignableVolume(geom->composeSymNameHalfStave(ilr, ihb, ist, ihst), getNonSensLabel(nonSensCnt++), mController));
85 sym2vol[volHSt->getSymName()] = volHSt;
86 volHSt->setParent(volSt);
87 for (int imd = 0; imd < geom->getNumberOfModules(ilr); imd++) {
88 addVolume(volMod = new AlignableVolume(geom->composeSymNameModule(ilr, ihb, ist, ihst, imd), getNonSensLabel(nonSensCnt++), mController));
89 sym2vol[volMod->getSymName()] = volMod;
90 volMod->setParent(volHSt);
91 } // module
92 } //halfstave
93 } // stave
94 } // layer halfBarrel
95 } // layer
96
97 for (int ich = 0; ich < geom->getNumberOfChips(); ich++) {
99 if (ich != chID) {
100 throw std::runtime_error(fmt::format("mismatch between counter {} and composed {} chip IDs", ich, chID));
101 }
103 int lay = 0, hba, sta = 0, ssta = 0, modd = 0, chip = 0;
104 geom->getChipId(chID, lay, hba, sta, ssta, modd, chip);
105 AlignableVolume* parVol = sym2vol[modd < 0 ? geom->composeSymNameStave(lay, hba, sta) : geom->composeSymNameModule(lay, hba, sta, ssta, modd)];
106 if (!parVol) {
107 throw std::runtime_error(fmt::format("did not find parent for chip {}", chID));
108 }
109 sens->setParent(parVol);
110 }
111 //
112}
113
114//____________________________________________
115int AlignableDetectorITS::processPoints(GIndex gid, int npntCut, bool inv)
116{
117 // Extract the points corresponding to this detector, recalibrate/realign them to the
118 // level of the "starting point" for the alignment/calibration session.
119 // If inv==true, the track propagates in direction of decreasing tracking X
120 // (i.e. upper leg of cosmic track)
121 //
122 auto algTrack = mController->getAlgTrack();
123 auto recoData = mController->getRecoContainer();
124 const auto& algConf = AlignConfig::Instance();
125 int npoints = 0;
126 auto procClus = [this, inv, &npoints, &algTrack](const ClusterD& clus) {
127 auto* sensor = this->getSensor(clus.getSensorID());
128 auto& pnt = algTrack->addDetectorPoint();
129 const auto* sysE = sensor->getAddError(); // additional syst error
130 pnt.setYZErrTracking(clus.getSigmaY2() + sysE[0] * sysE[0], clus.getSigmaYZ(), clus.getSigmaZ2() + sysE[1] * sysE[1]);
131 if (this->getUseErrorParam()) { // errors will be calculated just before using the point in the fit, using track info
132 pnt.setNeedUpdateFromTrack();
133 }
134 pnt.setXYZTracking(clus.getX(), clus.getY(), clus.getZ());
135 pnt.setSensor(sensor);
136 pnt.setAlphaSens(sensor->getAlpTracking());
137 pnt.setXSens(sensor->getXTracking());
138 pnt.setDetID(this->mDetID);
139 pnt.setSID(sensor->getSID());
140 pnt.setContainsMeasurement();
141 pnt.setInvDir(inv);
142 pnt.init();
143 npoints++;
144 };
145 std::array<int, 7> clusIDs{};
146 int nOverlaps = 0;
147 if (gid.getSource() == GIndex::ITS) {
148 const auto tracks = recoData->getITSTracks();
149 if (tracks.empty()) {
150 return -1; // source not loaded?
151 }
152 const auto& track = tracks[gid.getIndex()];
153 if (track.getNClusters() < npntCut) {
154 return -1;
155 }
156 const auto& clusIdx = recoData->getITSTracksClusterRefs();
157 // do we want to apply some cuts?
158 int clEntry = track.getFirstClusterEntry();
159 int preevSensID = -1;
160 bool errReported = false;
161 for (int icl = track.getNumberOfClusters(); icl--;) { // clusters refs are stored from outer to inner layers, we loop in inner -> outer direction
162 const auto& clus = mITSClustersArray[(clusIDs[npoints] = clusIdx[clEntry + icl])];
163 if (clus.getSensorID() < preevSensID && !errReported) { // clusters are ordered from outer to inner layer, hence decreasing sensorID
164 std::string errstr{};
165 for (int ie = track.getNumberOfClusters(); ie--;) {
166 errstr += fmt::format(" {}", mITSClustersArray[clusIdx[clEntry + ie]].getSensorID());
167 }
168 LOGP(error, "wrong ITS clusters order? : chips {}", errstr);
169 errReported = true;
170 }
171 preevSensID = clus.getSensorID();
172 if (clus.getBits()) { // overlapping clusters will have bit set
173 if (clus.isBitSet(EdgeFlags::Biased)) {
174 continue;
175 }
176 if (clus.getCount()) {
177 nOverlaps++;
178 }
179 }
180 procClus(clus);
181 }
182 } else { // ITSAB
183 const auto& trkITSABref = recoData->getITSABRefs()[gid.getIndex()];
184 const auto& ABTrackClusIdx = recoData->getITSABClusterRefs();
185 int nCl = trkITSABref.getNClusters();
186 int clEntry = trkITSABref.getFirstEntry();
187 for (int icl = 0; icl < nCl; icl++) { // clusters are stored from inner to outer layers
188 const auto& clus = mITSClustersArray[(clusIDs[npoints] = ABTrackClusIdx[clEntry + icl])];
189 if (clus.getBits()) { // overlapping clusters will have bit set
190 if (clus.isBitSet(EdgeFlags::Biased)) {
191 continue;
192 }
193 if (clus.getCount()) {
194 nOverlaps++;
195 }
196 }
197 procClus(clus);
198 }
199 }
200 if (npoints < npntCut) { // reset points to original start
201 algTrack->suppressLastPoints(npoints);
202 npoints = 0;
203 return 0;
204 }
205
206 // do we need to process overlaps?
207 if (nOverlaps) {
209 trcProp.resetCovariance(10);
210 auto propagator = o2::base::Propagator::Instance();
211 for (int icl = 0; icl < npoints; icl++) {
212 const auto& clus = mITSClustersArray[clusIDs[icl]];
213 float alp = getSensor(clus.getSensorID())->getAlpTracking();
214 if (!trcProp.rotate(alp) ||
215 !propagator->propagateToX(trcProp, clus.getX(), propagator->getNominalBz(), algConf.maxSnp, algConf.maxStep, base::Propagator::MatCorrType(algConf.matCorType)) ||
216 !trcProp.update(clus)) {
217 break;
218 }
219
220 if (clus.getCount()) { // there is an overlap, find best matching cluster
221 nOverlaps--;
222 int bestClusID = -1, clusIDtoCheck = mOverlapClusRef[mITSClustersArray.flatIndex(clusIDs[icl])];
223 float bestChi2 = algConf.ITSOverlapMaxChi2;
224 auto trPropOvl = trcProp;
225 for (int iov = 0; iov < clus.getCount(); iov++) {
226 int clusOvlID = mOverlapCandidateID[clusIDtoCheck];
227 const auto& clusOvl = mITSClustersArray[clusOvlID];
228 if (iov == 0) {
229 if (!trPropOvl.rotate(getSensor(clusOvl.getSensorID())->getAlpTracking()) ||
230 !propagator->propagateToX(trPropOvl, clusOvl.getX(), propagator->getNominalBz(), algConf.maxSnp, algConf.maxStep, base::Propagator::MatCorrType::USEMatCorrNONE)) {
231 break;
232 }
233 }
234 auto chi2 = trPropOvl.getPredictedChi2(clusOvl);
235 if (chi2 < bestChi2) {
236 bestChi2 = chi2;
237 bestClusID = clusOvlID;
238 }
239 }
240 if (bestClusID != -1) { // account overlapping cluster
241 procClus(mITSClustersArray[bestClusID]);
242 }
243 }
244 if (!nOverlaps) {
245 break;
246 }
247 }
248 }
249 mNPoints += npoints;
250 return npoints;
251}
252
253//____________________________________________
255{
256 // prepare TF data for processing: convert clusters
257 const auto& algConf = AlignConfig::Instance();
258 auto recoData = mController->getRecoContainer();
259 int nLr = recoData->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1;
260 mITSClustersArray.init(nLr);
261 if (algConf.ITSOverlapMargin > 0) {
262 mOverlapClusRef.clear();
263 mOverlapCandidateID.clear();
264 }
265 static std::vector<int> edgeClusters;
266 int ROFCount = 0;
267 int16_t curSensID = -1;
268 struct ROFChipEntry {
269 int16_t rofCount = -1;
270 int chipFirstEntry = -1;
271 };
272 std::array<ROFChipEntry, o2::itsmft::ChipMappingITS::getNChips()> chipROFStart{}; // fill only for clusters with overlaps
273
274 for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0
275 mITSClustersArray.beginLayer(lr);
276 const auto clusITS = recoData->getITSClusters(lr);
277 const auto clusITSROF = recoData->getITSClustersROFRecords(lr);
278 const auto patterns = recoData->getITSClustersPatterns(lr);
279 auto pattIt = patterns.begin();
280 const int clOffs = mITSClustersArray.getFirstIndex(lr); // flat index of the 1st cluster of this layer slot
281 mITSClustersArray.getClusters().reserve(clOffs + clusITS.size());
282 if (algConf.ITSOverlapMargin > 0) {
283 mOverlapClusRef.resize(clOffs + clusITS.size(), -1);
284 mOverlapCandidateID.reserve(clOffs + clusITS.size());
285 }
286
287 for (const auto& rof : clusITSROF) {
288 int maxic = rof.getFirstEntry() + rof.getNEntries();
289 edgeClusters.clear();
290 for (int ic = rof.getFirstEntry(); ic < maxic; ic++) {
291 const auto& c = clusITS[ic];
292 int16_t sensID = c.getSensorID();
293 auto* sensor = getSensor(sensID);
294 double sigmaY2, sigmaZ2, sigmaYZ = 0, locXYZC[3], traXYZ[3];
295 auto pattItCopy = pattIt;
296 auto locXYZ = o2::its::ioutils::extractClusterDataA(c, pattIt, mITSDict, sigmaY2, sigmaZ2); // local ideal coordinates
297 const auto& matAlg = sensor->getMatrixClAlg(); // local alignment matrix !!! RS FIXME
298 matAlg.LocalToMaster(locXYZ.data(), locXYZC); // aligned point in the local frame
299 const auto& mat = sensor->getMatrixT2L(); // RS FIXME check if correct
300 mat.MasterToLocal(locXYZC, traXYZ);
301 auto& cl3d = mITSClustersArray.getClusters().emplace_back(sensID, traXYZ[0], traXYZ[1], traXYZ[2], sigmaY2, sigmaZ2, sigmaYZ); // local --> tracking
302
303 if (algConf.ITSOverlapMargin > 0) {
304 // fill chips overlaps info for clusters whose center is within of the algConf.ITSOverlapMargin distance from the chip min or max row edge
305 // but the pixel closest to this edge has distance of at least algConf.ITSOverlapEdgeRows from the edge
306 int row = 0, col = 0;
308 int drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? row : o2::itsmft::SegmentationAlpide::NRows - row - 1; // distance to the edge
309 if (drow * o2::itsmft::SegmentationAlpide::PitchRow < algConf.ITSOverlapMargin) { // rough check is passed, check if the edge cluster is indeed good
310 cl3d.setBit(row < o2::itsmft::SegmentationAlpide::NRows / 2 ? EdgeFlags::LowRow : EdgeFlags::HighRow); // flag that this is an edge cluster and indicate the low/high row side
311 // check if it is not too close to the edge (to be biased)
312 if (algConf.ITSOverlapEdgeRows > 0) { // is there a restriction?
313 auto pattID = c.getPatternID();
314 drow = c.getRow();
316 if (!mITSDict->isGroup(pattID)) {
317 const auto& patt = mITSDict->getPattern(pattID); // reference pixel is min row/col corner
319 drow = o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() - 1);
320 }
321 } else { // group: reference pixel is the one containing the COG
322 o2::itsmft::ClusterPattern patt(pattItCopy);
323 drow = row < o2::itsmft::SegmentationAlpide::NRows / 2 ? drow - patt.getRowSpan() / 2 : o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() / 2 - 1);
324 }
325 } else {
326 o2::itsmft::ClusterPattern patt(pattItCopy); // reference pixel is min row/col corner
328 drow = o2::itsmft::SegmentationAlpide::NRows - 1 - (drow + patt.getRowSpan() - 1);
329 }
330 }
331 if (drow < algConf.ITSOverlapEdgeRows) { // too close to the edge, flag this
332 cl3d.setBit(EdgeFlags::Biased);
333 }
334 }
335 if (!cl3d.isBitSet(EdgeFlags::Biased)) {
336 if (chipROFStart[sensID].rofCount != ROFCount) { // remember 1st entry
337 chipROFStart[sensID].rofCount = ROFCount;
338 chipROFStart[sensID].chipFirstEntry = edgeClusters.size(); // remember 1st entry of edge cluster for this chip
339 }
340 edgeClusters.push_back(clOffs + ic);
341 }
342 }
343 }
344 } // clusters of ROF
345 // relate edge clusters of ROF to each other
346 int prevSensID = -1;
347 for (auto ic : edgeClusters) { // ic is the flat cluster index here
348 auto& cl = mITSClustersArray.getClusters()[ic];
349 int sensID = cl.getSensorID();
350 auto ovl = mOverlaps[sensID];
351 int ovlCount = 0;
352 for (int ir = 0; ir < OVL::NSides; ir++) {
353 if (ovl.rowSide[ir] == OVL::NONE) { // no overlap from this row side
354 continue;
355 }
356 int chipOvl = ovl.rowSide[ir]; // look for overlaps with this chip
357 // are there clusters with overlaps on chipOvl?
358 if (chipROFStart[chipOvl].rofCount == ROFCount) {
359 auto oClusID = edgeClusters[chipROFStart[chipOvl].chipFirstEntry];
360 while (oClusID < int(mITSClustersArray.size())) {
361 auto oClus = mITSClustersArray.getClusters()[oClusID];
362 if (oClus.getSensorID() != sensID) {
363 break; // no more clusters on the overlapping chip
364 }
365 if (oClus.isBitSet(ovl.rowSideOverlap[ir]) && // make sure that the edge cluster is on the right side of the row
366 !oClus.isBitSet(EdgeFlags::Biased) && // not too close to the edge
367 std::abs(oClus.getZ() - cl.getZ()) < algConf.ITSOverlapMaxDZ) { // apply fiducial cut on Z distance of 2 clusters
368 // register overlaping cluster
369 if (!ovlCount) { // 1st overlap
371 }
372 mOverlapCandidateID.push_back(o2::itsmft::composeClusID(lr, oClusID - clOffs)); // store the composed ID
373 ovlCount++;
374 }
375 oClusID++;
376 }
377 }
378 }
379 cl.setCount(std::min(127, ovlCount));
380 }
381
382 ROFCount++;
383 } // loop over ROFs
384 } // loop over the layer slots
385 mITSClustersArray.finalize();
386 return true;
387}
388
389//____________________________________________
390void AlignableDetectorITS::Print(const Option_t* opt) const
391{
393}
394
395//____________________________________________
396void AlignableDetectorITS::SetAddErrorLr(int ilr, double sigY, double sigZ)
397{
398 // set syst. errors for specific layer
400 int chMin = geom->getFirstChipIndex(ilr), chMax = geom->getLastChipIndex(ilr);
401 for (int isn = chMin; isn <= chMax; isn++) {
402 getSensor(isn)->setAddError(sigY, sigZ);
403 }
404}
405
406//____________________________________________
408{
409 // exclude sensor of the layer from alignment
411 int chMin = geom->getFirstChipIndex(ilr), chMax = geom->getLastChipIndex(ilr);
412 for (int isn = chMin; isn <= chMax; isn++) {
413 getSensor(isn)->setSkip();
414 }
415}
416
417//_________________________________________________
419{
420 // set type of points error parameterization // RS DO WE NEED THIS?
422}
423
424//_________________________________________________
426{
427 // update point using specific error parameterization
428 // the track must be in the detector tracking frame
429 //TODO RS
430 /*
431 const AlignableSensor* sens = pnt->getSensor();
432 int vid = sens->getVolID();
433 double angPol = ATan(t.getTgl());
434 double angAz = ASin(t.getSnp());
435 double errY, errZ;
436 GetErrorParamAngle(lr, angPol, angAz, errY, errZ);
437 const double* sysE = sens->getAddError(); // additional syst error
438 //
439 pnt->setYZErrTracking(errY * errY + sysE[0] * sysE[0], 0, errZ * errZ + sysE[1] * sysE[1]);
440 pnt->init();
441 */
442 //
443}
444
445} // namespace align
446} // namespace o2
Configuration file for global alignment.
ITS detector wrapper.
Base class of alignable volume.
Steering class for the global alignment.
Wrapper container for different reconstructed object types.
Definition of the ClusterTopology class.
Definition of the GeometryTGeo class.
float chi2
std::vector< o2::its::TrackITS > tracks
uint32_t col
Definition RawData.h:4
uint32_t c
Definition RawData.h:2
Definition of the ITS track.
Reference on ITS/MFT clusters set.
o2::itsmft::ClustersPerLayer< ClusterD > mITSClustersArray
void updatePointByTrackInfo(AlignmentPoint *pnt, const trackParam_t *t) const override
int processPoints(GIndex gid, int npntCut, bool inv) final
std::vector< o2::itsmft::ChipMappingITS::Overlaps > mOverlaps
void Print(const Option_t *opt="") const override
void SetAddErrorLr(int ilr, double sigY, double sigZ)
const o2::itsmft::TopologyDictionary * mITSDict
AlignableSensor * getSensor(int id) const
virtual void addVolume(AlignableVolume *vol)
void Print(const Option_t *opt="") const override
void setAddError(double y, double z)
void setParent(AlignableVolume *par)
const char * getSymName() const
GTrackID getCurrentTrackID() const
const o2::globaltracking::RecoContainer * getRecoContainer() const
Definition Controller.h:200
AlignmentTrack * getAlgTrack() const
Definition Controller.h:198
Controller * mController
Definition DOFSet.h:73
static const char * getSymbolicName(o2::detectors::DetID detid, int sensid)
static int getSensID(o2::detectors::DetID detid, int sensid)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:180
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:60
static GeometryTGeo * Instance()
static constexpr int getNChips()
number of chips per barrel
std::vector< Overlaps > getOverlapsInfo() const
Collect all FEEIDs for one layer (lr>=0) or all (lr==-1)
int getRowSpan() const
Returns the number of rows.
static constexpr unsigned short InvalidPatternID
Definition CompCluster.h:46
static constexpr float PitchRow
static void localToDetectorUnchecked(float xRow, float zCol, int &iRow, int &iCol)
same but w/o check for row/column range
const ClusterPattern & getPattern(int n) const
Returns the pattern of the topology.
bool isGroup(int n) const
Returns true if the element corresponds to a group of rare topologies.
const GLdouble * v
Definition glcorearb.h:832
typename track::TrackParametrizationWithError< double > trackParam_t
Definition utils.h:29
constexpr int MaxITSLayers
std::array< T, 3 > extractClusterDataA(const itsmft::CompClusterExt &c, iterator &iter, const itsmft::TopologyDictionary *dict, T &sig2y, T &sig2z)
Definition IOUtils.h:63
constexpr int composeClusID(int lr, int idx)
Definition ClusterID.h:37
void align(gsl::span< ElinkEncoder< BareFormat, CHARGESUM > > elinks)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
o2::InteractionRecord ir(0, 0)
std::vector< int > row